ATtiny85 I2C通信异常:移除从机后数据被旧值填充求助
解决从机断开后数据残留的问题
嘿,我看了你的代码,发现两个核心问题导致了断开从机后显示旧数据的奇怪现象,咱们一步步来解决:
1. 数组索引越界引发的未定义行为
你定义的v_data和t_data数组大小是CELL_COUNT(14),但C++数组是从0开始索引的,也就是说这两个数组的有效索引范围是0~13。但你的循环是从cell_num=1跑到cell_num=14,这意味着你会访问v_data[14]和t_data[14]——这已经超出了数组的内存范围,属于未定义行为。
这种情况下,你的赋值操作可能会覆盖相邻内存里的其他变量,或者旧数据没有被正确清零,最终导致断开从机后,错误的内存数据被显示出来。
2. 未检查I2C通信是否成功
你调用TinyWireM.requestFrom()后,没有判断返回值。这个函数会返回实际接收到的字节数,如果从机断开或通信失败,返回值会小于4(甚至0)。此时你的while(TinyWireM.available())循环根本不会执行,但因为数组越界的问题,旧数据没有被正确覆盖,就出现了残留。
修正后的代码片段
第一步:修复数组索引问题
把循环改成从0开始索引,对应1~14号电池:
#define CELL_COUNT 14 uint16_t v_data[CELL_COUNT]; // 索引0对应1号电池,索引13对应14号电池 uint16_t t_data[CELL_COUNT]; // 读取数据的循环修改为: for (int cell_num = 0; cell_num < CELL_COUNT; cell_num++) { int slave_add = 0x40 + cell_num; // 0号索引对应原1号电池的0x40地址,以此类推 v_data[cell_num] = 0; t_data[cell_num] = 0; // 关键:检查是否成功接收到完整的4字节数据 int received_bytes = TinyWireM.requestFrom(slave_add, 4); if (received_bytes == 4) { // 只有拿到完整数据才解析 v_low = TinyWireM.receive(); v_high = TinyWireM.receive(); t_low = TinyWireM.receive(); t_high = TinyWireM.receive(); v_data[cell_num] = (v_high << 8) | v_low; t_data[cell_num] = (t_high << 8) | t_low; } // 没收到完整数据的话,保持v_data和t_data为0 }
第二步:同步OLED打印的索引
打印部分也要对应调整索引,确保显示的电池编号和数据对应:
for (int cell_num = 0; cell_num < CELL_COUNT; cell_num++) { int display_battery_num = cell_num + 1; // 显示的电池编号还是1~14 oled.startScreen(); if (display_battery_num <=7) { oled.cursorTo(0, cell_num); // 从0行开始对应1号电池 } else { oled.cursorTo(66, cell_num -7); // 后半部分从第0行开始对应8号电池 } oled.printString(itoa(v_data[cell_num], cast1, 10)); oled.startScreen(); if (display_battery_num <=7) { oled.cursorTo(30, cell_num); } else { oled.cursorTo(96, cell_num -7); } oled.printString(itoa(t_data[cell_num], cast2, 10)); }
这样修改后,当某个从机断开时,因为received_bytes !=4,对应的电压和温度数据会保持为0,再也不会出现旧数据残留的问题,同时也解决了数组越界的隐患。
内容的提问来源于stack exchange,提问作者Christian Döring
相关产品推荐
相关产品推荐

