Chapter 4 Analog & PWM

In previous study, we have known that one button has two states: pressed and released, and LED has light-on/off state, then how to enter a middle state? How to output an intermediate state to let LED “semi bright”? That’s what we’re going to learn.

First, let’s learn how to control the brightness of a LED.

Project 4.1 Breathing LED

Breathing light, that is, LED is turned from off to on gradually, and gradually from on to off, just like “breathing”. So, how to control the brightness of a LED? We will use PWM to achieve this target.

Component List

ESP32-WROVER x1

Chapter01_00

GPIO Extension Board x1

Chapter01_01

Breadboard x1

Chapter01_02

LED x1

Chapter01_03

Resistor 220Ω x1

Chapter01_04

Jumper M/M x2

Chapter01_05

Circuit

This circuit is the same as the one in engineering Blink.

Schematic diagram

Chapter04_02

Hardware connection

If you need any support, please feel free to contact us via: support@freenove.com

Chapter04_03

Code

This project is designed to make PWM output GPIO2 with pulse width increasing from 0% to 100%, and then reducing from 100% to 0% gradually.

Move the program folder “Freenove_Ultimate_Starter_Kit_for_ESP32/Python/Python_Codes” to disk(D) in advance with the path of “D:/Micropython_Codes”.

Open “Thonny”, click”This computer” -> “D:” -> “Micropython_Codes” -> “04.1_BreatheLight” and double click “BreatheLight.py”.

04.1_BreatheLight

../../../_images/Chapter04_08.png

Click “Run current script”, and you’ll see that LED is turned from ON to OFF and then back from OFF to ON gradually like breathing.

../../../_images/Chapter04_09.png

The following is the program code:

 1from machine import Pin,PWM
 2import time
 3
 4pwm =PWM(Pin(2),10000)
 5try:
 6    while True:
 7        for i in range(0,1023):
 8            pwm.duty(i)
 9            time.sleep_ms(1)
10
11        for i in range(0,1023):
12            pwm.duty(1023-i)
13            time.sleep_ms(1)  
14except:
15    pwm.deinit()

The way that the ESP32 PWM pins output is different from traditionally controllers. It can change frequency and duty cycle by configuring PWM’s parameters at the initialization stage. Define GPIO2’s output frequency as 10000Hz, and assign them to PWM.

1pwm =PWM(Pin(2),10000)

The range of duty cycle is 0-1023, so we use the first for loop to control PWM to change the duty cycle value, making PWM output 0% -100%; Use the second for loop to make PWM output 100%-0%.

1for i in range(0,1023):
2    pwm.duty(i)
3    time.sleep_ms(1)
4
5for i in range(0,1023):
6    pwm.duty(1023-i)
7    time.sleep_ms(1)  

Each time PWM is used, the hardware Timer will be turned ON to cooperate it. Therefore, after each use of PWM, deinit() needs to be called to turned OFF the timer. Otherwise, the PWM may fail to work next time.

1pwm.deinit()

Reference

Class PWM(pin, freq)

Before each use of PWM module, please add the statement “from machine import PWM” to the top of the python file.

pin: PWM pins are supported, such as Pin(0)、Pin(2)、Pin(4)、Pin(5)、Pin(10)、Pin(12~19)、Pin(21)、Pin(22)、Pin(23)、Pin(25~27).

freq: Output frequency, with the range of 0-78125 Hz

duty: Duty cycle, with the range of 0-1023.

PWM.init(freq, duty): Initialize PWM, parameters are the same as above.

PWM.freq([freq_val]): When there is no parameter, the function obtains and returns PWM frequency; When parameters are set, the function is used to set PWM frequency and returns nothing.

PWM.duty([duty_val]): When there is no parameter, the function obtains and returns PWM duty cycle; When parameters are set, the function is used to set PWM duty cycle.

PWM.deinit(): Turn OFF PWM.

Project 4.2 Meteor Flowing Light

After learning about PWM, we can use it to control LED Bar Graph and realize a cooler Flowing Light.

Component List

ESP32-WROVER x1

Chapter01_00

GPIO Extension Board x1

Chapter01_01

Breadboard x1

Chapter01_02

Jumper M/M x10

Chapter01_05

Resistor 220Ω x10

Chapter01_04

LED bar graph x1

Chapter03_00

Circuit

Schematic diagram

Chapter04_10

Hardware connection

If you need any support, please feel free to contact us via: support@freenove.com

Chapter04_11

If LED bar does not work, try to rotate it for 180°. The label is random.

Code

Flowing Light with tail was implemented with PWM.

Open “Thonny”, click “This computer” -> “D:” -> “Micropython_Codes” -> “04.2_FlowingLight”. Select”pwm.py”, right click to select “Upload to /”, wait for “pwm.py” to be uploaded to ESP32-WROVER and then double click “FlowingLight.py”

04.2_FlowingLight

../../../_images/Chapter04_12.png

Click “Run current script”, and LED Bar Graph will gradually light up and out from left to right, then light up and out from right to left.

The following is the program code:

 1from machine import Pin,PWM
 2from pwm import myPWM
 3import time
 4
 5mypwm = myPWM(15,2,0,4,5,18,19,21)
 6chns=[0,1,2,3,4,5,6,7];
 7dutys=[0,0,0,0,0,0,0,0,1023,512,256,128,64,32,16,8,0,0,0,0,0,0,0,0];
 8delayTimes=50
 9
10try:
11    while True:
12        for i in range(0,16):
13            for j in range(0,8):
14                mypwm.ledcWrite(chns[j],dutys[i+j])
15            time.sleep_ms(delayTimes)
16
17        for i in range(0,16):
18            for j in range(0,8):
19                mypwm.ledcWrite(chns[7-j],dutys[i+j])
20            time.sleep_ms(delayTimes)
21except:
22    mypwm.deinit()

Import the object myPWM from pwm.py and set corresponding pins for PWM channel.

1from pwm import myPWM
2......
3mypwm = myPWM(15,2,0,4,5,18,19,21)

First we defined 8 GPIO, 8 PWM channels, and 24 pulse width values.

1mypwm = myPWM(15,2,0,4,5,18,19,21)
2chns=[0,1,2,3,4,5,6,7];
3dutys=[0,0,0,0,0,0,0,0,1023,512,256,128,64,32,16,8,0,0,0,0,0,0,0,0];

Call ledcWrite()to set duty cycle dutys[i+j] for the chns[j] channel of PWM.

1mypwm.ledcWrite(chns[j],dutys[i+j])

Close the PWM of the object myPWM.

1mypwm.deinit()

In the code, a nesting of two for loops are used to achieve this effect.

1for i in range(0,16):
2    for j in range(0,8):
3        mypwm.ledcWrite(chns[j],dutys[i+j])
4    time.sleep_ms(delayTimes)
5
6for i in range(0,16):
7    for j in range(0,8):
8        mypwm.ledcWrite(chns[7-j],dutys[i+j])
9    time.sleep_ms(delayTimes)

In the main function, a nested for loop is used to control the pulse width of the PWM. Every time i in the first for loop increases by 1, the LED Bar Graph will move one grid, and gradually change according to the value in the array dutys. As shown in the following table, the value in the second row is the value of the array dutys, and the 8 green grids in each row below represent the 8 LEDs on the LED Bar Graph. Each time i increases by 1, the value of the LED Bar Graph will move to the right by one grid, and when it reaches the end, it will move from the end to the starting point, achieving the desired effect.

../../../_images/Chapter04_13.png

How to import a custom python module

Each Python file, as long as it’s stored on the file system of ESP32, is a module. To import a custom module, the module file needs to be located in the MicroPython environment variable path or in the same path as the currently running program.

First, customize a python module “custom.py”. Create a new py file and name it “custom.py”. Write code to it and save it to ESP32.

../../../_images/Chapter04_14.png

Second, import custom module “custom” to main.py

../../../_images/Chapter04_15.png