Basic use case
Light up the onboard LED lamp bead
After completing MicroPython runtime environment settings, you can try programming immediately.
Create a new main.py script file and enter the following code in it:
from machine import Pin
from neopixel import NeoPixel
import time
pin_48 = Pin(48)
np = NeoPixel(pin_48, 1, bpp=3, timing=1)
while True:
np[0] = (25,25,25)
np. write()
time. sleep_ms(250)
np[0] = (0,0,0)
np. write()
time. sleep_ms(250)
Save the file to the MicroPython device, click the "Run" button to make the onboard colored LED flash.
Modify the data in the tuple on the right side of np[0] = (25,25,25)
to change the color, which corresponds to the brightness levels of R, G, and B respectively. The setting range is 0-255, and the recommended range is 0-25. When the brightness is too high, please do not look directly at it for a long time!
neopixel — control of WS2812 / NeoPixel LEDs — MicroPython documentation
Make the lights cycle through nine colors
from machine import Pin
from neopixel import NeoPixel
import time
pin_48 = Pin(48, Pin.OUT)
np = NeoPixel(pin_48, 1, bpp=3, timing=1)
RED = (255, 0, 0)
ORANGE = (255, 100, 0)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
PURPLE = (180, 0, 255)
WHITE = (255, 255, 255)
OFF = (0, 0, 0)
color_list = [RED,ORANGE,YELLOW,GREEN,CYAN,BLUE,PURPLE,WHITE,OFF]
brightness = 0.1
while True:
for i in color_list:
color = (round(i[0]*brightness),round(i[1]*brightness),round(i[2]*brightness))
np[0] = color
np. write()
time. sleep(1)
Full-color LED lamp beads cycle display rainbow colors
Based on the previous section, we can go one step further and write a loop to automatically change the color of the lamp bead.
from machine import Pin
from neopixel import NeoPixel
import time
def rainbow(num=1,level=25,delay=100):
def write_all(num,delay,red,green,blue):
for j in range (num):
np[j] = (red,green,blue)
np. write()
time. sleep_ms(delay)
red,green,blue = level,0,0
rainbow_step_list2 = [(0,1,0),(-1,0,0),(0,0,1),(0,-1,0),(1,0,0),(0,0, -1)]
for step in rainbow_step_list2:
for i in range (level):
red+=step[0]
green+=step[1]
blue+=step[2]
write_all(num,delay,red,green,blue)
np = NeoPixel(Pin(48, Pin.OUT), 1,bpp=3, timing=1)
while True:
rainbow(num=1,level=25,delay=10)
This routine can be applied to ws2812 light strips of any length.
Modify the first parameter in NeoPixel(Pin(48, Pin.OUT), 1,bpp=3, timing=1)
to any GPIO pin that you want to connect the light strips in series.
Modify the num parameter in rainbow(num=1,level=25,delay=100)
to be the number of corresponding lamp beads on the light strip.
Of course, we can also use for loop or while loop to make the color change pattern we want according to our own ideas.
Design button interrupt program to control colored lights
BPI-Leaf-S3 has two buttons, BOOT and RST, RST controls the hardware reset of the chip, and BOOT is connected to GPIO0, the circuit is shown in the figure below.
It can be seen that when the development board is powered on and working normally, when the BOOT button is not pressed, GPIO0 is connected to 3.3v with a resistor in series, and it is at a high potential at this time. When the BOOT button is pressed, GPIO0 will be directly grounded, and at this time it is a low potential. The ESP32-S3 chip can determine whether the button is pressed by detecting the potential of this GPIO pin.
MicroPython GPIO interrupt program machine.Pin.irq documentation
In the program, by detecting the trigger mode of the GPIO interrupt, you can design a set of interrupt program that records the number of times the button is pressed, and control the color of the colored light by judging the number of times that the button has been pressed.
from machine import Pin
from neopixel import NeoPixel
from array import array
import time
import micropython
micropython.alloc_emergency_exception_buf(100)
p_48 = Pin(48, Pin.OUT)
np = NeoPixel(p_48, 1, bpp=3, timing=1)
p0 = Pin(0,Pin.IN,Pin.PULL_UP)
trig_locks = array('B',[0])
trig_timeticks_list = array('L',[0,0])
count = array('L',[0])
def p0_irq(pin):
if pin.value()==0 and trig_locks[0]==0:
trig_timeticks_list[0]=time.ticks_ms()
trig_locks[0]=1
elif pin.value()==1 and trig_locks[0]==1:
trig_timeticks_list[1]=time.ticks_diff(time.ticks_ms(),trig_timeticks_list[0])
trig_locks[0]=0
if trig_timeticks_list[1] >= 20:
count[0] = count[0] + 1
if count[0] > 8:
count[0] = 0
p0.irq(handler=p0_irq, trigger= Pin.IRQ_FALLING | Pin.IRQ_RISING )
RED = (255, 0, 0)
ORANGE = (255, 100, 0)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
PURPLE = (180, 0, 255)
WHITE = (255, 255, 255)
OFF = (0, 0, 0)
color_list = [RED,ORANGE,YELLOW,GREEN,CYAN,BLUE,PURPLE,WHITE,OFF]
brightness = 0.1
while True:
print (count)
i = color_list[count[0]]
color = (round(i[0]*brightness),round(i[1]*brightness),round(i[2]*brightness))
np[0] = color
np. write()
time. sleep(0.1)
PWM Single Color LED Breathing Light
External Hardware Requirements
A LED light that can work on 3.3v.
connection method
The GPIO13 pin is used in the routine, and the positive pole of the LED light is connected to the GPIO13 pin, and the negative pole is connected to GND.
Code
from machine import Pin, PWM
import time
PWM_LED = PWM(Pin(13))
PWM_LED.freq(1000)
PWM_LED. duty(0)
while True:
for i in range(0,1024,1):
PWM_LED. duty(i)
time. sleep_ms(2)
for i in range(1022,0,-1):
PWM_LED. duty(i)
time. sleep_ms(1)
TB6612FNG module PWM drive motor
External hardware requirements
A TB6612FNG module, a 3.3~5V DC motor.
connection method
TB6612FNG | BPI-Leaf-S3 |
---|---|
PWMA | 11 |
AIN2 | 13 |
AIN1 | 12 |
STBY | 10 |
VM | 5V |
VCC | 3.3V |
GND | GND |
AO1 | Motor N pole |
AO2 | Motor S pole |
The connection sequence between AO1/AO2 and the motor can be exchanged arbitrarily to change the direction of rotation.
running result
The motor will start to rotate in one direction and gradually accelerate to the maximum speed achievable by the current current within 7 seconds, then gradually decelerate to stop within 5 seconds, then reverse the rotation and repeat the process.
Code
from machine import Pin,PWM
import time
PWM_A = PWM(Pin(11)) #Set PWM output pin
PWM_A.freq(20000) #Set PWM frequency
PWM_A. duty(0) #Set PWM duty cycle
AIN1 = Pin(12,Pin.OUT)
AIN2 = Pin(13,Pin.OUT)
STBY = Pin(10,Pin.OUT)
STBY.on() #When STBY pin is at high level, TB6612FNG starts.
def MOTOR_Forward():
AIN1.on()
AIN2.off()
def MOTOR_Reverse():
AIN1.off()
AIN2.on()
while True:
MOTOR_Forward()
#for cycle is used to control the PWM duty cycle change.
#The PWM duty cycle control precision is 10bit, ie 0~1023.
#Some motors require a certain PWM duty cycle to start.
for i in range(350,1024,1):
PWM_A. duty(i)
time. sleep_ms(10)
for i in range(1022,0,-1):
PWM_A. duty(i)
time. sleep_ms(5)
MOTOR_Reverse()
for i in range(350,1024,1):
PWM_A. duty(i)
time. sleep_ms(10)
for i in range(1022,0,-1):
PWM_A. duty(i)
time. sleep_ms(5)
Use ADC to detect potentiometer voltage
External Hardware Requirements
a potentiometer.
ESP32-S3 ADC
The ESP32-S3 chip integrates two ADC analog-to-digital converters, the measurement range is 0mV-3100mV, and the resolution is 12bit, that is, 0mV-3100mV is divided into 2^12=4096 levels, and each level is a digital quantity .
The two ADC analog-to-digital converters each have 10 measurement channels, ADC1 is GPIO1 ~ 10, and ADC2 is GPIO11 ~ 20.
connection method
GND is connected to GND, VCC is connected to 3V3, the S output terminal is connected to GPIO11 pin, and channel 1 of ADC2 is used for measurement.
GPIO1~20 pins can be used as ADC input pins.
Code
from machine import Pin,ADC
import time
adc11 = ADC(Pin(11),atten=ADC.ATTN_11DB)
#adc11 = ADC(Pin(11))
#adc11.atten(ADC.ATTN_11DB)
while True:
read=adc11.read()
read_u16 = adc11.read_u16()
read_uv = adc11.read_uv()
print("read={0},read_u16={1},read_uv={2}".format(read,read_u16,read_uv))
time. sleep_ms(100)
Attenuation value | Measurable input voltage range |
---|---|
ADC.ATTN_0DB | 0 mV ~ 950 mV |
ADC.ATTN_2_5DB | 0 mV ~ 1250 mV |
ADC.ATTN_6DB | 0 mV ~ 1750 mV |
ADC.ATTN_11DB | 0 mV ~ 3100 mV |
ADC(*, atten)
initializes the ADC channel of a GPIO pin, and you can choose to useatten
to set the attenuation value, which controls the measurable input voltage range of the chip. If not set, it will be the default valueatten=ADC.ATTN_0DB
or the value set last time.- You can modify the attenuation value through
ADC.atten()
after initializing an ADC channel. ADC.read()
reads the ADC and returns the read result. The ADC of the ESP32-S3 chip returns data with 12-bit precision.ADC.read_u16()
reads the ADC and returns 16-bit data.ADC.read_uv()
returns the calibrated input voltage inuV
microvolts according to the characteristics of the ADC. Return values only havemV
millivolt resolution (ie, will always be in multiples of 1000 microvolts).
The WiFi function also uses ADC2, so trying to read analog values from ADC2's measurement channels GPIO11 ~ 20 while WiFi is active will throw an exception.
It is recommended to use ADC.read_uv()
to read the voltage value, which is a decimal constant returned after calibration according to the characteristics of the ADC analog-to-digital converter, which is more accurate than the other two reading methods. At the same time, it is also recommended to directly divide the operation when using: ADC.read_uv()//1000
to get the data of mV
millivolt resolution.
Directly print out ADC.read()
or ADC.read_u16()
to get the decimal value, you can use the hex()
function to convert the data type into hexadecimal, for example hex(ADC.read() )
, or use the bin()
function to convert the data type to binary.
Use the potentiometer to steplessly adjust the brightness of the colored lights
Building on the [Cycle Through Nine Colors] (#Cycle Through Nine Colors) section, you can use a potentiometer to control the brightness of the lights.
Code
from machine import Pin,ADC
from neopixel import NeoPixel
from array import array
import time
import micropython
adc1 = ADC(Pin(1),atten=ADC.ATTN_11DB)
micropython.alloc_emergency_exception_buf(100)
p_48 = Pin(48, Pin.OUT)
np = NeoPixel(p_48, 1, bpp=3, timing=1)
p0 = Pin(0,Pin.IN,Pin.PULL_UP)
trig_locks = array('B',[0])
trig_timeticks_list = array('L',[0,0])
count = array('L',[0])
def p0_irq(pin):
if pin.value()==0 and trig_locks[0]==0:
trig_timeticks_list[0]=time.ticks_ms()
trig_locks[0]=1
elif pin.value()==1 and trig_locks[0]==1:
trig_timeticks_list[1]=time.ticks_diff(time.ticks_ms(),trig_timeticks_list[0])
trig_locks[0]=0
if trig_timeticks_list[1] >= 20:
count[0] = count[0] + 1
if count[0] > 8:
count[0] = 0
p0.irq(handler=p0_irq, trigger= Pin.IRQ_FALLING | Pin.IRQ_RISING )
RED = (255, 0, 0)
ORANGE = (255, 100, 0)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
PURPLE = (180, 0, 255)
WHITE = (255, 255, 255)
OFF = (0, 0, 0)
color_list = [RED,ORANGE,YELLOW,GREEN,CYAN,BLUE,PURPLE,WHITE,OFF]
while True:
adc1_read = adc1.read() # 12bit
adc1_read_mv = adc1.read_uv()/1000
adc1_read_u16 = adc1.read_u16() # 16bit
brightness = adc1_read/4095
i = color_list[count[0]]
color = (round(i[0]*brightness),round(i[1]*brightness),round(i[2]*brightness))
np[0] = color
np. write()
print(adc1_read,adc1_read_u16,adc1_read_mv,"mv",count[0],color)
time. sleep(0.1)
Use the ADC to measure the potentiometer to adjust the motor speed
External Hardware Requirements
- Potentiometer x 1
- TB6612FNG motor driver module x 1
- 5v DC motor x 1
- some connecting wires
connection method
Potentiometer | BPI-Leaf-S3 |
---|---|
GND | GND |
VCC | 3V3 |
S | 14 |
TB6612FNG | BPI-Leaf-S3 |
---|---|
PWMA | 11 |
AIN2 | 13 |
AIN1 | 12 |
STBY | 10 |
VM | 5V |
VCC | 3.3V |
GND | GND |
TB6612FNG | Motor |
---|---|
AO1 | Motor N pole |
AO2 | Motor S pole |
running result
The development board will output the voltage value read by the ADC in the REPL at an interval of 100ms, in mv, and the corresponding controlled PWM duty cycle.
Adjust the potentiometer by hand to change its output voltage. The higher the voltage, the higher the PWM duty cycle output by the development board, and the faster the motor speed.
Code
from machine import Pin,ADC,PWM
import time
adc14 = ADC(Pin(14),atten=ADC.ATTN_11DB)
PWM_A = PWM(Pin(11)) #Set PWM output pin
PWM_A.freq(20000) #Set PWM frequency
PWM_A. duty(0) #Set PWM duty cycle
AIN1 = Pin(12,Pin.OUT)
AIN2 = Pin(13,Pin.OUT)
STBY = Pin(10,Pin.OUT)
AIN1.on() #MOTOR forward
AIN2.off()
STBY.on() #When STBY pin is at high level, TB6612FNG starts.
while True:
read_mv=adc14.read_uv()//1000
if read_mv <= 3000:
duty_set = int(1023/3000 * read_mv)
else:
duty_set = 1023
PWM_A. duty(duty_set)
Duty_cycle = int(duty_set/1023*100)
print("ADC_read={0}mv,Duty_cycle={1}%".format(read_mv,Duty_cycle))
time. sleep_ms(100)
UART serial data read and write
External Hardware Requirements
USB to UART module (CH340, CP2102, etc.).
Software Requirements
A serial port debugging software such as PuTTY, and the driver required for the USB to UART module.
Wiring Reference
Connect the BPI-Leaf-S3 development board to the computer via USB, connect the RX of the USB to UART module to GPIO17 (TX of BPI-Leaf-S3), connect TX to GPIO18 (RX of BPI-Leaf-S3), and connect GND to GND (common ground) ), the USB interface of the USB to UART module is connected to the computer, which can be the same computer connected to the BPI-Leaf-S3, or two different computers.
running result
In the MicroPython REPL of the computer where the BPI-Leaf-S3 is located, the data received from the USB to UART module will be output every second.
In the serial port debugging software window of the computer where the USB to UART module is located, it can be seen that a line of characters Hello World!
sent by BPI-Leaf-S3 is output every second.
Code
from machine import UART
import time
uart1 = UART(1, tx=17, rx=18)
# Select the UART interface and specify the pins used by TX and RX
uart1.init(115200, bits=8, parity=None, stop=1)
# Initialization, set the baud rate, set the number of characters, set the parity, set the stop bit
def test():
for i in range(50):
uart1.write('Hello World!') # write data
time. sleep(0.5)
print(uart1. read()) # read data
time. sleep(0.5)
test()
I²C, SSD1306 OLED display
The SSD1306 OLED screen module is a very common screen module that can use the I2C communication protocol. It can output a maximum image of 128*64 bits, no gray scale, and a single pixel only has two states of on and off. The control logic is relatively simple, which is very suitable for getting started. Learn the project of single-chip microcomputer driving screen display.
External Hardware Requirements
A SSD1306 OLED screen module with I²C interface, preferably 128*64 pixels.
Driver library download
After downloading ssd1306.py locally, upload it to the MicroPython device.
Wiring Reference
SSD1306 OLED | Board |
---|---|
GND | GND |
VCC | 3V3 |
SCL | 16 |
SDA | 15 |
Scan I²C address
from machine import I2C,Pin
sda_pin=Pin(15,Pin. PULL_UP)
scl_pin=Pin(16,Pin. PULL_UP)
i2c = I2C(1,sda=sda_pin, scl=scl_pin, freq=400_000)
i2c_list = i2c.scan()
i2c_total=len(i2c_list)
print("Total num:",i2c_total)
j=0
for i in i2c_list:
j=j+1
print("NO.{0},address:{1}".format(j,hex(i)))
Usually the address of SSD1306 is 0x3c.
Display characters
MicroPython framebuf documentation
from machine import I2C, Pin
from ssd1306 import SSD1306_I2C
sda_pin = Pin(15, Pin.PULL_UP)
scl_pin = Pin(16, Pin.PULL_UP)
i2c = I2C(1, sda=sda_pin, scl=scl_pin, freq=800_000)
print(i2c. scan())
oled = SSD1306_I2C(128, 64, i2c, addr=0x3c)
def display():
# The framebuf library only supports ASCII printing characters encoded as 32~126
oled.text(" !\"#$%&'()*+,-./", 0, 0)
oled.text("0123456789:;<=>?", 0, 8)
oled.text("@ABCDEFGHIJKLMNO", 0, 16)
oled.text("PQRSTUVWXYZ[\]^_", 0, 24)
oled.text("`abcdefghijklmno", 0, 32)
oled.text("pqrstuvwxyz{|}~", 0, 40)
oled. show()
def testAscii():
# The return value of chr() is the ASCII character corresponding to the current integer
Ascii = ''
for i in range(32, 127):
Ascii = Ascii + chr(i)
for i in range(128, 256):
Ascii = Ascii + chr(i)
return Ascii
def display_Ascii():
# The framebuf library only supports ASCII printing characters encoded as 32~126
oled.text(testAscii()[0:16], 0, 0)
oled.text(testAscii()[16:32], 0, 8)
oled.text(testAscii()[32:48], 0, 16)
oled.text(testAscii()[48:64], 0, 24)
oled.text(testAscii()[64:80], 0, 32)
oled.text(testAscii()[80:95], 0, 40)
oled. show()
if __name__ == "__main__":
display()
# print(testAscii())
# display_Ascii()
# ASCII printing characters (character encoding: 32-127)
# 32~126 (95 in total) are characters: 32 is a space, among which 48~57 are ten Arabic numerals from 0 to 9,
# 65~90 are 26 uppercase English letters,
# 97~122 are 26 lowercase English letters,
# The rest are some punctuation marks, operation symbols, etc.
# The 127th character represents the delete command on the keyboard.
# ASCII extension code (character encoding: 128-255)
# The last 128 are called extended ASCII codes.
# Many x86-based systems support the use of extended (or "high") ASCII.
# The extended ASCII code allows the 8th bit of each character
# to be used to determine additional 128 special symbol characters, foreign language letters and graphic symbols.
OLED display potentiometer voltage and real-time progress bar
Continue to use the method of using the ADC to detect the voltage of the potentiometer in the chapter [Use the potentiometer to adjust the brightness of the colored lamp steplessly] (#Use the potentiometer steplessly adjust the brightness of the colored lamp) to design an OLED screen to display the potentiometer voltage and real-time progress Article procedure.
Wiring Reference
Potentiometer | Board |
---|---|
GND | GND |
VCC | 3V3 |
S | GPIO1 |
SSD1306 OLED | Board |
---|---|
GND | GND |
VCC | 3V3 |
SCL | 16 |
SDA | 15 |
Code
from machine import Pin,ADC,I2C
from ssd1306 import SSD1306_I2C
import time
adc1 = ADC(Pin(1),atten=ADC.ATTN_11DB)
sda_pin=Pin(15,Pin. PULL_UP)
scl_pin=Pin(16,Pin. PULL_UP)
i2c = I2C(1,sda=sda_pin, scl=scl_pin, freq=800_000)
print(i2c. scan())
oled = SSD1306_I2C(128, 64, i2c, addr=0x3c)
#Init, white background
oled.fill(1)
oled.rect(0,32,128,10,0)
while True:
#Read ADC
adc1_read = adc1.read() # 12bit
adc1_read_mv = adc1.read_uv()//1000
adc1_read_u16 = adc1.read_u16() # 16bit
#Set progress bar
bar_width = round (adc1_read / 4095 * 128)
oled.fill_rect(bar_width,33,128-bar_width,8,0)
oled.fill_rect(0,33,bar_width,8,1)
#Set ADC text, centered
text_adc1 = str(adc1_read_mv) + "mV"
start_x_text_adc1 = 64 - len(text_adc1)*4
oled.fill_rect(36,24,56,8,1)
oled.text(text_adc1,start_x_text_adc1,24,0)
#Show
oled. show()
print(adc1_read, adc1_read_u16, adc1_read_mv,"mv", bar_width,"width")
time. sleep(0.05)