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

ESP8266平台I2C扫描器输出顺序异常问题求助

ESP8266上I2C扫描器输出异常问题分析与解决

问题描述

我编写了一款I2C扫描器代码,用于打印I2C地址及总线设备连接状态标识。代码在ATmega328上运行无异常,但基于Arduino库在ESP8266上运行时,0123地址的输出正常,最后一行(124127地址)的内容却打印在"#2#"之后,与代码逻辑不符。

问题代码

uint8_t I2C_scan(uint8_t mode){         // mode0=no output, Mode1= Summery, mode2=full output

uint8_t device_cnt=0, I2C_adr=0, cnt;
uint8_t rc, colcnt=0, columns=4;
struct I2C_devices {
    uint8_t I2C_adr;
    char*   deviceID;
    char*   type;
} I2Cdevice[]={{0x36,"AS5600","Magn Rotary"},{0x27, "PCF8574","GPIO(diplay)"},{0x3C,"DS1306","OLED-Disp"}, {0x68,"DS3231","RTC"}, {0x57, "AT24C32", "2KB Mem"} };


switch (mode){
    case 2 : { 
        printf("I2C Scanner\n");
        for(cnt= 1; cnt <= 14*columns+5; cnt++) printf("%s","=");
        printf("\n     ");
        for(colcnt=0;colcnt<columns;colcnt++)  printf("%6s%02u%6s","",colcnt,"|");
        
        for(I2C_adr = 0; I2C_adr <= 127; I2C_adr++) {
            Wire.beginTransmission(I2C_adr);
            rc = Wire.endTransmission();
            if ( ((I2C_adr)%columns)==0) printf("\n %03u\t", I2C_adr); 
            if (rc) printf("0x%02X = %s  | ", I2C_adr, " - ");
            else    printf("0x%02X = %s  | ", I2C_adr, "Fnd");
        }
        printf("#1#\n");
        for(cnt= 1; cnt <= 14*columns+5; cnt++) printf("%s","=");
        printf("\n#2#\n");

    } break;
}
return device_cnt;
}

原因分析

  1. 行输出逻辑缺陷:代码仅在I2C_adr % columns == 0时触发换行,127是最后一个地址,127%4=3,不会触发换行,导致最后一行内容未完成换行就进入后续打印逻辑。
  2. 串口缓冲区差异:ESP8266的printf默认关联串口输出且带有缓冲区机制;而ATmega328的串口输出更接近即时刷新。当代码执行到打印"#1#"和"#2#"时,最后一行的扫描内容仍在缓冲区中未输出,后续缓冲区刷新时就会出现在"#2#"之后。

解决方案

方案1:强制刷新缓冲区+补全换行

在扫描循环结束后,主动换行并刷新输出缓冲区,确保所有扫描内容在打印分隔符前输出完成:

for(I2C_adr = 0; I2C_adr <= 127; I2C_adr++) {
    Wire.beginTransmission(I2C_adr);
    rc = Wire.endTransmission();
    if ( ((I2C_adr)%columns)==0) printf("\n %03u\t", I2C_adr); 
    if (rc) printf("0x%02X = %s  | ", I2C_adr, " - ");
    else    printf("0x%02X = %s  | ", I2C_adr, "Fnd");
}
// 添加以下两行,确保最后一行内容输出并刷新缓冲区
printf("\n");
fflush(stdout);
printf("#1#\n");
for(cnt= 1; cnt <= 14*columns+5; cnt++) printf("%s","=");
printf("\n#2#\n");

方案2:优化换行触发逻辑

调整换行判断条件,确保每columns个地址后换行,包括处理最后一行的收尾:

for(I2C_adr = 0; I2C_adr <= 127; I2C_adr++) {
    if ( ((I2C_adr)%columns)==0) {
        printf("\n %03u\t", I2C_adr); 
    }
    Wire.beginTransmission(I2C_adr);
    rc = Wire.endTransmission();
    if (rc) printf("0x%02X = %s  | ", I2C_adr, " - ");
    else    printf("0x%02X = %s  | ", I2C_adr, "Fnd");
    // 每columns个地址后换行,包括最后一组
    if ( ((I2C_adr + 1)%columns)==0 && I2C_adr != 127) {
        printf("\n");
    }
}
printf("\n");
fflush(stdout);
// 后续打印分隔符代码不变

补充说明

原代码中I2Cdevice结构体数组的最后一项初始化存在语法错误,已修正为{0x57, "AT24C32", "2KB Mem"},避免编译报错。

内容的提问来源于stack exchange,提问作者wogoos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 20:27:45