2. STM32 I2C外设概述:模块框图、时钟树、主要特性、工作模式
好,我们正式开始啃I2C外设。很多初学者上来就翻寄存器手册,结果越看越晕。我的习惯是——先看框图,再看时钟,最后看特性。脑子里有了整体画面,寄存器才有意义。
2.1 I2C模块框图:先看骨架
STM32的I2C外设,说白了就是一套硬件状态机。它帮你处理SCL时钟生成、数据移位、起始/停止条件检测、应答位检查这些繁琐的活儿。你只需要往数据寄存器里丢字节,或者从里面取字节就行。
下面这张图是我自己画的I2C模块核心框图,你看一眼就能明白数据是怎么流动的:
你看,整个数据通路其实很清晰。CPU把数据写到DR寄存器,硬件自动移位到SDA线上。反过来,接收到的数据从SDA进来,经过移位寄存器,最终出现在DR里等你读取。
关键点:I2C硬件帮你做了90%的位级工作。你只需要关注DR、SR1、SR2、CR1、CR2这五个核心寄存器组。别被手册里几十个寄存器吓到,大部分你根本用不上。
2.2 时钟树:I2C的脉搏从哪来
I2C的SCL时钟不是凭空产生的。它来自APB总线时钟,经过一个分频器,最终生成你想要的SCL频率。比如标准模式100kHz,快速模式400kHz。
时钟计算公式其实很简单:
SCL频率 = APB时钟频率 / (CCR值 × 2)
// 以STM32F103为例,APB1=36MHz,想得到400kHz:
// CCR = 36MHz / (400kHz × 2) = 45
// 所以CCR寄存器写45,就能得到400kHz
我的经验:实际项目中,我习惯把CCR值算出来后再加1~2。为什么?因为总线负载、引脚电容都会让实际频率偏低。加一点余量,测出来刚好是目标频率。我曾经在一个传感器项目里没加余量,结果SCL只有380kHz,传感器偶尔超时——折腾了两天才找到原因。
不同STM32系列的时钟源略有差异,但原理一样:
| 系列 | APB时钟 | 最大SCL | 备注 |
|---|---|---|---|
| STM32F1 | APB1 (最高36MHz) | 400kHz | 标准I2C外设 |
| STM32F4 | APB1 (最高42MHz) | 400kHz | 支持FM+模式 |
| STM32L4 | APB1 (最高80MHz) | 1MHz | 支持FM+,低功耗优化 |
| STM32H7 | APB1/APB4 | 1MHz | 双I2C外设,更灵活 |
2.3 主要特性:硬件到底帮你做了啥
我列一下I2C外设的核心特性,你心里有个数:
- 多主机功能:总线上可以有多个主机,硬件自动处理仲裁。说白了,两个主机同时发数据,硬件会判断谁赢了。
- 7位/10位地址:大部分传感器用7位地址。10位地址我几乎没用过,但硬件支持。
- 双缓冲数据寄存器:发送时你可以提前写下一字节,接收时你有时间取走当前字节。不会丢数据。
- 可编程的SCL时钟:通过CCR寄存器,你可以设100kHz、400kHz甚至1MHz。
- 事件中断和错误中断:发送完成、接收完成、仲裁丢失、应答失败……硬件都会给你发中断信号。
- DMA支持:大批量数据传输时,DMA可以帮你自动搬运数据,CPU只管睡觉。
注意:不是所有STM32系列都支持1MHz FM+模式。F1系列最高只有400kHz。如果你需要高速I2C,选型时一定要看数据手册的I2C特性表。我见过有人用F1去驱动1MHz的OLED屏,结果死活点不亮——查了半天才发现是频率上限问题。
2.4 工作模式:主机、从机、多主机
I2C外设支持三种工作模式。大部分时候我们用主机模式,但理解从机模式也很重要:
2.4.1 主机模式
你主动发起通信。流程是:
- 配置CR1的START位,硬件自动发送起始条件
- 发送从机地址 + 读写位
- 等待从机应答(检查SR1的ADDR位)
- 发送或接收数据
- 发送停止条件(配置STOP位)
说白了,主机就是那个「说了算」的角色。你想读哪个寄存器,想写什么数据,都由你决定。
2.4.2 从机模式
你被动响应。别人发地址给你,你匹配了就应答。这种模式在I2C多机通信中很常见,比如一个STM32作为主控,另一个STM32作为从设备。
从机模式下,你需要配置自己的地址(OAR1/OAR2寄存器),然后等待主机来访问。硬件会自动比较地址,匹配了就给你发中断。
2.4.3 多主机模式
多个主机共享一条I2C总线。硬件通过仲裁机制解决冲突。说白了,谁先拉低SDA谁就赢。输的那个自动退出,不会破坏总线数据。
我的建议:初学者先别碰多主机模式。老老实实一主一从,把中断和DMA玩熟了再说。多主机模式在工业现场总线里用得多,普通产品开发几乎用不到。
2.5 中断事件:硬件什么时候叫你
I2C外设的中断事件分为两类:
| 事件类型 | 触发条件 | 对应标志位 |
|---|---|---|
| 发送事件 | 数据寄存器空,可以写下一字节 | TXE |
| 接收事件 | 数据寄存器非空,可以读取 | RXNE |
| 地址匹配 | 从机模式下,主机地址匹配成功 | ADDR |
| 停止条件 | 检测到总线停止条件 | STOPF |
| 错误事件 | 应答失败、仲裁丢失、总线错误 | AFE/ARLO/BERR |
嗯,这里要注意:中断标志位在进入中断后必须手动清除。尤其是ADDR位,很多人忘了清,导致中断一直触发,CPU卡死在中断里。我早期做项目时就踩过这个坑——程序跑着跑着就死机了,后来发现是ADDR没清,中断嵌套把自己搞死了。
2.6 小结:你该记住什么
这一章内容不少,但核心就三点:
- 框图:数据从DR到移位寄存器再到SDA,状态从引脚回到SR1/SR2
- 时钟:SCL频率 = APB时钟 / (CCR × 2),记得加余量
- 模式:主机模式最常用,从机模式做从设备,多主机模式先别碰