2023年1月3日 星期二

MicroPython 學習筆記 : 1602 LED 顯示器測試 (一)

去年底重做 SSD1306 測試後, 又從零件箱中找出傳統 2*16 的 1602A LCD 顯示器, 趁著元旦假期也重測看看以前的函式庫是否還能用, 參考我在 2017 年寫的這篇 :


本系列全部文章參考 :


本篇仍是以 D1 mini 開發板進行測試, 用 ESP8266 驅動 1602A 需要下列兩個函式庫 :


也可以從原作者的 GitHub 下載 : 


將此兩個函式庫上傳到 ESP8266 開發板即可開始進行測試. 

在這之前要先將 1602A 與 D1 mini 透過 1602 I2C 模組用 I2C 介面連接起來. 也可以直接用 1602A 與 ESP8266 連接, 但那要用掉 ESP8266 八個 GPIO 埠來直接傳送資料給 1602A 的 D0~D7 腳, 而且還有其他接腳須要控制, 連接起來很麻煩, 一般都會用一個 1602  I2C 模組介面板插在 1602A 針腳上, 然後用上面那兩個 I2C 函式庫去控制, 這樣只要用兩個 GPIO 埠即可. 這個 1602 12C 模組其實是利用 PCF8574 多工器 IC 將 IO 埠集縮並轉成 I2C 介面以節省輸出入腳與簡化操作方式, 接線圖重貼如下 :





上圖中 1602 I2C 模組上有 VCC, GND, SCL, 與 SDA 四支腳, VCC 與 GND 分別接到 D1 min 的 3.3V 與 GND 腳, SCL 接到 D1 腳 (GPIO5), 而 SDA 則接到 D2 腳 (GPIO4), 這兩個 GPIO 埠是 ESP8266 的預設 I2C 輸出入埠, 但也可以用其他任何 GPIO 埠, 因為最新版的 MicroPython 韌體已經改用軟體 I2C 類別 SoftI2C 來處理 I2C 通訊, 取代原本的內建 I2C 類別, SoftI2C 可用任何 GPIO 腳模擬為 SCL 與 SDA 腳. 

其次要注意的是, 1602A 有 3.3V 與 5V 兩種電壓, 兩種板子的差別在於 3.3V 款的背板有一顆位準轉換 IC 與電容, 圖片重貼如下 : 




我使用的是上方的 3.3V 款, 可直接從 D1 mini 的 3.3V 與 GND 腳取得電源. 接好電源後 1602A 的藍色背光就會亮起來, 接著就可匯入函式庫來輸出字串到 1602A 顯示幕, 先使用 I2C 類別 : 

>>> from machine import I2C, Pin   
>>> from esp8266_i2c_lcd import I2cLcd   

然後呼叫內建的 I2C 類別建構函式來建立 I2C 物件 : 

>>> i2c=I2C(scl=Pin(5), sda=Pin(4), freq=400000)   
>>> type(i2c)  
<class 'SoftI2C'>     
>>> dir(i2c)  
['__class__', 'readinto', 'start', 'stop', 'write', 'init', 'readfrom', 'readfrom_into', 'readfrom_mem', 'readfrom_mem_into', 'scan', 'writeto', 'writeto_mem', 'writevto']
>>> 

可見 I2C() 會建立一個 SoftI2C 物件 (新版 MicroPython 韌體), 它提供了低階的讀寫方法. 但通常不會直接使用這些讀寫方法來通訊, 而是使用上面從 esp8266_i2c_lcd 模組匯入的 I2cLcd 類別. 此處 freq 參數設定 I2C 匯流排通訊速率為 400K bps, scl 與 sda 參數設定 GPIO5 與 GPIO4 為 I2C 通訊接腳, 此為 ESP8266 預設的 I2C 埠, 參考 : 



 板子腳位 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 TXD UART 送端
 RX RXD UART 收端
 A0 ADC 類比輸入 (0~3.3V)

 
接著呼叫 SoftI2C 物件的 scan() 方法掃描目前 I2C 匯流排上有哪些設備 (I2C 是一對多協定), 它會傳回設備的 10 位址串列 :
 
>>> i2c.scan()    
[39] 

此處只有 1601 I2C 模組這一個 I2C 設備, 其位址為 39, 此乃十進制, 須將其轉為二進制 0x27, 因為接下來要呼叫 I2cLcd 類別之建構函式 I2cLcd() 時要傳入此二進制位址做為第二參數, 此函式之參數結構如下 :

I2cLcd(i2c, i2c_addr, num_lines, num_columns)

第一參數為上面建立之 SoftI2C 物件, 第二參數為 I2C 設備之二進制位址, 第三參數為 LCD 顯示幕列數 (1602A 為 2), 第四參數為 LCD 顯示行數 (1602A 為 16) :

>>> lcd=I2cLcd(i2c, 0x27, 2, 16)     
>>> type(lcd)   
<class 'I2cLcd'>   

可見 I2cLcd() 會建立一個 I2cLcd 物件, 檢視其內容 : 

>>> dir(lcd)   
[object_link_for_thonny=1073677440]['__class__', '__init__', '__module__', '__qualname__', 'clear', '__dict__', 'i2c', 'i2c_addr', 'num_lines', 'num_columns', 'hal_write_init_nibble', 'LCD_FUNCTION_RESET', 'LCD_FUNCTION', 'LCD_FUNCTION_2LINES', 'hal_write_command', 'hal_backlight_on', 'hal_backlight_off', 'backlight', 'hal_write_data', 'LCD_CLR', 'LCD_HOME', 'LCD_ENTRY_MODE', 'LCD_ENTRY_INC', 'LCD_ENTRY_SHIFT', 'LCD_ON_CTRL', 'LCD_ON_DISPLAY', 'LCD_ON_CURSOR', 'LCD_ON_BLINK', 'LCD_MOVE', 'LCD_MOVE_DISP', 'LCD_MOVE_RIGHT', 'LCD_FUNCTION_8BIT', 'LCD_FUNCTION_10DOTS', 'LCD_CGRAM', 'LCD_DDRAM', 'LCD_RS_CMD', 'LCD_RS_DATA', 'LCD_RW_WRITE', 'LCD_RW_READ', 'cursor_x', 'cursor_y', 'display_off', 'backlight_on', 'hide_cursor', 'display_on', 'show_cursor', 'blink_cursor_on', 'blink_cursor_off', 'backlight_off', 'move_to', 'putchar', 'putstr', 'custom_char']

它提供了許多方法來顯示字串, 重貼如下 :


 I2cLcd 物件的方法 說明
 move_to(x, y) 移動游標至座標 (x, y)
 putchar(str) 從游標目前位置開始顯示字串 str, 然後將游標移到字串結束之下一位置
 putchar(char) 從游標目前位置開始顯示字元 char, 然後將游標移到下一位置
 custom_char(location, charmap) 將字元圖樣 charmap 寫入 CGRAM 記憶體位址 location=0~7 
 clear() 清除 LCD 螢幕並將游標移至左上角座標 (0, 0)
 show_cursor() 顯示游標 (底線)
 hide_cursor() 隱藏游標
 blink_cursor_on() 開啟游標閃爍功能
 blink_cursor_off() 關閉游標閃爍功能
 display_on() 開啟顯示功能
 display_off() 關閉顯示功能 (即顯示白屏)
 backlight_on() 開啟背光
 backlight_off() 關閉背光


其中最常用的是 putstr() 方法, 它會從目前游標位置開始顯示字串, 例如 : 

>>> lcd.putstr("Hello World!\nIt's working!")    

注意, 傳入字串中可用 '\n' 表示換列, 結果如下 : 




完整程式碼如下 : 

# main.py
from machine import I2C, Pin   
from esp8266_i2c_lcd import I2cLcd   
i2c=I2C(scl=Pin(5), sda=Pin(4), freq=400000)   
lcd=I2cLcd(i2c, 0x27, 2, 16)     
lcd.putstr("Hello World!\nIt's working!")    

由於新版 MicroPython 韌體另外內建了 SoftI2C 類別可模擬任何 GPIO 腳做 I2C 通訊, 所以上面程式碼改為從 machine 匯入 SoftI2C 類別, 並改為呼叫 SoftI2C() 建構式建立 SoftI2C 物件也是可以的 (因 I2C 類別未來將廢棄, 故建議改用 SoftI2C), 例如 : 

# main.py
from machine import SoftI2C, Pin   
from esp8266_i2c_lcd import I2cLcd   
i2c=SoftI2C(scl=Pin(5), sda=Pin(4), freq=400000)   
lcd=I2cLcd(i2c, 0x27, 2, 16)     
lcd.putstr("Hello World!\nIt's working!")    

結果是一樣的. 

接下來測試 SoftI2C 是否能將任何 GPIO 腳模擬成 I2C 的 scl 與 sda, 以下選定 D0 (GPIO 16) 當作 scl, D8 (GPIO15) 當作 sda : 

# main.py
from machine import SoftI2C, Pin   
from esp8266_i2c_lcd import I2cLcd   
i2c=SoftI2C(scl=Pin(16), sda=Pin(15), freq=400000)   
lcd=I2cLcd(i2c, 0x27, 2, 16)     
lcd.putstr("Hello World!\nIt's working!")    

更改 scl 與 sda 接線後在 Thonny 輸入

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

Type "help()" for more information.
>>> from machine import SoftI2C, Pin    
>>> from esp8266_i2c_lcd import I2cLcd   
>>> i2c=SoftI2C(scl=Pin(16), sda=Pin(15), freq=400000)   
>>> type(i2c)   
<class 'SoftI2C'>   
>>> lcd=I2cLcd(i2c, 0x27, 2, 16)     
>>> lcd.putstr("Hello World!\nIt's working!")   

結果與上面相同. 

參考 : 


沒有留言 :