I2C 的應用與 SPI 很類似,差別在於 I2C 只需要兩支線路 SDA 與 SCL 即可完成訊息通訊,在 ESP32 平台的 micropython 語言也已建立 I2C 的類別,當然也分了硬體與軟體的 I2C 機制,所以今天就來看看相關的語法如何使用,文末會用一個 I2C LCD1602 來實際操作顯示文字或數字。
1. I2C 原理
關於 I2C 的架構與原理,JIMI 哥在之前分享這篇 Arduino Uno I2C 時有提到過,有興趣的朋友可以再點擊該篇的第 2 節參考,這邊我們就快速講一下重點,I2C 的主要透過兩條資料線進行傳輸– SCK 與 SDA,架構上會分 Master 與 Slave,為了能夠辨別在這個 I2C 網路上的所有裝置,所以每個裝置(或設備),必須內建一個I2C 位置(Address),在訊息的封包上就會包含這個 Address,確認通訊的雙方對象為何,其完整的架構如下圖:
2. Micropython I2C 類別
Micropython I2C 跟 SPI 類似,都有硬體與軟體 I2C 的區別,硬體的 I2C 就是直接使 mcu 內部 I2C 控制器進行通訊,軟體的 I2C 則可以搭配任意的 GPIO,利用軟體模擬出通訊協定,雖然軟體 I2C 使用彈性較大,但 JIMI哥建議直接使用硬體 I2C 即可,因為在 ESP32 內,硬體 I2C 已可以搭配任意 Output 的 GPIO,較不會浪費 mcu 的執行效能,這邊我們先來看一下如何建立 Micropython 硬體 I2C 物件的簡單範例:
from machine import Pin, I2C hw_i2c = I2C(1, freq=200000)
Hardware I2C 的第一個參數為 id 可以填入 0 或 1,第 2 個參數指定頻率,如果各位使用的是預設腳位去操作 I2C 通訊,就可以省略腳位的設定,每個 id 都有一個預設的腳位,其設定如下:
id | 0 | 1 |
SCL | GPIO 18 | GPIO 25 |
SDA | GPIO 19 | GPIO 26 |
但想要使用其他 Output 腳位的話,就得使用下面的建構子:(一樣是 Hardware I2C)
hw_i2c=I2C(1,scl=Pin(27),sda=Pin(26),freq=200000)
初始化 I2C 物件後,可以操作的方法就有很多,下面為列出幾個基本的操作:
1.接收訊息
hw_i2c.readfrom(0x10, 2) #接收來自裝置位址 0x10 的兩個byte資料
2. 傳送訊息
hw_i2c.writeto(0x10, 'JR') #寫資料"JR"到裝置位址 0x10
當然也可以是用 python 內建的 bytes 資料型態定義好再傳送訊息
buf=['J','R'] hw_i2c.writeto(0x10, bytes(buf))
知道怎麼建立 I2C 物件與基本操作方法後,就來直接用 I2C 介面的 LCD1602 顯示文字看看。
3. I2C lcd1602 實驗
* 電路接法
這個實驗就用 ESP32 id1 的 I2C 來進行操作,所以 LCD I2C 腳位對應 ESP32 開發板分別為 SCL=GPIO25、SDA=GPIO26,LCD1602 VCC 與 GND 連接 ESP32 開發板上的 3.3V 與 GND 即可(要記得找 3.3V 可用的 LCD1602),完整的接法如下:
* 上傳 I2cLcd 模組到 ESP32
由於 micropython 沒有內建 lcd1602 的模組,所以 JIMI 哥這邊推薦大家可以下載在 Github上 Dave Hylands 作者的 python_lcd 專案,在 lcd 資料夾中找到其中兩個檔案 esp8266_i2c_lcd.py 跟 lcd_api.py 這兩個檔案,下載到電腦,後續上傳到 ESP32 開發板內,此時就可以開始撰寫我們自己的程式碼。
小提醒:忘記如何上傳檔案到 ESP32 板,可以參考這篇 205-micropython spi 內的說明
* 完整程式碼
我們簡單的利用此 I2cLcd 模組來顯示文字資訊,程式碼如下:
from machine import I2C, Pin from esp8266_i2c_lcd import I2cLcd DEFAULT_I2C_ADDR = 0x27 hw_i2c0 = I2C(1, freq=200000) lcd = I2cLcd(hw_i2c0, DEFAULT_I2C_ADDR, 2, 16) lcd.putstr("Hello World ~~") while 1: pass
* 程式講解
from machine import I2C, Pin from esp8266_i2c_lcd import I2cLcd
這邊除了 import 必須的 I2C 與 Pin 類別外,也導入 I2cLcd module(已事先上傳檔按到 ESP32 板內)。
DEFAULT_I2C_ADDR = 0x27 hw_i2c = I2C(1, freq=200000) lcd = I2cLcd(hw_i2c, DEFAULT_I2C_ADDR, 2, 16) lcd.putstr("Hello World ~~") while 1: pass
- DEFAULT_I2C_ADDR 這個參數是手邊的 lcd1602 的 I2C 位址,如果不確定可以檢查模組背面是否有標示,最常見的就是 0x27 或 0x20。
- hw_i2c 就是新建立 Micropython I2C 物件,採用內建的 id1 與預設腳位。
lcd = I2cLcd(hw_i2c, DEFAULT_I2C_ADDR, 2, 16)
這行是建立 I2cLcd 的物件,第1個參數為 I2C 物件,第2個參數為 lcd1602 的位址,第3個參數為 lcd 的行數,第四個參數就是 lcd 的字元數。- lcd.putstr 這個方法源自 lcdapi.py 這個檔案,功能為顯示字串,該模組內還有很多其他的方法,各位如果有興趣可以研究。
4. 結語
Micropython I2C 的使用方法與 SPI 非常類似,各位僅需要知道 I2C 原理,確認傳輸速度上限與位址後,在網路上搜尋對應模組就可以進行操作,當然 LCD1602 只是 I2C 應用的其中一環,還有其他的裝置像 EEPROM 跟很多 Sensor 都有 I2C 的版本,先預告下次的內容就是用 I2C 介面的 OLED 來顯示文字或圖案哦! 今天的內容就到這邊,如果在使用上有遇到任何問題,歡迎在下面留言給我~!!
↓↓↓↓↓↓賣場連結↓↓↓↓↓↓
歡迎大家有需要的話,可以多多支持一下我們的蝦皮賣場喔! 😀
吉米家官方店-創客機器人材料專賣 https://shopee.tw/jimirobot.tw
Follow JIMI哥 Twitter : https://twitter.com/jimirobot <–得到最新文章通知
This Post Has 4 Comments
黃傳宗
1 5 月 2021Traceback (most recent call last):
File “”, line 6, in
File “esp8266_i2c_lcd.py”, line 25, in __init__
OSError: [Errno 110] ETIMEDOUT
在執行後跑出這個錯誤 不知道是哪裡做錯了(使用esp8266,程式碼如下)
from machine import I2C, Pin
from esp8266_i2c_lcd import I2cLcd
DEFAULT_I2C_ADDR = 0x27
hw_i2c0 = I2C(scl=Pin(5),sda=Pin(4), freq=200000)
lcd = I2cLcd(hw_i2c0, DEFAULT_I2C_ADDR, 2, 16)
lcd.putstr(“Hello World ~~”)
while 1:
pass
jimi
3 5 月 2021Hi~ 因我手邊沒有esp8266的實驗板,無法直接跑這段程式看看,不過依經驗推斷,這應該跟 i2c 要初始化 lcd1602 時的timeout 有關,也就是可以試著檢查一下 i2c的周邊電路是否連接正確,如scl 或 clk 是否連接相反? pin腳連接是否正確? lcd模組的電壓是否選用3.3V規格的(8266應該是3.3V)?操作電源是否穩定之類的相關問題,先釐清一下是否為硬體的問題,或許這樣就會找出相關的答案,以上答案供您參考一下~
林品心
27 12 月 2021我也出現了這個問題,請問有舊版的esp8266_i2c_lcd函式庫嗎?新版的好像有地方寫錯
林品心
27 12 月 2021可能esp8266_i2c_lcd新版函式庫定義有誤
可以暫時用軟體模擬腳位,就能正常使用
程式碼如下:
from machine import I2C, Pin
from esp8266_i2c_lcd import I2cLcd
DEFAULT_I2C_ADDR = 0x27
i2c=I2C(scl=Pin(22),sda=Pin(21),freq=200000)
lcd = I2cLcd(i2c,0x27, 2, 16)
lcd.putstr(“Hello World ~~”)
while 1:
pass
互動環境(shell)訊息:
>>> %Run -c $EDITOR_CONTENT
Warning: I2C(-1, …) is deprecated, use SoftI2C(…) instead