news 2026/6/18 19:33:53

图解说明硬件I2C起始与停止条件实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
图解说明硬件I2C起始与停止条件实现原理

深入理解硬件I2C的起始与停止:不只是拉高拉低

在嵌入式开发中,你有没有遇到过这样的场景?

调试一个温湿度传感器,代码写得严丝合缝,地址也核对了八百遍,可就是读不到数据。用逻辑分析仪一抓——SDA线卡在低电平不动了,总线“死”了。

这时候问题往往不在于你的HAL_I2C_Master_Transmit()调用错了,而是在于你没有真正搞懂:I2C通信是怎么开始的?又是怎么结束的?

今天我们就来拆解这个看似简单、实则决定成败的关键机制——硬件I2C的起始条件(START)和停止条件(STOP)。不是泛泛而谈协议定义,而是从电气行为、状态机控制到实际代码落地,一步步讲清楚它们是如何被“制造出来”的。


为什么不能靠“软件延时”随便拉一下?

先说个扎心的事实:很多初学者写的“I2C”其实是GPIO模拟I2C,也就是俗称的“Bit-Banging”。比如:

// 错误示范:手动操作IO口实现“起始” SCL_High(); SDA_High(); delay_us(5); SDA_Low(); // 下降沿 → 起始? delay_us(5); SCL_Low();

这么做行不行?在实验室环境、短距离、单设备的情况下,可能勉强能用。但一旦系统复杂起来,问题就来了:

  • CPU占用率飙升;
  • 中断打断导致时序错乱;
  • 多主竞争时无法正确仲裁;
  • 抗干扰能力极差。

而真正的硬件I2C模块,是通过专用外设控制器+内部状态机自动完成这些关键动作的。它不会“随意”拉低SDA,而是在精确判断总线空闲后,按规范生成符合标准的电平跳变序列。

这才是我们今天要研究的重点。


起始条件:一次通信的“发令枪”

它到底是什么?

根据I2C协议标准,起始条件(START)的定义非常明确:

SCL为高电平时,SDA从高电平变为低电平,即构成一个起始条件。

注意关键词:SCL必须是高电平。如果SCL是低的时候SDA变化,那只是普通的数据位传输;只有当SCL稳定为高时发生的下降沿,才会被所有挂在总线上的设备识别为“新通信开始了”。

这就像体育比赛中的发令枪——只有裁判举旗示意准备就绪(SCL=H),然后开枪(SDA↓),运动员才开始跑。

硬件是怎么做到的?

STM32等MCU的I2C控制器内部有一个通信状态机。当你调用HAL_I2C_Master_Transmit()时,它并不是立刻去操作引脚,而是进入一套严谨的流程:

  1. 检测总线是否空闲
    控制器先检查SDA和SCL是否都为高电平(持续时间满足tSUP)。如果不是,说明总线正被占用,需等待或报错。

  2. 锁定SCL为高电平
    等待当前时钟周期结束,确保SCL处于高态。

  3. 主动驱动SDA下拉
    内部MOSFET导通,将SDA强制拉低。此时产生了一个干净的下降沿。

  4. 置位状态标志(SB)
    在寄存器I2C_SR1中设置SB位,表示“起始条件已发送”,供CPU查询或触发中断。

整个过程由硬件自主完成,无需CPU干预,保证了时序精度和可靠性。

图解时刻:起始条件的波形特征

SCL: ──────┬────────────── │ SDA: ─────┼─────╮ │ ╰────── ... ↑ START Condition (SDA falling edge while SCL = H)

这个小小的下降沿,启动了后续的所有通信步骤:地址发送、应答检测、数据收发……


停止条件:释放总线的“礼貌信号”

如果说起始条件是“我要说话了”,那么停止条件就是“我说完了,请别人发言”。

定义同样严格

停止条件(STOP)的定义是:

SCL保持高电平期间,SDA从低电平变为高电平

这意味着:
- 必须等到SCL为高;
- 然后释放SDA(让上拉电阻将其拉高);
- 上升沿发生在SCL=H期间才算有效。

一旦发出停止条件,总线进入空闲状态,其他主机可以申请使用权。

硬件如何执行?

以STM32为例,当一次传输完成后(如所有字节发完并收到ACK),硬件会根据配置决定是否生成停止条件:

// 默认情况下,以下函数会在末尾自动生成 STOP HAL_I2C_Master_Transmit(&hi2c1, dev_addr, data, size, 1000);

其底层流程如下:

  1. 最后一字节发送完毕;
  2. 接收从机ACK;
  3. 控制器检测到传输结束;
  4. 自动清除NO_STRETCH等控制位;
  5. 设置STOP控制位 → 硬件在下一个SCL高电平时释放SDA;
  6. 总线回归高电平(空闲);
  7. 置位STOPF标志位,可用于中断通知。

⚠️ 注意:如果你使用的是“重复起始”模式(Repeated Start),则不会生成停止条件,以便继续发起新的读写操作而不释放总线。

波形图示:STOP 条件长什么样?

SCL: ──────┬────────────── │ SDA: ╰─────┬──────── ↑ STOP Condition (SDA rising edge while SCL = H)

看到没?STOP不是一个简单的“设GPIO为高”,而是一个有时间约束的上升沿事件


实战案例:读取温度传感器全过程

我们来看一个典型的I2C交互流程,结合起始与停止的实际应用。

目标:从LM75温度传感器读取温度值。

正确通信流程分解

步骤操作是否涉及 START/STOP
1总线空闲检测——
2生成起始条件✅ START
3发送设备地址(写模式:0x90)——
4发送寄存器地址(0x00)——
5生成重复起始条件✅ Repeated START
6发送设备地址(读模式:0x91)——
7接收2字节温度数据——
8生成停止条件✅ STOP

其中第5步的“重复起始”尤为关键:它不发出STOP,直接再次发出START,从而维持主控权,避免其他设备插话。

HAL库如何支持?

uint8_t reg_addr = 0x00; uint8_t rx_data[2]; // 使用顺序传输接口,支持 Repeated Start HAL_I2C_Mem_Read(&hi2c1, LM75_ADDR << 1, // 从机地址 reg_addr, // 寄存器地址 I2C_MEMADD_SIZE_8BIT, rx_data, 2, // 读取2字节 1000); // 超时

这段代码背后发生了什么?

  • 第一次START → 发地址+写 → 写寄存器地址;
  • 硬件自动插入Repeated START;
  • 第二次地址+读 → 开始接收数据;
  • 数据接收完成后 → 自动生成STOP。

整个过程由硬件I2C外设流水线处理,CPU只需发起请求即可去做别的事。


常见坑点与调试秘籍

别以为用了硬件I2C就能高枕无忧。下面这些“经典故障”,几乎都和起始/停止有关。

❌ 坑点1:总线卡死,无法生成起始

现象:调用HAL_I2C_Master_Transmit()返回HAL_BUSY,逻辑分析仪显示SDA一直为低。

原因分析
- 某个从机异常拉低SDA(如复位失败、固件卡死);
- 上拉电阻虚焊或阻值过大(>10kΩ),无法将SDA拉高;
- MCU GPIO未配置为开漏输出(OD模式);
- I2C时钟未使能(RCC配置遗漏)。

解决方案
1. 用万用表测SDA/SCL静态电平;
2. 强制复位从机芯片;
3. 临时切换为GPIO模式,手动输出9个SCL脉冲“唤醒”从机;
4. 检查PCB焊接与上拉电阻(推荐4.7kΩ);
5. 确保RCC开启且GPIO复用正确。

💡 小技巧:可以在初始化阶段加一段“总线恢复”代码,模拟9个时钟周期帮助释放总线。

❌ 坑点2:通信结束后总线仍被占用

现象:第一次通信成功,第二次失败;逻辑分析仪发现上次通信后没出STOP。

根本原因
- DMA传输未完成就被中断打断;
- 错误处理路径中未手动补发STOP;
- 设置了SOFTEND_Mode但未调用GenerateStop()
- NVIC中断未使能,导致事件未响应。

应对策略
- 在错误回调中强制调用:
c if (__HAL_I2C_GET_FLAG(&hi2c1, I2C_FLAG_BUSY)) { __HAL_I2C_GENERATE_STOP(&hi2c1); }
- 启用BERR(总线错误)、ARLO(仲裁丢失)中断;
- 添加超时机制,防止无限等待。


设计建议:让I2C更可靠

项目推荐做法
上拉电阻一般选4.7kΩ;高速模式(>400kHz)可用2.2kΩ
总线电容不超过400pF,否则影响上升时间
电源去耦每个I2C器件旁加100nF陶瓷电容
PCB布局SDA/SCL走线尽量短,远离高频信号线
长距离传输>30cm建议使用I2C缓冲器(如PCA9515)
地址冲突用逻辑分析仪扫描总线上所有响应设备

特别提醒:不要为了省两个电阻就不加上拉!I2C是开漏结构,没有上拉=没有高电平=通信必崩。


结语:掌握本质,才能游刃有余

起始与停止条件,看似只是两个电平跳变,实则是I2C通信的“门把手”——开门进来,关门离开。

当我们理解了:
- 起始条件是如何由硬件状态机精准生成的;
- 停止条件为何不能随意省略;
- 重复起始如何避免总线争抢;
- 常见卡死问题背后的电气真相;

我们才能真正驾驭硬件I2C,而不是被它牵着鼻子走。

下次当你面对一个“读不出数据”的I2C设备时,不妨先问自己一句:

“它真的收到了起始信号吗?”
“通信结束后,总线被释放了吗?”

也许答案就在那一条上升沿里。

如果你正在做传感器集成、多设备通信或低功耗设计,欢迎在评论区分享你的I2C踩坑经历,我们一起排雷。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 13:16:16

AI人脸隐私卫士企业应用:合规性数据处理方案

AI人脸隐私卫士企业应用&#xff1a;合规性数据处理方案 1. 引言&#xff1a;AI驱动下的企业数据合规新挑战 随着人工智能技术的普及&#xff0c;人脸识别已广泛应用于安防、考勤、客户行为分析等企业场景。然而&#xff0c;随之而来的个人隐私泄露风险也日益凸显。近年来&am…

作者头像 李华
网站建设 2026/6/15 12:55:53

AI人脸隐私卫士绿色框样式修改:前端定制化部署指南

AI人脸隐私卫士绿色框样式修改&#xff1a;前端定制化部署指南 1. 背景与需求分析 随着数字影像的广泛应用&#xff0c;个人隐私保护成为不可忽视的技术议题。尤其在社交分享、公共监控、医疗影像等场景中&#xff0c;人脸信息的泄露风险日益突出。传统的手动打码方式效率低下…

作者头像 李华
网站建设 2026/6/17 7:02:30

Mealy状态机设计实验全过程:从状态图到电路一文说清

从状态图到FPGA&#xff1a;手把手带你实现Mealy序列检测器你有没有遇到过这样的情况——明明写好了Verilog代码&#xff0c;烧进FPGA却发现输出不对&#xff1f;或者仿真时波形跳来跳去&#xff0c;就是抓不到那个关键的“1”&#xff1f;别急&#xff0c;这很可能是因为你在设…

作者头像 李华
网站建设 2026/6/15 8:51:39

CANoe与UDS协议兼容性配置:新手入门必看

CANoe与UDS协议兼容性配置&#xff1a;从零打通诊断通信链路你有没有遇到过这种情况——在CANoe里发了一个0x22读数据请求&#xff0c;结果ECU毫无反应&#xff1f;或者明明代码写得没问题&#xff0c;却一直收到NRC 0x7F“服务不支持”&#xff1f;更离谱的是&#xff0c;明明…

作者头像 李华
网站建设 2026/6/15 7:37:17

YOLO12姿态估计新手指南:云端GPU 5分钟部署,1块钱体验

YOLO12姿态估计新手指南&#xff1a;云端GPU 5分钟部署&#xff0c;1块钱体验 1. 为什么选择YOLO12做体感游戏&#xff1f; 想象一下&#xff0c;你只需要一个普通摄像头&#xff0c;就能让电脑实时捕捉你的动作&#xff0c;控制游戏角色做出相同的姿势——这就是YOLO12姿态估…

作者头像 李华
网站建设 2026/6/15 7:35:44

直播字幕生成实战:HY-MT1.5-1.8B边缘部署方案

直播字幕生成实战&#xff1a;HY-MT1.5-1.8B边缘部署方案 1. 引言 随着全球直播内容的爆发式增长&#xff0c;实时多语言字幕已成为提升跨语言观众体验的关键能力。传统云翻译服务受限于网络延迟、调用成本和数据隐私问题&#xff0c;难以满足高质量直播场景的需求。腾讯开源…

作者头像 李华