HAL_I2C_Transmit轮询模式无法通信但中断模式正常的原因是什么?
故障原因分析
1 时序不匹配(最核心原因)
轮询模式的HAL_I2C_Master_Transmit、HAL_I2C_Slave_Receive均为阻塞函数,调用后会一直等待对应操作完成或超时才会返回。
你现有代码的执行顺序是先启动主机发送,再启动从机接收:主机发起传输时从机尚未进入监听状态,总线上没有从机返回的应答信号,主机会直接报错退出,后续执行的从机接收逻辑已经错过传输帧,自然无法完成通信。
而中断模式下HAL_I2C_Master_Transmit_IT、HAL_I2C_Slave_Receive_IT均为非阻塞函数,调用后立刻返回,同时启动主从两端的硬件监听逻辑,硬件异步完成整个传输流程,时序完全匹配,所以可以正常通信。
2 超时参数配置不合理
你当前设置的超时时间为20ms,如果I2C总线速率配置偏低、或者总线上有轻微毛刺导致传输延迟,很容易触发超时强制中断传输。中断模式没有超时限制,只有通信完成才会触发回调,受超时参数的影响极小。
3 外设残留错误标志
如果测试时先运行了中断模式的代码,没有复位I2C外设、清空错误标志就直接切换到轮询模式测试,残留的BUSY、NACK等状态标志会导致轮询函数直接返回错误,无法正常启动传输。
修复方案
- 调整执行逻辑:如果是双MCU测试架构,保证从机先执行
HAL_I2C_Slave_Receive进入监听状态后,主机再发起传输;如果是单MCU同时用两个I2C外设做主从自测,不要直接顺序调用两个阻塞函数(会导致第一个调用的函数永久阻塞,第二个函数无法执行),建议将主从逻辑拆分到不同任务,保证从机先进入监听状态。 - 适当调大超时参数,比如将超时值从20改为100,排除超时导致的异常。
- 切换通信模式前,先调用
HAL_I2C_DeInit反初始化外设,再重新执行I2C初始化逻辑,清空所有残留的状态标志。 - 可以打印两个轮询函数的返回值,根据返回的HAL状态(HAL_OK/HAL_TIMEOUT/HAL_ERROR)定位故障点,如果返回HAL_ERROR可读取I2C状态寄存器判断具体错误类型。
内容的提问来源于stack exchange,提问作者죽기장인
相关产品推荐
相关产品推荐

