IoT devices (a.k.a., Things) aren’t very interesting if they cannot interact with the world around them. As Makers, we need to hook up sensors, light up LEDs, and communicate with other devices that are wired up to our Things. To do this, we need IO functionality that can be programmed.
GPIO (General Purpose Input/Output) refers to a set of generic pins of a microcontroller that can be used for digital signaling. GPIO pins can be individually set to act as input or output, and values can be either logically high (1) or low (0).
The voltage value is ideally set to VCC for high and GND for low. But, the underlying technology determines the actual acceptable logic levels. For example, 3v3 CMOS commonly accepts anything above 2V as being high and anything below 0.8V as being logical low. Notice the range from 0.8 to 2V – this is the land of undefined logic, where unpredictable read results will occur from chip to chip.
GPIO on the ESP8266-12
While the ESP8266EX microcontroller itself has 17 GPIO pins, only 11 are available on the ESP8266-12 module because the chip is already connected to external SPI flash memory using some of the pins.
GPIO on the ESP8266EX is multiplexed with other functions, which may limit the availability of pins for GPIO usage. So, for example, while HSPI is enabled, the pins for GPIO12-15 are unavailable for GPIO use, and when you need to connect to the module via the UART, then GPIO1 and GPIO3 are unavailable for GPIO use.
All digital I/O pins are protected from over-voltage by means of a snap-back circuit between the pin and ground. The output devices are also protected from reverse voltages with diodes. This suggests that the ESP may be 5V-tolerant, but official guidance from Espressif says to stick to 3.3V to prevent damaging the chip. Note: I have accidentally connected 5V to my ESP’s GPIO without any noticeable damage.
The available pins in NodeMCU include:
|1||10||X||X||X||The is the TXD0 pin by default|
|3||9||X||X||X||This is the RXD0 pin by default|
|4||2||X||X||X||Caution: Sometimes misidentified as #5|
|5||1||X||X||X||Caution: Sometimes misidentified as #4|
|12||6||X||X||X||This is the HSPI MISO pin|
|13||7||X||X||X||This is the HSPI MOSI pin|
|14||5||X||X||X||This is the HSPI CLK pin|
|15||8||X||X||X||This is the HSPI CSn pin|
|16||0||X||X||X||Belongs to the RTC module, not the general GPIO module, so behaves differently|
Note: The “ID” column shows the IO index that is used to identify GPIO pins in the Lua function calls. Yep, it’s confusing for everybody else, too… unless you happen to use the NodeMCU DevKit, and then the indexes are the same as the “Dx” pins that are labeled here: DevKit 1.0 Pinouts
Note: During reset, certain pins must be pulled high/low with an external resistor so that the chip enters the correct boot mode. For normal operations, GPIO1=1, GPIO2=1, GPIO15=0
Programming GPIO in NodeMCU (ESP8266)
First, the obvious: you will need a NodeMCU firmware image that includes the “gpio” module. Otherwise, you won’t have the API available to program against.
Let’s suppose that we want to add a button to our Thing that the user can press. So, we need to determine the default logic level for when the button is not pressed, and then the opposite logic level would represent when it is being pressed.
Default logic is often set by means of a pull-up or pull-down resistor. This is a relatively high value resistor (2k to 10k Ohm) that bridges the GPIO pin to either VCC (pulling the value up) or GND (pulling the value down).
A switch then will connect that GPIO to the opposite voltage. When the switch is not engaged, the only path from the GPIO pin is through the resistor, so you’ll get a 1 or 0 as a result (depending on whether the resistor leads to VCC or GND, respectively). But, when the switch is pressed, the path of least resistance goes through the switch, so you get its value instead.
Most of the GPIO pins on the ESP8266 have an internal pull-up resistor that can be enabled (GPIO16 is the oddball, because it actually belongs to a different part of the silicon than the rest of the GPIO). This means that we don’t need any external resistors in order to set a default value because it can be controlled programmatically. So, we configure the GPIO to be pulled high (default value=1), wire up a switch between the GPIO pin and GND (switched pressed=0), and our requirements are satisfied.
From the table above, the index for GPIO5 is 1, so that needs to be provided in any function call that works with GPIO5:
> gpio.mode(1, gpio.INPUT, gpio.PULLUP)
> = gpio.read(1) -- button not pressed
> = gpio.read(1) -- button is pressed
> = gpio.read(1) -- button not pressed
How about controlling a LED? The ESP cannot source much current, but it can sink current to ground. So, hook a resistor (i.e., 300 ohm) between VCC and the anode (long lead) of a LED, then connect the cathode (short lead) of the LED to a GPIO pin. When a “1” is written to the pin, the LED will be off. When a “0” is written to the pin, the LED will light up.
> gpio.write(2,gpio.HIGH) -- LED OFF
> gpio.write(2,gpio.LOW) -- LED ON
And finally, how can we detect a change in a GPIO without constantly polling the value? For example, suppose that we want to turn the light on when the user presses the button.
To do this, we need to take advantage of the interrupts for GPIO. Once set up, a callback function will execute when the state of the GPIO pin changes. Note: Interrupts are not supported for that weird GPIO16 pin (index=0).
> gpio.mode(1, gpio.INT, gpio.PULLUP)
> gpio.trig(1, "both", function(level)
>> gpio.write(2, level)
Documentation for the NodeMCU API can be found here: http://nodemcu.readthedocs.org/en/dev/en/modules/gpio/
If you are interested in seeing details about the lower-level C SDK API provided by Espressif, then look at this document: 8A_ESP8266_Interface_GPIO_EN_v0.5.pdf
Also published on Medium.
Latest posts by Falafel Posts (see all)
- Matching Complex Query String Rewrite Rule in IIS - March 22, 2017
- Using Google Services in UWP C# Apps – Part 2 - February 7, 2017
- Using Google Services in UWP C# Apps – Part 1 - February 6, 2017
- Redis Caching in the Google Cloud Platform - February 3, 2017
- Entity Framework with Google Cloud SQL - February 2, 2017