Arduino冰箱项目:EC11旋转编码器调节SSR触发温度异常
Arduino冰箱控制系统编码器故障排查与修复
问题回顾
- 使用EC11旋转编码器调节SSR触发温度时,无论旋转方向如何,阈值仅增加不减少
- 编码器单独测试正常,加入项目后失效;移除
printTemperature函数后编码器恢复正常 - 单独测试显示屏+编码器时,未触碰旋钮却持续输出0值
核心问题分析
编码器方向判断逻辑完全颠倒
EC11顺时针旋转时,A相状态变化时B相状态与A相相反;逆时针旋转时B相状态与A相相同。原代码的判断逻辑刚好搞反,导致无论怎么转都触发阈值增加。阻塞式防抖函数卡死程序
stateContactA函数使用while(1)死循环做防抖,会完全阻塞Arduino的主循环,导致编码器检测、温度读取等操作无法正常并行执行。尤其是当printTemperature中还有传感器通信和显示操作时,编码器的状态检测被彻底阻塞。printTemperature中的阻塞式延时
当阈值调整后,代码用while循环实现3秒闪烁效果,这期间程序完全无法响应任何输入(包括编码器),直接导致编码器失效。变量类型冗余与初始化问题
motorThreshold定义为int却用浮点值20.0初始化,虽不报错但不规范;单独测试时的异常输出也源于阻塞式防抖导致的引脚状态读取异常。
修复后的完整代码
#include <TM1637Display.h> #include <OneWire.h> #include <DallasTemperature.h> const int oneWireBus = 2; OneWire oneWire(oneWireBus); DallasTemperature sensors(&oneWire); const int CLK = 3; const int DIO = 4; TM1637Display display = TM1637Display(CLK, DIO); const uint8_t celsiusSymbol[] = { SEG_A | SEG_B | SEG_F | SEG_G, SEG_A | SEG_D | SEG_E | SEG_F }; #define ContactA 10 #define ContactB 11 // 编码器状态变量 bool lastStateA; bool currentStateA; bool currentStateB; const int SSR_PIN = 9; // 温度阈值(用int存储整数阈值,如需小数可改为float) int motorThreshold = 20; bool thresholdAdjusted = false; // 非阻塞闪烁相关变量 unsigned long flashStartTime = 0; const unsigned long flashDuration = 3000; bool flashState = false; unsigned long lastFlashToggle = 0; void setup() { Serial.begin(9600); Serial.println("Initializing..."); display.clear(); display.setBrightness(7); sensors.begin(); pinMode(SSR_PIN, OUTPUT); digitalWrite(SSR_PIN, LOW); // 编码器引脚配置(INPUT_PULLUP模式,编码器A/B引脚需接GND) pinMode(ContactA, INPUT_PULLUP); pinMode(ContactB, INPUT_PULLUP); lastStateA = digitalRead(ContactA); Serial.println("Initialization complete."); } void adjustThresholdTemperature() { currentStateA = digitalRead(ContactA); // 检测A相状态变化(简单防抖:连续两次读取相同状态才判定有效) static bool prevReadA = currentStateA; if (currentStateA != prevReadA) { delay(5); // 5ms防抖延时,避免抖动干扰 currentStateA = digitalRead(ContactA); prevReadA = currentStateA; return; } if (currentStateA != lastStateA) { currentStateB = digitalRead(ContactB); // 修正方向判断逻辑: // 顺时针:A相变化时,B相与A相状态相反 → 阈值增加 if (currentStateA != currentStateB) { motorThreshold += 2; Serial.print("Threshold increased to: "); Serial.println(motorThreshold); thresholdAdjusted = true; } // 逆时针:A相变化时,B相与A相状态相同 → 阈值减少 else { // 防止阈值过低 if (motorThreshold > 0) { motorThreshold -= 2; Serial.print("Threshold decreased to: "); Serial.println(motorThreshold); thresholdAdjusted = true; } } lastStateA = currentStateA; } } void updateTemperatureAndDisplay() { // 非阻塞读取温度(避免频繁读取,每500ms读取一次) static unsigned long lastTempRead = 0; static float measuredTemperature = 0; if (millis() - lastTempRead >= 500) { sensors.requestTemperatures(); measuredTemperature = sensors.getTempCByIndex(0); Serial.print("Current temperature: "); Serial.print(measuredTemperature); Serial.println("°C"); lastTempRead = millis(); } // 控制SSR if (measuredTemperature >= motorThreshold) { digitalWrite(SSR_PIN, HIGH); } else { digitalWrite(SSR_PIN, LOW); } // 处理显示屏显示:优先显示闪烁的阈值,否则显示当前温度 if (thresholdAdjusted) { // 初始化闪烁计时 if (flashStartTime == 0) { flashStartTime = millis(); lastFlashToggle = millis(); } // 3秒后结束闪烁 if (millis() - flashStartTime >= flashDuration) { thresholdAdjusted = false; flashStartTime = 0; display.clear(); } else { // 每250ms切换一次显示状态 if (millis() - lastFlashToggle >= 250) { flashState = !flashState; lastFlashToggle = millis(); } if (flashState) { display.showNumberDec(motorThreshold, false, 2, 0); display.setSegments(celsiusSymbol, 2, 2); } else { display.clear(); } } } else { // 显示当前温度(取整数部分显示,如需小数可调整showNumberDec参数) display.showNumberDec((int)measuredTemperature, false, 2, 0); display.setSegments(celsiusSymbol, 2, 2); } } void loop() { adjustThresholdTemperature(); updateTemperatureAndDisplay(); }
关键修复说明
- 修正编码器方向逻辑:调整了顺时针/逆时针的判断条件,匹配EC11的实际相位特性。
- 替换阻塞式防抖:用简单的
delay(5)防抖替代死循环防抖,同时增加连续读取校验,既避免抖动又不阻塞程序。 - 非阻塞闪烁实现:用
millis()计时实现3秒闪烁效果,主循环始终保持响应,编码器操作不会被卡死。 - 优化温度读取:添加500ms的读取间隔,减少传感器通信频率,避免占用过多资源。
- 增加阈值下限保护:防止逆时针旋转导致阈值变为负数。
额外注意事项
- 确保EC11编码器的A、B引脚连接到Arduino的10、11引脚,且编码器的公共端接GND(因为用了
INPUT_PULLUP模式)。 - DS18B20传感器的接线要正确:VCC接5V,GND接GND,DATA引脚接2号引脚并添加4.7k上拉电阻。
- TM1637显示屏的CLK、DIO引脚分别接3、4号引脚,注意接线顺序。
内容的提问来源于stack exchange,提问作者youssef samy
相关产品推荐
相关产品推荐

