GPIO - uraich/IoT4AQ GitHub Wiki
Introduction
The most common interface to the outside world are General Purpose Input Output (GPIO) lines. These provide digital signals, which can either be driven by external hardware, in which case the CPU reads the signals, or it can be driven by the CPU, in which case it is used to control external devices.
GPIOs on the ESP32 CPU card
There are two devices, controlled by GPIO lines, which are already installed on the ESP32 DevKit CPU. Observing the CPU card attentively will show you that there are two LEDs (Light Emitting Diodes). The first one is the power LED which will light when power is applied to the board. The other one is marked "D2" indicating that it is connected to the GPIO 2 line on the CPU. Then there are 2 push buttons on the CPU card, one marked "EN", which resets the CPU when pushed, the other one marked "BOOT", which allows to put the CPU into flash programming mode. Usually it is not necessary to push the "BOOT" button, because a signal on the first serial port (we will see serial ports later) can be used for this purpose. "BOOT" is connected to GPIO 0 and can be used by user programs when the board is in normal running mode.
The user LED
An LED is connected to the CPU like this:
V+ is connected to the GPIO line, which is programmed as an output (the CPU defines the voltage level on the line). When the CPU writes a logic one to the line, 3.3V will appear at V+. This means that a current is flowing through the resistor and the LED and it lights up. If the CPU writes a logic zero, then the V+ lead is set to GND level and the LED is switched off.
Programming the LED
As we said, on the ESP32-DevKitC-32 ESPWROOM, which we use in our kit, the GPIO line 2 is connected to the user LED and must be programmed to be output. In fact almost all ESP32 CPU cards have a user programmable LED, which allows to quickly check if the CPU card works fine. However, different manufacturers connect this user LED to different GPIO lines. The Arduino defines a constant LED_BUILTIN which corresponds to the GPIO number to which the user LED is connected on the CPU card selected in the Arduino SDK. Programming the GPIO line to be input or output is done with the pinMode() function, setting a level on the GPIO line uses the digitalWrite() function. Programming the GPIO line then reads:
pinMode(LED_BUILTIN,OUTPUT);
This statement goes into the setup() function as it is executed only once.
Then we can set the line HIGH to put 3.3V onto it and switch on the LED:
digitalWrite(LED_BUILTIN,HIGH);
Wait for 500 ms:
delay(500);
and switch it off again.
digitalWrite(LED_BUILTIN,LOW);
delay(500);
These statements go into the loop() function and are repeated eternally, which make the LED blink at a rate of 1 Hz.
Dimming the LED
You may think that changing the light intensity on the LED is not possible. After all, the GPIO line can only take the states HIGH or LOW.
Instead of sending a constant level to the GPIO pin, you can send a frequency. Usually people use a 1 kHz signal. This signal can have a duty cycle (amount of time the signal is high with respect to the time it is low) which determines the amount of average current flowing through the LED. The human eye can only see a frequency of ~ 25 Hz and it will therefore not see the switching on and off of the LED, but only see the average light intensity. This principle is called Pulse Width Modulation (PWM). At its extremes, the duty cycle can be zero % in which case the LED is off or 100% in which case the LED is permanently supplied with 3.3V and the light intensity is at its maximum.
On the Arduino PWM is accessed by
analogWrite(LED_BUILTIN, duty); // duty can run from zero to 255
Reading a switch
A push button switch is usually connected as follows:
Since this is very common, the ESP32 incorporates pullup resistors that can be connected to the GPIO lines by program.
#define PUSH_BUTTON 0 // this is a pre-processor instruction defining the constant PUSH_BUTTON
// everywhere where PUSH_BUTTON appears in the source code, it will be replaced by 0
// this makes your program more readable since PUSH_BUTTON explains better what you are doing than "0"
pinMode(PUSH_BUTTON, INPUT_PULLUP); // The GPIO line 0 (PUSH_BUTTON) will be an input and a pull-up resistor will be attached
// if you want to program the line as input but without the pull-up use
// pinMode(PUSH_BUTTON, INPUT);
This code of course goes into setup() again, because it is executed only once. In loop() you may find something like this:
void loop() {
for (int i=0;i<100;i++) {
Serial.print(digitalRead(PUSH_BUTTON)); // reads the push button every 100 ms and print its state
}
Serial.println(); // go to the next line
}