(1)基本电路结构
一、 串口 (UART) 的局限性与 I2C 的优势
- 串口缺点:只能实现一对一的通信。例如一个单片机若有三个串口,则最多只能连接三个串口设备。
- I2C 优势:只需一个接口即可连接大量设备,连接数量几乎不受限制。
二、 I2C 总线基本电路结构
- 信号线组成:主要由两根线组成:
- SCL (Serial Clock):串行时钟线。
- SDA (Serial Data):串行数据线。
- 主从关系:
- 主机 (Master):通常由单片机担任,总线上只有一个主机。
- 从机 (Slave):被连接的其他设备,可以有多个。
- 物理连接:所有设备的 SCL 引脚连接到总线的 SCL 线上,SDA 引脚连接到总线的 SDA 线上。
- 必要组件:必须分别为 SCL 和 SDA 线加装一个上拉电阻。
- 寻址机制:每个从机都有一个7 位地址(范围 0-127),扣除特殊地址后,总线最多可同时与 100 多个设备通信。(现在中因为有电容等物理原因,只能连接很少)
- 通信流程简述:主机先发送目标从机的 7 位地址建立通信,随后即可进行数据发送或读取
三、 时钟线与数据线的作用
- SCL (时钟线):用于传输时钟(高低电平),始终(大多数情况下)由主机发送给从机(单向)。其频率控制着数据传输的快慢。 从机有刹车功能,主机(单片机)发送数据的速度太快了,从机还没处理完上一个字节,从机可以强行把SCL 线拉低(写0)。
- SDA (数据线):用于传输有效数据,其通信方向是双向的
模拟一次:发送数字5(二进制0101)的过程(SCL高电压的时候SDA才会变成有效数据)
第一拍:
SCL 变成0(交警说:变阵!)。SDA 赶紧变成0。
SCL 变成1(交警说:拍照!)。接收方看一眼 SDA,哦,是0。
第二拍:
SCL 变成0(交警说:变阵!)。SDA 赶紧变成1。
SCL 变成1(交警说:拍照!)。接收方看一眼 SDA,哦,是1。
第三拍:
SCL 变成0(交警说:变阵!)。SDA 赶紧变成0。
SCL 变成1(交警说:拍照!)。接收方看一眼 SDA,哦,是0。
第四拍:
SCL 变成0(交警说:变阵!)。SDA 赶紧变成1。
SCL 变成1(交警说:拍照!)。接收方看一眼 SDA,哦,是1。
四、 逻辑“线与” (Wired-AND) 机制
- 关键设置:所有连接到 I2C 总线的设备引脚(SCL 和 SDA)都必须设置为开漏输出 (Open-Drain)模式。
- 开漏输出原理:
- 写 0:引脚内部 MOS 管闭合,引脚接地,输出低电平。
- 写 1:引脚内部 MOS 管断开,引脚呈高阻态,相当于从电路上断开。
- “线与”逻辑实现:
- 结果为 1:只有当总线上所有设备都写 1(即全部断开)时,总线才通过上拉电阻被拉至高电平。
- 结果为 0:只要有任何一个设备写 0(引脚接地),整条总线就会被拉低至低电平。
五、 信号的发送与接收
- 发送时钟信号 (SCL):所有从机将 SCL 引脚写 1(释放),由主机交替写 0 和 1 来产生高低变化的方波信号。
- 主机向从机发送数据:所有从机将 SDA 引脚写 1,主机通过控制其 SDA 引脚写 0 或 1,从而在总线上产生对应的数据信号。
- 从机向主机发送数据(主机读取):
- 主机写 1 释放 SDA 线。
- 非目标从机也写 1 释放 SDA 线。
- 目标从机通过控制其 SDA 引脚写 0 或 1,将数据发送到总线上供主机读取
主机向从机发送数据
从机向主机发送数据(主机读取)
发送时钟信号
(2)I²C通信协议
一、 I2C 通信基本流程
I2C 通信由主机(Master)主动发起,完整的过程包含以下四个阶段:
- 起始阶段:主机发送起始位(Start Bit)。
- 寻址阶段:主机发送从机地址及读写方向。
- 数据传输阶段:主机与从机之间进行数据交换。
- 停止阶段:主机发送停止位(Stop Bit)结束通信。
二、 I2C 数据帧格式
与串口通信不同,I2C 总线在一个数据帧内可以一次性传输多个字节。
- 起始位/停止位:标识通信的开始与结束。
- 寻址阶段:包含 7 位从机地址 所以只能是(0x00-0x7F)+ 1 位读写位(R/W)。
- 0:写操作(Write)。
- 1:读操作(Read)。
- 数据阶段:以字节(Byte)为单位传输,每个字节后必须跟一个应答位(ACK)。
1.起始位与停止位
起始位和停止位的产生都是在SCL(时钟线)保持高电压的前提下通过SDA(数据线)的电平跳变实现的:
- 起始位 (Start Bit):SCL 为高电平时,SDA 产生一个下降沿。
- 停止位 (Stop Bit):SCL 为高电平时,SDA 产生一个上升沿。
- 空闲状态:当总线没有通信时,SCL 和 SDA 均通过上拉电阻保持为高电平。
2.寻址与应答
- 寻址过程:主机发送 8 位数据(7位地址 + 1位读写位)后,会释放 SDA 线。
- 应答 (ACK):释放 SDA 线后,SDA由于上拉电阻,电压被拉高。被寻址的从机如果存在,会将 SDA 线拉低,表示“收到”。(谁发谁释放,另一者拉低)
- 非应答 (NACK):如果 SDA 保持高电平(可能是从机不存在或无法处理)不被拉低,则视为非应答。
| NACK 情况 | |
|---|---|
| 谁发的 | 作用 |
| 从机 NACK | 没接收到/有异常(接受到了) |
| 主机NACK(ACK) | “我不读了”/有异常 |
(3)I²C模块
一、 I2C 模块简介
- 模块:I2C 模块是单片机内部的片上外设,专门用于提供 I2C 通信接口。该单片机通常包含两个 I2C 模块:I2C1和I2C2。
- 内部结构:
- 数据通路:包含发送数据寄存器 (DR)、接收数据寄存器 (DR)和移位寄存器。发送时,数据从 DR 移动到移位寄存器并逐位发出;接收时,移位寄存器解析 SDA 波形后存入 DR。
- 状态寄存器 (SR1 & SR2):包含反映模块运行状态的各种标志位。
和USART不同 没有反着发反着接收,全是正着进正着出。
- 速度模式:
- 标准模式 (SM):波特率 ≤100 Kbps。
- 快速模式 (FM):波特率 ≤400 Kbps(单片机最高支持此模式)。
- 注:还存在 FM+ (1Mbps)、HSM (3.4Mbps) 和 UFM (5Mbps),但该单片机不支持。
- 占空比 (Duty Cycle):
- 仅在快速模式 (FM) 下有效。
- 2:1 模式:低电平时间 : 高电平时间 = 2:1(常用)。
- 16:9 模式:低电平时间 : 高电平时间 = 16:9。
二、通信引脚与重映射
三、 模块初始化代码流程
- 开启时钟:需开启I2C 模块时钟(在 APB1 总线上)、AFIO 时钟(若需重映射)和GPIO 时钟。
- 引脚重映射:使用
GPIO_PinRemapConfig将 I2C 映射到目标引脚(如 PB8/PB9)。 - GPIO 初始化:设置引脚为
GPIO_Mode_AF_OD,最大输出速度设为 2MHz 即可满足 400K 波特率需求。 - 模块强制复位:通过
RCC_APB1PeriphResetCmd先使能复位(按下复位键),再失能复位(松开复位键),以清除潜在故障状态。 - I2C 结构体初始化:
I2C_ClockSpeed:设置波特率(如 400,000)。I2C_Mode:选择I2C_Mode_I2C。I2C_DutyCycle:设置占空比。
- 开启总开关:调用
I2C_Cmd使能模块,否则无法传输数据。
四、 主机发送数据流程
- 等待总线空闲:查询 SR2 寄存器中的
BUSY标志位,确保其为 0。 - 发送起始位:向
START位写 1,并等待SB(Start Bit) 标志位置位。 - 寻址阶段:
- 先清除AF
- 发送7位从机地址 + 方向位 0。代码中使用
ADDR & 0xFE实现最低位清零。 - 应答检测:使用
while循环同时监测ADDR(成功) 和AF(应答失败) 标志位。 - 寻址失败处理:若
AF=1,需发送停止位并返回错误码(如 -1)。
- 清除 ADDR 标志:这是硬件强制规定,必须先后读取 SR1 和 SR2 寄存器。
- 数据传输循环:
- 检查
TXE(发送寄存器空) 标志后写入数据。 - 每发一个字节都要检测
AF位,若从机拒收则发送停止位并返回错误码(如 -2)。
- 检查
- 传输完成:等待
BTF(字节传输完成) 标志,确保移位寄存器中的最后一位也已发出。 - 发送停止位:向
STOP位写 1 结束通信。
五、 主机接收数据 流程
- 寻址阶段:发送7位从机地址 + 方向位 1。代码中使用
ADDR | 0x01实现最低位置 1。 - ACK/NAK 关键机制:主机在接收最后一个字节后,必须回复NAK(不应答),防止从机继续发送导致总线冲突。
- 不同数据量的读取逻辑:
- 读取 1 个字节:
- 清除 ADDR 标志。
- 立即设置
ACK=0(发送 NAK) 和STOP=1。 - 等待
RXNE置位并读取数据寄存器。
- 读取 2 个字节:
- 清除 ADDR 标志后设置
ACK=1。 - 等待第一个
RXNE并读取字节 1。 - 立即设置
ACK=0和STOP=1。 - 等待第二个
RXNE并读取字节 2。
- 清除 ADDR 标志后设置
- 读取 N 个字节 (N>2):
- 清除 ADDR 后开启 ACK。
- 循环读取前 N−1 个字节。
- 读取倒数第二个字节后,重复“读取 1 个字节”的 NAK 和 STOP 流程。
- 读取 1 个字节: