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

Arduino冰箱项目:EC11旋转编码器调节SSR触发温度异常

Arduino冰箱控制系统编码器故障排查与修复

问题回顾

  • 使用EC11旋转编码器调节SSR触发温度时,无论旋转方向如何,阈值仅增加不减少
  • 编码器单独测试正常,加入项目后失效;移除printTemperature函数后编码器恢复正常
  • 单独测试显示屏+编码器时,未触碰旋钮却持续输出0值

核心问题分析

  1. 编码器方向判断逻辑完全颠倒
    EC11顺时针旋转时,A相状态变化时B相状态与A相相反;逆时针旋转时B相状态与A相相同。原代码的判断逻辑刚好搞反,导致无论怎么转都触发阈值增加。

  2. 阻塞式防抖函数卡死程序
    stateContactA函数使用while(1)死循环做防抖,会完全阻塞Arduino的主循环,导致编码器检测、温度读取等操作无法正常并行执行。尤其是当printTemperature中还有传感器通信和显示操作时,编码器的状态检测被彻底阻塞。

  3. printTemperature中的阻塞式延时
    当阈值调整后,代码用while循环实现3秒闪烁效果,这期间程序完全无法响应任何输入(包括编码器),直接导致编码器失效。

  4. 变量类型冗余与初始化问题
    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();
}

关键修复说明

  1. 修正编码器方向逻辑:调整了顺时针/逆时针的判断条件,匹配EC11的实际相位特性。
  2. 替换阻塞式防抖:用简单的delay(5)防抖替代死循环防抖,同时增加连续读取校验,既避免抖动又不阻塞程序。
  3. 非阻塞闪烁实现:用millis()计时实现3秒闪烁效果,主循环始终保持响应,编码器操作不会被卡死。
  4. 优化温度读取:添加500ms的读取间隔,减少传感器通信频率,避免占用过多资源。
  5. 增加阈值下限保护:防止逆时针旋转导致阈值变为负数。

额外注意事项

  • 确保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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 15:04:51