LED状态指示灯
LED状态指示灯
本节介绍了为RFID签到/签退操作提供视觉反馈的LED指示灯系统。学习本节将使您能够:
- 设计和实现用于用户反馈的LED状态指示灯
- 处理不同的LED状态(签到、签退、错误、就绪)
- 实现MQTT控制的LED模式
- 排查常见的LED电路问题
开始本节之前,请确保您已完成:
- 按照05-02连接LED电路
- ESP32与Node-RED之间的MQTT通信正常工作
- 已实现签到/签退流程(05-08)
- 掌握ESP32 GPIO控制基础知识
LED颜色含义
Section titled “LED颜色含义”系统使用两个LED来传达当前状态:
| LED颜色 | 状态 | 含义 |
|---|---|---|
| 绿灯 亮 | 签到成功 | 标签已注册,时间记录开始 |
| 红灯 亮 | 签退成功 | 时间已记录到TimeTagger |
| 绿灯 闪烁 | 系统就绪 | ESP32已连接并等待中 |
| 红灯 闪烁 | 错误 | 连接问题或API失败 |
| 两者均灭 | 深度睡眠或空闲 | 无活动或省电模式 |
用户体验流程
Section titled “用户体验流程”用户使用时间线:1. 用户靠近读取器 → 两个LED均灭(空闲)2. 用户轻触RFID标签 → 短暂停顿3. ✓ 签到确认 → 绿灯亮3秒4. 用户离开 → LED熄灭5. 用户返回,再次轻触 → 短暂停顿6. ✓ 签退确认 → 红灯亮3秒7. 记录已保存 → 快速闪烁,然后熄灭步骤1:LED引脚配置
Section titled “步骤1:LED引脚配置”// LED引脚定义#define LED_GREEN 22#define LED_RED 21
// LED定时常量const unsigned long LED_INDICATE_TIME = 3000; // 3秒const unsigned long BLINK_INTERVAL = 250; // 250ms闪烁间隔步骤2:LED控制函数
Section titled “步骤2:LED控制函数”// LED状态管理enum LEDState { LED_OFF, LED_GREEN_ON, LED_RED_ON, LED_GREEN_BLINK, LED_RED_BLINK, LED_BOTH_BLINK};
LEDState currentLEDState = LED_OFF;unsigned long ledStateStartTime = 0;
void setLED(LEDState state) { currentLEDState = state; ledStateStartTime = millis();
switch (state) { case LED_OFF: digitalWrite(LED_GREEN, LOW); digitalWrite(LED_RED, LOW); break;
case LED_GREEN_ON: digitalWrite(LED_GREEN, HIGH); digitalWrite(LED_RED, LOW); break;
case LED_RED_ON: digitalWrite(LED_GREEN, LOW); digitalWrite(LED_RED, HIGH); break;
case LED_GREEN_BLINK: case LED_RED_BLINK: case LED_BOTH_BLINK: // 闪烁在主循环中处理 break; }}
void updateLED() { unsigned long now = millis();
switch (currentLEDState) { case LED_GREEN_ON: case LED_RED_ON: // 指示时间后自动关闭 if (now - ledStateStartTime >= LED_INDICATE_TIME) { setLED(LED_OFF); } break;
case LED_GREEN_BLINK: // 绿灯闪烁(系统就绪指示) if ((now / BLINK_INTERVAL) % 2 == 0) { digitalWrite(LED_GREEN, HIGH); } else { digitalWrite(LED_GREEN, LOW); } break;
case LED_RED_BLINK: // 红灯闪烁(错误指示) if ((now / BLINK_INTERVAL) % 2 == 0) { digitalWrite(LED_RED, HIGH); } else { digitalWrite(LED_RED, LOW); } break;
case LED_BOTH_BLINK: // 交替闪烁(系统启动) if ((now / BLINK_INTERVAL) % 2 == 0) { digitalWrite(LED_GREEN, HIGH); digitalWrite(LED_RED, LOW); } else { digitalWrite(LED_GREEN, LOW); digitalWrite(LED_RED, HIGH); } break;
case LED_OFF: default: // 不执行任何操作 — LED保持熄灭 break; }}步骤3:MQTT消息的LED反馈
Section titled “步骤3:MQTT消息的LED反馈”ESP32监听来自Node-RED的MQTT反馈并相应更新LED:
void setup() { pinMode(LED_GREEN, OUTPUT); pinMode(LED_RED, OUTPUT);
// 启动指示 setLED(LED_BOTH_BLINK);
// ... 其余设置代码
// 就绪指示 setLED(LED_GREEN_BLINK); // 绿灯闪烁 = 系统就绪}
// MQTT反馈回调void callback(char* topic, byte* payload, unsigned int length) { // 解析消息 String message; for (int i = 0; i < length; i++) { message += (char)payload[i]; }
Serial.print("收到反馈:"); Serial.println(message);
// 解析JSON DynamicJsonDocument doc(256); DeserializationError error = deserializeJson(doc, message);
if (error) { Serial.println("JSON解析错误"); setLED(LED_RED_BLINK); return; }
String action = doc["action"] | ""; bool success = doc["success"] | true;
if (success) { if (action == "CHECK_IN") { // 绿灯 = 已签到 setLED(LED_GREEN_ON); Serial.println("✓ 签到成功"); } else if (action == "CHECK_OUT") { // 红灯 = 已签退 setLED(LED_RED_ON); Serial.println("✓ 签退成功"); } } else { // 错误状态 setLED(LED_RED_BLINK); Serial.print("✗ 操作失败:"); Serial.println(doc["error"].as<String>()); }}步骤4:连接状态指示
Section titled “步骤4:连接状态指示”通过LED模式指示WiFi和MQTT连接状态:
void setup() { // 启动序列 setLED(LED_BOTH_BLINK);
// 连接WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); // 连接尝试期间快速闪烁 digitalWrite(LED_GREEN, !digitalRead(LED_GREEN)); }
// WiFi已连接 → 绿灯闪烁 setLED(LED_GREEN_BLINK);
// 连接MQTT client.setServer(mqtt_server, 1883); while (!client.connected()) { if (client.connect("ESP32_RFID")) { // MQTT已连接 → 短暂绿灯常亮 setLED(LED_GREEN_ON); delay(500); } else { delay(2000); } }
// 系统就绪 setLED(LED_GREEN_BLINK); // 慢闪 = 等待标签}步骤5:完整的LED管理类
Section titled “步骤5:完整的LED管理类”为更清晰的代码组织:
class LEDManager {private: int greenPin; int redPin; LEDState currentState; unsigned long stateStartTime; unsigned long indicationDuration;
public: LEDManager(int gp, int rp) : greenPin(gp), redPin(rp) { pinMode(greenPin, OUTPUT); pinMode(redPin, OUTPUT); currentState = LED_OFF; stateStartTime = 0; indicationDuration = 3000; }
void indicateCheckIn() { setState(LED_GREEN_ON); }
void indicateCheckOut() { setState(LED_RED_ON); }
void indicateError() { setState(LED_RED_BLINK); }
void indicateReady() { setState(LED_GREEN_BLINK); }
void indicateStartup() { setState(LED_BOTH_BLINK); }
void turnOff() { setState(LED_OFF); }
void update() { unsigned long now = millis();
switch (currentState) { case LED_GREEN_ON: case LED_RED_ON: if (now - stateStartTime >= indicationDuration) { turnOff(); } break;
case LED_GREEN_BLINK: if ((now / 250) % 2 == 0) { digitalWrite(greenPin, HIGH); digitalWrite(redPin, LOW); } else { digitalWrite(greenPin, LOW); } break;
case LED_RED_BLINK: if ((now / 250) % 2 == 0) { digitalWrite(redPin, HIGH); digitalWrite(greenPin, LOW); } else { digitalWrite(redPin, LOW); } break;
case LED_BOTH_BLINK: if ((now / 150) % 2 == 0) { digitalWrite(greenPin, HIGH); digitalWrite(redPin, LOW); } else { digitalWrite(greenPin, LOW); digitalWrite(redPin, HIGH); } break;
case LED_OFF: default: digitalWrite(greenPin, LOW); digitalWrite(redPin, LOW); break; } }
private: void setState(LEDState state) { currentState = state; stateStartTime = millis(); }};
// 全局实例LEDManager leds(LED_GREEN, LED_RED);步骤6:Node-RED端反馈生成
Section titled “步骤6:Node-RED端反馈生成”Node-RED流程发送MQTT反馈消息以控制LED:
// Function节点:"生成LED反馈"// 根据操作结果创建适当的反馈消息
const uid = msg.payload?.uid || "UNKNOWN";const operation = msg.action || "UNKNOWN";const success = msg.success !== false;
if (success) { if (operation === "CHECK_IN") { msg.payload = { action: "CHECK_IN", success: true, name: msg.record?.ds || uid, message: "时间记录已开始" }; } else if (operation === "CHECK_OUT") { msg.payload = { action: "CHECK_OUT", success: true, name: msg.record?.ds || uid, duration: (msg.record?.t2 - msg.record?.t1) || 0, message: "时间记录成功" }; }} else { msg.payload = { action: "ERROR", success: false, uid: uid, error: msg.error || "未知错误", message: "操作失败" };}
msg.topic = "asset/tracking/feedback";msg.retain = false;
return msg;测试LED系统:
// 1. 给ESP32上电// 预期:启动时两个LED交替闪烁// 然后:绿灯慢闪(系统就绪)
// 2. 扫描已注册的RFID标签(第一次)// 预期:绿灯亮3秒(签到)
// 3. 再次扫描同一标签// 预期:红灯亮3秒(签退)
// 4. 暂时断开WiFi// 预期:红灯闪烁(连接错误)
// 5. 重新连接WiFi// 预期:绿灯闪烁(系统就绪)验证检查表:
- 启动序列:两个LED闪烁
- 系统就绪:绿灯慢闪
- 签到:绿灯常亮3秒
- 签退:红灯常亮3秒
- 错误:红灯闪烁
- WiFi已连接:绿灯模式
- WiFi断开:红灯模式
问题1:LED太暗
Section titled “问题1:LED太暗”症状:即使在室内光线下LED也几乎不可见
原因:电阻值过大
解决方案:
// 尝试较低的电阻值:// 对于10mA电流:// R = (3.3V - 2.0V) / 0.01A = 130Ω → 使用150Ω
// 对于15mA(推荐最大值):// R = (3.3V - 2.0V) / 0.015A = 87Ω → 使用100Ω问题2:LED太亮
Section titled “问题2:LED太亮”症状:LED亮度过高,刺眼
解决方案:增大电阻值或使用PWM进行软件亮度控制:
// 使用PWM进行软件亮度控制void setLEDBrightness(int pin, int brightness) { // brightness: 0-255 analogWrite(pin, brightness);}
// 在setup中使用:// ledcSetup(0, 5000, 8); // 通道0,5kHz,8位// ledcAttachPin(LED_GREEN, 0);// ledcWrite(0, 128); // 50%亮度问题3:错误的LED亮起
Section titled “问题3:错误的LED亮起”症状:签退时绿灯亮起而不是红灯
原因:LED接线反向(阴极/阳极互换)或代码逻辑错误
解决方案:
// 验证接线:LED阳极(+)→ GPIO经电阻 → LED阴极(-)→ GND// 用万用表检查:GPIO HIGH应点亮LED
// 如果接线反向:// digitalWrite(pin, HIGH) → 灭(如果LED接线反向)// digitalWrite(pin, LOW) → 亮// 在代码中交换:// #define LED_ON LOW// #define LED_OFF HIGH- ✅ 推荐:使用一致的LED含义(绿灯=好,红灯=坏)
- ✅ 推荐:包含启动自检序列,让用户知道两个LED都正常工作
- ✅ 推荐:使用非阻塞LED控制(使用
millis()而非delay()) - ❌ 避免:在LED控制代码中使用
delay()(会阻塞其他操作) - ❌ 避免:以最大电流驱动LED——10mA足以作为指示
- 绿灯:系统就绪(闪烁),签到成功(常亮3秒)
- 红灯:错误(闪烁),签退成功(常亮3秒)
- 非阻塞控制:使用
millis()定时器,而非delay() - MQTT反馈:Node-RED发布LED命令到
asset/tracking/feedback - 启动序列:上电时验证两个LED功能正常