1、IIC 介绍
IIC(Inter-Integrated Circuit)总线是一种由数据线 SDA 和时钟线 SCL 构成的两线式串行总线,可发送和接收数据,常用于 MPU/MCU 与外部设备连接通信、数据传输。每个连接到总线的设备都有一个独立的地址,主机可以通过该地址来访问不同设备。因为 IIC 协议比较简单,常用GPIO 来模拟 II C时序,这种方法称为模拟 IIC。
IIC 总线的特点:
- 一主多从:IIC 协议允许多个“从机”芯片和一个或更多的“主机”芯片进行通讯。这种通信模式使得一个微控制器可以轻松地与多个外围设备通信,连接到总线的接口数量只由总线电容 400pF 的限制决定。
- 两根线:IIC 通信仅需要两根信号线来完成信息交换,即 SCL 时钟信号线和 SDA 数据输入/输出线。这种简化的硬件接口降低了系统的复杂性和成本。
- 半双工:IIC 通信是半双工的,说明数据可以在两个方向上传输,但同一时刻只能在一个方向上传输。这限制了数据的传输速率,但满足大多数低速外围设备的需求。
- 同步通信:IIC 是一种同步通信协议,发送端在发送串行数据的同时提供一个时钟信号。接收端根据发送端提供的时钟信号接收数据,这确保了数据的准确性和一致性。
- 总线上数据的传输速率在标准模式下可达 100Kbit/s,在快速模式下可达 400Kbit/s,在高速模式下可达 3.4Mbit/s。
2、模拟 IIC 的时序
- 空闲状态:当 IIC 总线不处于通信状态时,SDA 和 SCL 两条信号线同时处于高电平,这被定义为总线的空闲状态,即释放总线。
- 开始信号:当 SCL 为高期间,SDA 由高到低的跳变。这个信号标志着通信的开始,并使所有从机变为活动状态,等待接收地址位。
- 停止信号:当 SCL 为高期间,SDA 由低到高的跳变。这个信号标志着通信的结束。
- 应答信号:在 IIC 通信中,每传输一个字节后,接收端会发送一个应答信号来告知发送端数据是否接收成功。当主机发送了 8 位数据后,也就是在第 9 个时钟周期会再产生一个时钟,此时主机放开 SDA 的控制,读取 SDA 电平, 在上拉电阻的影响下,此时SDA默认为高,必须从机拉低, 以确认收到数据。应答信号为低电平时表示有效应答(ACK),高电平时表示非应答(NACK)。
3、模拟 IIC 传输流程
- SDA 和 SCL 开始都为高, 然后主机将 SDA 拉低, 表示开始信号;
- 在接下来的 8 个时间周期里,主机控制 SDA 的高低, 发送从机地址。 其中第 8 位如果为0, 表示接下来是写操作,即主机传输数据给从机; 如果为 1,表示接下来是读操作,即从机传输数据给主机;注意,数据传输方式为 MSB,即从最高位到最低位。
- 总线中对应从机地址的设备,发出应答信号;
- 在接下来的 8 个时间周期里,如果是写操作,则主机控制 SDA 的高低;如果是读操作,则从机控制 SDA 的高低;
- 每次传输完成, 接收数据的设备, 都发出应答信号;
- 最后, 在 SCL 为高时, 主机由低拉高 SDA, 表示停止信号,整个传输结束;
4、模拟 IIC 的实现代码
4.1、GPIO 引脚定义与初始化
IIC 的SCL 和 SDA 引脚在 iic.h 中定义:
/* 定义 I2C 引脚 */
#define I2C_SCL_PIN GPIO_Pin_6
#define I2C_SDA_PIN GPIO_Pin_7
#define I2C_GPIO_PORT GPIOB
#define I2C_RCC_CLOCK RCC_AHB1Periph_GPIOB
/* I2C SDA 或 SCL 引脚拉高或拉低 */
#define SCL_H() GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN)
#define SCL_L() GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN)
#define SDA_H() GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN)
#define SDA_L() GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN)
IIC 的 GPIO 则在 iic.c 文件中初始化: