本系列之前的測試紀錄參考 :
# 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 v1.9.1 版韌體測試
# MicroPython on ESP8266 (十) : socket 模組測試
# MicroPython on ESP8266 (十一) : urllib.urequest 模組測試
# MicroPython on ESP8266 (十二) : urequests 模組測試
# MicroPython on ESP8266 (十三) : DHT11 溫溼度感測器測試
# MicroPython 使用 ampy 突然無法上傳檔案問題
# MicroPython on ESP8266 (十四) : 網頁伺服器測試
# WeMOS D1 Mini 開發板測試
# MicroPython on ESP8266 (十五) : 光敏電阻與 ADC 測試
# MicroPython on ESP8266 (十六) : 蜂鳴器測試
# MicroPython on ESP8266 (十七) : 液晶顯示器 1602A 測試
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 (驅動程式)
# http://www.solomon-systech.com/zh/product/display-ic/oled-driver-controller/ssd1306/
其規格書可在 Adafruit 網站下載 :
# https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
我手上這塊模組的面板非常小巧, 只有 0.91 吋, 解析度 128*32, 為 I2C 介面只有 VCC (3.3V), GND, 以及 SCL 與 SDA 四支腳, 方便插在麵包板上做實驗. 硬體接線非常簡單. 當時在露天買花了 90 元, 但現在似乎漲到 100 元 :
# 向 tsai_pl 與 bluetaipei 購買零組件兩批
# 0.91吋 OLED 128x32 Arduino SSD1306 3.3V $100
在 AliExpree 這塊模組最低賣 US$2.68 (一件免運費), 折合台幣 80 元 :
# Free Shipping 0.91 Inch 128x32 IIC I2C White OLED LCD Display DIY Oled Module SSD1306 Driver IC DC 3.3V 5V For Arduino PIC US$2.68
淘寶網賣人民幣 8.8 元, 折合台幣 41 元, 但運費選擇淘寶集運每公斤 ¥14 人民幣起跳, 合計 ¥22.8 元合台幣 108 元, 要買兩件以上才會跟 AliExpress 或露天打平.
# 0.91寸OLED液晶模塊 IIC接口 128*32點陣 SSD1306驅動 ¥ 8.80
買 5 個是 ¥44 元, 大陸國內段運費 ¥10 合計 ¥54 元, 折合台幣約 246 元, 台灣集運運費不計的話平均每個 49 元. 若選擇淘寶 4PX 集運 1KG 內 ¥14 元, 合計是 ¥54+¥14=¥68 元, 合台幣 324 元, 平均每個 65 元, 也比露天便宜. 如果買 10 個含運費是 ¥88+10+14=¥112, 合台幣 533 元, 平均每個 53 元, 即買越多就能把運費攤平了.
另外還有使用 128*64 解析度面板 (與 SSD1306 控制能力一致) 的模組, 大小跟 NOKIA 5110 LCD 模組相同 :
# OLED液晶模組 0.96吋 黃藍雙色 12864點陣 SSD1306驅動 3.3V-5V 4線IIC介面 $200
SSD1306 的 MicroPython 驅動程式可從下面兩個 GitHub 下載, 此驅動模組同時支援 I2C 與 SPI 介面, 只要傳入 I2C 或 SPI 物件即可驅動顯示器 :
# micropython/drivers/display/ssd1306.py (MicroPython 官網)
此驅動模組提供下列 SSD1306_I2C 物件函數以方便操控面板的顯示. API 整理如下 :
SSD1306_I2C 物件的方法 | 說明 |
fill(col) | 將顯示記憶體全部畫素填入 col=1 (亮) 或 0 (暗) |
pixel(x, y, col) | 在顯示記憶體指定畫素位置 (x, y) 填入 col=1 (亮) 或 0 (暗) |
text(string, x, y, col=1) | 在顯示記憶體指定畫素位置 (x, y) 起填入預設 col=1 之字串 string |
show() | 將顯示記憶體內容輸出於面板顯示內容 |
scroll(dx, dy) | 將顯示記憶體畫素內容向上下 (dy) 或向左右 (dx) 捲動 |
注意, 顯示面板座標 (x,y) 的原點位置 (0, 0) 是在 0.91 吋模組 SDA 腳的那一側. 將驅動模組 ssd1306.py 上傳到 ESP8266 後, 即可參考 Adafruit 網站的用法說明進行測試 :
# How to use a SSD1306 OLED display with MicroPython boards
不過這篇文章使用的是 Adafruit 的 Circuit Python 控制板搭配其 FeatherWing OLED SSD1306 模組, 面板一樣是 128x32 OLED, 但模組價格卻非常貴, 要價 US$14.95, 合新台幣約 449 元, 是我買的模組的 4 倍多, 只是搭配 Adafruit 的 ESP8266 Feather 系列開發板較方便而已, 可以上下疊起來 :
# FeatherWing OLED - 128x32 OLED Add-on For All Feather Boards US$14.95
Adafruit CircuitPython+FeatherWing OLED 所使用的 SSD1306 驅動模組事實上是從上面 MicroPython 官網版本修改而來, 僅加入適應 CircuitPython 部分 :
# https://github.com/adafruit/Adafruit_CircuitPython_SSD1306
在下面的測試中我仍然使用 WeMOS D1 Mini 微控器, 當然 ESP-01 模組, ESP-12 模組或 NodeMCU 開發板也是可以的. SSD1360 模組與 D1 Mini 的硬體接線很簡單, 就是 SCL 接 D1 (GPIO 5), SDA 接 D2 (GPIO 4), 如下圖所示 :
軟體部分, ESP8266 模組需燒錄 MicroPython v1.8.5 版以上韌體, 否則無法執行 ssd1306.py 模組. 首先須匯入已上傳的 ssd1306.py 模組, 另外還須從 machine 模組匯入 Pin 與 I2C :
import ssd1306
from machine import Pin, I2C
i2c=I2C(scl=Pin(5), sda=Pin(4)) #指定 GPIO 腳建立 I2C 物件
oled=ssd1306.SSD1306_I2C(128, 32, i2c) #指定解析度建立 SSD1306 物件
此處 SSD1306_I2C() 建構函數的傳入參數為 (width, height, i2c), 分別是 OLED 面板的寬度 128, 高度 32, 以及 I2C 物件, 傳回值為一個 SSD1306_I2C 物件, 這樣便可以呼叫 SSD1306_I2C 物件的方法如 fill(), pixel() 或 text() 等來顯示資訊.
例如 fill(1) 是將顯示記憶體的每一個像素都點亮, 用 show() 輸出後就會使整個螢幕全亮; 而 fill(0) 則是全暗, 相當於 1602 LCD 裡的 clear() 清除螢幕的作用.
oled.fill(1) #將顯示記憶體每一個畫素填滿 1 (點亮)
oled.show() #將顯示記憶體內容輸出到面板 (全亮)
oled.fill(0) #將顯示記憶體每一個畫素填滿 0 (熄滅)
oled.show() #將顯示記憶體內容輸出到面板 (全暗)
事實上 fill(1) 與 fill(0) 與下列用 pixel() 填像素作用相同 :
for x in range(128):
for y in range(32):
oled.pixel(x, y, 1)
for x in range(128):
for y in range(32):
oled.pixel(x, y, 0)
注意, 不管是 fill(), pixel() 或 text(), 都只是在 SSD1306 內的顯示記憶體上操作而已, 並不是實際輸出到顯示面板上, 執行後面板上不會顯示任何訊息, 必須呼叫 show() 函數將顯示記憶體之內容輸出才會顯示.
測試 1 : 每隔 2 秒點亮與熄滅整個 OLED 面板
#main.py
import ssd1306
from machine import Pin, I2C
import time
i2c=I2C(scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 32, i2c)
while True:
oled.fill(1)
oled.show()
time.sleep(2)
oled.fill(0)
oled.show()
time.sleep(2)
接下來要測試 pixel(x, y, col) 方法, 此方法是在指定的畫素位置 (x, y) 輸出一個亮點 (col=1) 或暗點 (col=0). 下列測試 2 是要在面板的四周畫出一個長方形框 :
測試 2 : 在 OLED 面板的四周畫出一個長方形框
#main.py
import ssd1306
from machine import Pin, I2C
i2c=I2C(scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 32, i2c)
for i in range(128):
oled.pixel(i, 0, 1) #填上邊框
oled.pixel(i, 31, 1) #填下邊框
if i < 32:
oled.pixel(0, i, 1) #填左邊框
oled.pixel(127, i, 1) #填右邊框
oled.show()
此程式為了節省時間只使用一個迴圈填畫素, 由於 X 軸座標 0~127, Y 軸座標 0~31, range() 函數會傳回串列 [0,1,....,127], 以 X 軸座標當迴圈運行 128 次, 同時填上邊框與下邊框, 在 i 於 0~31 期間, 也同時填 Y 軸的左右邊框. 結果如下 :
下面測試 3 要測試 text() 方法, 即在 OLED 面板上顯示文字. 此驅動程式的 text() 以 8*8=64 bits 描繪一個 ASCII 碼, 不過實際描繪寬度為 6 bits, 亦即左右各保留 1 px 的間距以免前後字元連在一起. 例如下面是 '0' 的 Bitmap :
因此一列可顯示 128/8=16 個字元, 一行可顯示 32/8=4 列字元, 整個面板可顯示 16*4=64 個字元. 在顯示多列文字時, 下一列 y 座標應往下移 8 才不會黏在一起, 如下面測試 3 所示 :
測試 3 : 在 OLED 面板上顯示文字
#main.py
import ssd1306
from machine import Pin, I2C
i2c=I2C(scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 32, i2c)
str='012345678901234567890'
for i in range(5):
oled.text(str, 0, i*8)
oled.show()
此程式中 str 含有 20 個字元, 卻只顯示 16 個, 可見多出來的字元事實上被驅動模組丟棄了, 並沒有存入顯示記憶體中.
接下來參考 MicroPython 1602 測試的範例 4, 在 OLED 面板上顯示溫溼度與亮度等氣候資訊, 硬體接線參考 :
# MicroPython on ESP8266 (十七) : 液晶顯示器 1602A 測試
跟 1602 LCD 顯示器一樣, SSD1306 OLED 也是一列只能顯示 16 個字元, 但可以顯示 4 列, 所以我把顯示格式做了些調整, 第一列顯示日期與星期, 第二列顯示時分秒, 第三列顯示環境資訊, 規劃如下 :
不過 SSD1306_I2C 物件的 text() 方法只要指定第一個字元要顯示的開始座標位置即可, 其他字元會自動往後一一顯示, 超過 16 個的字元會被丟棄.
測試 4 : 在 OLED 面板上顯示溫溼度亮度資訊
#main.py
import time, ntptime, dht
from machine import I2C, Pin, ADC
import ssd1306
def fill_zero(n):
if n<10:
return '0' + str(n)
else:
return str(n)
def fill_blank(n):
if n<10:
return ' ' + str(n)
else:
return str(n)
i2c=I2C(scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 32, i2c)
DHTPIN=Pin(16, Pin.IN)
LEDPIN=Pin(2, Pin.OUT)
d=dht.DHT11(DHTPIN)
adc=ADC(0)
week={0:'Mon',1:'Tue',2:'Wed',3:'Thu',4:'Fri',5:'Sat',6:'Sun'}
try:
ntptime.settime()
except:
pass
n=0
while True:
d.measure()
t=d.temperature()
h=d.humidity()
a=adc.read()
a=int(0.3*a + 0.7*adc.read())
a=round(a*100/1024)
utc_epoch=time.mktime(time.localtime())
Y,M,D,H,m,S,W,DY=time.localtime(utc_epoch + 28800)
YMD='%s-%s-%s' % (str(Y),fill_zero(M),fill_zero(D))
WD=week[W]
HmS='%s:%s:%s' % (fill_zero(H),fill_zero(m),fill_zero(S))
A='%s%%' % (fill_blank(a))
T='%sC' % (fill_blank(t))
H='%sH' % (fill_blank(h))
line1='%s %s' % (YMD, WD)
line2=HmS
line3='%s %s %s' % (T, H, A)
oled.fill(0) #清除螢幕以免舊資訊殘留疊加
#
oled.text(line1, 0, 0) #顯示日期星期
oled.text(line2, 0, 8) #顯示時間
oled.text(line3, 0, 16) #顯示溫溼度亮度
oled.show()
time.sleep(1)
n=n+1
if n >= 3600:
try:
ntptime.settime()
except:
pass
n=0
因為要避免舊資訊殘留疊加, 所以在更新顯示資料前先做清除螢幕動作, 但是這麼一來卻造成換頁時螢幕會跳動一下. 我嘗試用 pixel() 方法只清除要顯示的前三列, 即將上述程式碼中的 oled.fill(0) 改成下列 :
for x in range(128):
for y in range(24):
oled.pixel(x, y, 0)
但這並無法消除換頁跳動現象, 還是跟 fill(0) 一樣. 畢竟 SSD1306 與 1602 不同, 1602 的 putstr() 方法是以字元為單位, 更新時會清除舊的 bitmap 以新的字元之 bitmap 取代, 所以 1602 不需要清除畫面, 也就不會有換頁跳動現象.
2017-08-12 補充 :
晚上回到鄉下後測試發現, 只要單用 oled.fill(0) 即可清除舊畫面, 亦即只要將顯示記憶體全部 reset 就達到清除畫面目的了, 不需要呼叫 oled.show() 去刷新頁面, 就是後面這指令造成換頁跳動現象的.
在上面測試 4 裡我用 'C' 代表攝氏度數的單位, 能不能像 1602 測試中那用 custom_char() 方法自訂右上角一個小圈圈的度數符號呢? 很可惜地, 在 ssd1306.py 模組中並未提供類似的函數, 因此必須自己做, 攝氏度數小圓圈的 bitmap 如下 :
依據上面對於顯示區域的規劃, 此符號之座標位置為 (2,2), 即原本顯示 'C' 之處. 描繪此符號需使用 pixel() 方法將指定之畫素點亮, 上面這個度數小圓圈的亮點畫素座標可用下列元組串列表示, 只要將這 8 個點設為 1 即可 :
bitlist=[(2,0),(3,0),(1,1),(4,1),(1,2),(4,2),(2,3),(3,3)]
這些亮點的實際位置可用字元座標計算而得, 因為每個字元是 8*8 bitmap 所描繪, 因此畫素實際座標就是字元座標乘以 8 再加上字元內亮點座標即得. 例如第一個亮點之字元內座標為 (2,0)經此換算為實際座標 (18, 16), 其中 18=2*8+2, 16=2*8+0.
我模仿 1602 驅動模組的 custom_char() 函數寫了一個 SSD1306 版的函數如下 :
def custom_char(oled, x, y, bitlist, col=1):
for i in bitlist:
oled.pixel(x*8+i[0], y*8+i[1], col)
呼叫此函數後自訂字元的 bitmap 亮點就被寫入指定位置的顯示記憶體了. 完整程式如下, 新增的程式碼以藍色標示 :
測試 5 : 在 OLED 面板上顯示溫溼度亮度資訊 (使用自訂之攝氏度數符號)
#main.py
import time, ntptime, dht
from machine import I2C, Pin, ADC
import ssd1306
def fill_zero(n):
if n<10:
return '0' + str(n)
else:
return str(n)
def fill_blank(n):
if n<10:
return ' ' + str(n)
else:
return str(n)
def custom_char(oled, x, y, bitlist, col=1):
for i in bitlist:
oled.pixel(x*8+i[0], y*8+i[1], col)
i2c=I2C(scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 32, i2c)
DHTPIN=Pin(16, Pin.IN)
LEDPIN=Pin(2, Pin.OUT)
d=dht.DHT11(DHTPIN)
adc=ADC(0)
week={0:'Mon',1:'Tue',2:'Wed',3:'Thu',4:'Fri',5:'Sat',6:'Sun'}
try:
ntptime.settime()
except:
pass
n=0
while True:
d.measure()
t=d.temperature()
h=d.humidity()
a=adc.read()
a=int(0.3*a + 0.7*adc.read())
a=round(a*100/1024)
utc_epoch=time.mktime(time.localtime())
Y,M,D,H,m,S,W,DY=time.localtime(utc_epoch + 28800)
YMD='%s-%s-%s' % (str(Y),fill_zero(M),fill_zero(D))
WD=week[W]
HmS='%s:%s:%s' % (fill_zero(H),fill_zero(m),fill_zero(S))
A='%s%%' % (fill_blank(a))
T='%s' % (fill_blank(t))
H='%sH' % (fill_blank(h))
line1='%s %s' % (YMD, WD)
line2=HmS
line3='%s %s %s' % (T, H, A)
oled.fill(0)
oled.text(line1, 0, 0)
oled.text(line2, 0, 8)
oled.text(line3, 0, 16)
bitlist=[(2,0),(3,0),(1,1),(4,1),(1,2),(4,2),(2,3),(3,3)]
custom_char(oled, 2, 2, bitlist)
oled.show()
time.sleep(1)
n=n+1
if n >= 3600:
try:
ntptime.settime()
except:
pass
n=0
其實我們可以在每一個字元 8*8=64 bits 畫板上製作任何 bitmap 呼叫 text() 方法顯示於 16*4=64 個字元位置上, 在下列測試 6 中我製作了 0%, 20%, 40%, 60%, 80%, 100% 電池電量顯示符號 (包括垂直與水平方向) :
測試 6 : 在 OLED 面板上顯示 WiFi 連線狀態
#main.py
import time
from machine import I2C, Pin
import ssd1306
def custom_char(oled, x, y, bitlist, col=1):
for i in bitlist:
oled.pixel(x*8+i[0], y*8+i[1], col)
i2c=I2C(scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 32, i2c)
bv0p=[(3,0),(4,0),(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),
(1,2),(6,2),(1,3),(6,3),(1,4),(6,4),(1,5),(6,5),
(1,6),(6,6),(1,7),(2,7),(3,7),(4,7),(5,7),(6,7)]
bv100p=[(3,0),(4,0),(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),
(2,2),(3,2),(4,2),(5,2),
(2,3),(3,3),(4,3),(5,3),
(2,4),(3,4),(4,4),(5,4),
(2,5),(3,5),(4,5),(5,5),
(2,6),(3,6),(4,6),(5,6),
(1,2),(6,2),(1,3),(6,3),(1,4),(6,4),(1,5),(6,5),
(1,6),(6,6),(1,7),(2,7),(3,7),(4,7),(5,7),(6,7)]
bv20p=[(3,0),(4,0),(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),
(2,6),(3,6),(4,6),(5,6),
(1,2),(6,2),(1,3),(6,3),(1,4),(6,4),(1,5),(6,5),
(1,6),(6,6),(1,7),(2,7),(3,7),(4,7),(5,7),(6,7)]
bv40p=[(3,0),(4,0),(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),
(2,5),(3,5),(4,5),(5,5),
(2,6),(3,6),(4,6),(5,6),
(1,2),(6,2),(1,3),(6,3),(1,4),(6,4),(1,5),(6,5),
(1,6),(6,6),(1,7),(2,7),(3,7),(4,7),(5,7),(6,7)]
bv60p=[(3,0),(4,0),(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),
(2,4),(3,4),(4,4),(5,4),
(2,5),(3,5),(4,5),(5,5),
(2,6),(3,6),(4,6),(5,6),
(1,2),(6,2),(1,3),(6,3),(1,4),(6,4),(1,5),(6,5),
(1,6),(6,6),(1,7),(2,7),(3,7),(4,7),(5,7),(6,7)]
bv80p=[(3,0),(4,0),(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),
(2,3),(3,3),(4,3),(5,3),
(2,4),(3,4),(4,4),(5,4),
(2,5),(3,5),(4,5),(5,5),
(2,6),(3,6),(4,6),(5,6),
(1,2),(6,2),(1,3),(6,3),(1,4),(6,4),(1,5),(6,5),
(1,6),(6,6),(1,7),(2,7),(3,7),(4,7),(5,7),(6,7)]
bh100p=[ (1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),
(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),
(0,3),(1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),
(0,4),(1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),
(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6)]
bh80p=[ (1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),
(1,2), (3,2),(4,2),(5,2),(6,2),(7,2),
(0,3),(1,3), (3,3),(4,3),(5,3),(6,3),(7,3),
(0,4),(1,4), (3,4),(4,4),(5,4),(6,4),(7,4),
(1,5), (3,5),(4,5),(5,5),(6,5),(7,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6)]
bh60p=[ (1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),
(1,2), (4,2),(5,2),(6,2),(7,2),
(0,3),(1,3), (4,3),(5,3),(6,3),(7,3),
(0,4),(1,4), (4,4),(5,4),(6,4),(7,4),
(1,5), (4,5),(5,5),(6,5),(7,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6)]
bh40p=[ (1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),
(1,2), (5,2),(6,2),(7,2),
(0,3),(1,3), (5,3),(6,3),(7,3),
(0,4),(1,4), (5,4),(6,4),(7,4),
(1,5), (5,5),(6,5),(7,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6)]
bh20p=[ (1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),
(1,2), (6,2),(7,2),
(0,3),(1,3), (6,3),(7,3),
(0,4),(1,4), (6,4),(7,4),
(1,5), (6,5),(7,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6)]
bh0p=[ (1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),
(1,2), (7,2),
(0,3),(1,3), (7,3),
(0,4),(1,4), (7,4),
(1,5), (7,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6)]
custom_char(oled, 0, 0, bv0p)
custom_char(oled, 1, 0, bv20p)
custom_char(oled, 2, 0, bv40p)
custom_char(oled, 3, 0, bv60p)
custom_char(oled, 4, 0, bv80p)
custom_char(oled, 5, 0, bv100p)
custom_char(oled, 0, 1, bh0p)
custom_char(oled, 1, 1, bh20p)
custom_char(oled, 2, 1, bh40p)
custom_char(oled, 3, 1, bh60p)
custom_char(oled, 4, 1, bh80p)
custom_char(oled, 5, 1, bh100p)
oled.show()
最後我想修改設定無線網路連線的程式, 讓 ESP8266 模組連線 AP 時的狀態可以在 SSD1306 OLED 面板上, 參考 :
# MicroPython v1.9.1 版韌體測試
測試 7 : 在 OLED 面板上顯示 WiFi 連線狀態
from machine import Pin,PWM,I2C
import network
import time
import ssd1306
WAIT_FOR_CONNECT=8
pwm2=PWM(Pin(2), freq=5, duty=512)
i2c=I2C(scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 32, i2c)
def set_ap():
html="""
<!DOCTYPE html>
<html>
<head><title>AP Setup</title></head>
<body>
%s
</body>
</html>
"""
form="""
<form method=get action='/update_ap'>
<table border="0">
<tr>
<td>SSID</td>
<td><input name=ssid type=text></td>
</tr>
<tr>
<td>PWD </td>
<td><input name=pwd type=text></td>
</tr>
<tr>
<td></td>
<td align=right><input type=submit value=Connect></td>
</tr>
</table>
</form>
"""
import socket
addr=socket.getaddrinfo('192.168.4.1', 80)[0][-1]
s=socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print('listening on', addr)
while True:
cs, addr=s.accept()
print('client connected from', addr)
data=cs.recv(1024)
request=str(data,'utf8')
print(request, end='\n')
if request.find('update_ap?') == 5:
para=request[request.find('ssid='):request.find(' HTTP/')]
ssid=para.split('&')[0].split('=')[1]
pwd=para.split('&')[1].split('=')[1]
sta.connect(ssid,pwd)
while not sta.isconnected():
pass
print('Connected:IP=',sta.ifconfig()[0])
cs.send(html % 'Connected:IP=' + sta.ifconfig()[0])
oled.fill(0)
oled.text('IP=' + sta.ifconfig()[0],0,0)
oled.show()
else:
cs.send(html % form)
cs.close()
s.close()
def get_ip():
return (network.WLAN(network.STA_IF).ifconfig()[0],
network.WLAN(network.AP_IF).ifconfig()[0])
def ap_on():
network.WLAN(network.AP_IF).active(True)
def ap_off():
network.WLAN(network.AP_IF).active(False)
#try connecting to lastest configured AP
sta=network.WLAN(network.STA_IF)
sta.active(True)
print('Connecting to AP ...')
oled.text('Connecting to AP',0,0)
oled.show()
time.sleep(WAIT_FOR_CONNECT)
if not sta.isconnected():
set_ap()
else:
pwm2.deinit()
Pin(2).value(0)
print('Connected:IP=', sta.ifconfig()[0])
oled.fill(0)
oled.text('IP=' + sta.ifconfig()[0],0,0)
oled.show()
#Application code is written here or import from a separate file
import myapp
myapp.main()
藍色部分為新增的程式碼, 當 ESP-12 模組或 D1 Mini 開機時 OLED 面板會顯示 'Connecting to AP', 板上 LED 會快閃, 若能連線到之前設定的 AP, 則 8 秒後會顯示 'ap=192.168.xxx.xxx', 板上 LED 熄滅, 並開始執行 myapp.py 應用程式. 若無法連線前次 AP, 可用手機 WiFi 連線 SSID 為 MicroPython_xxxxxx 之 ESP8266 內建基地台 (密碼為 micropythoN), 開啟手機瀏覽器連線 192.168.4.1, 在顯示的網頁中輸入附近可連線之 AP, 然後將 ESP-12 或 D1 Mini 重開機即可.
參考 :
# DIY - ESP8266:SSD1306 0.96吋 I2C OLED 屏電路(十九)
# I2C driver for micropython esp8266 ssd1306 OLED (ssd1306a.py is paired down and works with the font.py file to allowing generating text)
# ssd1306 using I2C on the esp8266
# https://github.com/adafruit/micropython-adafruit-ssd1306
# ESP01(ESP8266) driving an SSD1306 display in microPython
# A playground for various MicroPython scripts
# A sensor monitor with OLED in MicroPython
# ssd1306 using I2C on the esp8266
# I2C driver for micropython esp8266 ssd1306 OLED (另一個驅動程式)
# Micropython - OLED module with the ssd1306 chip (Pyboard)
# Adafruit's Extended Ascii font as stmhal/framebuf's default font. #2673
沒有留言 :
張貼留言