STM32F103 学习笔记-24-I2C-读写EEPROM(第4节)-STM32的I2C通讯过程

一、I2C 硬件外设与状态监控概述

STM32 的 I2C 外设完全兼容标准 I2C 协议,能够自动处理起始信号、停止信号、地址帧、数据帧和应答信号的收发。在通讯过程中,I2C 外设会通过 状态寄存器 SR1 ​ 和 SR2​ 实时更新当前的工作状态。我们通过读取这些寄存器的特定位,就能精确掌握通讯的每一个环节是否正常完成。

生活类比:I2C 通讯就像两个人打电话。你(主机)先拨号(发送起始信号+从机地址),对方接听(应答),然后你说话(发送数据)或者听对方说话(接收数据),最后挂电话(停止信号)。状态寄存器就像是电话的通话状态提示,告诉你"对方已接听"、"对方正在说话"、"通话已结束"等信息。

二、I2C 主发送器通讯过程

主发送器模式是指 STM32 作为主机,向 I2C 总线上的从设备发送数据。

2.1 整体通讯流程

标准 I2C 主发送流程如下:

复制代码
起始信号(S) → 从机地址(7位)+写方向(0) → 应答(A) → 数据1 → 应答(A) → ... → 数据N → 应答(A) → 停止信号(P)

2.2 分步详解与硬件事件

每一步操作都会触发相应的硬件事件,我们通过检测这些事件来确认操作完成。

1. 产生起始信号 (S)
  • 控制操作 :将 控制寄存器 CR1 ​ 的 START 位​ 置 1

  • 硬件事件 :产生 EV5 事件 ,对应 SR1 寄存器的 SB 位 = 1

  • 事件含义:起始条件已成功发送到 I2C 总线

2. 发送从机地址与写方向
  • 控制操作 :向 数据寄存器 DR​ 写入从机地址 + 写方向位(最低位为 0)

  • 硬件事件 :产生 EV6 事件 (SR1 的 ADDR 位 = 1)和 EV8 事件(SR1 的 TXE 位 = 1)

  • 事件含义

    • ADDR = 1:从机地址已发送完毕,且收到了从机的应答信号

    • TXE = 1:数据寄存器 DR 已为空,可以写入下一个数据

3. 发送数据字节
  • 控制操作 :向 数据寄存器 DR​ 写入要发送的字节数据

  • 硬件事件 :产生 EV8 事件(SR1 的 TXE 位 = 1)

  • 事件含义:当前字节已发送完毕,数据寄存器为空,可以写入下一个字节

  • 重复此过程:直到所有数据字节都发送完成

4. 产生停止信号 (P)
  • 控制操作 :将 控制寄存器 CR1 ​ 的 STOP 位​ 置 1

  • 前置条件 :必须先检测 EV8_2 事件(SR1 的 TXE 位 = 1 且 BTF 位 = 1)

  • 事件含义:BTF(字节发送完成)位 = 1 表示不仅数据寄存器为空,移位寄存器中的最后一位数据也已经发送到总线上

重要区别:TXE 只表示数据寄存器为空,而 BTF 表示整个字节都已发送完毕。发送最后一个字节后必须检测 BTF 位,否则可能导致最后一个字节丢失。

三、I2C 主接收器通讯过程

主接收器模式是指 STM32 作为主机,从 I2C 总线上的从设备读取数据。

3.1 整体通讯流程

标准 I2C 主接收流程如下:

复制代码
起始信号(S) → 从机地址(7位)+读方向(1) → 应答(A) → 数据1 → 主机应答(A) → ... → 数据N → 主机非应答(NACK) → 停止信号(P)

3.2 分步详解与硬件事件

1. 产生起始信号 (S)
  • 控制操作 :将 控制寄存器 CR1 ​ 的 START 位​ 置 1

  • 硬件事件 :产生 EV5 事件 ,对应 SR1 寄存器的 SB 位 = 1

  • 事件含义:起始条件已成功发送到 I2C 总线

2. 发送从机地址与读方向
  • 控制操作 :向 数据寄存器 DR​ 写入从机地址 + 读方向位(最低位为 1)

  • 硬件事件 :产生 EV6 事件(SR1 的 ADDR 位 = 1)

  • 事件含义:从机地址已发送完毕,且收到了从机的应答信号,从机即将开始发送数据

3. 接收数据字节(非最后一个字节)
  • 前置配置 :将 控制寄存器 CR1 ​ 的 ACK 位​ 置 1(使能应答)

  • 硬件事件 :产生 EV7 事件(SR1 的 RXNE 位 = 1)

  • 事件含义:已成功接收一个字节,数据寄存器 DR 中有有效数据

  • 控制操作 :读取 数据寄存器 DR​ 的值,存入内存变量

  • 重复此过程:直到接收完倒数第二个字节

4. 接收最后一个字节并结束通讯
  • 前置配置 :在接收最后一个字节之前,将 控制寄存器 CR1 ​ 的 ACK 位 ​ 置 0(禁止应答),同时将 STOP 位​ 置 1

  • 硬件事件 :产生 EV7 事件(SR1 的 RXNE 位 = 1)

  • 控制操作 :读取 数据寄存器 DR​ 的值,存入内存变量

  • 自动操作:I2C 硬件会自动发送非应答信号 (NACK) 和停止信号 (P)

关键要点:I2C 协议规定,主机接收最后一个字节时必须发送非应答信号,通知从机停止发送数据。这个操作必须在读取最后一个字节之前完成。

四、状态寄存器标志位的清除方法

所有状态寄存器的标志位都需要通过特定的软件操作来清除,否则会影响下一次通讯。常用标志位的清除方式如下表:

标志位 所在寄存器 清除方法
SB(起始位发送) SR1 先读 SR1,再写 DR 寄存器
ADDR(地址发送完成) SR1 先读 SR1,再读 SR2 寄存器
TXE(发送数据寄存器空) SR1 向 DR 寄存器写入数据
RXNE(接收数据寄存器非空) SR1 读取 DR 寄存器
BTF(字节发送完成) SR1 先读 SR1,再读/写 DR 寄存器
AF(应答失败) SR1 软件写 0 清除

五、为什么必须检测状态事件?

STM32 的 CPU 内核运行速度非常快(最高 72 MHz),而 I2C 总线的最高速度只有 400 kHz。CPU 执行一条指令只需要十几个纳秒,而 I2C 发送一个字节需要几十微秒。

如果 CPU 不等待 I2C 硬件完成当前操作就直接进行下一步,会导致:

  1. 数据还没发送完就被新数据覆盖

  2. 还没接收到数据就读取 DR 寄存器得到无效值

  3. 通讯时序混乱,从设备无法正确识别信号

检测状态事件本质上是让 CPU "等一等" I2C 硬件,确保每一步操作都正确完成后再进行下一步。

六、注意事项(避坑指南)

  1. 必须正确清除标志位:每个标志位的清除方式都不同,错误的清除方式会导致通讯卡死。

  2. 最后一个字节必须发送非应答:主接收模式下,忘记在最后一个字节前关闭应答会导致从机持续发送数据,总线被占用。

  3. 发送停止信号前必须检测 BTF 位:只检测 TXE 位会导致最后一个字节丢失。

  4. 总线忙检测:通讯开始前应检测 SR2 的 BUSY 位,确保总线空闲。

  5. 超时处理:所有状态检测都应添加超时机制,防止总线故障导致程序无限等待。

参考出处

《零死角玩转 STM32F103 - 指南者》第 24 章 I2C - 读写 EEPROM

STM32F10x 中文参考手册 第 24 章 I2C 接口

相关推荐
aaaameliaaa31 分钟前
进制练习题【找出只出现一次的数字、交换两个变量(不创建临时变量)、统计二进制中1的个数、打印整数二进制的奇数位和偶数位、求两个数二进制中不同位的个数】
c语言·数据结构·笔记·算法
吃好睡好便好1 小时前
泰戈尔的诗歌7
学习·生活
RainCity2 小时前
Java Swing 自定义组件库分享(十三)
java·笔记·后端
星夜夏空992 小时前
C++学习(2) —— 类与对象基础
开发语言·c++·学习
-To be number.wan2 小时前
数据库系统 | 数据库安全与完整性
数据库·学习
czysoft3 小时前
se被限速
科技·学习·it·技术·魔法·先进·领先
子不语1804 小时前
从0开始学习S7-1200+ET200SP(3)——两台S7-1200通过TCP连接
网络协议·学习·tcp/ip
llllliznc4 小时前
LLM 学习笔记 Day 5:Agent 核心组件——Planner、Memory 与 Reflection
笔记·学习
risc1234564 小时前
“解决了什么痛点”与“为什么有这个东西”的关系?
笔记
hj2862514 小时前
Docker 容器化技术标准化笔记
java·笔记·docker