STM8S单片机C语言开发I2C数据发送故障排查求助
STM8S105K4与PCA8575 I2C通信卡主发送模式事件的问题排查
问题背景
本人为工科本科生,毕设中使用16通道IO扩展器PCA8575与STM8S105K4单片机通过I2C通信。开发环境为STVD(已正确设置ARF6字节),同款单片机的SPI通信功能正常。
当前程序卡在I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED宏的循环中,无法进入后续数据发送步骤。代码中@标记部分为已验证的可靠代码,硬件因集成在PCB上导致调试难度较大。
已尝试反转事件与标志判断、简化I2C通信流程等方法,均未解决问题,现请教:
- a) 是否遇到过类似问题及对应的解决方法;
- b) 该故障更可能源于软件还是硬件;
- c) 提供故障排查的切入点。
核心代码
// @inclusion of "stm8s.h", "stm8s_gpio.h", "stm8s_delay.h" and "stm8s_i2c.h" // @defining of C and D port // @defining P1,P2,... Pin macros // @defining I2C_SLAVE_ADDRESS, I2C_OUTPUT_CLK_FREQ, I2C_OWN_ADDRESS, I2C_INTERNAL_CLK_FREQ // @defining BLINK_LED_A,... macros // @defining I2C flag checking macros #define wait ; void I2C_Setup(void); void main() { uint8_t rgbMSB, rgbLSB; // @initiating GPIO I2C_DeInit(); I2C_Setup(); // see below this main function while (1) { DEBUG_LED_B(); while (I2C_BUS_IS_BUSY) // ok wait DEBUG_LED_A(); I2C_GenerateSTART(ENABLE); while (I2C_MASTER_MODE_NOT_SELECTED) // ok wait DEBUG_LED_B(); I2C_Send7bitAddress(I2C_SLAVE_ADDRESS, I2C_DIRECTION_TX); while(I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCES); // 程序卡在此循环 DEBUG_LED_A(); I2C_SendData(rgbLSB); while (I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS) ; DEBUG_LED_B(); I2C_SendData(rgbMSB); I2C_AcknowledgeConfig(I2C_ACK_NONE); I2C_GenerateSTOP(ENABLE); delay_ms(500); } } void I2C_Setup(void) { u8 Input_Clock = 0; Input_Clock = CLK_GetClockFreq() / 1000000; I2C_Init(I2C_OUTPUT_CLK_FREQ, I2C_OWN_ADDRESS, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, Input_Clock); }
尝试过的简化代码
// previous code while(1){ I2C_GenerateSTART(ENABLE); I2C_Send7bitAddress(I2C_SLAVE_ADDRESS, I2C_DIRECTION_TX); I2C_SendData(rgbLSB); I2C_SendData(rgbMSB); I2C_AcknowledgeConfig(I2C_ACK_NONE); I2C_GenerateSTOP(ENABLE); delay_ms(500); }
问题解答
a) 类似问题的解决方法
- 从机地址错误:PCA8575的7位基础地址为
0x20,实际地址由A0/A1/A2引脚电平决定(每接高电平对应位加1),比如A0/A1/A2全接地时地址为0x20。注意I2C_Send7bitAddress传入的是7位地址,库函数会自动拼接读写位,若误传8位地址(如0x40)会导致从机无响应。 - 初始化参数错误:STM8S105的I2C标准模式最高速率为100kHz,若
I2C_OUTPUT_CLK_FREQ设为400kHz可能时序异常;另外Input_Clock需与系统时钟匹配(如HSI 16MHz时应为16),分频错误会导致总线时序紊乱。 - ACK配置异常:发送地址前需确保I2C处于ACK使能状态,若之前操作关闭了ACK,会无法接收从机的应答信号,卡主模式判断。
- 总线锁定修复:I2C总线可能因异常通信处于锁定状态,初始化前可通过GPIO手动拉低再拉高SDA、SCL引脚几次,释放总线。
b) 故障原因倾向
软件优先排查,再确认硬件:
- 软件端:最易忽略的是代码笔误——核心代码中
SUCCES少写了一个S,而标准库返回值为SUCCESS,会导致循环永远成立;其次是地址、初始化参数错误。 - 硬件端:SDA/SCL引脚缺失4.7kΩ上拉电阻、引脚虚焊、PCA8575供电异常(需2.5V-5.5V)、设备损坏等都可能导致无应答。
c) 故障排查切入点
- 检查代码笔误:优先确认
SUCCES是否为SUCCESS的拼写错误,这是最常见的低级问题。 - 验证从机地址:若有逻辑分析仪/示波器,抓取总线地址帧确认是否匹配;无仪器可尝试发送广播地址
0x00,看能否跳出循环。 - 核对初始化参数:手动计算
Input_Clock值(如系统时钟16MHz时应为16),将I2C_OUTPUT_CLK_FREQ改为100kHz标准速率测试。 - GPIO模拟I2C测试:暂时替换硬件I2C为GPIO模拟时序,验证PCA8575是否能响应,排除硬件问题。
- 硬件信号检测:用万用表测SDA/SCL静态电平,正常应为上拉后的高电平;若为低电平,说明总线被拉死,需排查短路问题。
- 添加总线释放步骤:在
I2C_DeInit()后添加GPIO操作,将SDA、SCL设为推挽输出,拉低再拉高3-5次,再初始化I2C。
内容的提问来源于stack exchange,提问作者Joerie
相关产品推荐
相关产品推荐

