news 2026/4/27 12:51:51

通俗解释I2C总线应答与非应答信号

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
通俗解释I2C总线应答与非应答信号

I2C通信中,为什么最后一个字节要发NACK?一文讲透应答机制的底层逻辑

你有没有遇到过这样的情况:STM32读取传感器数据时,程序卡在I²C接收循环里出不来?或者用逻辑分析仪抓包发现,明明只想要两个字节,但从设备还在不停地发第三个、第四个?

如果你排查到最后发现是“忘了发NACK”,那这篇文章就是为你写的。

我们今天不堆术语、不抄手册,就从一个最朴素的问题出发:I²C通信中,每传完一个字节后那个“应答位”到底是谁控制的?什么时候该拉低(ACK),什么时候必须放手(NACK)?

搞懂这个问题,不仅能让你写出更稳健的驱动代码,还能在调试通信故障时一眼看出波形里的“致命破绽”。


一根数据线,如何确认对方“听到了”?

想象你在嘈杂的工厂车间里,对着对讲机喊:“老张,把阀门关一下!”
如果老张没回应,你是继续喊第二遍,还是以为他已经去执行了?

在电子世界里,这种“确认收到”的机制叫应答(ACK)。而I²C总线的设计者很聪明——他们不用额外信号线,就在每个字节后面加了一个“确认周期”,让接收方亲自表态。

这个周期只有1个时钟(SCL)宽度,在这期间:
- 如果接收方把SDA拉低 → 表示“我收到了,继续”
- 如果接收方不碰SDA(保持高电平)→ 表示“停!别发了”或“我没准备好”

这就是所谓的第9位——不是数据,也不是命令,而是纯粹的握手信号。

⚠️ 注意:SDA是开漏输出,靠上拉电阻维持高电平。所以“不动作”就等于“发高电平”,也就是NACK。


谁来决定ACK还是NACK?规则其实很简单

很多人被I²C状态机图搞得头晕,其实核心规则就一条:

谁是接收方,谁负责生成ACK/NACK。

来看几个典型场景:

场景1:主设备写数据给从设备

[主] 发地址 → [从] 接收 → 拉低SDA(ACK) [主] 发寄存器地址 → [从] 接收 → 拉低SDA(ACK) [主] 发数据 → [从] 接收 → 拉低SDA(ACK)

全程都是从设备在接收,所以每次都要由它来拉低SDA表示确认。

场景2:主设备读数据(重点来了!)

[主] 发起Start + 地址+读标志 [从] 开始发送第一个字节 [主] 接收 → 此时主是接收方!→ 必须由主拉低SDA(ACK)告诉从:“我还想再听一个” [从] 发送第二个字节 [主] 接收 → 这次是最后一个 → 主不再拉低SDA(即NACK)→ 通知从:“到此为止” [主] 立刻发Stop

看到关键了吗?读操作中,主设备虽然是“发起者”,但在接收数据时,角色变成了接收方,必须主动控制ACK/NACK!

这也是为什么很多初学者会犯错:以为“主机永远主导一切”,结果在最后一步忘记关闭应答,导致从设备以为还要继续发数据,死死拽着SDA不放,总线就被锁死了。


NACK不只是“错误”,更是“控制指令”

很多人一看到NACK就以为是通信失败,其实大错特错。

NACK有三种含义,取决于上下文:

情况含义是错误吗?
写地址后立即NACK从设备不存在 / 地址错了 / 没上电✅ 是问题
写数据过程中NACK从设备忙(如EEPROM正在写入)⚠️ 正常现象,需重试
读最后一个字节后NACK主设备明确说“够了”❌ 不是错误,是正确行为

最后一个尤其重要。比如你要从温度传感器读2个字节,流程应该是:

  1. 发Start + 设备地址(写)
  2. 写寄存器地址
  3. 重复Start + 设备地址(读)
  4. 收第1字节 → 主发ACK → “继续”
  5. 收第2字节 → 主发NACK → “到此为止”
  6. 发Stop

✅ 第5步必须NACK!否则从设备会继续发第3个字节,可能造成缓冲区溢出或总线僵持。


实战演示:HAL库怎么自动处理NACK?

以STM32 HAL库为例,当你调用:

uint8_t data[2]; HAL_I2C_Mem_Read(&hi2c1, DEV_ADDR, REG_TEMP, I2C_MEMADD_SIZE_8BIT, data, 2, 100);

你传了2作为长度,HAL库内部就会这样安排:

  • 前1个字节:开启应答(ACK)
  • 最后1个字节:关闭应答(NACK),然后发Stop

它背后做了什么?其实就是这几句关键操作:

// 接收前N-1个字节:保持ACK使能 I2C_AcknowledgeConfig(I2Cx, ENABLE); // 接收最后一个字节前:提前关闭ACK I2C_AcknowledgeConfig(I2Cx, DISABLE); // 手动产生Stop条件 I2C_GenerateSTOP(I2Cx, ENABLE);

如果你写裸机驱动,这些细节就必须自己把控。一旦漏掉DISABLE Ack,通信就会卡住。


常见坑点与调试秘籍

❌ 坑1:读操作末尾没发NACK,总线被从设备“霸占”

现象:主设备已经发了Stop,但从设备还在输出数据,SDA一直被拉低。
原因:主设备没有通过NACK明确终止通信,从设备误以为主机还想收更多。
解决:确保最后一次接收前关闭应答功能。

❌ 坑2:地址扫描时误判“设备不存在”

有些开发者写了个循环,挨个试0x08~0x77的地址,看哪个能返回ACK。
但如果某个地址返回NACK,就断定“设备不在”——这也不一定准确!

真实案例:某项目中BMP280始终检测不到,打印显示所有地址都NACK。
结果用逻辑分析仪一看,地址帧其实是ACK的!但因为后续没发寄存器地址,直接进读操作,协议断了,所以整体失败。

✅ 正确做法:先写地址+寄存器 → 再读数据,才算完整事务。

🛠 调试技巧:用逻辑分析仪看第九位

这是最直观的方法。抓一段I²C波形,重点关注每个字节后的第9个SCL周期:

  • 如果是低电平 → ACK
  • 如果是高电平 → NACK

比如你期望读两个字节,波形应该是:
[Byte1][ACK][Byte2][NACK][Stop]
如果看到[Byte2][ACK],那就说明你的代码还在等下一个字节,很可能陷入超时等待。


设计建议:让I²C通信更可靠

1. 上拉电阻别省

标准值4.7kΩ,负载重可降到2.2kΩ。太大会导致上升沿缓慢,影响高速模式;太小则功耗高。

2. 多设备共存?注意地址冲突

常见传感器如AT24C02(EEPROM)、SHT30(温湿度)、OLED屏都可能使用0x78/0x7A这类地址。焊接前务必查清设备实际地址。

3. 别迷信“设备就绪”函数

HAL_I2C_IsDeviceReady()本质就是不断发地址+等待ACK。对于某些响应慢的设备(如刚上电的传感器),可能需要重试多次才能成功。

可以加个延时再探测:

HAL_Delay(10); // 上电稳定 while (HAL_I2C_IsDeviceReady(&hi2c1, addr, 2, 100) != HAL_OK) { HAL_Delay(5); }

4. 总线锁死怎么办?

如果SDA一直为低,可能是某个从设备崩溃了,死死拉着总线。

急救方法:模拟9个SCL脉冲,强迫从设备释放SDA:

// 手动翻转SCL引脚9次(GPIO模式) for (int i = 0; i < 9; i++) { HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET); delay_us(5); HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET); delay_us(5); } // 然后发一个Stop条件恢复

结语:掌握ACK/NACK,才算真正入门I²C

你可以不会配置DMA,可以不懂时钟延展,但如果你不清楚每一个字节之后的那个“确认位”是怎么来的、谁该负责、何时该放手,那你离写出稳定可靠的I²C代码还差最后一公里。

记住一句话:

在I²C的世界里,礼貌很重要——发完数据要等对方点头(ACK),想结束对话要说“再见”(NACK + Stop)。

下次当你面对一堆跳动的波形时,不妨问自己一句:
“现在轮到谁来拉低SDA了?”

答案清楚了,问题也就解开了。

如果你在项目中遇到过因NACK引发的奇葩bug,欢迎在评论区分享经历,我们一起排雷拆弹。

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

一文说清24l01话筒通信协议与寄存器配置

深入理解24L01话筒&#xff1a;从寄存器配置到实战音频传输在构建低功耗无线语音系统时&#xff0c;你是否曾为频繁丢包、语音断续或电池续航短而苦恼&#xff1f;如果你正在使用所谓的“24L01话筒”——这个听起来像是nRF24L01的变种模块&#xff0c;但又缺乏完整文档支持的小…

作者头像 李华
网站建设 2026/4/27 5:42:13

去耦电容放置策略:一文说清早期电路布局原则

去耦电容怎么放才对&#xff1f;一个被低估的PCB设计生死线你有没有遇到过这样的情况&#xff1a;电路原理图没问题&#xff0c;元器件也都是正品&#xff0c;可板子一上电&#xff0c;处理器就复位、ADC读数乱跳、Wi-Fi信号时断时续&#xff1f;调试几天后发现——电源轨上200…

作者头像 李华
网站建设 2026/4/24 11:19:40

csdn官网发文技巧:以Fun-ASR为主题打造爆款博客

Fun-ASR&#xff1a;如何用本地化语音识别打造爆款技术博客 在智能办公与远程协作日益普及的今天&#xff0c;会议纪要、课程录音、访谈笔录这些“声音资产”的转写需求正以前所未有的速度增长。但你是否也遇到过这样的困境&#xff1a;主流云语音识别服务虽然方便&#xff0c;…

作者头像 李华
网站建设 2026/4/21 6:59:05

华为诺亚方舟实验室关注:是否可用于鸿蒙设备端侧

华为诺亚方舟实验室关注&#xff1a;是否可用于鸿蒙设备端侧 在智能终端日益普及的今天&#xff0c;语音交互早已不再是“未来科技”的代名词&#xff0c;而是用户每天与手机、手表、智慧屏甚至车载系统沟通的核心方式。然而&#xff0c;当网络信号不佳、隐私顾虑加剧或响应延迟…

作者头像 李华
网站建设 2026/4/20 14:26:15

字节跳动火山引擎调研:能否整合进飞书会议系统

字节跳动火山引擎调研&#xff1a;能否整合进飞书会议系统 在远程协作日益成为企业常态的今天&#xff0c;一场线上会议结束后&#xff0c;你是否曾为“谁说了什么”而反复回放录音&#xff1f;是否因跨语言沟通障碍错过了关键信息&#xff1f;又是否担心敏感对话通过公有云ASR…

作者头像 李华
网站建设 2026/4/23 12:26:52

语音识别中的噪声问题:如何提升Fun-ASR抗噪能力

语音识别中的噪声问题&#xff1a;如何提升Fun-ASR抗噪能力 在会议室里&#xff0c;空调嗡鸣、同事翻页、走廊人声不断——这样的录音你是否也处理过&#xff1f;当你满怀期待地把一段长达一小时的会议音频丢进语音识别系统&#xff0c;结果却满屏错字&#xff1a;“项目进度”…

作者头像 李华