You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取设备地址?I2C读触摸屏时TXIS标志位等待代码异常修复求助

我来一步步帮你解决这两个问题:

问题1:如何获取设备地址?
  • 优先查硬件手册或触摸屏 datasheet:这是最可靠的方式,手册里会直接给出设备的7位I2C地址,部分设备还支持通过引脚配置修改地址。
  • 编写I2C扫描程序:遍历I2C总线上0x03到0x77的所有可能地址,发送起始信号后检测ACK响应,有响应的地址就是目标设备的地址。
  • 借助示波器/逻辑分析仪:抓取I2C总线的通信波形,直接从总线上读取设备的地址帧。
问题2:修复I2C读取中的while((I2C_GetFlagStatus(I2C1, I2C_ISR_TXIS) == RESET))异常问题

先看你提供的代码,首先发现EXTI中断处理函数里有两处明显错误,这可能间接影响了I2C的正常执行:

  1. EXTI_GetITStatus((EXTI_Line1) != RESET) 写法错误,正确判断应该是EXTI_GetITStatus(EXTI_Line1) != RESET,你把条件误写到了函数参数里。
  2. 中断清除位用了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:57:32