class I2C -- 雙線串列協定#

I2C 是一種用於裝置間通訊的雙線協定。在實體層上,它由 2 條線組成:SCL 與 SDA,分別為時脈線與資料線。

I2C 物件在建立時會附接至特定的匯流排。它們可以在建立時初始化,或稍後再行初始化。

列印 I2C 物件可取得其組態的相關資訊。

硬體與軟體 I2C 實作分別透過 I2CSoftI2C 類別提供。硬體 I2C 利用系統底層的硬體支援來執行讀寫,通常有效率且快速,但可能限制可使用哪些接腳。軟體 I2C 以位元觸發(bit-banging)方式實作,可用於任何接腳,但效率不如硬體。這些類別提供相同的方法,主要差異在於建構方式。

備註

I2C 匯流排運作時需要在 SDA 與 SCL 上加裝上拉電路。通常這些是阻值範圍在 1 - 10 kOhm 的電阻,從各 SDA/SCL 連接至 Vcc。若沒有這些電阻,行為將無法預期,從阻塞、非預期的看門狗重置到單純的錯誤值都有可能。這類上拉電路通常已內建於 MCU 開發板或感測器擴充板上,但這並非通則。因此若遇到問題請務必檢查。亦可參閱 Adafruit 關於 I2C 接線這份出色的 學習指南

使用範例:

from machine import I2C

i2c = I2C(freq=400000)          # create I2C peripheral at frequency of 400kHz
                                # depending on the port, extra parameters may be required
                                # to select the peripheral and/or pins to use

i2c.scan()                      # scan for peripherals, returning a list of 7-bit addresses

i2c.writeto(42, b'123')         # write 3 bytes to peripheral with 7-bit address 42
i2c.readfrom(42, 4)             # read 4 bytes from peripheral with 7-bit address 42

i2c.readfrom_mem(42, 8, 3)      # read 3 bytes from memory of peripheral 42,
                                #   starting at memory-address 8 in the peripheral
i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42
                                #   starting at address 2 in the peripheral

建構式#

class machine.I2C(id: int, *, scl: Pin | None = None, sda: Pin | None = None, freq: int = 400000, timeout: int = 50000)#

使用下列參數建構並回傳一個新的 I2C 物件:

  • id 用於識別特定的 I2C 周邊裝置。允許的值取決於特定的 port/開發板

  • scl 應為一個接腳物件,指定要用於 SCL 的接腳。

  • sda 應為一個接腳物件,指定要用於 SDA 的接腳。

  • freq 應為一個整數,用於設定 SCL 的最大頻率。

  • timeout 是允許 I2C 交易的最長時間,以微秒為單位。某些 port 不允許使用此參數。

請注意,某些 port/開發板會有 sclsda 的預設值,可在此建構式中變更。其他則會有無法變更的 sclsda 固定值。

一般方法#

init(scl: Pin, sda: Pin, *, freq: int = 400000) None#

使用給定的引數初始化 I2C 匯流排:

  • scl 是 SCL 線的接腳物件

  • sda 是 SDA 線的接腳物件

  • freq 是 SCL 的時脈速率

在硬體 I2C 的情況下,實際的時脈頻率可能低於所要求的頻率。這取決於平台硬體。實際速率可透過列印 I2C 物件來判定。

scan() List[int]#

掃描介於 0x08 至 0x77(含)之間的所有 I2C 位址,並回傳有回應者的清單。當某裝置的位址(包含寫入位元)在匯流排上送出後,若該裝置將 SDA 線拉低,即表示該裝置有回應。

原始 I2C 操作#

下列方法實作了原始的 I2C 控制器匯流排操作,可組合以構成任何 I2C 交易。當你需要更多對匯流排的控制時可使用它們,否則可使用標準方法(見下文)。

這些方法僅在 SoftI2C 類別上可用。

start() None#

在匯流排上產生 START 條件(當 SCL 為高時 SDA 由高轉低)。

stop() None#

在匯流排上產生 STOP 條件(當 SCL 為高時 SDA 由低轉高)。

readinto(buf: bytearray, nack: bool = True, /) None#

從匯流排讀取位元組並存入 buf。讀取的位元組數為 buf 的長度。在接收除最後一個位元組以外的所有位元組後,會於匯流排上送出 ACK。在接收最後一個位元組後,若 nack 為真則會送出 NACK,否則會送出 ACK(在此情況下,周邊裝置會假設後續呼叫還會讀取更多位元組)。

write(buf: bytes) int#

buf 中的位元組寫入匯流排。每個位元組之後會檢查是否收到 ACK,若收到 NACK 則停止傳送剩餘的位元組。此函式回傳所收到的 ACK 數量。

標準匯流排操作#

下列方法實作了針對給定周邊裝置的標準 I2C 控制器讀寫操作。

readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes#

addr 所指定的周邊裝置讀取 nbytes。若 stop 為真,則在傳輸結束時產生 STOP 條件。回傳一個包含所讀取資料的 bytes 物件。

readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None#

addr 所指定的周邊裝置讀取資料至 buf。讀取的位元組數為 buf 的長度。若 stop 為真,則在傳輸結束時產生 STOP 條件。

此方法回傳 None

writeto(addr: int, buf: bytes, stop: bool = True, /) int#

buf 中的位元組寫入 addr 所指定的周邊裝置。若在寫入 buf 中某個位元組後收到 NACK,則不再傳送剩餘的位元組。若 stop 為真,則即使收到 NACK,仍會在傳輸結束時產生 STOP 條件。此函式回傳所收到的 ACK 數量。

writevto(addr: int, vector: tuple | list, stop: bool = True, /) int#

vector 中所含的位元組寫入 addr 所指定的周邊裝置。vector 應為一個由具備緩衝協定的物件所組成的元組或清單。addr 只會送出一次,接著 vector 中每個物件的位元組會依序寫出。vector 中的物件長度可以為零位元組,此情況下它們不會對輸出有所貢獻。

若在寫入 vector 中某個物件的某個位元組後收到 NACK,則不再傳送剩餘的位元組以及任何剩餘的物件。若 stop 為真,則即使收到 NACK,仍會在傳輸結束時產生 STOP 條件。此函式回傳所收到的 ACK 數量。

記憶體操作#

某些 I2C 裝置可作為記憶體裝置(或一組暫存器),可從中讀取與寫入。在此情況下,一次 I2C 交易會關聯兩個位址:周邊位址與記憶體位址。下列方法是用於與此類裝置通訊的便利函式。

readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes#

addr 所指定的周邊裝置、自 memaddr 所指定的記憶體位址開始讀取 nbytes。引數 addrsize 以位元為單位指定位址大小。回傳一個包含所讀取資料的 bytes 物件。

readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None#

addr 所指定的周邊裝置、自 memaddr 所指定的記憶體位址開始讀取資料至 buf。讀取的位元組數為 buf 的長度。引數 addrsize 以位元為單位指定位址大小。

此方法回傳 None

writeto_mem(addr: int, memaddr: int, buf: bytes, *, addrsize: int = 8) None#

memaddr 所指定的記憶體位址開始,將 buf 寫入 addr 所指定的周邊裝置。引數 addrsize 以位元為單位指定位址大小。

此方法回傳 None

class SoftI2C -- 軟體模擬的 I2C 匯流排#

SoftI2C 類別透過對任意 GPIO 接腳進行位元觸發(bit-banging)來實作 I2C。它公開與 I2C 相同的方法介面,並額外提供低階的原始匯流排操作(start()stop()readinto()write()),供需要組裝非標準交易的呼叫端使用。當你需要的接腳未接至硬體 I2C 區塊、需要的匯流排數量多於硬體所提供、或需要與要求特殊序列(額外的時脈、寫入後重複的 START 等)的裝置通訊時,可使用它。

建構式#

class machine.SoftI2C(scl: Pin, sda: Pin, *, freq: int = 400000, timeout: int = 50000)#

建構一個由 scl / sda 驅動的軟體 I2C 匯流排。

freq 是目標 SCL 時脈速率,以 Hz 為單位(由於位元觸發迴圈的額外開銷,實際速率通常較低)。

timeout 是等待時脈延展(clock stretching,即匯流排上其他裝置將 SCL 持續拉低)的最長時間,以微秒為單位;逾時即會引發 OSError(ETIMEDOUT)

一般方法#

init(scl: Pin, sda: Pin, *, freq: int = 400000) None#

使用給定的接腳與頻率重新初始化軟體 I2C 匯流排。等同於在同一物件上建構一個新的 SoftI2C

scan() List[int]#

掃描介於 0x08 至 0x77(含)之間的所有 I2C 位址,並回傳有回應者的清單。

原始 I2C 操作#

下列方法實作了原始的 I2C 控制器匯流排操作,可組合以構成任何 I2C 交易。它們僅限 SoftI2C 使用——硬體 I2C 類別並不公開它們。

start() None#

在匯流排上產生 START 條件(當 SCL 為高時 SDA 由高轉低)。

stop() None#

在匯流排上產生 STOP 條件(當 SCL 為高時 SDA 由低轉高)。

readinto(buf: bytearray, nack: bool = True, /) None#

從匯流排讀取位元組至 buf。會讀取 len(buf) 個位元組;除最後一個外,每個位元組之後都會送出 ACK。在最後一個位元組之後,nack=True(預設值)會送出 NACK 以結束傳輸;nack=False 則送出 ACK,使裝置維持選定狀態以供後續的 readinto()

write(buf: bytes) int#

buf 寫入匯流排,每個位元組之後檢查 ACK。傳輸會在首次出現 NACK 時停止。回傳所收到的 ACK 數量。

標準匯流排操作#

下列方法實作了針對給定周邊裝置的標準 I2C 控制器讀寫操作。

readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes#

從 7 位元位址 addr 的裝置讀取 nbytes。若 stop 為真,則在傳輸結束時產生 STOP 條件。

readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None#

addr 的裝置讀取 len(buf) 個位元組至 buf。若 stop 為真,則在傳輸結束時產生 STOP 條件。

writeto(addr: int, buf: bytes, stop: bool = True, /) int#

buf 寫入 addr 的裝置。傳輸會在首次出現 NACK 時停止。若 stop 為真,則一律在傳輸結束時產生 STOP 條件(即使提早出現 NACK 亦然)。回傳所收到的 ACK 數量。

writevto(addr: int, vector: tuple | list, stop: bool = True, /) int#

vector 中各緩衝區的串接內容作為單一交易寫入 addr 的裝置。空緩衝區會被忽略。在 stop 語意與回傳值方面的行為與 writeto() 相同。

記憶體操作#

某些 I2C 裝置可作為記憶體裝置(或一組暫存器),可從中讀取與寫入。在此情況下,一次 I2C 交易會關聯兩個位址:周邊位址與記憶體位址。下列方法是用於與此類裝置通訊的便利輔助函式。

readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes#

addr 的裝置、自暫存器 memaddr 開始讀取 nbytesaddrsize 是暫存器位址的寬度,以位元為單位(通常為 816)。

readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None#

addr 的裝置、自暫存器 memaddr 開始讀取資料至 buf

writeto_mem(addr: int, memaddr: int, buf: bytes, *, addrsize: int = 8) None#

從暫存器 memaddr 開始,將 buf 寫入 addr 的裝置。