跳转到内容

LED状态指示灯

LED状态指示灯

本节介绍了为RFID签到/签退操作提供视觉反馈的LED指示灯系统。学习本节将使您能够:

  • 设计和实现用于用户反馈的LED状态指示灯
  • 处理不同的LED状态(签到、签退、错误、就绪)
  • 实现MQTT控制的LED模式
  • 排查常见的LED电路问题

开始本节之前,请确保您已完成:

  • 按照05-02连接LED电路
  • ESP32与Node-RED之间的MQTT通信正常工作
  • 已实现签到/签退流程(05-08)
  • 掌握ESP32 GPIO控制基础知识

系统使用两个LED来传达当前状态:

LED颜色状态含义
绿灯签到成功标签已注册,时间记录开始
红灯签退成功时间已记录到TimeTagger
绿灯 闪烁系统就绪ESP32已连接并等待中
红灯 闪烁错误连接问题或API失败
两者均灭深度睡眠或空闲无活动或省电模式
用户使用时间线:
1. 用户靠近读取器 → 两个LED均灭(空闲)
2. 用户轻触RFID标签 → 短暂停顿
3. ✓ 签到确认 → 绿灯亮3秒
4. 用户离开 → LED熄灭
5. 用户返回,再次轻触 → 短暂停顿
6. ✓ 签退确认 → 红灯亮3秒
7. 记录已保存 → 快速闪烁,然后熄灭
// 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闪烁间隔
// 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;
}
}

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>());
}
}

通过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); // 慢闪 = 等待标签
}

为更清晰的代码组织:

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);

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断开:红灯模式

症状:即使在室内光线下LED也几乎不可见

原因:电阻值过大

解决方案

// 尝试较低的电阻值:
// 对于10mA电流:
// R = (3.3V - 2.0V) / 0.01A = 130Ω → 使用150Ω
// 对于15mA(推荐最大值):
// R = (3.3V - 2.0V) / 0.015A = 87Ω → 使用100Ω

症状: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%亮度

症状:签退时绿灯亮起而不是红灯

原因: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足以作为指示
  1. 绿灯:系统就绪(闪烁),签到成功(常亮3秒)
  2. 红灯:错误(闪烁),签退成功(常亮3秒)
  3. 非阻塞控制:使用millis()定时器,而非delay()
  4. MQTT反馈:Node-RED发布LED命令到asset/tracking/feedback
  5. 启动序列:上电时验证两个LED功能正常