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; }
原因分析
- 行输出逻辑缺陷:代码仅在
I2C_adr % columns == 0时触发换行,127是最后一个地址,127%4=3,不会触发换行,导致最后一行内容未完成换行就进入后续打印逻辑。 - 串口缓冲区差异: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
相关产品推荐
相关产品推荐

