Try   HackMD

MicroPython 與有採樣間距需求的感測器

tags: MicroPython ESP32

PaoyungJun 06, 2022

ℳ𝒾𝒸𝓇ℴ𝒫𝓎𝓉𝒽ℴ𝓃 隨手記

前言

在 MicroPython 的創作中,常常要用上多種感測或顯示元件,以標準的撰寫風格會以 while 讓任務輪詢,當遇上有採樣間距的元件則以 sleep 稍做停等,但一旦遇上多種感測元件却有著不同停等間隔時,就很容易造成干擾或卡頓。若每個被調用元件的模組都能做好時間的管理,令人困擾的問題或許就能得以改善。在此以坊間經常使用的 DHT11 溫濕度傳感器配搭 ESP32 做為例子。

Timer

MicroPython 在 ESP32 上有 4 組 Timer 可用,模式有 ONE_SHOT 和 PERIODIC,相當於 Javascript 中的 setTimeout 和 setInterval。相關文件可參閱官方說明。而在下方的範例中,要做時間管理就必須佔用一組,預設是 Timer3,也可視情況自行指定。

Quick reference for the ESP32

數據與異常

  • DHT11 的官方文件說其採樣週期間隔不得低於 1 秒,網路上的教學則建議為 2 秒,以下的範例仍依官方建議,可視個人需求再行修改
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
  • 而在某些元件或應用時,數據容易產生跳動,但正常情況下溫濕度是不會在幾秒內產生明顯變化,所以通常會用上一點小技巧做去抖均化,不過 DHT11 的精度不高,比較看不出其差別,因此暫不納入考量,待日後有機會再行展示。

DHT11 datasheet

穿外套

MicroPython 的 dht 模組如前所述,採樣週期過短時會發出異常,造成程式執行的中斷,若希望能有一個可自行管理時間,不管何時呼叫它都不要阻斷和中斷的程式模組,就必須擴充模組的功能。擴充的方式有很多,正規做法是用 class 的繼承再加上 funtion 的覆寫來達成,在此不打算這麼做,而只是要幫原來的模組穿個外套

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
,將原來的 dht 包在裡面,利用 timer 在安全的時間才做動作,僅此而已。其用法必須和原來的 dht 一致,才能讓已套用它的程式碼做最小幅的修改,即能改善異常的問題。

程式

dht11.py

# name: dht11.py, version: 0.1.0, author: paoyung.chang@gmail.com
# Copyright (c) 2022 Paoyung Chang. See the file LICENSE for copying permission.
# License link: https://gist.github.com/paoyung/7e465ad984a6cf24024508831ec54516
from machine import Pin, Timer
from time import sleep, ticks_ms, ticks_diff
import dht
class DHT11:
def __init__(self, pin, timer=Timer(3)):
self.dht11 = dht.DHT11(pin)
self.timer = timer
self.last_ticks = 0
self.t = 0
self.h = 0
def measure(self):
now = ticks_ms()
# 間隔要超過1秒以上才不會異常
if ticks_diff(now, self.last_ticks) > 1200:
self.last_ticks = now
try:
self.dht11.measure()
except:
return
else:
self.timer.init(period=1100, mode=Timer.ONE_SHOT, callback=self.read_data)
else:
# 間隔太短,略過
pass
def read_data(self, t):
self.t = self.dht11.temperature()
self.h = self.dht11.humidity()
def temperature(self):
return self.t
def humidity(self):
return self.h
view raw dht11.py hosted with ❤ by GitHub

將上述的程式存為 dht11.py 並上傳至 ESP32。用法就和原來的相同,僅做小幅的改變即可。

範例1

from machine import Pin from dht11 import DHT11 from time import sleep def demo(): # 未指定 Timer,預設使用 Timer3 d11 = DHT11(Pin(13)) led = Pin(2, Pin.OUT) while 1: led.value(not led.value()) d11.measure() print('T:', d11.temperature()) print('H:', d11.humidity()) print('---------') sleep(0.5)

範例2

from machine import Pin, Timer from dht11 import DHT11 from time import sleep def demo_interval(): # 指定使用 Timer0 tim0 = Timer(0) d11 = DHT11(Pin(13), tim0) led = Pin(2, Pin.OUT) def callback(t): d11.measure() print('T:', d11.temperature()) print('H:', d11.humidity()) print('---------') tim2 = Timer(2) tim2.init(period=1200, mode=Timer.PERIODIC, callback=callback) while 1: led.value(not led.value()) sleep(0.5)

使用建議

範例 1 因在 measure 後執行了 sleep,而 measure 執行會佔用一小段時間,因此會增加實際 sleep 的時間,相對於較為要求精確的 case 會建議使用範例 2 的做法。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

關於作者  

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

我是 𝙋𝙖𝙤𝙮𝙪𝙣𝙜,是 MicroPythonEspruino 的愛好者,一直認為:

「Maker 應該把重心放在應用上,而不該被語言工具限制了創意」

所以想藉由較為簡捷且詳細的解說讓更多人可以學習進而自由發揮,而非淪為只能將程式碼複製貼上的複製人,如果你認同這樣的理念,請一起為此目標努力,如果我的文章內容對你有幫助,請轉發或協助需要的人。

若有專案需求,請利用 連絡我,謝謝!