2022年12月20日 星期二

MicroPython 學習筆記 : SSD1306 OLED 顯示器測試 (二)

本篇繼續來測試 SSD1306 OLED 顯示器, 但這回改用 0.96 吋的 OLED, 其解析度為 128*64 可顯示 16 行 8 列共 128 個字元. 我前陣子在 Aliexpress 買的十片 0.96 吋 SSD1306 OLED 目前尚未沒到貨, 但 12/12 日在 momo 買的旗標 "Flag’s 創客•自造者工作坊 Python 感測器大應用 - 智慧生活X雲端" 套件盒裡附了一顆 0.96 吋的 SSD1306, 剛好可以先拿來做實驗 :




五年前測試 SSD1306 的文章 :


本系列全部文章參考 :


MicroPython 的 ssd1306 模組用法教學文件參考 :


在前篇 SSD1306 OLED 測試中使用了 ESP-WROOM-32 開發板, 這次改用 D1 mini 來測試, 關於此板參考 : 


此開發板的接腳定義如下表 : 


 板子腳位 ESP8266 腳位 功能
 D0 GPIO16 IO
 D1 GPIO5 IO, SCL 
 D2 GPIO4 IO, SDA 
 D3 GPIO0 IO, 內建 10K 上拉電阻
 D4 GPIO2 IO, 內建 10K 上拉電阻與 LED
 D5 GPIO14 IO, SCK
 D6 GPIO12 IO, MISO
 D7 GPIO13 IO, MOSI
 D8 GPIO15 IO, SS, 內建 10K 上拉電阻
 TX GPIO1 UART 送端
 RX GPIO3 UART 收端
 A0 ADC0 類比輸入 (0~3.3V)


參考 :


可見預設的 I2C 接腳為 D1(GPIO5) : scl 與 D2 (GPIO4) : sda, 接線圖如下 :




參考前一篇測試文章, 可用上傳 ssd1306.py 模組或用 upip.install() 線上安裝模組 : 


此處使用 upip.install() 線上安裝, 先用 xtools 的函式將 D1 mini 連上網路 :

MicroPython v1.19.1 on 2022-06-18; ESP module with ESP8266

Type "help()" for more information.
>>> import xtools    
>>> xtools.connect_wifi_led(ssid='EDIMAX-tony', passwd='blablabla')     
Connecting to network...
network config: ('192.168.2.116', '255.255.255.0', '192.168.2.1', '168.95.1.1')
'192.168.2.116'

然後匯入 upip 模組, 呼叫其 install() 函式線上安裝 micropython-ssd1306 模組 :  
>>> import upip   
>>> upip.install('micropython-ssd1306')     
Installing to: /lib/
Warning: micropython.org SSL certificate is not validated
Installing micropython-ssd1306 0.3 from https://files.pythonhosted.org/packages/01/d0/0841d47772962c80af3ab178ef062ed2cd524cb99eb38463e669428402a8/micropython-ssd1306-0.3.tar.gz
>>> import ssd1306  
>>> dir(ssd1306)  
['__class__', '__name__', 'const', 'framebuf', 'SSD1306', 'SSD1306_I2C', 'SSD1306_SPI', 'SET_CONTRAST', 'SET_ENTIRE_ON', 'SET_NORM_INV', 'SET_DISP', 'SET_MEM_ADDR', 'SET_COL_ADDR', 'SET_PAGE_ADDR', 'SET_DISP_START_LINE', 'SET_SEG_REMAP', 'SET_MUX_RATIO', 'SET_IREF_SELECT', 'SET_COM_OUT_DIR', 'SET_DISP_OFFSET', 'SET_COM_PIN_CFG', 'SET_DISP_CLK_DIV', 'SET_PRECHARGE', 'SET_VCOM_DESEL', 'SET_CHARGE_PUMP'] 

這樣就安裝完成了, 先測試全屏填入 1, 這會點亮全部畫素 :

>>> from machine import Pin, SoftI2C   
>>> i2c=SoftI2C(scl=Pin(5), sda=Pin(4))   # SCL=GPIO5. SDA=GPIO4
>>> oled=ssd1306.SSD1306_I2C(128, 64, i2c)    # 0.96 吋解析度 128*64 
>>> oled.fill(1)      # 將 1 填滿顯示緩衝器 (點亮畫素)
>>> oled.show()    # 將顯示緩衝器內容輸出到螢幕

結果如下 : 




可見螢幕為黃藍兩色 (白的是照相時出現的 alias 假信號, 像掃描線一樣不斷往上跑, 這是取樣頻率較掃描頻率低造成的), 其兩列是黃底, 可做為標題, 後 6 列是藍底, 可做為內容. 

下面依序在 1~8 列顯示 Hello World :

>>> oled.text('Hello World', 0, 0, 0)   
>>> oled.show()   
>>> oled.text('Hello World', 0, 8, 0)     
>>> oled.show()   
>>> oled.text('Hello World', 0, 16, 0)      
>>> oled.show()   
>>> oled.text('Hello World', 0, 24, 0)   
>>> oled.show()   
>>> oled.text('Hello World', 0, 32, 0)  
>>> oled.show()   
>>> oled.text('Hello World', 0, 40, 0)   
>>> oled.show()   
>>> oled.text('Hello World', 0, 48, 0)   
>>> oled.show()   
>>> oled.text('Hello World', 0, 56, 0)   
>>> oled.show()   

因為前面先用 1 填滿螢幕, 所以這裡 oled.text() 的第 3 參數要填 0 (畫素熄滅, 變黑), 結果如下 :




有三列 Hello World 被假信號遮住了. 

上面輸出 8 列 Hello World 的指令用迴圈處理叫精簡, 下面改用亮點來顯示文字, 所以先用 fill(0) 熄滅每個畫素, 然後用迴圈顯示 Hello World :

>>> oled.fill(0)     # 熄滅全部畫素
>>> oled.show()   
>>> for i in range(0, 8):      # i=0~7
     oled.text('Hello World', 0, i*8, 1)      # 點亮畫素
     oled.show()   

結果如下 : 




可見暗的背景在拍照時 alias 形成的掃瞄線比較不明顯. 

接下來要測試 SoftI2C() 是否可將 D1 mini 其他的 GPIO 腳模擬成 I2C 通訊埠, 例如改用預設為 SPI 通訊埠的 GPIO13 (D7, 預設的 MOSI 腳) 當 SCL; GPIO12 (D6, 預設的 MISO 腳) 當 SDA, 接團如下所示 : 

 


然後輸入如下程式碼 :

>>> import ssd1306    
>>> from machine import Pin, SoftI2C     
>>> i2c=SoftI2C(scl=Pin(13), sda=Pin(12))       # 改用 D7 與 D6 當 I2C 介面
>>> oled=ssd1306.SSD1306_I2C(128, 64, i2c)     
>>> for i in range(0, 8):     
     oled.text('Hello World', 0, i*8, 1)   
     oled.show()   

結果與上面相同, SoftI2C() 確實可模擬非預設 GPIO 腳當 I2C 介面用. 

接下來想延伸下面這篇文章的範例, 將 SSD1306 應用在現場設定 WiFi 基地台的連線設定上 :


程式的一般架構如下圖所示, 由 boot.py, main.py, 與 app1.py 構成, 執行控制權也是依此順序交遞 :




但此處只有一個 App : app1.py, 一個讓板載 LED 閃爍的 App, 程式碼如下 :

# app1.py
from machine import Pin,PWM

def main():
    #application codes are placed here  
    pwm2=PWM(Pin(2), freq=1, duty=512)

if __name__ == "__main__":  
    main()  

主程式 main 則改成如下內容 :

# main.py 
import xtools    
import config
import app1
import ssd1306
from machine import Pin, SoftI2C

i2c=SoftI2C(scl=Pin(13), sda=Pin(12))
oled=ssd1306.SSD1306_I2C(128, 64, i2c)
oled.fill(0)
oled.text('Connecting WiFi', 0, 0, 1)
oled.show()  
ip=xtools.connect_wifi_led(config.SSID, config.PASSWORD)   # 從 config.py 讀取
if not ip:
    mac=xtools.get_mac().replace(':', '')[6:]    # 取得 MAC 的最後 6 碼
    oled.fill(0)
    oled.text('Connect AP', 0, 0, 1)
    oled.text('SSID:', 0, 8, 1)
    oled.text('MicroPython-', 0, 16, 1)    # SSID 太長分成兩列顯示
    oled.text(mac, 0, 24, 1)
    oled.text('Password:', 0, 32, 1)          # Password  太長分成兩列顯示
    oled.text('micropythoN', 0, 40, 1)
    oled.text('IP:192.168.4.1', 0, 48, 1)
    oled.show()
    ip=xtools.set_ap()    # OLED 顯示完再呼叫 set_ap()
    if not ip:  
        print('無法連線 WiFi 基地台')
        oled.fill(0)
        oled.text('Connection fail', 0, 0, 1)   # 連線 WiFi 失敗, 按 Reset 重設
        oled.text('Press reset', 0, 8, 1)
        oled.text('Try again', 0, 16, 1)
        oled.show()
    else:
        print("WiFi 連線成功! IP : ", ip)
        oled.fill(0)
        oled.text('WiFi connected', 0, 0, 1)
        oled.text(ip, 0, 8, 1)
        oled.show()        
        app1.main()  
else:
    print("WiFi 連線成功! IP : ", ip)
    oled.text('WiFi connected', 0, 8, 1)
    oled.text(ip, 0, 16, 1)
    oled.show()            
    app1.main()

將 app1.py 與 main.py 用 Thonny 上傳到 D1 mini 開發板根目錄, 當 config.py 設定的 WiFi 基地台資訊正確, 順利連線的結果如下 : 




SSD1306 螢幕上首先會在第一列顯示 "Connecting WiFi", 當連線成功時則在第二列顯示 "WiFi connected", 以及在第三列顯示所獲得的 IP. 

然後故意將 config.py 中的連線資訊打錯, 上傳開發板後按 Reset 鈕重開機, 結果會因為連線失敗而進入 AP 模式, 並在 SSD1306 螢幕上依序顯示如下提示訊息 : 

Connect AP
SSID : MicroPython-xxxxxx
Password : micropythoN
IP : 192.168.4.1 

其中 SSID 太長所以拆分在兩列顯示.




這是提醒使用者開啟手機 WiFi 連線到 SSID 為 MicroPython-xxxxxx 的 ESP32/ESP8266 本身 AP, 再開啟手機瀏覽器連線其網頁伺服器 192.168.4.1, 然後於網頁中設定要連線的 WiFi 基地台 : 




按連線即進行設定並更新 config.py :




連線成功後按 Reset 重開機即可順利連線 WiFi 並執行 app1.py :




這樣就可以將此開發板拿到任何有 WiFi 涵蓋的處所現場設定連線資訊, 不須在實驗室預先設定好 config.py 設定檔了. 但如果沒有現場設定的需求, 那麼上面的 main.py 就有點麻煩, 因為只要換個地方, 原先的 config.py 就無法連線了, 得用手機連線 ESP32/ESP8266 的 AP 模式網頁伺服器進行設定. 如果沒有現場設定 WiFi 需求, 那就直接在 Thonny 改 config.py 就好了, 下面是移除 AP 模式現場設定後的 main.py :

# main.py
import xtools    
import config
import app1
import ssd1306
from machine import Pin, SoftI2C

i2c=SoftI2C(scl=Pin(13), sda=Pin(12))
oled=ssd1306.SSD1306_I2C(128, 64, i2c)
oled.fill(0)
oled.text('Connecting WiFi', 0, 0, 1)
oled.show()  
ip=xtools.connect_wifi_led(config.SSID, config.PASSWORD)
if not ip:
    print('無法連線 WiFi 基地台')
    oled.fill(0)
    oled.text('Connection fail', 0, 0, 1)
    oled.text('Set config.py', 0, 8, 1)
    oled.text('Try again', 0, 16, 1)
    oled.show()
else:
    print("WiFi 連線成功! IP : ", ip)
    oled.text('WiFi connected', 0, 8, 1)
    oled.text(ip, 0, 16, 1)
    oled.show()            
    app1.main()

平常接筆電測試就可以用這個 main.py, 連線失敗用 Thonny 去改 config.py 即可. 否則用前面現場設定的 main.py 會進入 AP 模式網頁伺服器的無限迴圈, 這時要用 Thonny 管理板子上的檔案會出現 busy 現象, 必須在按 Reset 時於進 AP 模式前抓時間切入. 

沒有留言 :