如何获取设备地址?I2C读触摸屏时TXIS标志位等待代码异常修复求助
我来一步步帮你解决这两个问题:
问题1:如何获取设备地址?
- 优先查硬件手册或触摸屏 datasheet:这是最可靠的方式,手册里会直接给出设备的7位I2C地址,部分设备还支持通过引脚配置修改地址。
- 编写I2C扫描程序:遍历I2C总线上0x03到0x77的所有可能地址,发送起始信号后检测ACK响应,有响应的地址就是目标设备的地址。
- 借助示波器/逻辑分析仪:抓取I2C总线的通信波形,直接从总线上读取设备的地址帧。
问题2:修复I2C读取中的
while((I2C_GetFlagStatus(I2C1, I2C_ISR_TXIS) == RESET))异常问题 先看你提供的代码,首先发现EXTI中断处理函数里有两处明显错误,这可能间接影响了I2C的正常执行:
EXTI_GetITStatus((EXTI_Line1) != RESET)写法错误,正确判断应该是EXTI_GetITStatus(EXTI_Line1) != RESET,你把条件误写到了函数参数里。- 中断清除位用了
EXTI_Line0,但你处理的是EXTI_Line1,这会导致中断无法被正确清除,后续触发异常。
再回到while((I2C_GetFlagStatus(I2C1, I2C_ISR_TXIS) == RESET))的死循环问题,通常有这些原因:
- I2C初始化配置错误:比如时钟频率、主从模式、ACK使能等参数未正确设置。
- 设备地址格式错误:I2C读操作时,7位设备地址需要左移一位并加上读位(0x01),比如你传的0x3C是7位地址,读操作时应该用
0x3C << 1 | 0x01。 - 缺少超时机制:如果硬件故障或总线异常,这个循环会一直死等,建议添加超时计数,超过阈值就返回错误并释放总线。
- 中断上下文冲突:在EXTI中断里调用I2C读取,可能和I2C自身中断(若开启)产生优先级冲突,建议确保中断优先级配置合理,或改用阻塞式I2C操作。
这里给你修改后的代码片段,修复了EXTI的错误,并给touch_i2c_read添加了超时处理:
void EXTI1_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line1) != RESET) { // 修复参数传递错误 uint8_t i2c_buffer[22]; uint32_t res = touch_i2c_read(0x3C, 0x00, i2c_buffer, 22); // printf("deneme"); if (!res) { // 读取成功的处理逻辑 } else { // 读取失败的处理逻辑 } EXTI_ClearITPendingBit(EXTI_Line1); // 修复中断线清除错误 } } #define I2C_TIMEOUT_MAX 100000 // 定义超时阈值,可根据实际情况调整 static uint32_t touch_i2c_read(uint8_t DeviceAddr, uint8_t RegAddr, uint8_t *pBuffer, uint16_t len) { uint32_t timeout = I2C_TIMEOUT_MAX; // 等待I2C总线空闲 while(I2C_GetFlagStatus(I2C1, I2C_ISR_BUSY) != RESET) { if(--timeout == 0) return 1; // 超时返回错误码 } // 发送起始信号 I2C_GenerateSTART(I2C1, ENABLE); timeout = I2C_TIMEOUT_MAX; while(!I2C_GetFlagStatus(I2C1, I2C_ISR_SB)) { if(--timeout == 0) return 1; } // 发送设备写地址(先写入寄存器地址) I2C_Send7bitAddress(I2C1, DeviceAddr << 1, I2C_Direction_Transmitter); timeout = I2C_TIMEOUT_MAX; while(!I2C_GetFlagStatus(I2C1, I2C_ISR_ADDR)) { if(--timeout == 0) return 1; } I2C_ClearFlag(I2C1, I2C_ICR_ADDRCF); // 清除ADDR标志 // 等待发送寄存器为空,添加超时处理 timeout = I2C_TIMEOUT_MAX; while((I2C_GetFlagStatus(I2C1, I2C_ISR_TXIS) == RESET)) { if(--timeout == 0) { I2C_GenerateSTOP(I2C1, ENABLE); // 超时后发送停止信号释放总线 return 1; } } I2C_SendData(I2C1, RegAddr); // 发送目标寄存器地址 timeout = I2C_TIMEOUT_MAX; while(!I2C_GetFlagStatus(I2C1, I2C_ISR_TC)) { // 等待寄存器地址发送完成 if(--timeout == 0) return 1; } // 发送重复起始信号,切换到读模式 I2C_GenerateSTART(I2C1, ENABLE); timeout = I2C_TIMEOUT_MAX; while(!I2C_GetFlagStatus(I2C1, I2C_ISR_SB)) { if(--timeout == 0) return 1; } // 发送设备读地址 I2C_Send7bitAddress(I2C1, (DeviceAddr << 1) | 0x01, I2C_Direction_Receiver); timeout = I2C_TIMEOUT_MAX; while(!I2C_GetFlagStatus(I2C1, I2C_ISR_ADDR)) { if(--timeout == 0) return 1; } I2C_ClearFlag(I2C1, I2C_ICR_ADDRCF); // 读取数据 while(len > 0) { timeout = I2C_TIMEOUT_MAX; while(!I2C_GetFlagStatus(I2C1, I2C_ISR_RXNE)) { if(--timeout == 0) return 1; } *pBuffer++ = I2C_ReceiveData(I2C1); len--; // 最后一个字节不发送ACK,同时发送停止信号 if(len == 1) { I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); } } // 恢复ACK使能,保证后续I2C操作正常 I2C_AcknowledgeConfig(I2C1, ENABLE); return 0; // 读取成功返回0 }
内容的提问来源于stack exchange,提问作者NetworkStudent
相关产品推荐
相关产品推荐

