# Arduino 光敏電阻測試
本系列之前的測試紀錄參考 :
# MicroPython on ESP8266 (二) : 數值型別測試
# MicroPython on ESP8266 (三) : 序列型別測試
# MicroPython on ESP8266 (四) : 字典與集合型別測試
# MicroPython on ESP8266 (五) : WiFi 連線與 WebREPL 測試
# MicroPython on ESP8266 (六) : 檔案系統測試
# MicroPython on ESP8266 (七) : 時間日期測試
# MicroPython on ESP8266 (八) : GPIO 測試
# MicroPython on ESP8266 (九) : PIR 紅外線移動偵測
# MicroPython on ESP8266 (十) : socket 模組測試
# MicroPython on ESP8266 (十一) : urllib.urequest 模組測試
# MicroPython on ESP8266 (十二) : urequests 模組測試
# MicroPython on ESP8266 (十三) : DHT11 溫溼度感測器測試
# MicroPython on ESP8266 (十四) : 網頁伺服器測試
MicroPython 文件參考 :
# MicroPython tutorial for ESP8266 (官方教學)
# http://docs.micropython.org/en/latest/micropython-esp8266.pdf
# http://docs.micropython.org/en/latest/pyboard/library/usocket.html#class-socket
# http://docs.micropython.org/en/v1.8.7/esp8266/library/usocket.html#module-usocket
# https://gist.github.com/xyb/9a4c8d7fba92e6e3761a (驅動程式)
# ESP8266 ADC – Reading Analog Values with NodeMCU
ESP8266 的 ADC 腳接受 0~3.3V 的類比輸入電壓, 內建的 10 位元類比數位轉換電路會將其轉成 0~1024 的整數數值, 亦即 0V 對應 0, 而 3.3V 對應 1024. 但根據上面這篇文章, 較早製造的 ESP8266 的 ADC 雖然可輸入 3.3V 以內的電壓, 但是到 1V 時就已到達 1024 了, 亦即事實上 ADC 的轉換範圍只有 0~1 V 而已 :
"Note: with earlier versions of the ESP, the A0 pin operated at maximum voltage of 1.0V, so check your board A0 voltage before following the next circuit."
在 MicroPython 官網也有相同的說明, 參考 :
# 8. Analog to Digital Conversion
"The values returned from the read() function are between 0 (for 0.0 volts) and 1024 (for 1.0 volts). Please note that this input can only tolerate a maximum of 1.0 volts and you must use a voltage divider circuit to measure larger voltages."
其實官網說 ADC 最大容忍電壓為 1V 似乎言過其實, 我手上的三塊 ESP-12 模組都是在 1V 時即輸出 1024, 但我將 ADC 接到 3.3V 去測試並不會燒毀此腳 (還是輸出 1024), 我想 ESP8266 裡面可能有內建限壓電路, 但為了讓 ADC 輸出與光度呈線性變化, 必須去除 1~3.3V 的非線性飽和區域, 所以還是照它建議使用一個電阻分壓電路來將 ADC 最高電壓限制在 1V.
我參考下面這篇建議, 使用 220 歐姆與 100 歐姆串聯來分壓, 這樣 100 歐姆電阻的壓降就剛剛好是 1V 左右 (若使用 D1 Mini 不需要這 220+100 的分壓電路, 接 3.3v 即可, 參考底下補充說明) :
3.3V*100/(100+220)=1.03V
# ESP8266 ADC - Analog Sensors
我用 upverter 繪製完整電路圖如下 :
上圖中經過 220+100 歐姆分壓電路獲得 1V 電壓後接到光敏電阻與 10K 的串聯電路, 光敏電阻在上, 10K 電阻在下, 中間分壓點就直接連到 ESP8266 的 ADC 腳即可. 這裡光敏電阻放在上面的原因是我想讓 ADC 輸出與光度成正比, 亦即最亮時輸出 1024, 完全暗掉時輸出 0, 如果反過來光敏電阻在下, 10K 在上的話就會呈反比 : 最亮時輸出 0, 最暗時輸出 1024 (之前在做 Arduino 測試時就是採用這種配置). 因為光敏電阻的電阻值會隨亮度增加而降低, 最亮時會降到接近 1 歐姆, 而最暗時則在 1M 歐姆左右. 因此最亮時壓降幾乎落在 10K 電阻上, ADC 輸入電壓為 1V 左右, 因此輸出為 1024; 而最暗時壓降落在光敏電阻, 10K 的壓降接近 0V, 因此輸出接近 0.
MicroPython 在 machine 模組提供了 ADC() 函數來建立一個 ADC 物件, 呼叫此物件的 read() 方法即可讀取類比數位轉換器的輸出 (對應 0~1V 的整數 0~1024) :
>>> import machine
>>> adc=machine.ADC(0) #指定 Analog Pin 0 建立 ADC 物件
>>> type(adc)
<class 'ADC'> #型態為 ADC 的物件
>>> adc.read()
535
下面測試 1 以無窮迴圈來連續測量 ADC 的數位輸出 (每秒測量一次) :
測試 1 : 每秒測量一次亮度 (0~100%)
#main.py
import machine
import time
while True:
adc=machine.ADC(0) #建立 ADC 物件
value=adc.read() #讀取類比數位轉換器輸出
print(value, str(round(value*100/1024)) + '%') #輸出值與百分數
time.sleep(1) #延遲 1 秒
因為要用到延遲功能以免讀取頻率太快, 所以也要匯入 time 模組. 這裡要注意 round() 的輸出為數值, 與 '%' 串接之前必須用 str() 函數轉成字串.
MicroPython v1.9.1-8-g7213e78d on 2017-06-12; ESP module with ESP8266
Type "help()" for more information.
>>>
PYB: soft reboot
#11 ets_task(40100164, 3, 3fff829c, 4)
WebREPL is not configured, run 'import webrepl_setup'
Connecting to AP ...
Connected:IP= 192.168.2.111
1024 100%
451 44%
499 49%
454 44%
853 83%
870 85%
871 85%
881 86%
870 85%
869 85%
871 85%
871 85%
877 86%
872 85%
874 85%
979 96%
871 85%
977 95%
1024 100%
1024 100%
4 0%
5 0%
下面測試 2 是複製 Arduino 版的範例 2, 使用積分濾波器來抑制雜訊突波 :
測試 2 : 每秒測量一次亮度 (0~100%) - 使用積分濾波器
import machine
import time
while True:
adc=machine.ADC(0) #建立 ADC 物件
value=adc.read() #讀取類比數位轉換器輸出
value=0.3*value + 0.7*adc.read(); #積分濾波
print(value, str(round(value*100/1024)) + '%') #輸出值與百分數
time.sleep(1) #延遲 1 秒
下面測試 3 複製 Arduino 版的範例 3, 我把 GPIO 14 設為輸出埠, 然後串接一個 LED 與 150 歐姆電阻, 利用 CdS 的亮度來控制 LED 閃爍, 光度越亮 LED 閃爍速率越慢, 越暗閃得越快 :
測試 3 : 利用 CdS 的亮度來控制 LED 閃爍
import machine
import time
p14=machine.Pin(14, machine.Pin.OUT) #設定 GPIO 14 為輸出
while True:
adc=machine.ADC(0) #建立 ADC 物件
value=adc.read() #讀取類比數位轉換器輸出
value=int(0.3*value + 0.7*adc.read()); #積分濾波 (轉成整數)
print(value, str(round(value*100/1024)) + '%') #輸出值與百分數
p14.value(1) #點亮 LED
time.sleep_ms(value) #延遲 value 毫秒
p14.value(0) #熄滅 LED
time.sleep_ms(value) #延遲 value 毫秒
這裡仍然延續測試 2 的積分濾波器來抑制雜訊, 但是另外加上 int() 函數來轉成整數, 因為 time.sleep() 函數的傳入參數必須是整數.
接著要複製 Arduino 版的範例 5, 利用光敏電阻測得之亮度來控制 LED 燈明滅. 這裡要用到上回買的一路低準位觸發繼電器, 輸入端有 3 隻腳 : VCC, GND 與 IN (控制信號輸入), 雖然繼電器蓋子上低壓側打的是 5V, 但實際上 VCC 與 IN 用 3.3V 也是可以驅動的. 輸出端也有 3 個電器端子 : COM (共接點), NO (Normal Open) 與 NC (Normal Close), 表示控制信號未觸發時 (即 IN 為 HIGH), NO 接點與 COM 之間是斷路的, NC 接點與 COM 之間是接通的. 當 IN 在 LOW 位準時將觸發繼電器動作, 使 NO-COM 之間接通, 而 NC-COM 之間斷開, 參考 :
# 1路 繼電器 模組 5V 低電平 arduino 適用 $18
高壓側部分此繼電器最高可接 250V, 此處為了安全我把智慧小車用的兩節 18650 (約 8.5V) 拿來驅動規格為 12V 的 LED 聚光燈, 亦即將 LED 聚光燈接在 NO 端子後串接 18650 電池再接到 COM 端子, 當 IN 未觸發 (=3.3V) 時高壓側是斷開的, LED 不亮, 當 IN 觸發時 (=0V), NO-COM 閉合使得 LED 點亮.
測試 4 : 利用光敏電阻控制 LED 燈明滅
import machine
import time
p14=machine.Pin(14, machine.Pin.OUT)
while True:
adc=machine.ADC(0) #建立 ADC 物件
value=adc.read() #讀取類比數位轉換器輸出
value=int(0.3*value + 0.7*adc.read()); #積分濾波
luminance=round(value*100/1024)
print(value, str(luminance) + '%') #輸出值與百分數
if luminance < 30: #點亮 LED 燈
p14.value(0) #此繼電器為低觸發 (LED 燈接 NO 端)
elif luminance > 35: #熄滅 LED 燈
p14.value(1) #HIGH:不觸發
time.sleep(1)
上面程式中我為了測試方便將點亮 LED 的亮度設為低於 30% 時點亮 LED; 高於 35% 時熄滅 LED, 中間的 5% 差距用來抑制臨界現象, 如果只用單一門檻來明滅 LED 的話, 當亮度在該臨界值附近徘徊時會造成 LED 閃爍. 實際上運用時應該調低, 例如控制路燈時 10% 以下點亮路燈, 15% 以上熄滅路燈應該是很適當的.
關於繼電器控制, 可以參考下面這篇不錯的文章 :
# Controlling relays using Micropython and an ESP8266
既然已可利用 ADC 與光敏電阻取得亮度資訊, 就可以在之前的 DHT 溫溼度實驗上添加亮度資訊, 並記錄在 ThingSpeak 物聯網資料庫 (亮度我指定為 field4), 關於 DHT 參考 :
# MicroPython on ESP8266 (十三) : DHT11 溫溼度感測器測試
在下面的測試 5 中我照上述實驗重新接上 DHT 模組, 並將其輸出信號連接到 ESP8266 的 GPIO 14. 此外, 為了方便觀察系統是否有在正常運作, 我也在 GPIO 16 串接了一個 LED 與 150 歐姆電阻, 在等待 ThingSpeak 規定的 16 秒寫入週期時間內, 讓此 LED 閃爍, 然後會停頓 1~2 秒以便傳送資料.
測試 5 : 將光敏電阻與 DHT 模組之亮度與溫濕度紀錄在 ThingSpeak 資料庫
from machine import Pin,ADC
import dht
import time
import urequests
DHTPIN=Pin(16, Pin.IN)
LEDPIN=Pin(14, Pin.OUT)
d=dht.DHT11(DHTPIN)
adc=ADC(0)
host='http://api.thingspeak.com'
api_key='NO5N8C7T2KINFCQE'
def LED_blink(pin,s):
for i in range(1,10*s):
pin.value(1)
time.sleep_ms(50)
pin.value(0)
time.sleep_ms(50)
while True:
try:
d.measure()
t=d.temperature()
f=round(t * 9/5 + 32)
h=d.humidity()
a=adc.read()
a=int(0.3*a + 0.7*adc.read())
a=round(a*100/1024)
url='%s/update?api_key=%s&field1=%s&field2=%s&field3=%s&field4=%s' %(host, api_key, t, f, h, a)
print('Temperature=', t, 'C', '/', f, 'F', 'Humidity=', h, '%', 'Luminance=', a, '%')
r=urequests.get(url)
print('response=', r.text)
except:
print('urequests.get() exception occurred!')
LED_blink(LEDPIN,16)
注意, 這裡我改寫了 LED_brink() 函數, 添加了 pin 當作第一參數以便傳入任何作為 LED 輸出的 PIN 物件, 而非原先使用 ESP-01 模組時寫死在 GPIO 2 腳.
OK, 在這個尼莎颱風來襲的夜晚, 終於把 ADC 相關的實驗做完了, 真是可喜可賀. 本來下午看沒風沒雨的, 二哥補習班也停課, 有點想回鄉下去, 但舅媽說颱風天不用跑一趟, 她會煮冬粉與咖哩帶去我家給爸. 而且菁菁與姊姊明天傍晚回到高雄要去高鐵載她們, 周一可能還有個海棠要撲來, 所以就只好待在高雄了.
颱風天窩在家做實驗最棒了.
參考 :
# 自製光控開關 (天黑時自動點燈的電路)
# ESP8266-based DIY wifi baby monitor
# ESP8266 ADC – Reading Analog Values with NodeMCU
# ESP8266 ADC - Analog Sensors
# https://github.com/mithru/MicroPython-Examples
# ESP8266 first project: home automation with relays, switches, PWM, and an ADC
# ESP8266 ADC - Analog Sensors
2017-08-09 補充 :
這幾天在測試 1602 LCD 顯示溫溼度與亮度時發現, D1 Mini 的 A0 (ADC) 接腳與上面實驗使用的 ESP-12 模組不一樣, D1 Mini 不需要用 100+220 歐姆電阻分壓電路將 3.3v 分出 1V 電壓, 這樣做的話會在最亮強光下只得到 50% 亮度. 若使用 D1 Mini 應撤除分壓電路, 直接將光敏電阻與 10K 歐姆分壓電路接 3.3V 即可, 參考 D1 Mini 的接腳介紹 :
# https://wiki.wemos.cc/products:d1:d1_mini
沒有留言:
張貼留言