2023年4月3日 星期一

MicroPython 學習筆記 : 離網太陽能系統 ATS 切換偵測 (一)

趁春假連假休 5 天, 想把偵測頂樓離網太陽能系統 ATS 切換的電路安裝起來, 構想是利用上個月在露天買的檢測交流電光耦模組的信號輸出來中斷 ESP8266, 然後透過 Line Notify 發出訊息, 也可以紀錄在 ThingSpeak 上. 

注意, 本實驗會接觸 110V 交流電, 做實驗時要穿球鞋戴手套操作, 否則有觸電危險

我 4/1 晚上已經簡單地用三用電表測試過光耦模組功能正常, 參考 :


4/2 晚上則用 D1 mini 開發板先做了一個 MicroPython 的硬體中斷實驗, 參考 :


接下來要將交流 ON/OFF 偵測光耦模組輸出連接到 D1 mini 模擬實際運作情形, 首先我製作了一個實際安裝要用到的插頭電源線 (紅黑線), 線頭鎖在光耦模組的交流輸入端 : 




然後將光耦模組的 OUT 信號輸出 (黃線) 連接到 D1 mini 的 GPIO5 (D1 腳) 並將該腳設定為硬體中斷輸入 : 




另外因為 D1 mini 是 3.3V 系統, 故光耦模組的 VCC 取自 D1 mini 的 3.3V 輸出. 接好後執行下列程式, 開關 AC 電源測試看看能否正常觸發中斷, 測試程式如下 :


測試 1 : 電源開啟 (下降緣) 與關閉  (上升緣) 都觸發中斷 [看原始碼]

from machine import Pin
from time import sleep

def irq_handler(pin):
    global irq_pin
    global irq_occurred
    irq_occurred=True
    irq_pin=pin

irq_occurred=False
led_pin=Pin(2, Pin.OUT)
led_pin.value(1) 
solar_pin=Pin(5, Pin.IN, Pin.PULL_UP)
solar_pin.irq(trigger=3, handler=irq_handler)   # 上升與下降緣都觸發

while True:
    if irq_occurred:
        print(f'{irq_pin} 發生中斷')
        led_pin.value(0)
        sleep(3)
        led_pin.value(1)
        irq_occurred=False
        
此處 solar_pin 為輸入中斷腳的 Pin 物件, 而 irq_pin 則是 MicroPython 回報的發生硬體中斷的 Pin 物件, 結果如下 :




可見不管是開電源還是關電源都會觸發中斷 (因 trigger=3). 

但上面的程式無法判斷是電源 ON 還是 OFF 觸發中斷, 這樣後續要用 Line Notify 發出通知時無法區辨到底是斷電還是復電, 解決辦法是設置兩個中斷輸入腳, 一個負責觸發下降緣中斷 (表示復電, 因光耦模組斷電時輸出 High, 復電時輸出 Low), 另一個觸發上升緣中斷 (表示斷電). 

在下面範例中, 我在光耦模組的 OUT 輸出端並接一條線連到 D1 mini 的 GPIO4 (D2 腳) 用來觸發下降緣中斷 (表示復電), 而原來的 GPIO5 (D1 腳) 用來觸發上升緣中斷 (表示斷電) : 




程式修改如下 : 


測試 2 : 用兩個中斷輸入來區別下降緣上升緣中斷 [看原始碼]

# main.py
from machine import Pin
from time import sleep

def irq_handler(pin):
    global irq_pin
    global irq_occurred
    irq_occurred=True
    irq_pin=pin

irq_occurred=False
led_pin=Pin(2, Pin.OUT)
led_pin.value(1) 
solar_pin_r=Pin(5, Pin.IN, Pin.PULL_UP)
solar_pin_r.irq(trigger=1, handler=irq_handler)   # 上升緣觸發 (斷電)
solar_pin_f=Pin(4, Pin.IN, Pin.PULL_UP)
solar_pin_f.irq(trigger=2, handler=irq_handler)   # 下降緣觸發 (復電)

while True:
    if irq_occurred:
        print(f'{irq_pin} 發生中斷')
        print(str(irq_pin))
        led_pin.value(0)
        sleep(3)
        led_pin.value(1)
        irq_occurred=False
        
此例 solar_pin_r 為觸發上升緣中斷的 GPIO5 的 Pin 物件; 而 solar_pin_f 則是觸發下降緣中斷的 GPIO4 的 Pin 物件, 發生中斷時命令列會顯示哪一個 Pin 觸發中斷, 結果如下 : 




可見當電源關閉時會觸發上升緣中斷, 顯示 'Pin(5) 發生中斷'; 而電源開啟時會觸發下降緣中斷, 顯示 'Pin(4) 發生中斷'. 

不過上面是正常狀況, 如果多做幾次會發現結果可能錯亂, 關電時應該顯示 'Pin(5) 發生中斷' 卻顯示 'Pin(4) 發生中斷', 復電時應顯示 'Pin(4) 發生中斷' 卻顯示 'Pin(5) 發生中斷', 研判可能是 OUT 輸出信號狀態切換時的彈跳造成的. 

解決辦法是要依據穩定狀態時的 OUT 信號位準來判斷目前是斷電還是復電狀態, 這就需要一點延遲時間 (例如 0.5 秒) 再去讀取 OUT 位準, 中斷發生時若 OUT 位準為 Low 表示為復電狀態, 若為 High 表示斷電狀態, 這樣就只要一個中斷輸入即可, 不需要兩個 (真的有點奇怪), 所以可以將上面那條接到 GPIO4 (D2 腳) 的白線移除, 然後改寫程式如下 : 


測試 3 : 用一個中斷配合延遲讀取位準來區別下降緣上升緣中斷 [看原始碼]

from machine import Pin
from time import sleep

def irq_handler(pin):
    global irq_pin
    global irq_occurred
    irq_occurred=True
    irq_pin=pin

irq_occurred=False
led_pin=Pin(2, Pin.OUT)
led_pin.value(1) 
solar_pin=Pin(5, Pin.IN, Pin.PULL_UP)
solar_pin.irq(trigger=3, handler=irq_handler)

while True:
    if irq_occurred:
        sleep(0.5)                           # 延遲 0.5 秒才去讀取穩定的 OUT 輸出
        if solar_pin.value():           # OUT 位準為 1 : 斷電狀態 (上升緣觸發中斷)
            print(f'{irq_pin} 發生中斷 : 斷電')
        else:                                   # OUT 位準為 0 : 復電狀態 (下降緣觸發中斷)
            print(f'{irq_pin} 發生中斷 : 復電')
        led_pin.value(0)
        sleep(1)
        led_pin.value(1)
        irq_occurred=False

此例關鍵之處為發生中斷後的 sleep(0.5) 延遲 0.5 秒才去讀取中斷輸入腳的狀態 (即光耦模組的 OUT 輸出), 根據此位準來判斷剛剛的中斷是下降緣 (OUT=0) 還是上升緣 (OUT=1), 據此判斷目前交流電是斷電還是復電狀態, 結果如下 : 




MicroPython v1.18 on 2022-01-17; ESP module with ESP8266
Type "help()" for more information.
>>> Pin(5) 發生中斷 : 斷電
Pin(5) 發生中斷 : 復電
Pin(5) 發生中斷 : 斷電
Pin(5) 發生中斷 : 復電
Pin(5) 發生中斷 : 斷電

沒有留言 :