ESP8266复用器逻辑外部化后报错及显示异常求助
故障原因分析及修复方案
核心故障原因
1. SH1106Wire对象副本引发资源冲突
DisplayService::display()方法返回的是全局displayObject的值副本,而SH1106Wire类内部持有I2C总线操作句柄。每次返回副本时会触发对象拷贝构造,销毁副本时又会释放相关资源,反复的拷贝-销毁会导致I2C总线资源混乱,最终触发ESP8266硬件看门狗复位(报错里的rst cause:2就是硬件看门狗复位)。
2. 重复调用init()方法导致通信异常
每次调用display()都执行displayObject.init(),SH1106的init()会向显示屏发送初始化指令,重复初始化会干扰I2C总线通信,导致显示屏响应异常,出现偶尔闪烁的情况。
3. 初始化流程缺失
setup()函数中未初始化I2C总线(Wire.begin())和串口,封装类后总线初始化不明确,会加重通信异常。
修复后的代码
修改DisplayService_h
#ifndef DisplayService_h #define DisplayService_h #include "SH1106Wire.h" class DisplayService { public: DisplayService(); // 返回引用,避免拷贝对象 SH1106Wire& display(u_int8_t displayNumber); private: SH1106Wire displayObject; // 改为成员变量,而非全局 void changeDisplay(u_int8_t displayNumber); }; #endif
修改DisplayService.cpp
#include "Arduino.h" #include "SH1106Wire.h" #include <Wire.h> #include "DisplayService_h" DisplayService::DisplayService() : displayObject(0x3C, SDA, SCL) { Wire.begin(); // 初始化I2C总线 displayObject.init(); // 仅初始化一次显示屏 } SH1106Wire& DisplayService::display(u_int8_t displayNumber){ Serial.println(displayNumber); this->changeDisplay(displayNumber); // 不再重复调用init() return displayObject; } void DisplayService::changeDisplay(u_int8_t displayNumber){ Wire.beginTransmission(0x70); // TCA9548A地址 Wire.write(1 << displayNumber); // 选择对应通道 Wire.endTransmission(); // 添加短暂延迟确保多路复用器切换完成 delay(10); }
修改main.cpp
#include <Arduino.h> #include <services/displayservice/DisplayService_h> #include "SH1106Wire.h" DisplayService displayService; void setup() { Serial.begin(115200); // 初始化串口用于调试 } void loop() { for (int i = 2; i <= 6; i++) { // 用引用接收,避免拷贝对象 SH1106Wire& display = displayService.display(i); delay(2000); display.clear(); display.flipScreenVertically(); display.setFont(ArialMT_Plain_24); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(64, 20, "TEST"); display.display(); delay(500); } }
额外注意事项
- TCA9548A通道切换后添加10ms左右延迟,确保多路复用器稳定切换到目标通道。
- 避免在循环中频繁创建和销毁SH1106Wire对象,复用同一个对象可减少资源开销和通信异常。
内容的提问来源于stack exchange,提问作者coolaturon
相关产品推荐
相关产品推荐

