ESP32使用MicroPython:I2C總線

概要

本節教程爲大家簡要介紹I²C總線協議,並以一個簡單的例程教會大家在MicroPython下使用I²C

快速開始

from machine import Pin, I2C

# construct a software I2C bus
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)

# construct a hardware I2C bus
i2c = I2C(0)
i2c = I2C(1, scl=Pin(5), sda=Pin(4), freq=400000)

i2c.scan()              # scan for slave devices

i2c.readfrom(0x3a, 4)   # read 4 bytes from slave device with address 0x3a
i2c.writeto(0x3a, '12') # write '12' to slave device with address 0x3a

什麼是I²C

I²C(Inter-integrated Circuit)最早是飛利浦在1982年開發設計的一種總線協議。I²C總線支持設備之間的短距離通信,用於處理器和一些外圍設備之間的接口,它只需要兩根信號線來完成信息交換。

通信原理

物理接線

I²C最少只需要兩根線,和異步串口類似,但可以支持多個從(slave)設備,和SPI不同的是,I²C可以支持多主機(mul-master)系統,允許有多個master並且每個master都可以與所有的slaves通信(master之間不可通過I²C通信,並且每個master只能輪流使用I²C總線)。master是指啓動數據傳輸的設備並在總線上生成時鐘信號以驅動該傳輸,而被尋址的通信設備都作爲slaves。

I²C通訊只需要2條雙向總線:

功能編號 含義
SDA(serial data:串行數據線) 傳輸數據,SDA線傳輸數據是大端傳輸,每次傳輸一個字節
SCL(serial clock:串行時鐘線) 同步數據收發

我們以最爲簡單的一個主機對應多個從機爲例,進行接下來的原理科普。

數據有效性

SDA 線上的數據必須在時鐘的高電平週期保持穩定,數據線的高或低電平狀態只有在 SCL 線的時鐘信號是低電平時才能改變。

換言之,SCL爲高電平時表示有效數據,SDA爲高電平表示“1”,低電平表示“0”;SCL爲低電平時表示無效數據,此時SDA會進行電平切換,爲下次數據表示做準備。如圖13-1爲數據有效性的時序圖。

起始條件S和停止條件P

  • 起始條件S:當SCL高電平時,SDA由高電平向低電平轉換;

  • 停止條件P:當SCL高電平時,SDA由低電平向高電平轉換。

起始和停止條件一般由主機產生。總線在起始條件後處於busy的狀態,在停止條件的某段時間後,總線纔再次處於空閒狀態。如下圖爲起始和停止條件的信號產生時序圖。

數據格式

I2C傳輸的數據以字節爲單位,每個字節必須爲8位,可以傳輸任意多個字節,上圖中以一個字節的數據爲例進行分析,I2C的數據格式具有以下特點:

  • 每個字節後必須跟一個響應位 ACK(如上圖中的SCL上ACK),因此實際上傳輸一個字節(8位)的數據需要花費9位的時間。

  • SDA上首先傳輸字節的最高位,從上圖中我們可以看出,位數編號的發送順序從左至右 是 Bit7-Bit0

響應ACK

數據接收方收到傳輸的一個字節數據後,需要給出響應,此時處在第九個時鐘,發送端釋放SDA線控制權 ,將SDA電平拉高,由接收方控制。

接收方表示成功的接收到了8位一個字節的數據,便將SDA拉低爲低電平,即ACK信號,表示應答

PDU

當你理解了時序圖之後,接下來我們爲大家貼出I2C的PDU(Protocol Data Unit:協議數據單元,即數據格式):

以下圖片均來自網絡

硬件資源

ESP32 本身擁有 2 個 I²C 總線接口,根據用戶的配置,總線接口可以用作 I²C 主機或從機模式。

然而遺憾的是,MicroPython ESP32上的I²C是軟件模擬的,並沒有充分利用到ESP32的硬件資源。

理論上來講,大部分同時支持輸入與輸出的GPIO都能夠被配置爲I²C的管腳資源。

I2C API文檔

class machine.I2C(scl, sda, freq)

scl: I²C設備時鐘引腳對象
sda: I²C設備數據線引腳對象
freq: SCL時鐘頻率 0 <freq≤ 500000(Hz)

定義I2C

示例:

from machine import I2C, Pin
I2C = I2C(scl=Pin(5), sda=Pin(4), freq=100000)

常用類函數

I2C.init(scl, sda, freq)

函數說明:初始化構造I²C總線。

scl:SCL信號線的I/O口
sda:SDA信號線的I/O口
freq:SCL時鐘頻率

示例:

I2C.init(scl=Pin(5), sda=Pin(4), freq=100000)

I2C.scan()

函數說明:掃描0x08到0x77之間的I²C地址,並返回設備列表。
示例:

I2C.scan()

I2C.start()

函數說明:在總線上觸發START狀態(SCL爲高電平時,SDA轉爲低電平)。
示例:

I2C.start()

I2C.stop()

函數說明:在總線上觸發STOP狀態 (SCL爲高電平時,SDA轉爲高電平)。
示例:

I2C.stop()

I2C.write(buf)

函數說明:buf中的數據寫入到總線,並返回寫入的字節數。

buf:存儲數據的緩衝區

注意
使用write()函數時要與start函數一起使用,否則無法返回寫入的字節數。
示例:

buf = b'123'
I2C.start()
I2C.write(buf)

I2C.readinto(buf, nack=True)

函數說明:從總線上讀取數據並存放到buf,無返回值。

buf:存儲數據的緩衝區

注意:
讀取的字節數是buf的長度。在接收到最後一個字節之前,總線將發送ACK信號。在接收到最後一個字節後,如果nack爲True,那麼將發送一個NACK信號,否則將發送一個ACK信號。 示例:

buf=bytearray(3)
I2C.readinto(buf)

標準總線操作

下面介紹的函數是標準的I²C主模式讀寫操作。

I2C.readfrom(addr, nbytes)

函數說明:從指定地址設備讀取數據,返回讀取對象,這個對象與I²C設備有關。

addr:I²C設備地址(可由scan函數讀取出來)
nbytes:要讀取數據的大小

示例:

>>> print(I2C.scan())
[24]
>>> data = I2C.readfrom(24, 8)
>>> print(data)
b'\x00\x02\x00\x00\xe8\x03\xe8\x03'

I2C.readfrom_into(addr, buf)

函數說明:從指定地址設備讀取buf.len()個數據到buf。

addr:I²C設備地址(可由scan函數讀取出來)
buf:存儲數據的緩衝區

示例:

>>> buf = bytearray(8)
>>> I2C.readfrom_into(24, buf)
>>> print(buf)
bytearray(b'\x00\x02\x00\x00\xe8\x03\xe8\x03')

I2C.writeto(addr, buf)

函數說明:將buf中的數據寫入設備,並返回寫入數據的大小。

addr:I²C設備地址(可由scan函數讀取出來)
buf:存儲數據的緩衝區

示例:

>>> b = bytearray(3)
>>> b[0] = 24
>>> b[1] = 111
>>> b[2] = 107
>>> i = I2C.writeto(24,b)
3

內存操作

某些 I²C 設備作爲存儲設備 (或一組寄存器) ,可以讀取或者寫入。這種情況下,有兩個地址和 I²C 事務相關: 從設備地址和內存地址。下面方法用於和這些設備進行通信。

I2C.readfrom_mem(addr, memaddr, nbytes, addrsize=8)

函數說明:從I²C設備的寄存器中讀取並返回數據。

addr:I²C設備地址(可由scan函數讀取出來)
memaddr:寄存器地址
nbytes:要讀取的字節大小
addrsize:指定地址大小,默認爲8位(在ESP8266上這個參數無效,地址大小總是8位)

示例:

b = I2C. readfrom_mem(24,  0x58, 3)
print(b)

運行結果:

b'\x00\x02\x01'

I2C.readfrom_mem_into(addr, memaddr, buf, addrsize=8)

函數說明:從I²C設備的寄存器中讀取buf.len()個數據到buf,無返回值。

addr:I²C設備地址(可由scan函數讀取出來)
memaddr:寄存器地址
buf:存儲數據的緩衝區
addrsize:指定地址大小,默認爲8位(在ESP8266上這個參數無效,地址大小總是8位),讀取數據數量是buf的長度。

示例:

buf=bytearray(8)
I2C.readfrom_mem_into(24, 0x58, buf)

I2C.writeto_mem(addr, memaddr, buf, addrsize=8)

函數說明: 將buf 中的數據全部寫入到從設備 addr 的內存 memaddr。

addr:I²C設備地址(可由scan函數讀取出來)
memaddr:寄存器地址
buf:存儲數據的緩衝區
addrsize:指定地址大小,默認爲8位(在ESP8266上這個參數無效,地址大小總是8位),讀取數據數量是buf的長度。

示例:

buf = b'123'
I2C.writeto_mem(24, 0x58, buf)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章