In this article we’re going to take a look on how to interact with the ESP32 and ESP8266 GPIOs using MicroPython. We’ll show you how to read digital and analog inputs, how to control digital outputs and how to generate PWM signals.
To program the ESP32 and ESP8266 with MicroPython, we use uPyCraft IDE as a programming environment. Follow the next tutorials to install uPyCraft IDE and flash MicroPython firmware on your board:
- Install uPyCraft IDE: Windows PC, MacOS X, or Linux Ubuntu
- Flash/Upload MicroPython Firmware to ESP32 and ESP8266
Alternatively, if you’re having trouble using uPyCraftIDE, we recommend using Thonny IDE instead: Getting Started with Thonny MicroPython (Python) IDE for ESP32 and ESP8266
If this is your first time dealing with MicroPython you may find these next tutorials useful:
- Getting Started with MicroPython on ESP32 and ESP8266
- MicroPython Programming Basics with ESP32 and ESP8266
With this tutorial you’ll learn how to use the ESP32 or ESP8266 GPIOs with MicroPython. You can read the separate guide for each topic:
We’ll build a simple example that works as follows:
- Read the state of a pushbutton and set the LED state accordingly – when you press the pushbutton the LED lights up.
- Read the voltage from a potentiometer and dim an LED accordingly to the shaft’s position of the potentiometer.
The circuit for this project involves wiring two LEDs, a pushbutton, and a potentiometer. Here’s a list of all the parts needed to build the circuit:
- ESP32 or ESP8266 (read: ESP32 vs ESP8266)
- 2x LEDs
- 2x 330 Ohm resistor
- Jumper wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
ESP32 – Schematic
Follow the next schematic diagram if you’re using an ESP32:
Note: the ESP32 supports analog reading in several GPIOs: 0, 2, 4, 12, 13, 14, 15, 25, 26, 27 32, 33, 34, 35, 36, and 39.
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
ESP8266 – Schematic
Follow the next schematic diagram if you’re using an ESP8266:
Note: the ESP8266 only supports analog reading in pin ADC0 (A0).
Copy the following code to the main.py file in the uPyCraft IDE.
Note: analog reading works differently in ESP32 and ESP8266. The code works right away in ESP32. To use with ESP8266, you have to uncomment and comment the lines described in the MicroPython script.
# Complete project details at https://RandomNerdTutorials.com # Created by Rui Santos from machine import Pin, ADC, PWM from time import sleep led = Pin(2, Pin.OUT) button = Pin(15, Pin.IN) #Configure ADC for ESP32 pot = ADC(Pin(34)) pot.width(ADC.WIDTH_10BIT) pot.atten(ADC.ATTN_11DB) #Configure ADC for ESP8266 #pot = ADC(0) led_pwm = PWM(Pin(4),5000) while True: button_state = button.value() led.value(button_state) pot_value = pot.read() led_pwm.duty(pot_value) sleep(0.1)
How the code works
Continue reading to learn on how the code works.
To interact with the GPIOs you need to import the machine module that contains classes to interact with the GPIOs. Import the Pin class to interact with the pins, the ADC class to read analog value, and the PWM class to generate PWM signals.
from machine import Pin, ADC, PWM
Import the sleep() method from the time module. The sleep() method allows you to add delays to the code.
from time import sleep
After importing all the necessary modules, instantiate a Pin object called led on GPIO 2 that is an OUTPUT.
led = Pin(2, Pin.OUT)
The Pin object accepts the following attributes in the following order:
Pin(Pin number, pin mode, pull, value)
- Pin number refers to the GPIO we want to control;
- Pin mode can be input (IN), output (OUT) or open-drain (OPEN_DRAIN);
- The pull argument is used if we want to activate a pull up or pull down internal resistor (PULL_UP, or PULL_DOWN);
- The valuecorresponds to the GPIO state (if is is on or off): it can be 0 or 1 (True or False). Setting 1 means the GPIO is on. If we don’t pass any parameter, its state is 0 by default (that’s what we’ll do in this example).
After instantiating the led object, you need another instance of the Pin class for the pushbutton. The pushbutton is connected to GPIO 15 and it’s set as an input. So, it looks as follows:
button = Pin(15, Pin.IN)
In the ESP32, to create an ADC object for the potentiometer on GPIO 34:
pot = ADC(Pin(34))
If you’re using an ESP8266, it only supports ADC on ADC0 (A0) pin. To instantiate an ADC object with the ESP8266:
pot = ADC(0)
The following line applies just to the ESP32. It defines that we want to be able to read voltage in full range. This means we want to read voltage from 0 to 3.3 V.
The next line means we want readings with 10 bit resolution (from 0 to 1023)
The width() method accepts other parameters to set other resolutions:
- WIDTH_9BIT: range 0 to 511
- WIDTH_10BIT: range 0 to 1023
- WIDTH_11BIT: range 0 to 2047
- WIDTH_12BIT: range 0 to 4095
If you don’t specify the resolution, it will be 12-bit resolution by default on the ESP32.
Then, create a PWM object called led_pwm on GPIO 4 with 5000 Hz.
led_pwm = PWM(Pin(4), 5000)
To create a PWM object, you need to pass as parameters: pin, signal’s frequency, and duty cycle.
The frequency can be a value between 0 and 78125. A frequency of 5000 Hz for an LED works just fine.
The duty cycle can be a value between 0 and 1023. In which 1023 corresponds to 100% duty cycle (full brightness), and 0 corresponds to 0% duty cycle (unlit LED).
We’ll just set the duty in the while loop, so we don’t need to pass the duty cycle parameter at the moment. If you don’t set the duty cycle when instantiating the PWM object, it will be 0 by default.
Getting the GPIO state
Then, we have a while loop that is always True. This is similar to the loop() function in the Arduino IDE.
We start by getting the button state and save it in the button_state variable. To get the pin state use the value() method as follows:
button_state = button.value()
This returns 1 or 0 depending on whether the button is pressed or not.
Setting the GPIO state
To set the pin state, use the value(state) method in the Pin object. In this case we’re setting the button_state variable as an argument. This way the LED turns on when we press the pushbutton:
Reading analog inputs
To read an analog input, use the read() method on an ADC object (in this case the ADC object is called pot).
pot_value = pot.read()
Controlling duty cycle
To control the duty cycle, use the duty() method on the PWM object (led_pwm). The duty() method accepts a value between 0 and 1023 (in which 0 corresponds to 0% duty cycle, and 1023 to 100% duty cycle). So, pass as argument the pot_value (that varies between 0 and 1023). This way you change the duty cycle by rotating the potentiometer.
Testing the Code
Upload the main.py file to your ESP32 or ESP8266. For that, open uPyCraft IDE and copy the code provided to the main.py file. Go to Tools > Serial and select the serial port. Select your board in Tools > Board.
Then, upload the code to the ESP32 or ESP8266 by pressing the Download and Run button.
Note: to get you familiar with uPyCraft IDE youn can read the following tutorial – Getting Started with MicroPython on ESP32 and ESP8266
After uploading the code, press the ESP32/ESP8266 on-board EN/RST button to run the new script.
Now, test your setup. The LED should light up when you press the pushbutton.
The LED brightness changes when you rotate the potentiometer.
This simple example showed you how to read digital and analog inputs, control digital outputs and generate PWM signals with the ESP32 and ESP8266 boards using MicroPython.
If you like MicroPython, you may like the following projects:
- ESP32/ESP8266 MicroPython Interrrupts
- MicroPython: WS2812B Addressable RGB LEDs with ESP32/ESP8266
- Low Power Weather Station Datalogger using ESP8266 and BME280 with MicroPython
- ESP32/ESP8266 MicroPython Web Server
We hope you’ve found this article about how to control ESP32 and ESP8266 GPIOs with MicroPython useful. If you want to learn more about MicroPython, make sure you take a look at our eBook: MicroPython Programming with ESP32 and ESP8266.
Thanks for reading.