class I2C —— 一种双线串行协议¶
I2C 是一种用于设备间通信的双线协议。在物理层面上,它由 2 根线组成:SCL 和 SDA,分别是时钟线和数据线。
I2C 对象在创建时会绑定到特定的总线。它们可以在创建时初始化,也可以稍后再初始化。
打印 I2C 对象可以查看其配置信息。
硬件和软件两种 I2C 实现分别通过 I2C 和 SoftI2C 类提供。硬件 I2C 利用系统底层的硬件支持来执行读写操作,通常高效快速,但可能对可使用的引脚有所限制。软件 I2C 通过位操作(bit-banging)实现,可用于任意引脚,但效率不如硬件 I2C。这两个类提供相同的方法,主要区别在于构造方式不同。
备注
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 外设。允许的取值取决于具体的移植版本/开发板
scl 应为指定用于 SCL 的引脚对象。
sda 应为指定用于 SDA 的引脚对象。
freq 应为一个整数,用于设置 SCL 的最大频率。
timeout 是 I2C 事务所允许的最长时间(以微秒为单位)。某些移植版本不允许使用此参数。
请注意,某些移植版本/开发板会为 scl 和 sda 提供默认值,可在此构造函数中更改。另一些则会为 scl 和 sda 提供固定值,无法更改。
通用方法¶
原始 I2C 操作¶
以下方法实现了原始的 I2C 控制器总线操作,可以组合起来完成任意 I2C 事务。它们用于在你需要对总线进行更精细控制时使用,否则使用标准方法(见下文)即可。
这些方法仅在
SoftI2C类上可用。标准总线操作¶
以下方法实现了针对指定外设设备的标准 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 为真,则在传输结束时生成一个 STOP 条件,即使收到了 NACK 也是如此。该函数返回收到的 ACK 数量。
- writevto(addr: int, vector: tuple | list, stop: bool = True, /) int¶
将 vector 中包含的字节写入由 addr 指定的外设。vector 应为一个由支持缓冲区协议的对象组成的元组或列表。addr 只发送一次,随后 vector 中每个对象的字节依次写出。vector 中的对象长度可以为零字节,在这种情况下它们不会对输出产生贡献。
如果在写入 vector 中某个对象的某个字节后收到 NACK,则不再发送剩余字节以及任何剩余对象。如果 stop 为真,则在传输结束时生成一个 STOP 条件,即使收到了 NACK 也是如此。该函数返回收到的 ACK 数量。
内存操作¶
某些 I2C 设备充当可读写的内存设备(或一组寄存器)。在这种情况下,一次 I2C 事务关联着两个地址:外设地址和内存地址。以下方法是用于与此类设备通信的便捷函数。
- readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes¶
从由 addr 指定的外设、起始于由 memaddr 指定的内存地址,读取 nbytes 个字节。参数 addrsize 以位为单位指定地址大小。返回包含所读数据的
bytes对象。
class SoftI2C —— 软件模拟的 I2C 总线¶
SoftI2C 类通过对任意 GPIO 引脚进行位操作(bit-banging)来实现 I2C。它对外提供与 I2C 相同的方法集合,外加底层的原始总线操作(start()、stop()、readinto()、write()),供需要组装非标准事务的调用者使用。当你所需的引脚未连接到硬件 I2C 模块、当你需要的总线数量超过硬件所能提供的数量,或者需要与要求特殊时序(额外时钟、写后重复启动等)的设备通信时,可使用它。
构造函数¶
- class machine.SoftI2C(scl: Pin, sda: Pin, *, freq: int = 400000, timeout: int = 50000)¶
构造一个由
scl/sda驱动的软件 I2C 总线。freq是目标 SCL 时钟速率(以 Hz 为单位)(由于位操作循环的开销,实际速率通常会更低)。timeout是等待时钟拉伸(总线上另一设备将 SCL 保持为低)的最长时间(以微秒为单位);超时后会引发OSError(ETIMEDOUT)。通用方法¶
原始 I2C 操作¶
以下方法实现了原始的 I2C 控制器总线操作,可以组合起来完成任意 I2C 事务。它们仅 SoftI2C 可用——硬件
I2C类并不对外提供这些方法。- readinto(buf: bytearray, nack: bool = True, /) None¶
从总线读取字节到
buf中。读取len(buf)个字节;除最后一个字节外,每个字节之后都会发送 ACK。在最后一个字节之后,nack=True(默认值)会发送 NACK 以结束传输;nack=False则发送 ACK,使设备保持选中状态,以便后续的readinto()。
标准总线操作¶
以下方法实现了针对指定外设设备的标准 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 条件。
内存操作¶
某些 I2C 设备充当可读写的内存设备(或一组寄存器)。在这种情况下,一次 I2C 事务关联着两个地址:外设地址和内存地址。以下方法是用于与此类设备通信的便捷辅助函数。
- readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes¶
从
addr处的设备、起始于寄存器memaddr,读取nbytes个字节。addrsize是以位为单位的寄存器地址宽度(通常为8或16)。