05 micropython
(2022/07/25)
利用暑假利用NodeMCU-32S+EZ Start Kit+ 再來玩玩MicroPython!開發板使用Web:Bit或PocketCard也都可以用!
一、安裝Thonny
Thonny官網:https://thonny.org/
下載3.3.13版:
https://github.com/thonny/thonny/releases/download/v3.3.13/thonny-3.3.13.exe
直接下載安裝版,也有ZIP檔
也有4.0.03b版
二、下載ESP32的韌體
下載 v1.19.1 (2022-06-18) .bin (目前最新的版本) https://micropython.org/resources/firmware/esp32-20220618-v1.19.1.bin
三、開啟Thonny及安裝ESP32的韌體
將電腦與ESP32連接,以下幾塊開發版均可使用,本文以NodeMCU-32S(+EZ Start Kit+擴展板)為主,其他兩板再另文介紹!
NodeMCU-32S
Web:Bit
PocketCard
開啟Thonny
點擊 工具/選項
點擊【直譯器】
選擇【MicroPython(ESP32)】
選擇正確的【連接埠】
點擊【安裝或更新韌體】
四、EZ Start Kit+與ESP32的腳位說明韌體
腳位圖如下:
測試一:按鍵點燈
按A鍵(或B鍵),點亮NodeMCU-32S內建的LED燈
腳位說明:
A鍵:GPIO5
B鍵:GPIO36
內建的LED燈:GPIO2
擴展板上的紅燈:GPIO16
擴展板上的黃燈:GPIO12
擴展板上的綠燈:GPIO13
MicroPython程式:
from machine import Pin #使用外部模組功能的動作叫做匯入 (import),匯入的有類別或函式,這邊是匯入Pin類別
led = Pin(2, Pin.OUT) #建立Pin物件,名稱叫led ,內建LED燈
button = Pin(5, Pin.IN) #A鍵
led.on() #led.value(1) 也可以
while True:
if button.value() == 0:
led.on()
else:
led.off()
按A鍵點燈、按B鍵關燈
MicroPython程式:
from machine import Pin
led = Pin(2, Pin.OUT) #內建LED燈
buttonA = Pin(5, Pin.IN) #A鍵
buttonB = Pin(36, Pin.IN) #B鍵
led.on()
while True:
if buttonA.value() == 0:
led.on()
elif buttonB.value() == 0:
led.off()
LED燈一閃一滅 (1秒)
MicroPython程式:
from machine import Pin
import time #from time import sleep ,後面sleep(1)
led = Pin(2 , Pin.OUT)
while True:
led.value(1)
time.sleep(1) #等待1秒,也可用 time.sleep_ms(1000)
led.value(0)
time.sleep(1)
如果按鍵不是採用【模組】,而是只有2支腳(一支接GND)時,設定【上拉電阻】如下:button = Pin(5, Pin.IN, Pin.PULL_UP)
將檔案儲存在【MicroPython設備】(ESP32上),並將檔名存成main.py,就可離線執行
測試二:繼電器控制
按A鍵啟動繼電器、按B鍵關閉繼電器
腳位說明:
A鍵:GPIO5
B鍵:GPIO36
繼電器:GPIO25
MicroPython程式:
from machine import Pin
relay = Pin(25, Pin.OUT) #繼電器
buttonA = Pin(5, Pin.IN) #A鍵
buttonB = Pin(36, Pin.IN) #B鍵
while True:
if buttonA.value() == 0:
relay.value(1)
elif buttonB.value() == 0:
relay.value(0)
程式跟開關LED燈一樣,並且要用擴展板供電才能啟動及關閉繼電器
測試三:OLED顯示
下載ssd1306 OLED驅動模組
網址:https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py
複製程式碼到Thonny下,並另存到ESP32的設備上 (如下圖說明)
在LED上顯示Hello World
簡單程式如下:
from machine import Pin, SoftI2C #匯入Pin及I2C模組
import ssd1306 #匯入ssd1306模組
i2c = SoftI2C( scl=Pin(22), sda=Pin(21), freq=400000) #建立SoftI2C類別物件
width = 128
height = 64
display = ssd1306.SSD1306_I2C(width, height,i2c) #建OLED物件
display.text('Hello World',0 ,0) #ssd1306函式
display.show() #顯示螢幕
要利用EZ Start kit+擴展板供電,這邊害我浪費好多時間
測試四:溫濕度感測
在OLED上顯示溫濕度的值
腳位說明:
DHT11溫濕度感測器:GPIO15
MicroPython程式:
import dht
from machine import Pin, SoftI2C #匯入Pin及I2C模組
import ssd1306 #匯入ssd1306模組
import time
sensor = dht.DHT11(Pin(15))
i2c = SoftI2C( scl=Pin(22), sda=Pin(21), freq=400000) #建立SoftI2C類別物件
width = 128
height = 64
display = ssd1306.SSD1306_I2C(width, height,i2c) #建OLED物件
while True:
display.fill(0) #螢幕全變黑(清除螢幕)
sensor.measure() #溫濕度量測
temp = sensor.temperature() #取得溫度
humi = sensor.humidity() #取得濕度
temp = 'Temp = {0:4.1f} '.format(temp) + ' C' #格式化
humi = 'Humi = {0:4.1f} '.format(humi) + ' %'
display.text(temp,0 ,0)
display.text(humi,0 ,8)
display.show() #顯示螢幕
time.sleep(1) #等待1秒
可以利用哈氣來看量測到的值有沒有變化
測試五:光照量測
在OLED上顯示光照亮度的值(或可變電阻值)
腳位說明:
光感測器:GPIO39
可變電阻:GPIO34
MicroPython程式:
from machine import Pin, ADC, SoftI2C #匯入Pin,ADC及I2C模組
import ssd1306 #匯入ssd1306模組
import time
adc1 = ADC(Pin(39))
adc2 = ADC(Pin(34))
adc1.atten(ADC.ATTN_11DB) #設定最高的量測電壓,此為3.6V
adc2.atten(ADC.ATTN_11DB)
i2c = SoftI2C( scl=Pin(22), sda=Pin(21), freq=400000) #建立SoftI2C類別物件
width = 128
height = 64
display = ssd1306.SSD1306_I2C(width, height,i2c) #建OLED物件
while True:
display.fill(0)
light = 'Light = '+ str(adc1.read())
vr = 'VR = '+str(adc2.read())
display.text(light,0 ,0)
display.text(vr,0 ,8)
display.show()
time.sleep(0.5)
量測出的結果:
光感測器的值為0~2800,遮光可到0,但加光的值變化不大
可變電阻器的值為0~4095
測試六:燈條測試
點亮燈條的燈
腳位說明:
燈條(WS2812B):GPIO26
只有3顆燈
MicroPython程式:
from machine import Pin
import neopixel
#import machine, neopixel
n = 3 #燈數
p = 26 #腳位
#np = neopixel.NeoPixel(machine.Pin(p), n) #搭配上面紫色的
np = neopixel.NeoPixel(Pin(p, Pin.OUT), n) #建立neopixel物件
np[0] = (255, 0, 0) #設定第一顆燈顏色
np[1] = (0, 255, 0)
np[2] = (0, 0, 255)
np.write() #write()方法
基本使用很簡單,但不知如何設定【亮度】?!
測試七:蜂鳴器測試
使蜂鳴器發出 1KHz 的 Bee Bee 告警聲
腳位說明:
蜂鳴器:GPIO14
MicroPython程式:
from machine import Pin,PWM
import time
def alarmBeep(pwm):
pwm.init() #初始化PWM ,之前沒設這條出錯誤
pwm.freq(1000) #設定頻率為 1KHz
pwm.duty(512) #設定工作週期為 50%
time.sleep(1) #持續時間 1 秒
pwm.deinit() #停止發聲
time.sleep(2) #持續時間 2 秒
pwm=PWM(Pin(14))
while True:
alarmBeep(pwm)
一開始一直出現"ValueError: failed to bind timer to channel"錯誤,在函式一開始加個pwm.init()就解決了!
按A鍵播放全家歡迎的音樂
全家歡迎音樂簡譜:3 1 5(低音) 1 / 2 5~ 2 / 3 2 5(低音) 1
MicroPython程式:
from machine import Pin,PWM
import time
buttonA = Pin(5, Pin.IN) #A鍵
buzzer = 14 #蜂鳴器
pwm=PWM(Pin(buzzer))
pwm.deinit() #去除一開始的雜音
def family(pwm):
pwm.init() #初始化PWM
pwm.duty(512)
pwm.freq(330)
time.sleep(0.5)
pwm.freq(262)
time.sleep(0.5)
pwm.freq(196)
time.sleep(0.5)
pwm.freq(262)
time.sleep(0.5)
pwm.freq(294)
time.sleep(0.5)
pwm.freq(392)
time.sleep(1)
pwm.freq(294)
time.sleep(0.5)
pwm.freq(330)
time.sleep(0.5)
pwm.freq(294)
time.sleep(0.5)
pwm.freq(196)
time.sleep(0.5)
pwm.freq(262)
time.sleep(0.5)
pwm.deinit()
while True:
if buttonA.value() == 0:
family(pwm)
測試八:超音波測距感測器測試
顯示HC-SR04P所量測到的距離
腳位:
TRIG:GPIO16 (IO4)
ECHO:GPIO12 (IO5)
MicroPython程式:
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
from hcsr04 import HCSR04
import utime
oled = SSD1306_I2C(128, 64, I2C(scl=Pin(22), sda=Pin(21)))
sonar = HCSR04(trigger_pin=16, echo_pin=12)
while True:
distance = sonar.distance_cm()
oled.fill(0)
oled.text("Distance:", 0, 0)
oled.text(str(distance) + " cm", 0, 16)
oled.show()
print("偵測距離: " + str(distance) + " 公分")
utime.sleep_ms(25)
hcsr04.py:直接把下面程式內容上傳到ESP32裝置上,此檔取自謝昌勳老師
import machine, time
from machine import Pin
__version__ = '0.2.0'
__author__ = 'Roberto Sánchez'
__license__ = "Apache License 2.0. https://www.apache.org/licenses/LICENSE-2.0"
class HCSR04:
"""
Driver to use the untrasonic sensor HC-SR04.
The sensor range is between 2cm and 4m.
The timeouts received listening to echo pin are converted to OSError('Out of range')
"""
# echo_timeout_us is based in chip range limit (400cm)
def __init__(self, trigger_pin, echo_pin, echo_timeout_us=500*2*30):
"""
trigger_pin: Output pin to send pulses
echo_pin: Readonly pin to measure the distance. The pin should be protected with 1k resistor
echo_timeout_us: Timeout in microseconds to listen to echo pin.
By default is based in sensor limit range (4m)
"""
self.echo_timeout_us = echo_timeout_us
# Init trigger pin (out)
self.trigger = Pin(trigger_pin, mode=Pin.OUT, pull=None)
self.trigger.value(0)
# Init echo pin (in)
self.echo = Pin(echo_pin, mode=Pin.IN, pull=None)
def _send_pulse_and_wait(self):
"""
Send the pulse to trigger and listen on echo pin.
We use the method `machine.time_pulse_us()` to get the microseconds until the echo is received.
"""
self.trigger.value(0) # Stabilize the sensor
time.sleep_us(5)
self.trigger.value(1)
# Send a 10us pulse.
time.sleep_us(10)
self.trigger.value(0)
try:
pulse_time = machine.time_pulse_us(self.echo, 1, self.echo_timeout_us)
return pulse_time
except OSError as ex:
if ex.args[0] == 110: # 110 = ETIMEDOUT
raise OSError('Out of range')
raise ex
def distance_mm(self):
"""
Get the distance in milimeters without floating point operations.
"""
pulse_time = self._send_pulse_and_wait()
# To calculate the distance we get the pulse_time and divide it by 2
# (the pulse walk the distance twice) and by 29.1 becasue
# the sound speed on air (343.2 m/s), that It's equivalent to
# 0.34320 mm/us that is 1mm each 2.91us
# pulse_time // 2 // 2.91 -> pulse_time // 5.82 -> pulse_time * 100 // 582
mm = pulse_time * 100 // 582
return mm
def distance_cm(self):
"""
Get the distance in centimeters with floating point operations.
It returns a float
"""
pulse_time = self._send_pulse_and_wait()
# To calculate the distance we get the pulse_time and divide it by 2
# (the pulse walk the distance twice) and by 29.1 becasue
# the sound speed on air (343.2 m/s), that It's equivalent to
# 0.034320 cm/us that is 1cm each 29.1us
cms = (pulse_time / 2) / 29.1
return cms