---
# System prepended metadata

title: MicroPython 與有採樣間距需求的感測器
tags: [ESP32, MicroPython]

---

---
title: MicroPython 與有採樣間距需求的感測器
image: https://i.imgur.com/f2cjXwk.png
disqus: paoyung
---

# MicroPython 與有採樣間距需求的感測器
###### tags: `MicroPython` `ESP32`
> [color=#58f][name=Paoyung][time=Jun 06, 2022] [:snake: ℳ𝒾𝒸𝓇ℴ𝒫𝓎𝓉𝒽ℴ𝓃 隨手記](/@PaoyungChang/mpy_trifiles)

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

Timer
---
MicroPython 在 ESP32 上有 4 組 Timer 可用，模式有 ONE_SHOT 和 PERIODIC，相當於 Javascript 中的 setTimeout 和 setInterval。相關文件可參閱官方說明。而在下方的範例中，要做時間管理就必須佔用一組，預設是 Timer3，也可視情況自行指定。
> [color=green][Quick reference for the ESP32](https://docs.micropython.org/en/latest/esp32/quickref.html#timers)

數據與異常
---
- DHT11 的官方文件說其採樣週期間隔不得低於 1 秒，網路上的教學則建議為 2 秒，以下的範例仍依官方建議，**可視個人需求再行修改**。
![](https://i.imgur.com/f2cjXwk.png)
- 而在某些元件或應用時，數據容易產生跳動，但正常情況下溫濕度是不會在幾秒內產生明顯變化，所以通常會用上一點小技巧做去抖均化，不過 DHT11 的精度不高，比較看不出其差別，因此暫不納入考量，待日後有機會再行展示。
> [color=green][DHT11 datasheet](https://cdn-shop.adafruit.com/datasheets/DHT11-chinese.pdf)

穿外套
---
MicroPython 的 dht 模組如前所述，採樣週期過短時會發出異常，造成程式執行的中斷，若希望能有一個可自行管理時間，不管何時呼叫它都不要阻斷和中斷的程式模組，就必須擴充模組的功能。擴充的方式有很多，正規做法是用 class 的繼承再加上 funtion 的覆寫來達成，在此不打算這麼做，而只是要幫原來的模組穿個外套:coat:，將原來的 dht 包在裡面，利用 timer 在安全的時間才做動作，僅此而已。其用法必須和原來的 dht 一致，才能讓已套用它的程式碼做最小幅的修改，即能改善異常的問題。

程式
---
[dht11.py](https://gist.githubusercontent.com/paoyung/664cc0367fe310fe7edac1b687d32c03/raw/17881cc3f2b47ea7b650f44ae05d8e5d97a9ab5a/dht11.py)
{%gist paoyung/664cc0367fe310fe7edac1b687d32c03%}
將上述的程式存為 [dht11.py]() 並上傳至 ESP32。用法就和原來的相同，僅做小幅的改變即可。

範例1
---

```python=
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
---
```python=
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 的做法。
:sunglasses:

{%hackmd /@PaoyungChang/intro_v0702 %}