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 接口

相关推荐
江屿风1 小时前
C++图论基础单源最短路-常规版dijkstra算法/堆优化版dijkstra算法/bellman-ford 算法/spfa 算法流食般投喂
开发语言·c++·笔记·算法·图论
颖火虫盟主2 小时前
Linux USB 探测→枚举→RNDIS 驱动匹配 全流程笔记
linux·运维·笔记
振南的单片机世界2 小时前
PWM调压调速,H桥换向:直流电机四象限控制
arm开发·stm32·单片机·嵌入式硬件
长葡萄的叶子2 小时前
Transformer:让机器读懂上下文的艺术
笔记·transformer
相醉为友2 小时前
Trae IDE WSL2/SSH 环境网络故障排查笔记
ide·笔记·ssh
又是进步的一天2 小时前
一台虚拟机学习CI流程
学习·ci/cd·云原生·容器·kubernetes·devops
深圳市晶科鑫实业有限公司2 小时前
国产TCXO温补晶振是否可以完美替代欧美日系主流型号
人工智能·stm32·单片机·物联网·51单片机·信息与通信
问心无愧05132 小时前
ctfshow web入门114
android·前端·笔记
十月的皮皮2 小时前
C语言学习笔记20260614-数组奇偶数调整3种方法
c语言·笔记·学习