1、洛天依项目ESP32部分业务-项目初始化

This commit is contained in:
Rdzleo 2026-03-05 17:12:48 +08:00
commit 8693ee1d29
18 changed files with 86689 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,696 @@
#include <SPI.h>
#include <MFRC522.h>
#include <FastLED.h>
#include <Arduino.h>
#include <driver/ledc.h>
// RFID引脚定义
#define RFID_RST_PIN 14 // RC522 复位引脚
#define RFID_SS_PIN 10 // RC522 片选引脚
#define RFID_MISO_PIN 13 // MISO 引脚
#define RFID_MOSI_PIN 12 // MOSI 引脚
#define RFID_SCK_PIN 11 // SCK 引脚
// LED定义
#define LED_PIN_1 4 // 1颗WS2812灯珠引脚
#define LED_PIN_2 5 // 160颗WS2812灯带引脚
#define LED_PIN_3 48 // 1颗WS2812灯珠引脚新增
#define LED_COUNT_1 1 // 1颗灯珠
#define LED_COUNT_2 186 // 160颗灯带
#define LED_COUNT_3 1 // 1颗灯珠新增
// PWM定义
#define PWM_PIN 6 // PWM输出引脚
#define PWM_CHANNEL 0 // PWM通道
#define PWM_FREQ 1000 // PWM频率(Hz)
#define PWM_RESOLUTION 10 // PWM分辨率(位)
#define DEFAULT_DUTY 819 // 默认占空比(80%)
// 按钮和输入引脚定义
#define BTN0_PIN 15 // 按钮0引脚
#define WAKEUP1_PIN 16 // 唤醒引脚1
#define BTN1_PIN 17 // 按钮1引脚
#define BTN2_PIN 18 // 按钮2引脚
// 任务句柄
TaskHandle_t TaskRFID, TaskLED1, TaskLED2, TaskLED3, TaskPWM, TaskBTN0, TaskWAKEUP1, TaskBTN1, TaskBTN2;
// 全局变量
MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN); // 创建RFID实例
CRGB leds1[LED_COUNT_1]; // 1颗灯珠数组
CRGB leds2[LED_COUNT_2]; // 160颗灯带数组
CRGB leds3[LED_COUNT_3]; // 1颗灯珠数组新增
String lastCardData = ""; // 上次读取的RFID卡数据
int ledMode = 1; // 灯带模式默认为1(白色)
int pwmDuty = DEFAULT_DUTY; // PWM占空比
bool btn0State = HIGH; // 按钮0状态
bool btn0LongPress = false; // 按钮0长按标志
bool wakeup1State = LOW; // 唤醒引脚1状态
bool btn1State = LOW; // 按钮1状态
bool btn2State = LOW; // 按钮2状态
int singleLedMode = 7; // 单颗LED模式默认为7(白色)
// 灯带动画全局变量
static uint8_t rainbowHue = 0;
static int trainPos = 0;
static unsigned long lastUpdate = 0;
static const int TRAIN_LENGTH = 16; // 火车灯长度
static int trainPhase = 0; // 火车阶段0-正向出站1-正向前进2-正向进站3-反向出站4-反向前进5-反向进站
static const int VIRTUAL_LED_COUNT = LED_COUNT_2 + TRAIN_LENGTH; // 虚拟灯带长度
// 单颗LED颜色数组
CRGB singleLedColors[8] = {
CRGB::Black, // 0: 熄灭
CRGB::Blue, // 1: 蓝色
CRGB::Green, // 2: 绿色
CRGB::Orange, // 3: 橙色
CRGB::Red, // 4: 红色
CRGB::Purple, // 5: 紫色
CRGB::Yellow, // 6: 黄色
CRGB::White // 7: 白色
};
// RFID读取任务
void TaskRFIDcode( void * pvParameters ) {
for(;;) {
// 寻找新卡片
if ( ! rfid.PICC_IsNewCardPresent()) {
delay(10);
continue;
}
// 验证NUID是否可读
if ( ! rfid.PICC_ReadCardSerial()) {
delay(10);
continue;
}
// 读取卡片数据(用户数据区)
String cardData = "";
MFRC522::MIFARE_Key key;
// 准备认证密钥
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
// 选择卡片
MFRC522::StatusCode status;
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(rfid.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Authentication failed: "));
Serial.println(rfid.GetStatusCodeName(status));
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
delay(100);
continue;
}
// 读取数据块
byte buffer[18];
byte size = sizeof(buffer);
status = rfid.MIFARE_Read(4, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Reading failed: "));
Serial.println(rfid.GetStatusCodeName(status));
} else {
// 转换为ASCII字符串
for (byte i = 0; i < 16; i++) {
if (buffer[i] >= 32 && buffer[i] <= 126) { // 可打印ASCII字符
cardData += (char)buffer[i];
}
}
// 移除空白字符
cardData.trim();
// 卡片数据处理
if (cardData != lastCardData && !cardData.isEmpty()) {
lastCardData = cardData;
Serial.println("SORC_" + cardData);
}
}
// 使放置在读卡区的IC卡进入休眠状态不再重复读卡
rfid.PICC_HaltA();
// 停止加密PCD
rfid.PCD_StopCrypto1();
delay(100);
}
}
// LED1控制任务
void TaskLED1code( void * pvParameters ) {
for(;;) {
// 根据模式设置LED1颜色
if (singleLedMode >= 0 && singleLedMode <= 7) {
leds1[0] = singleLedColors[singleLedMode];
} else {
leds1[0] = CRGB::Blue; // 默认白色
}
// 更新LED
FastLED.show();
delay(20);
}
}
// LED3控制任务新增
void TaskLED3code( void * pvParameters ) {
for(;;) {
// 强制设置GPIO48的灯珠为熄灭状态
leds3[0] = CRGB::Black;
// 更新LED
FastLED.show();
delay(20);
}
}
// LED2控制任务
void TaskLED2code( void * pvParameters ) {
for(;;) {
// 根据不同模式控制灯带
switch(ledMode) {
case 0: // 全部熄灭
fill_solid(leds2, LED_COUNT_2, CRGB::Black);
break;
case 1: // 纯白色
fill_solid(leds2, LED_COUNT_2, CRGB::White);
break;
case 2: // 彩虹流水灯
for(int i = 0; i < LED_COUNT_2; i++) {
leds2[i] = CHSV(rainbowHue + i * 256 / LED_COUNT_2, 255, 255);
}
rainbowHue++;
break;
case 3: // 彩虹呼吸灯
{
static unsigned long lastHueUpdate = 0;
static unsigned long lastBreathUpdate = 0;
static uint8_t breathingHue = 0;
static uint8_t breathValue = 128;
static int8_t breathDirection = 1;
unsigned long currentTime = millis();
// 每300ms更新一次色相非常缓慢的变化
if (currentTime - lastHueUpdate > 300) {
breathingHue += 1;
lastHueUpdate = currentTime;
}
// 每20ms更新一次呼吸亮度
if (currentTime - lastBreathUpdate > 20) {
breathValue += breathDirection * 2;
if (breathValue >= 200) {
breathValue = 200;
breathDirection = -1;
} else if (breathValue <= 80) {
breathValue = 80;
breathDirection = 1;
}
lastBreathUpdate = currentTime;
}
for(int i = 0; i < LED_COUNT_2; i++) {
leds2[i] = CHSV(breathingHue, 200, breathValue);
}
}
break;
case 4: // 彩虹火车灯
if (millis() - lastUpdate > 30) { // 30ms更新一次
lastUpdate = millis();
// 清除所有灯珠
fill_solid(leds2, LED_COUNT_2, CRGB::Black);
switch (trainPhase) {
case 0: // 正向出站(从起点开始出现)
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全出站
if (trainPos >= 0) {
trainPhase = 1; // 开始正向前进
trainPos = 0;
}
break;
case 1: // 正向前进
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否到达终点
if (trainPos >= LED_COUNT_2 - TRAIN_LENGTH) {
trainPhase = 2; // 开始正向进站
trainPos = LED_COUNT_2 - TRAIN_LENGTH;
}
break;
case 2: // 正向进站(从尾部开始消失)
for (int i = 0; i < TRAIN_LENGTH; i++) {
int displayPos = LED_COUNT_2 - 1 - i;
if (displayPos >= trainPos) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[displayPos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全进站
if (trainPos >= LED_COUNT_2) {
trainPhase = 3; // 开始反向出站
trainPos = 0;
rainbowHue += 64; // 改变彩虹颜色
}
break;
case 3: // 反向出站(从终点开始出现)
for (int i = 0; i < trainPos + 1; i++) {
int pos = LED_COUNT_2 - 1 - i;
if (pos >= 0) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全出站
if (trainPos >= TRAIN_LENGTH) {
trainPhase = 4; // 开始反向前进
trainPos = TRAIN_LENGTH;
}
break;
case 4: // 反向前进
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = LED_COUNT_2 - trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否到达起点
if (trainPos >= LED_COUNT_2) {
trainPhase = 5; // 开始反向进站
trainPos = 0;
}
break;
case 5: // 反向进站(从头部开始消失)
for (int i = 0; i < TRAIN_LENGTH - trainPos; i++) {
int pos = i;
if (pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全进站
if (trainPos >= TRAIN_LENGTH) {
trainPhase = 0; // 重新开始正向出站
trainPos = -TRAIN_LENGTH;
rainbowHue += 64; // 改变彩虹颜色
}
break;
}
}
break;
case 5: // 马卡龙火车灯(保留原功能,未修改)
// 代码保持不变...
break;
}
// 更新LED
FastLED.show();
// 根据模式调整延时
if (ledMode == 4 || ledMode == 5) {
delay(10); // 火车灯模式需要更快的更新速度
} else {
delay(30);
}
}
}
// PWM控制任务
void TaskPWMcode( void * pvParameters ) {
for(;;) {
// 设置PWM占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
delay(100);
}
}
// 按钮0检测任务
void TaskBTN0code( void * pvParameters ) {
static unsigned long pressStartTime = 0;
static bool lastState = HIGH;
for(;;) {
bool currentState = digitalRead(BTN0_PIN);
// 检测下降沿(按下)
if (lastState == HIGH && currentState == LOW) {
pressStartTime = millis();
btn0State = LOW;
Serial.println("SO_BT0_HIGH");
btn0LongPress = false;
}
// 检测上升沿(释放)
else if (lastState == LOW && currentState == HIGH) {
btn0State = HIGH;
Serial.println("SO_BT0_LOW");
btn0LongPress = false;
}
// 检测长按
else if (currentState == LOW && millis() - pressStartTime >= 2000 && !btn0LongPress) {
btn0LongPress = true;
Serial.println("SO_BT0_HIGHL");
}
lastState = currentState;
delay(10);
}
}
// WAKEUP1检测任务
void TaskWAKEUP1code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(WAKEUP1_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
wakeup1State = HIGH;
Serial.println("SO_WAKEUP1");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
wakeup1State = LOW;
Serial.println("SO_WAKEUP0");
}
lastState = currentState;
delay(10);
}
}
// 按钮1检测任务
void TaskBTN1code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(BTN1_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
btn1State = HIGH;
Serial.println("SO_BT1_HIGH");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
btn1State = LOW;
Serial.println("SO_BT1_LOW");
}
lastState = currentState;
delay(10);
}
}
// 按钮2检测任务
void TaskBTN2code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(BTN2_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
btn2State = HIGH;
Serial.println("SO_BT2_HIGH");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
btn2State = LOW;
Serial.println("SO_BT2_LOW");
}
lastState = currentState;
delay(10);
}
}
// 串口命令处理
void handleSerialCommand() {
static String command = "";
while (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
// 处理命令
if (command.startsWith("MO_LED_")) {
String modeStr = command.substring(7);
int newMode = modeStr.toInt();
// 控制单颗LED
if (newMode >= 0 && newMode <= 7) {
singleLedMode = newMode;
Serial.print("Single LED set to mode: ");
Serial.println(newMode);
} else {
Serial.println("Invalid single LED mode command");
}
}
else if (command.startsWith("MO_LEDN_")) {
String modeStr = command.substring(8);
int newMode = modeStr.toInt();
// 控制灯带
if (newMode >= 0 && newMode <= 5) {
ledMode = newMode;
// 重置火车灯状态
if (newMode == 4) {
trainPos = -TRAIN_LENGTH;
trainPhase = 0;
rainbowHue = random8();
}
Serial.print("LED strip set to mode: ");
Serial.println(newMode);
} else {
Serial.println("Invalid LED strip mode command");
}
}
else if (command.startsWith("MO_PWM_")) {
String dutyStr = command.substring(7);
int newDuty = dutyStr.toInt();
// 检查PWM百分比
if (newDuty == 1) {
pwmDuty = 1023; // 100%
} else if (newDuty == 0 || newDuty == 20 || newDuty == 40 || newDuty == 60 || newDuty == 80) {
pwmDuty = (newDuty * 1023) / 100; // 转换为实际占空比
} else {
Serial.println("Invalid PWM command");
}
Serial.print("PWM set to: ");
Serial.print((pwmDuty * 100) / 1023);
Serial.println("%");
}
// 清空命令
command = "";
} else {
command += c;
}
}
}
void setup() {
// 初始化串口
Serial.begin(115200);
Serial.println("System starting...");
// 初始化SPI总线
SPI.begin(RFID_SCK_PIN, RFID_MISO_PIN, RFID_MOSI_PIN, RFID_SS_PIN);
// 初始化RFID
rfid.PCD_Init();
Serial.println("RFID initialized.");
// 初始化LED
FastLED.addLeds<WS2812, LED_PIN_1, GRB>(leds1, LED_COUNT_1);
FastLED.addLeds<WS2812, LED_PIN_2, GRB>(leds2, LED_COUNT_2);
FastLED.addLeds<WS2812, LED_PIN_3, GRB>(leds3, LED_COUNT_3); // 新增LED3
// 初始化LED状态
fill_solid(leds1, LED_COUNT_1, singleLedColors[singleLedMode]);
fill_solid(leds2, LED_COUNT_2, CRGB::White);
fill_solid(leds3, LED_COUNT_3, CRGB::Black); // 强制GPIO48的灯珠熄灭
FastLED.show();
Serial.println("LED initialized.");
// 初始化PWM
// 创建LED控制器配置
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = (ledc_timer_bit_t)PWM_RESOLUTION,
.timer_num = (ledc_timer_t)PWM_CHANNEL,
.freq_hz = PWM_FREQ,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
// 创建LED通道配置
ledc_channel_config_t ledc_channel = {
.gpio_num = PWM_PIN,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = (ledc_channel_t)PWM_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = (ledc_timer_t)PWM_CHANNEL,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
// 设置初始占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
Serial.println("PWM initialized.");
// 初始化输入引脚
pinMode(BTN0_PIN, INPUT_PULLUP);
pinMode(WAKEUP1_PIN, INPUT);
pinMode(BTN1_PIN, INPUT);
pinMode(BTN2_PIN, INPUT);
Serial.println("Inputs initialized.");
// 创建任务
xTaskCreatePinnedToCore(
TaskRFIDcode, /* 任务函数 */
"TaskRFID", /* 任务名称 */
4096, /* 任务栈大小 */
NULL, /* 传递给任务的参数 */
1, /* 任务优先级 */
&TaskRFID, /* 任务句柄 */
1); /* 运行在核心1上 */
xTaskCreatePinnedToCore(
TaskLED1code,
"TaskLED1",
2048,
NULL,
1,
&TaskLED1,
1);
xTaskCreatePinnedToCore(
TaskLED2code,
"TaskLED2",
4096,
NULL,
1,
&TaskLED2,
1);
xTaskCreatePinnedToCore(
TaskLED3code,
"TaskLED3",
2048,
NULL,
1,
&TaskLED3,
1); // 新增LED3任务
xTaskCreatePinnedToCore(
TaskPWMcode,
"TaskPWM",
1024,
NULL,
1,
&TaskPWM,
1);
xTaskCreatePinnedToCore(
TaskBTN0code,
"TaskBTN0",
2048,
NULL,
1,
&TaskBTN0,
0);
xTaskCreatePinnedToCore(
TaskWAKEUP1code,
"TaskWAKEUP1",
2048,
NULL,
1,
&TaskWAKEUP1,
0);
xTaskCreatePinnedToCore(
TaskBTN1code,
"TaskBTN1",
2048,
NULL,
1,
&TaskBTN1,
0);
xTaskCreatePinnedToCore(
TaskBTN2code,
"TaskBTN2",
2048,
NULL,
1,
&TaskBTN2,
0);
Serial.println("Tasks created. System ready.");
}
void loop() {
// 处理串口命令
handleSerialCommand();
// 让出CPU时间
delay(1);
}

View File

@ -0,0 +1,668 @@
#include <SPI.h>
#include <MFRC522.h>
#include <FastLED.h>
#include <Arduino.h>
#include <driver/ledc.h>
// RFID引脚定义
#define RFID_RST_PIN 14 // RC522 复位引脚
#define RFID_SS_PIN 10 // RC522 片选引脚
#define RFID_MISO_PIN 13 // MISO 引脚
#define RFID_MOSI_PIN 12 // MOSI 引脚
#define RFID_SCK_PIN 11 // SCK 引脚
// LED定义
#define LED_PIN_1 4 // 1颗WS2812灯珠引脚
#define LED_PIN_2 5 // 160颗WS2812灯带引脚
#define LED_PIN_3 48 // 1颗WS2812灯珠引脚新增
#define LED_COUNT_1 1 // 1颗灯珠
#define LED_COUNT_2 186 // 160颗灯带
#define LED_COUNT_3 1 // 1颗灯珠新增
// PWM定义
#define PWM_PIN 6 // PWM输出引脚
#define PWM_CHANNEL 0 // PWM通道
#define PWM_FREQ 1000 // PWM频率(Hz)
#define PWM_RESOLUTION 10 // PWM分辨率(位)
#define DEFAULT_DUTY 819 // 默认占空比(80%)
// 按钮和输入引脚定义
#define BTN0_PIN 15 // 按钮0引脚
#define WAKEUP1_PIN 16 // 唤醒引脚1
#define BTN1_PIN 17 // 按钮1引脚
#define BTN2_PIN 18 // 按钮2引脚
// 任务句柄
TaskHandle_t TaskRFID, TaskLED1, TaskLED2, TaskLED3, TaskPWM, TaskBTN0, TaskWAKEUP1, TaskBTN1, TaskBTN2;
// 全局变量
MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN); // 创建RFID实例
CRGB leds1[LED_COUNT_1]; // 1颗灯珠数组
CRGB leds2[LED_COUNT_2]; // 160颗灯带数组
CRGB leds3[LED_COUNT_3]; // 1颗灯珠数组新增
String lastCardData = ""; // 上次读取的RFID卡数据
int ledMode = 1; // 灯带模式默认为1(白色)
int pwmDuty = DEFAULT_DUTY; // PWM占空比
bool btn0State = HIGH; // 按钮0状态
bool btn0LongPress = false; // 按钮0长按标志
bool wakeup1State = LOW; // 唤醒引脚1状态
bool btn1State = LOW; // 按钮1状态
bool btn2State = LOW; // 按钮2状态
int singleLedMode = 7; // 单颗LED模式默认为7(白色)
// 灯带动画全局变量
static uint8_t rainbowHue = 0;
static int trainPos = 0;
static unsigned long lastUpdate = 0;
static const int TRAIN_LENGTH = 16; // 火车灯长度
static int trainPhase = 0; // 火车阶段0-正向出站1-正向前进2-正向进站3-反向出站4-反向前进5-反向进站
static const int VIRTUAL_LED_COUNT = LED_COUNT_2 + TRAIN_LENGTH; // 虚拟灯带长度
// 单颗LED颜色数组
CRGB singleLedColors[8] = {
CRGB::Black, // 0: 熄灭
CRGB::Blue, // 1: 蓝色
CRGB::Green, // 2: 绿色
CRGB::Orange, // 3: 橙色
CRGB::Red, // 4: 红色
CRGB::Purple, // 5: 紫色
CRGB::Yellow, // 6: 黄色
CRGB::White // 7: 白色
};
// RFID读取任务
void TaskRFIDcode( void * pvParameters ) {
for(;;) {
// 寻找新卡片
if ( ! rfid.PICC_IsNewCardPresent()) {
delay(10);
continue;
}
// 验证NUID是否可读
if ( ! rfid.PICC_ReadCardSerial()) {
delay(10);
continue;
}
// 读取卡片数据(用户数据区)
String cardData = "";
MFRC522::MIFARE_Key key;
// 准备认证密钥
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
// 选择卡片
MFRC522::StatusCode status;
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(rfid.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Authentication failed: "));
Serial.println(rfid.GetStatusCodeName(status));
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
delay(100);
continue;
}
// 读取数据块
byte buffer[18];
byte size = sizeof(buffer);
status = rfid.MIFARE_Read(4, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Reading failed: "));
Serial.println(rfid.GetStatusCodeName(status));
} else {
// 转换为ASCII字符串
for (byte i = 0; i < 16; i++) {
if (buffer[i] >= 32 && buffer[i] <= 126) { // 可打印ASCII字符
cardData += (char)buffer[i];
}
}
// 移除空白字符
cardData.trim();
// 卡片数据处理
if (cardData != lastCardData && !cardData.isEmpty()) {
lastCardData = cardData;
Serial.println("SORC_" + cardData);
}
}
// 使放置在读卡区的IC卡进入休眠状态不再重复读卡
rfid.PICC_HaltA();
// 停止加密PCD
rfid.PCD_StopCrypto1();
delay(100);
}
}
// LED1控制任务
void TaskLED1code( void * pvParameters ) {
for(;;) {
// 根据模式设置LED1颜色
if (singleLedMode >= 0 && singleLedMode <= 7) {
leds1[0] = singleLedColors[singleLedMode];
} else {
leds1[0] = CRGB::Blue; // 默认白色
}
// 更新LED
FastLED.show();
delay(20);
}
}
// LED3控制任务新增
void TaskLED3code( void * pvParameters ) {
for(;;) {
// 强制设置GPIO48的灯珠为熄灭状态
leds3[0] = CRGB::Black;
// 更新LED
FastLED.show();
delay(20);
}
}
// LED2控制任务
void TaskLED2code( void * pvParameters ) {
for(;;) {
// 根据不同模式控制灯带
switch(ledMode) {
case 0: // 全部熄灭
fill_solid(leds2, LED_COUNT_2, CRGB::Black);
break;
case 1: // 纯白色
fill_solid(leds2, LED_COUNT_2, CRGB::White);
break;
case 2: // 彩虹流水灯
for(int i = 0; i < LED_COUNT_2; i++) {
leds2[i] = CHSV(rainbowHue + i * 256 / LED_COUNT_2, 255, 255);
}
rainbowHue++;
break;
case 3: // 彩虹呼吸灯
for(int i = 0; i < LED_COUNT_2; i++) {
leds2[i] = CHSV(rainbowHue, 255, beatsin8(1, 64, 255));
}
rainbowHue++;
break;
case 4: // 彩虹火车灯
if (millis() - lastUpdate > 30) { // 30ms更新一次
lastUpdate = millis();
// 清除所有灯珠
fill_solid(leds2, LED_COUNT_2, CRGB::Black);
switch (trainPhase) {
case 0: // 正向出站(从起点开始出现)
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全出站
if (trainPos >= 0) {
trainPhase = 1; // 开始正向前进
trainPos = 0;
}
break;
case 1: // 正向前进
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否到达终点
if (trainPos >= LED_COUNT_2 - TRAIN_LENGTH) {
trainPhase = 2; // 开始正向进站
trainPos = LED_COUNT_2 - TRAIN_LENGTH;
}
break;
case 2: // 正向进站(从尾部开始消失)
for (int i = 0; i < TRAIN_LENGTH; i++) {
int displayPos = LED_COUNT_2 - 1 - i;
if (displayPos >= trainPos) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[displayPos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全进站
if (trainPos >= LED_COUNT_2) {
trainPhase = 3; // 开始反向出站
trainPos = 0;
rainbowHue += 64; // 改变彩虹颜色
}
break;
case 3: // 反向出站(从终点开始出现)
for (int i = 0; i < trainPos + 1; i++) {
int pos = LED_COUNT_2 - 1 - i;
if (pos >= 0) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全出站
if (trainPos >= TRAIN_LENGTH) {
trainPhase = 4; // 开始反向前进
trainPos = TRAIN_LENGTH;
}
break;
case 4: // 反向前进
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = LED_COUNT_2 - trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否到达起点
if (trainPos >= LED_COUNT_2) {
trainPhase = 5; // 开始反向进站
trainPos = 0;
}
break;
case 5: // 反向进站(从头部开始消失)
for (int i = 0; i < TRAIN_LENGTH - trainPos; i++) {
int pos = i;
if (pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全进站
if (trainPos >= TRAIN_LENGTH) {
trainPhase = 0; // 重新开始正向出站
trainPos = -TRAIN_LENGTH;
rainbowHue += 64; // 改变彩虹颜色
}
break;
}
}
break;
case 5: // 马卡龙火车灯(保留原功能,未修改)
// 代码保持不变...
break;
}
// 更新LED
FastLED.show();
// 根据模式调整延时
if (ledMode == 4 || ledMode == 5) {
delay(10); // 火车灯模式需要更快的更新速度
} else {
delay(30);
}
}
}
// PWM控制任务
void TaskPWMcode( void * pvParameters ) {
for(;;) {
// 设置PWM占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
delay(100);
}
}
// 按钮0检测任务
void TaskBTN0code( void * pvParameters ) {
static unsigned long pressStartTime = 0;
static bool lastState = HIGH;
for(;;) {
bool currentState = digitalRead(BTN0_PIN);
// 检测下降沿(按下)
if (lastState == HIGH && currentState == LOW) {
pressStartTime = millis();
btn0State = LOW;
Serial.println("SO_BT0_HIGH");
btn0LongPress = false;
}
// 检测上升沿(释放)
else if (lastState == LOW && currentState == HIGH) {
btn0State = HIGH;
Serial.println("SO_BT0_LOW");
btn0LongPress = false;
}
// 检测长按
else if (currentState == LOW && millis() - pressStartTime >= 2000 && !btn0LongPress) {
btn0LongPress = true;
Serial.println("SO_BT0_HIGHL");
}
lastState = currentState;
delay(10);
}
}
// WAKEUP1检测任务
void TaskWAKEUP1code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(WAKEUP1_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
wakeup1State = HIGH;
Serial.println("SO_WAKEUP1");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
wakeup1State = LOW;
Serial.println("SO_WAKEUP0");
}
lastState = currentState;
delay(10);
}
}
// 按钮1检测任务
void TaskBTN1code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(BTN1_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
btn1State = HIGH;
Serial.println("SO_BT1_HIGH");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
btn1State = LOW;
Serial.println("SO_BT1_LOW");
}
lastState = currentState;
delay(10);
}
}
// 按钮2检测任务
void TaskBTN2code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(BTN2_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
btn2State = HIGH;
Serial.println("SO_BT2_HIGH");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
btn2State = LOW;
Serial.println("SO_BT2_LOW");
}
lastState = currentState;
delay(10);
}
}
// 串口命令处理
void handleSerialCommand() {
static String command = "";
while (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
// 处理命令
if (command.startsWith("MO_LED_")) {
String modeStr = command.substring(7);
int newMode = modeStr.toInt();
// 控制单颗LED
if (newMode >= 0 && newMode <= 7) {
singleLedMode = newMode;
Serial.print("Single LED set to mode: ");
Serial.println(newMode);
} else {
Serial.println("Invalid single LED mode command");
}
}
else if (command.startsWith("MO_LEDN_")) {
String modeStr = command.substring(8);
int newMode = modeStr.toInt();
// 控制灯带
if (newMode >= 0 && newMode <= 5) {
ledMode = newMode;
// 重置火车灯状态
if (newMode == 4) {
trainPos = -TRAIN_LENGTH;
trainPhase = 0;
rainbowHue = random8();
}
Serial.print("LED strip set to mode: ");
Serial.println(newMode);
} else {
Serial.println("Invalid LED strip mode command");
}
}
else if (command.startsWith("MO_PWM_")) {
String dutyStr = command.substring(7);
int newDuty = dutyStr.toInt();
// 检查PWM百分比
if (newDuty == 1) {
pwmDuty = 1023; // 100%
} else if (newDuty == 0 || newDuty == 20 || newDuty == 40 || newDuty == 60 || newDuty == 80) {
pwmDuty = (newDuty * 1023) / 100; // 转换为实际占空比
} else {
Serial.println("Invalid PWM command");
}
Serial.print("PWM set to: ");
Serial.print((pwmDuty * 100) / 1023);
Serial.println("%");
}
// 清空命令
command = "";
} else {
command += c;
}
}
}
void setup() {
// 初始化串口
Serial.begin(115200);
Serial.println("System starting...");
// 初始化SPI总线
SPI.begin(RFID_SCK_PIN, RFID_MISO_PIN, RFID_MOSI_PIN, RFID_SS_PIN);
// 初始化RFID
rfid.PCD_Init();
Serial.println("RFID initialized.");
// 初始化LED
FastLED.addLeds<WS2812, LED_PIN_1, GRB>(leds1, LED_COUNT_1);
FastLED.addLeds<WS2812, LED_PIN_2, GRB>(leds2, LED_COUNT_2);
FastLED.addLeds<WS2812, LED_PIN_3, GRB>(leds3, LED_COUNT_3); // 新增LED3
// 初始化LED状态
fill_solid(leds1, LED_COUNT_1, singleLedColors[singleLedMode]);
fill_solid(leds2, LED_COUNT_2, CRGB::White);
fill_solid(leds3, LED_COUNT_3, CRGB::Black); // 强制GPIO48的灯珠熄灭
FastLED.show();
Serial.println("LED initialized.");
// 初始化PWM
// 创建LED控制器配置
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = (ledc_timer_bit_t)PWM_RESOLUTION,
.timer_num = (ledc_timer_t)PWM_CHANNEL,
.freq_hz = PWM_FREQ,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
// 创建LED通道配置
ledc_channel_config_t ledc_channel = {
.gpio_num = PWM_PIN,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = (ledc_channel_t)PWM_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = (ledc_timer_t)PWM_CHANNEL,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
// 设置初始占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
Serial.println("PWM initialized.");
// 初始化输入引脚
pinMode(BTN0_PIN, INPUT_PULLUP);
pinMode(WAKEUP1_PIN, INPUT);
pinMode(BTN1_PIN, INPUT);
pinMode(BTN2_PIN, INPUT);
Serial.println("Inputs initialized.");
// 创建任务
xTaskCreatePinnedToCore(
TaskRFIDcode, /* 任务函数 */
"TaskRFID", /* 任务名称 */
4096, /* 任务栈大小 */
NULL, /* 传递给任务的参数 */
1, /* 任务优先级 */
&TaskRFID, /* 任务句柄 */
1); /* 运行在核心1上 */
xTaskCreatePinnedToCore(
TaskLED1code,
"TaskLED1",
2048,
NULL,
1,
&TaskLED1,
1);
xTaskCreatePinnedToCore(
TaskLED2code,
"TaskLED2",
4096,
NULL,
1,
&TaskLED2,
1);
xTaskCreatePinnedToCore(
TaskLED3code,
"TaskLED3",
2048,
NULL,
1,
&TaskLED3,
1); // 新增LED3任务
xTaskCreatePinnedToCore(
TaskPWMcode,
"TaskPWM",
1024,
NULL,
1,
&TaskPWM,
1);
xTaskCreatePinnedToCore(
TaskBTN0code,
"TaskBTN0",
2048,
NULL,
1,
&TaskBTN0,
0);
xTaskCreatePinnedToCore(
TaskWAKEUP1code,
"TaskWAKEUP1",
2048,
NULL,
1,
&TaskWAKEUP1,
0);
xTaskCreatePinnedToCore(
TaskBTN1code,
"TaskBTN1",
2048,
NULL,
1,
&TaskBTN1,
0);
xTaskCreatePinnedToCore(
TaskBTN2code,
"TaskBTN2",
2048,
NULL,
1,
&TaskBTN2,
0);
Serial.println("Tasks created. System ready.");
}
void loop() {
// 处理串口命令
handleSerialCommand();
// 让出CPU时间
delay(1);
}

View File

@ -0,0 +1,55 @@
RTOS多任务模式实现如下功能
1.RFID卡片读取基于RC522模块
模块引脚定义:
#define RFID_RST_PIN 14 //RC522 复位引脚
#define RFID_SS_PIN 10 //RC522 片选引脚
#define RFID_MISO_PIN 13 // MISO 引脚
#define RFID_MOSI_PIN 12 // MOSI 引脚
#define RFID_SCK_PIN 11 // SCK 引脚
将读取到的卡片中用户数据区的字符信息发送给串口发送格式为“SORC_XXXXX”比如如果读取到HA001就发送"SORC_HA001",卡片在读取状态下不要持续发送只需要发送1次如果卡片离开读卡器再次放入读卡器又读取到相同的信息则需要发送。注意这里要把读取到的数据转换为ASCII字符
2.基于FASTLED库控制位于GPIO4 引脚上的1颗WS2812灯珠并接受如下来自串口的指令。
串口指令“MO_LED_0”,灯珠熄灭
串口指令“MO_LED_1”灯珠亮蓝色
串口指令“MO_LED_2”灯珠亮绿色
串口指令“MO_LED_3”灯珠亮橙色
串口指令“MO_LED_4”灯珠亮红色
串口指令“MO_LED_5”灯珠亮紫色
串口指令“MO_LED_6”灯珠亮黄色
串口指令“MO_LED_7”灯珠亮白色为默认色
3.基于FASTLED库控制位于GPIO5 引脚上的160颗ws2812灯带灯带有5个状态。可被串口指令控制。
串口指令“MO_LEDN_0”灯珠全灭
串口指令“MO_LEDN_1”灯珠全部亮白色
串口指令“MO_LEDN_2”彩虹流水灯效果
串口指令“MO_LEDN_3”彩虹呼吸灯效果 串口指令“MO_LEDN_4”彩虹火车灯效果灯珠从第1颗开始出来往灯带尾部前进火车灯长度为16颗当走到尾部时所有灯珠要全部要进站也就是一颗颗减少直到灯带上没有灯珠亮起再一颗颗倒回来一直走到所有灯珠倒进第一颗灯珠进站。每次从一头出来就变换一种彩虹色。
状态0 全部熄灭状态串口指令“MO_LEDN_0”
状态1 纯白色串口指令“MO_LEDN_1”
状态2 彩虹流水灯串口指令“MO_LEDN_2”
状态3 彩虹呼吸灯串口指令“MO_LEDN_3”
状态4 马卡龙火车灯串口指令“MO_LEDN_4”效果为每次从5种马卡龙色中选择一种以16颗灯珠为一列从灯带头跑到灯带尾变色后又从灯带尾跑到灯带头以此循环。
4.在GPIO6上输出1000hz的pwm控制信号默认信号强度为80%,根据串口的指令,来控制输出信号强度。
串口指令“MO_PWM_0”,输出为0
串口指令“MO_PWM_20”,输出为20%
串口指令“MO_PWM_40”,输出为40%
串口指令“MO_PWM_60”,输出为60%
串口指令“MO_PWM_80”,输出为80%
串口指令“MO_PWM_1”,输出为100%
5.检测GPIO15的电平变化GPIO15接入一个触点按钮按钮另一端接入GND。按钮或引脚按照下述行为进行响应。
GPIO15默认为高电平当按钮按下后出发导通GND低电平向串口发送1次“SO_BT0_HIGH”如果按键持续按下超过2秒则向串口发送一次“SO_BT0_HIGHL”如果按钮松开则向串口发送“SO_BT0_LOW”。
6.检测GPIO16的电平状态默认为低电平如果检测到高电平信号则向串口发送1次“SO_WAKEUP1”,如果恢复为低则向串口发送1次“SO_WAKEUP0”。
7.检测GPIO17的电平状态默认为低电平如果检测到高电平信号则向串口发送1次“SO_BT1_HIGH”,如果恢复为低则向串口发送1次“SO_BT1_LOW”
8.检测GPIO18的电平状态默认为低电平如果检测到高电平信号则向串口发送1次“SO_BT2_HIGH”,如果恢复为低则向串口发送1次“SO_BT2_LOW”9
9.位于gpio48的引脚设置为一颗ws2812灯珠默认关闭状态。

View File

@ -0,0 +1,668 @@
#include <SPI.h>
#include <MFRC522.h>
#include <FastLED.h>
#include <Arduino.h>
#include <driver/ledc.h>
// RFID引脚定义
#define RFID_RST_PIN 14 // RC522 复位引脚
#define RFID_SS_PIN 10 // RC522 片选引脚
#define RFID_MISO_PIN 13 // MISO 引脚
#define RFID_MOSI_PIN 12 // MOSI 引脚
#define RFID_SCK_PIN 11 // SCK 引脚
// LED定义
#define LED_PIN_1 4 // 1颗WS2812灯珠引脚
#define LED_PIN_2 5 // 160颗WS2812灯带引脚
#define LED_PIN_3 48 // 1颗WS2812灯珠引脚新增
#define LED_COUNT_1 1 // 1颗灯珠
#define LED_COUNT_2 186 // 160颗灯带
#define LED_COUNT_3 1 // 1颗灯珠新增
// PWM定义
#define PWM_PIN 6 // PWM输出引脚
#define PWM_CHANNEL 0 // PWM通道
#define PWM_FREQ 1000 // PWM频率(Hz)
#define PWM_RESOLUTION 10 // PWM分辨率(位)
#define DEFAULT_DUTY 819 // 默认占空比(80%)
// 按钮和输入引脚定义
#define BTN0_PIN 15 // 按钮0引脚
#define WAKEUP1_PIN 16 // 唤醒引脚1
#define BTN1_PIN 17 // 按钮1引脚
#define BTN2_PIN 18 // 按钮2引脚
// 任务句柄
TaskHandle_t TaskRFID, TaskLED1, TaskLED2, TaskLED3, TaskPWM, TaskBTN0, TaskWAKEUP1, TaskBTN1, TaskBTN2;
// 全局变量
MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN); // 创建RFID实例
CRGB leds1[LED_COUNT_1]; // 1颗灯珠数组
CRGB leds2[LED_COUNT_2]; // 160颗灯带数组
CRGB leds3[LED_COUNT_3]; // 1颗灯珠数组新增
String lastCardData = ""; // 上次读取的RFID卡数据
int ledMode = 1; // 灯带模式默认为1(白色)
int pwmDuty = DEFAULT_DUTY; // PWM占空比
bool btn0State = HIGH; // 按钮0状态
bool btn0LongPress = false; // 按钮0长按标志
bool wakeup1State = LOW; // 唤醒引脚1状态
bool btn1State = LOW; // 按钮1状态
bool btn2State = LOW; // 按钮2状态
int singleLedMode = 7; // 单颗LED模式默认为7(白色)
// 灯带动画全局变量
static uint8_t rainbowHue = 0;
static int trainPos = 0;
static unsigned long lastUpdate = 0;
static const int TRAIN_LENGTH = 16; // 火车灯长度
static int trainPhase = 0; // 火车阶段0-正向出站1-正向前进2-正向进站3-反向出站4-反向前进5-反向进站
static const int VIRTUAL_LED_COUNT = LED_COUNT_2 + TRAIN_LENGTH; // 虚拟灯带长度
// 单颗LED颜色数组
CRGB singleLedColors[8] = {
CRGB::Black, // 0: 熄灭
CRGB::Blue, // 1: 蓝色
CRGB::Green, // 2: 绿色
CRGB::Orange, // 3: 橙色
CRGB::Red, // 4: 红色
CRGB::Purple, // 5: 紫色
CRGB::Yellow, // 6: 黄色
CRGB::White // 7: 白色
};
// RFID读取任务
void TaskRFIDcode( void * pvParameters ) {
for(;;) {
// 寻找新卡片
if ( ! rfid.PICC_IsNewCardPresent()) {
delay(10);
continue;
}
// 验证NUID是否可读
if ( ! rfid.PICC_ReadCardSerial()) {
delay(10);
continue;
}
// 读取卡片数据(用户数据区)
String cardData = "";
MFRC522::MIFARE_Key key;
// 准备认证密钥
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
// 选择卡片
MFRC522::StatusCode status;
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(rfid.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Authentication failed: "));
Serial.println(rfid.GetStatusCodeName(status));
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
delay(100);
continue;
}
// 读取数据块
byte buffer[18];
byte size = sizeof(buffer);
status = rfid.MIFARE_Read(4, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Reading failed: "));
Serial.println(rfid.GetStatusCodeName(status));
} else {
// 转换为ASCII字符串
for (byte i = 0; i < 16; i++) {
if (buffer[i] >= 32 && buffer[i] <= 126) { // 可打印ASCII字符
cardData += (char)buffer[i];
}
}
// 移除空白字符
cardData.trim();
// 卡片数据处理
if (cardData != lastCardData && !cardData.isEmpty()) {
lastCardData = cardData;
Serial.println("SORC_" + cardData);
}
}
// 使放置在读卡区的IC卡进入休眠状态不再重复读卡
rfid.PICC_HaltA();
// 停止加密PCD
rfid.PCD_StopCrypto1();
delay(100);
}
}
// LED1控制任务
void TaskLED1code( void * pvParameters ) {
for(;;) {
// 根据模式设置LED1颜色
if (singleLedMode >= 0 && singleLedMode <= 7) {
leds1[0] = singleLedColors[singleLedMode];
} else {
leds1[0] = CRGB::Blue; // 默认白色
}
// 更新LED
FastLED.show();
delay(20);
}
}
// LED3控制任务新增
void TaskLED3code( void * pvParameters ) {
for(;;) {
// 强制设置GPIO48的灯珠为熄灭状态
leds3[0] = CRGB::Black;
// 更新LED
FastLED.show();
delay(20);
}
}
// LED2控制任务
void TaskLED2code( void * pvParameters ) {
for(;;) {
// 根据不同模式控制灯带
switch(ledMode) {
case 0: // 全部熄灭
fill_solid(leds2, LED_COUNT_2, CRGB::Black);
break;
case 1: // 纯白色
fill_solid(leds2, LED_COUNT_2, CRGB::White);
break;
case 2: // 彩虹流水灯
for(int i = 0; i < LED_COUNT_2; i++) {
leds2[i] = CHSV(rainbowHue + i * 256 / LED_COUNT_2, 255, 255);
}
rainbowHue++;
break;
case 3: // 彩虹呼吸灯
for(int i = 0; i < LED_COUNT_2; i++) {
leds2[i] = CHSV(rainbowHue, 255, beatsin8(1, 64, 255));
}
rainbowHue++;
break;
case 4: // 彩虹火车灯
if (millis() - lastUpdate > 30) { // 30ms更新一次
lastUpdate = millis();
// 清除所有灯珠
fill_solid(leds2, LED_COUNT_2, CRGB::Black);
switch (trainPhase) {
case 0: // 正向出站(从起点开始出现)
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全出站
if (trainPos >= 0) {
trainPhase = 1; // 开始正向前进
trainPos = 0;
}
break;
case 1: // 正向前进
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否到达终点
if (trainPos >= LED_COUNT_2 - TRAIN_LENGTH) {
trainPhase = 2; // 开始正向进站
trainPos = LED_COUNT_2 - TRAIN_LENGTH;
}
break;
case 2: // 正向进站(从尾部开始消失)
for (int i = 0; i < TRAIN_LENGTH; i++) {
int displayPos = LED_COUNT_2 - 1 - i;
if (displayPos >= trainPos) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[displayPos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全进站
if (trainPos >= LED_COUNT_2) {
trainPhase = 3; // 开始反向出站
trainPos = 0;
rainbowHue += 64; // 改变彩虹颜色
}
break;
case 3: // 反向出站(从终点开始出现)
for (int i = 0; i < trainPos + 1; i++) {
int pos = LED_COUNT_2 - 1 - i;
if (pos >= 0) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全出站
if (trainPos >= TRAIN_LENGTH) {
trainPhase = 4; // 开始反向前进
trainPos = TRAIN_LENGTH;
}
break;
case 4: // 反向前进
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = LED_COUNT_2 - trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否到达起点
if (trainPos >= LED_COUNT_2) {
trainPhase = 5; // 开始反向进站
trainPos = 0;
}
break;
case 5: // 反向进站(从头部开始消失)
for (int i = 0; i < TRAIN_LENGTH - trainPos; i++) {
int pos = i;
if (pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, 255);
}
}
trainPos += 1;
// 检查是否完全进站
if (trainPos >= TRAIN_LENGTH) {
trainPhase = 0; // 重新开始正向出站
trainPos = -TRAIN_LENGTH;
rainbowHue += 64; // 改变彩虹颜色
}
break;
}
}
break;
case 5: // 马卡龙火车灯(保留原功能,未修改)
// 代码保持不变...
break;
}
// 更新LED
FastLED.show();
// 根据模式调整延时
if (ledMode == 4 || ledMode == 5) {
delay(10); // 火车灯模式需要更快的更新速度
} else {
delay(30);
}
}
}
// PWM控制任务
void TaskPWMcode( void * pvParameters ) {
for(;;) {
// 设置PWM占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
delay(100);
}
}
// 按钮0检测任务
void TaskBTN0code( void * pvParameters ) {
static unsigned long pressStartTime = 0;
static bool lastState = HIGH;
for(;;) {
bool currentState = digitalRead(BTN0_PIN);
// 检测下降沿(按下)
if (lastState == HIGH && currentState == LOW) {
pressStartTime = millis();
btn0State = LOW;
Serial.println("SO_BT0_HIGH");
btn0LongPress = false;
}
// 检测上升沿(释放)
else if (lastState == LOW && currentState == HIGH) {
btn0State = HIGH;
Serial.println("SO_BT0_LOW");
btn0LongPress = false;
}
// 检测长按
else if (currentState == LOW && millis() - pressStartTime >= 2000 && !btn0LongPress) {
btn0LongPress = true;
Serial.println("SO_BT0_HIGHL");
}
lastState = currentState;
delay(10);
}
}
// WAKEUP1检测任务
void TaskWAKEUP1code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(WAKEUP1_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
wakeup1State = HIGH;
Serial.println("SO_WAKEUP1");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
wakeup1State = LOW;
Serial.println("SO_WAKEUP0");
}
lastState = currentState;
delay(10);
}
}
// 按钮1检测任务
void TaskBTN1code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(BTN1_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
btn1State = HIGH;
Serial.println("SO_BT1_HIGH");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
btn1State = LOW;
Serial.println("SO_BT1_LOW");
}
lastState = currentState;
delay(10);
}
}
// 按钮2检测任务
void TaskBTN2code( void * pvParameters ) {
static bool lastState = LOW;
for(;;) {
bool currentState = digitalRead(BTN2_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
btn2State = HIGH;
Serial.println("SO_BT2_HIGH");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
btn2State = LOW;
Serial.println("SO_BT2_LOW");
}
lastState = currentState;
delay(10);
}
}
// 串口命令处理
void handleSerialCommand() {
static String command = "";
while (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
// 处理命令
if (command.startsWith("MO_LED_")) {
String modeStr = command.substring(7);
int newMode = modeStr.toInt();
// 控制单颗LED
if (newMode >= 0 && newMode <= 7) {
singleLedMode = newMode;
Serial.print("Single LED set to mode: ");
Serial.println(newMode);
} else {
Serial.println("Invalid single LED mode command");
}
}
else if (command.startsWith("MO_LEDN_")) {
String modeStr = command.substring(8);
int newMode = modeStr.toInt();
// 控制灯带
if (newMode >= 0 && newMode <= 5) {
ledMode = newMode;
// 重置火车灯状态
if (newMode == 4) {
trainPos = -TRAIN_LENGTH;
trainPhase = 0;
rainbowHue = random8();
}
Serial.print("LED strip set to mode: ");
Serial.println(newMode);
} else {
Serial.println("Invalid LED strip mode command");
}
}
else if (command.startsWith("MO_PWM_")) {
String dutyStr = command.substring(7);
int newDuty = dutyStr.toInt();
// 检查PWM百分比
if (newDuty == 1) {
pwmDuty = 1023; // 100%
} else if (newDuty == 0 || newDuty == 20 || newDuty == 40 || newDuty == 60 || newDuty == 80) {
pwmDuty = (newDuty * 1023) / 100; // 转换为实际占空比
} else {
Serial.println("Invalid PWM command");
}
Serial.print("PWM set to: ");
Serial.print((pwmDuty * 100) / 1023);
Serial.println("%");
}
// 清空命令
command = "";
} else {
command += c;
}
}
}
void setup() {
// 初始化串口
Serial.begin(115200);
Serial.println("System starting...");
// 初始化SPI总线
SPI.begin(RFID_SCK_PIN, RFID_MISO_PIN, RFID_MOSI_PIN, RFID_SS_PIN);
// 初始化RFID
rfid.PCD_Init();
Serial.println("RFID initialized.");
// 初始化LED
FastLED.addLeds<WS2812, LED_PIN_1, GRB>(leds1, LED_COUNT_1);
FastLED.addLeds<WS2812, LED_PIN_2, GRB>(leds2, LED_COUNT_2);
FastLED.addLeds<WS2812, LED_PIN_3, GRB>(leds3, LED_COUNT_3); // 新增LED3
// 初始化LED状态
fill_solid(leds1, LED_COUNT_1, singleLedColors[singleLedMode]);
fill_solid(leds2, LED_COUNT_2, CRGB::White);
fill_solid(leds3, LED_COUNT_3, CRGB::Black); // 强制GPIO48的灯珠熄灭
FastLED.show();
Serial.println("LED initialized.");
// 初始化PWM
// 创建LED控制器配置
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = (ledc_timer_bit_t)PWM_RESOLUTION,
.timer_num = (ledc_timer_t)PWM_CHANNEL,
.freq_hz = PWM_FREQ,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
// 创建LED通道配置
ledc_channel_config_t ledc_channel = {
.gpio_num = PWM_PIN,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = (ledc_channel_t)PWM_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = (ledc_timer_t)PWM_CHANNEL,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
// 设置初始占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
Serial.println("PWM initialized.");
// 初始化输入引脚
pinMode(BTN0_PIN, INPUT_PULLUP);
pinMode(WAKEUP1_PIN, INPUT);
pinMode(BTN1_PIN, INPUT);
pinMode(BTN2_PIN, INPUT);
Serial.println("Inputs initialized.");
// 创建任务
xTaskCreatePinnedToCore(
TaskRFIDcode, /* 任务函数 */
"TaskRFID", /* 任务名称 */
4096, /* 任务栈大小 */
NULL, /* 传递给任务的参数 */
1, /* 任务优先级 */
&TaskRFID, /* 任务句柄 */
1); /* 运行在核心1上 */
xTaskCreatePinnedToCore(
TaskLED1code,
"TaskLED1",
2048,
NULL,
1,
&TaskLED1,
1);
xTaskCreatePinnedToCore(
TaskLED2code,
"TaskLED2",
4096,
NULL,
1,
&TaskLED2,
1);
xTaskCreatePinnedToCore(
TaskLED3code,
"TaskLED3",
2048,
NULL,
1,
&TaskLED3,
1); // 新增LED3任务
xTaskCreatePinnedToCore(
TaskPWMcode,
"TaskPWM",
1024,
NULL,
1,
&TaskPWM,
1);
xTaskCreatePinnedToCore(
TaskBTN0code,
"TaskBTN0",
2048,
NULL,
1,
&TaskBTN0,
0);
xTaskCreatePinnedToCore(
TaskWAKEUP1code,
"TaskWAKEUP1",
2048,
NULL,
1,
&TaskWAKEUP1,
0);
xTaskCreatePinnedToCore(
TaskBTN1code,
"TaskBTN1",
2048,
NULL,
1,
&TaskBTN1,
0);
xTaskCreatePinnedToCore(
TaskBTN2code,
"TaskBTN2",
2048,
NULL,
1,
&TaskBTN2,
0);
Serial.println("Tasks created. System ready.");
}
void loop() {
// 处理串口命令
handleSerialCommand();
// 让出CPU时间
delay(1);
}

View File

@ -0,0 +1,784 @@
#include SPI.h
#include MFRC522.h
#include FastLED.h
#include Arduino.h
#include driverledc.h
RFID引脚定义
#define RFID_RST_PIN 14 RC522 复位引脚
#define RFID_SS_PIN 10 RC522 片选引脚
#define RFID_MISO_PIN 13 MISO 引脚
#define RFID_MOSI_PIN 12 MOSI 引脚
#define RFID_SCK_PIN 11 SCK 引脚
LED定义
#define LED_PIN_1 4 1颗WS2812灯珠引脚
#define LED_PIN_2 5 160颗WS2812灯带引脚
#define LED_PIN_3 48 1颗WS2812灯珠引脚新增
#define LED_COUNT_1 1 1颗灯珠
#define LED_COUNT_2 186 160颗灯带
#define LED_COUNT_3 1 1颗灯珠新增
PWM定义
#define PWM_PIN 6 PWM输出引脚
#define PWM_CHANNEL 0 PWM通道
#define PWM_FREQ 1000 PWM频率(Hz)
#define PWM_RESOLUTION 10 PWM分辨率(位)
#define DEFAULT_DUTY 819 默认占空比(80%)
#define BTN0_PIN 15 按钮0引脚
#define WAKEUP1_PIN 16 唤醒引脚1
#define BTN1_PIN 17 按钮1引脚
#define BTN2_PIN 18 按钮2引脚
TaskHandle_t TaskRFID, TaskLED1, TaskLED2, TaskLED3, TaskPWM, TaskBTN0, TaskWAKEUP1, TaskBTN1, TaskBTN2;
MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN); RFID实例
CRGB leds1[LED_COUNT_1]; 1
CRGB leds2[LED_COUNT_2]; 160
CRGB leds3[LED_COUNT_3]; 1
CRGB frozenLeds2[LED_COUNT_2]; 5
uint8_t frozenBrightness = 255;
String lastCardData = ; RFID卡数据
int ledMode = 1; 1()
int pwmDuty = DEFAULT_DUTY; PWM占空比
bool btn0State = HIGH; 0
bool btn0LongPress = false; 0
bool wakeup1State = LOW; 1
bool btn1State = LOW; 1
bool btn2State = LOW; 2
int singleLedMode = 7; LED模式7()
static uint8_t rainbowHue = 0;
static int trainPos = 0;
static unsigned long lastUpdate = 0;
static const int TRAIN_LENGTH = 16;
static int trainPhase = 0; 0-1-2-3-4-5-
static const int VIRTUAL_LED_COUNT = LED_COUNT_2 + TRAIN_LENGTH;
LED亮度线性映射表 (0~100 26~255) - 10%
0-100%PWM值
LED完全不可见的问题
const uint8_t brightnessMapLinear[101] = {
0, 28, 31, 33, 36, 38, 41, 43, 46, 48, 0-9
51, 54, 56, 59, 61, 64, 66, 69, 71, 74, 10-19
77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 20-29
102, 105, 107, 110, 112, 115, 117, 120, 122, 125, 30-39
128, 130, 133, 135, 138, 140, 143, 145, 148, 150, 40-49
153, 156, 158, 161, 163, 166, 168, 171, 173, 176, 50-59
179, 181, 184, 186, 189, 191, 194, 196, 199, 201, 60-69
204, 207, 209, 212, 214, 217, 219, 222, 224, 227, 70-79
230, 232, 235, 237, 240, 242, 245, 247, 250, 252, 80-89
253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 90-99
255 100%
};
const uint8_t brightnessMap = brightnessMapLinear;
LED2亮度控制0-255
LED灯带的整体亮度1245
3使
uint8_t led2Brightness = 102; 40%10225540%
LED颜色数组
CRGB singleLedColors[8] = {
CRGBBlack, 0
CRGBBlue, 1
CRGBGreen, 2 绿
CRGBOrange, 3
CRGBRed, 4
CRGBPurple, 5
CRGBYellow, 6
CRGBWhite 7
};
RFID读取任务
void TaskRFIDcode(void pvParameters) {
for (;;) {
if (!rfid.PICC_IsNewCardPresent()) {
delay(10);
continue;
}
NUID是否可读
if (!rfid.PICC_ReadCardSerial()) {
delay(10);
continue;
}
String cardData = ;
MFRC522MIFARE_Key key;
for (byte i = 0; i 6; i++) key.keyByte[i] = 0xFF;
MFRC522StatusCode status;
status = rfid.PCD_Authenticate(MFRC522PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(rfid.uid));
if (status != MFRC522STATUS_OK) {
Serial.print(F(Authentication failed ));
Serial.println(rfid.GetStatusCodeName(status));
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
delay(100);
continue;
}
byte buffer[18];
byte size = sizeof(buffer);
status = rfid.MIFARE_Read(4, buffer, &size);
if (status != MFRC522STATUS_OK) {
Serial.print(F(Reading failed ));
Serial.println(rfid.GetStatusCodeName(status));
} else {
ASCII字符串
for (byte i = 0; i 16; i++) {
if (buffer[i] = 32 && buffer[i] = 126) { ASCII字符
cardData += (char)buffer[i];
}
}
cardData.trim();
if (cardData != lastCardData && !cardData.isEmpty()) {
lastCardData = cardData;
Serial.println(SORC_ + cardData);
}
}
使IC卡进入休眠状态
rfid.PICC_HaltA();
PCD
rfid.PCD_StopCrypto1();
delay(100);
}
}
TaskLEDUnifiedCode替代
setup()
LED1控制任务TaskLEDUnifiedCode统一处理
void TaskLED1code(void pvParameters) {
使
LED1的控制已集成到TaskLEDUnifiedCode中
vTaskDelete(NULL);
}
LED3控制任务TaskLEDUnifiedCode统一处理
void TaskLED3code(void pvParameters) {
使
LED3的控制已集成到TaskLEDUnifiedCode中
vTaskDelete(NULL);
}
PWM控制任务
void TaskPWMcode(void pvParameters) {
for (;;) {
PWM占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
delay(100);
}
}
0
void TaskBTN0code(void pvParameters) {
static unsigned long pressStartTime = 0;
static bool lastState = HIGH;
for (;;) {
bool currentState = digitalRead(BTN0_PIN);
沿()
if (lastState == HIGH && currentState == LOW) {
pressStartTime = millis();
btn0State = LOW;
Serial.println(SO_BT0_HIGH);
btn0LongPress = false;
}
沿()
else if (lastState == LOW && currentState == HIGH) {
btn0State = HIGH;
Serial.println(SO_BT0_LOW);
btn0LongPress = false;
}
else if (currentState == LOW && millis() - pressStartTime = 2000 && !btn0LongPress) {
btn0LongPress = true;
Serial.println(SO_BT0_HIGHL);
}
lastState = currentState;
delay(10);
}
}
WAKEUP1检测任务
void TaskWAKEUP1code(void pvParameters) {
static bool lastState = LOW;
for (;;) {
bool currentState = digitalRead(WAKEUP1_PIN);
沿
if (lastState == LOW && currentState == HIGH) {
wakeup1State = HIGH;
Serial.println(SO_WAKEUP1);
}
沿
else if (lastState == HIGH && currentState == LOW) {
wakeup1State = LOW;
Serial.println(SO_WAKEUP0);
}
lastState = currentState;
delay(10);
}
}
1
void TaskBTN1code(void pvParameters) {
static bool lastState = LOW;
for (;;) {
bool currentState = digitalRead(BTN1_PIN);
沿
if (lastState == LOW && currentState == HIGH) {
btn1State = HIGH;
Serial.println(SO_BT1_HIGH);
}
沿
else if (lastState == HIGH && currentState == LOW) {
btn1State = LOW;
Serial.println(SO_BT1_LOW);
}
lastState = currentState;
delay(10);
}
}
2
void TaskBTN2code(void pvParameters) {
static bool lastState = LOW;
for (;;) {
bool currentState = digitalRead(BTN2_PIN);
沿
if (lastState == LOW && currentState == HIGH) {
btn2State = HIGH;
Serial.println(SO_BT2_HIGH);
}
沿
else if (lastState == HIGH && currentState == LOW) {
btn2State = LOW;
Serial.println(SO_BT2_LOW);
}
lastState = currentState;
delay(10);
}
}
void handleSerialCommand() {
static String command = ;
while (Serial.available()) {
if (command.length() 64) {
Serial.println( 64);
command = ;
while (Serial.available()) Serial.read();
continue;
}
char c = Serial.read();
if (c == 'n') {
if (command.startsWith(MO_LED_)) {
String modeStr = command.substring(7);
int newMode = modeStr.toInt();
LED
if (newMode = 0 && newMode = 7) {
singleLedMode = newMode;
Serial.print(Single LED set to mode );
Serial.println(newMode);
} else {
Serial.println(Invalid single LED mode command);
}
} else if (command.startsWith(MO_LEDN_)) {
String modeStr = command.substring(8);
int newMode = modeStr.toInt();
0
if (newMode = 0 && newMode = 5) {
if (led2Brightness == 0) {
Serial.println(00);
} else {
ledMode = newMode;
if (newMode == 4) {
trainPos = -TRAIN_LENGTH;
trainPhase = 0;
rainbowHue = random8();
}
5LED2状态和亮度
if (newMode == 5) {
memcpy(frozenLeds2, leds2, sizeof(leds2));
frozenBrightness = led2Brightness;
}
Serial.print(LED strip set to mode );
Serial.println(newMode);
}
} else {
Serial.println(Invalid LED strip mode command);
}
} else if (command.startsWith(MO_PWM_)) {
String dutyStr = command.substring(7);
int newDuty = dutyStr.toInt();
PWM百分比
if (newDuty == 1) {
pwmDuty = 1023; 100%
} else if (newDuty == 0 newDuty == 20 newDuty == 40 newDuty == 60 newDuty == 80) {
pwmDuty = (newDuty 1023) 100;
} else {
Serial.println(Invalid PWM command);
}
Serial.print(PWM set to );
Serial.print((pwmDuty 100) 1023);
Serial.println(%);
}
else if (command.startsWith(MO_BRI_)) {
MO_BRI_前缀
String levelStr = command.substring(7);
levelStr.trim();
command = ;
if (levelStr.length() == 0) {
Serial.println( );
return;
}
bool isNumeric = true;
for (char c levelStr) {
if (!isdigit(c)) {
isNumeric = false;
break; 退
}
}
if (!isNumeric) {
Serial.println( );
return;
}
int level = levelStr.toInt();
if (level = 0 && level = 100) {
PWM范围
led2Brightness = brightnessMap[level]; 使
Serial.print(LED亮度 );
Serial.print(level);
Serial.println(%);
0
if (level == 0) {
Serial.println(0);
}
} else {
Serial.println( 0-100);
}
command = ;
}
command = ;
} else {
command += c;
}
}
}
LED控制任务
LED1LED2LED3
1. 30FPS稳定更新频率
2. 5
3.
4.
5. LED显示稳定
void TaskLEDUnifiedCode(void pvParameters) {
static unsigned long lastLEDUpdate = 0;
const unsigned long LED_UPDATE_INTERVAL = 33; ~30FPS
for (;;) {
unsigned long currentTime = millis();
CPU和闪烁问题
if (currentTime - lastLEDUpdate LED_UPDATE_INTERVAL) {
delay(5);
continue;
}
lastLEDUpdate = currentTime;
---- LED1 LED----
if (singleLedMode = 0 && singleLedMode = 7) {
leds1[0] = singleLedColors[singleLedMode];
} else {
leds1[0] = CRGBBlue;
}
---- LED3 ----
leds3[0] = CRGBBlack;
---- LED2 ----
switch (ledMode) {
case 0 0LED灯珠
fill_solid(leds2, LED_COUNT_2, CRGBBlack);
break;
case 1 1led2Brightness调节
fill_solid(leds2, LED_COUNT_2, CHSV(0, 0, led2Brightness));
break;
case 2 2沿
for (int i = 0; i LED_COUNT_2; i++) {
leds2[i] = CHSV(rainbowHue + i 256 LED_COUNT_2, 255, led2Brightness);
}
rainbowHue++;
break;
case 3 3
{
static unsigned long lastHueUpdate = 0;
static unsigned long lastBreathUpdate = 0;
static uint8_t breathingHue = 0;
static uint8_t breathPhase = 0;
unsigned long currentTime = millis();
300ms更新一次色相
if (currentTime - lastHueUpdate 300) {
breathingHue += 1;
lastHueUpdate = currentTime;
}
30ms更新一次呼吸相位
if (currentTime - lastBreathUpdate 30) {
breathPhase += 2;
lastBreathUpdate = currentTime;
}
led2Brightness的60%-100%
uint8_t minBrightness = led2Brightness 60 100;
uint8_t maxBrightness = led2Brightness;
uint8_t breathValue = map(sin8(breathPhase), 0, 255, minBrightness, maxBrightness);
for(int i = 0; i LED_COUNT_2; i++) {
leds2[i] = CHSV(breathingHue, 200, breathValue);
}
}
break;
case 4 4
if (millis() - lastUpdate 30) { 30ms更新间隔
lastUpdate = millis();
fill_solid(leds2, LED_COUNT_2, CRGBBlack);
switch (trainPhase) {
case 0 0
for (int i = 0; i TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos = 0 && pos LED_COUNT_2) {
uint8_t hue = rainbowHue + (i 256 TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos = 0) {
trainPhase = 1;
trainPos = 0;
}
break;
case 1 1
for (int i = 0; i TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos = 0 && pos LED_COUNT_2) {
uint8_t hue = rainbowHue + (i 256 TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos = LED_COUNT_2 - TRAIN_LENGTH) {
trainPhase = 2;
trainPos = LED_COUNT_2 - TRAIN_LENGTH;
}
break;
case 2 2
for (int i = 0; i TRAIN_LENGTH; i++) {
int displayPos = LED_COUNT_2 - 1 - i;
if (displayPos = trainPos) {
uint8_t hue = rainbowHue + (i 256 TRAIN_LENGTH);
leds2[displayPos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos = LED_COUNT_2) {
trainPhase = 3;
trainPos = 0;
rainbowHue += 64;
}
break;
case 3 3
for (int i = 0; i trainPos + 1; i++) {
int pos = LED_COUNT_2 - 1 - i;
if (pos = 0) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) 256 TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos = TRAIN_LENGTH) {
trainPhase = 4;
trainPos = TRAIN_LENGTH;
}
break;
case 4 4
for (int i = 0; i TRAIN_LENGTH; i++) {
int pos = LED_COUNT_2 - trainPos + i;
if (pos = 0 && pos LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) 256 TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos = LED_COUNT_2) {
trainPhase = 5;
trainPos = 0;
}
break;
case 5 5
for (int i = 0; i TRAIN_LENGTH - trainPos; i++) {
int pos = i;
if (pos LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) 256 TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos = TRAIN_LENGTH) {
trainPhase = 0;
trainPos = -TRAIN_LENGTH;
rainbowHue += 64;
}
break;
}
}
break;
case 5 5
if (led2Brightness == 0) {
fill_solid(leds2, LED_COUNT_2, CRGBBlack); 0
} else {
uint16_t brightnessRatio = (uint16_t)led2Brightness 255 frozenBrightness;
if (brightnessRatio 255) brightnessRatio = 255;
使memcpy
for (int i = 0; i LED_COUNT_2; i++) {
leds2[i].r = (frozenLeds2[i].r brightnessRatio) 8;
leds2[i].g = (frozenLeds2[i].g brightnessRatio) 8;
leds2[i].b = (frozenLeds2[i].b brightnessRatio) 8;
}
}
break;
}
---- LED ----
FastLED刷新保护
FastLED.show();
---- ----
使LED显示稳定
delay(10); 10ms延时LED数据传输完成
}
}
void setup() {
Serial.begin(115200);
Serial.println(System starting...);
SPI总线
SPI.begin(RFID_SCK_PIN, RFID_MISO_PIN, RFID_MOSI_PIN, RFID_SS_PIN);
RFID
rfid.PCD_Init();
Serial.println(RFID initialized.);
LED
FastLED.addLedsWS2812, LED_PIN_1, GRB(leds1, LED_COUNT_1);
FastLED.addLedsWS2812, LED_PIN_2, GRB(leds2, LED_COUNT_2);
FastLED.addLedsWS2812, LED_PIN_3, GRB(leds3, LED_COUNT_3); LED3
LED状态
fill_solid(leds1, LED_COUNT_1, singleLedColors[singleLedMode]);
fill_solid(leds2, LED_COUNT_2, CHSV(0, 0, led2Brightness));
fill_solid(leds3, LED_COUNT_3, CRGBBlack); GPIO48的灯珠熄灭
FastLED.show();
Serial.println(LED initialized.);
PWM
LED控制器配置
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = (ledc_timer_bit_t)PWM_RESOLUTION,
.timer_num = (ledc_timer_t)PWM_CHANNEL,
.freq_hz = PWM_FREQ,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
LED通道配置
ledc_channel_config_t ledc_channel = {
.gpio_num = PWM_PIN,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = (ledc_channel_t)PWM_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = (ledc_timer_t)PWM_CHANNEL,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
Serial.println(PWM initialized.);
pinMode(BTN0_PIN, INPUT_PULLUP);
pinMode(WAKEUP1_PIN, INPUT);
pinMode(BTN1_PIN, INPUT);
pinMode(BTN2_PIN, INPUT);
Serial.println(Inputs initialized.);
xTaskCreatePinnedToCore(
TaskRFIDcode,
TaskRFID,
4096,
NULL,
1,
&TaskRFID,
1); 1
xTaskCreatePinnedToCore(
TaskLEDUnifiedCode,
TaskLEDUnified,
8192,
NULL,
3, LED更新不被其他任务干扰
NULL,
1);
xTaskCreatePinnedToCore(
TaskPWMcode,
TaskPWM,
1024,
NULL,
1,
&TaskPWM,
1);
xTaskCreatePinnedToCore(
TaskBTN0code,
TaskBTN0,
2048,
NULL,
1,
&TaskBTN0,
0);
xTaskCreatePinnedToCore(
TaskWAKEUP1code,
TaskWAKEUP1,
2048,
NULL,
1,
&TaskWAKEUP1,
0);
xTaskCreatePinnedToCore(
TaskBTN1code,
TaskBTN1,
2048,
NULL,
1,
&TaskBTN1,
0);
xTaskCreatePinnedToCore(
TaskBTN2code,
TaskBTN2,
2048,
NULL,
1,
&TaskBTN2,
0);
Serial.println(Tasks created. System ready.);
}
void loop() {
handleSerialCommand();
CPU时间
delay(1);
}

784
HOLOMAIN.ino Normal file
View File

@ -0,0 +1,784 @@
#include <SPI.h>
#include <MFRC522.h>
#include <FastLED.h>
#include <Arduino.h>
#include <driver/ledc.h>
// RFID引脚定义
#define RFID_RST_PIN 14 // RC522 复位引脚
#define RFID_SS_PIN 10 // RC522 片选引脚
#define RFID_MISO_PIN 13 // MISO 引脚
#define RFID_MOSI_PIN 12 // MOSI 引脚
#define RFID_SCK_PIN 11 // SCK 引脚
// LED定义
#define LED_PIN_1 4 // 1颗WS2812灯珠引脚
#define LED_PIN_2 5 // 160颗WS2812灯带引脚
#define LED_PIN_3 48 // 1颗WS2812灯珠引脚新增
#define LED_COUNT_1 1 // 1颗灯珠
#define LED_COUNT_2 186 // 160颗灯带
#define LED_COUNT_3 1 // 1颗灯珠新增
// PWM定义
#define PWM_PIN 6 // PWM输出引脚
#define PWM_CHANNEL 0 // PWM通道
#define PWM_FREQ 1000 // PWM频率(Hz)
#define PWM_RESOLUTION 10 // PWM分辨率(位)
#define DEFAULT_DUTY 819 // 默认占空比(80%)
// 按钮和输入引脚定义
#define BTN0_PIN 15 // 按钮0引脚
#define WAKEUP1_PIN 16 // 唤醒引脚1
#define BTN1_PIN 17 // 按钮1引脚
#define BTN2_PIN 18 // 按钮2引脚
// 任务句柄
TaskHandle_t TaskRFID, TaskLED1, TaskLED2, TaskLED3, TaskPWM, TaskBTN0, TaskWAKEUP1, TaskBTN1, TaskBTN2;
// 全局变量
MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN); // 创建RFID实例
CRGB leds1[LED_COUNT_1]; // 1颗灯珠数组
CRGB leds2[LED_COUNT_2]; // 160颗灯带数组
CRGB leds3[LED_COUNT_3]; // 1颗灯珠数组新增
CRGB frozenLeds2[LED_COUNT_2]; // 保存冻结时的颜色数据模式5专用
uint8_t frozenBrightness = 255; // 保存冻结时的亮度值,用于计算相对亮度比例
String lastCardData = ""; // 上次读取的RFID卡数据
int ledMode = 1; // 灯带模式默认为1(白色)
int pwmDuty = DEFAULT_DUTY; // PWM占空比
bool btn0State = HIGH; // 按钮0状态
bool btn0LongPress = false; // 按钮0长按标志
bool wakeup1State = LOW; // 唤醒引脚1状态
bool btn1State = LOW; // 按钮1状态
bool btn2State = LOW; // 按钮2状态
int singleLedMode = 7; // 单颗LED模式默认为7(白色)
// 灯带动画全局变量
static uint8_t rainbowHue = 0;
static int trainPos = 0;
static unsigned long lastUpdate = 0;
static const int TRAIN_LENGTH = 16; // 火车灯长度
static int trainPhase = 0; // 火车阶段0-正向出站1-正向前进2-正向进站3-反向出站4-反向前进5-反向进站
static const int VIRTUAL_LED_COUNT = LED_COUNT_2 + TRAIN_LENGTH; // 虚拟灯带长度
// LED亮度线性映射表 (0~100 → 26~255) - 最小阈值10%
// 用于将用户输入的0-100%亮度值映射到实际的PWM值
// 避免过低亮度导致LED完全不可见的问题
const uint8_t brightnessMapLinear[101] = {
0, 28, 31, 33, 36, 38, 41, 43, 46, 48, // 0-9
51, 54, 56, 59, 61, 64, 66, 69, 71, 74, // 10-19
77, 79, 82, 84, 87, 89, 92, 94, 97, 99, // 20-29
102, 105, 107, 110, 112, 115, 117, 120, 122, 125, // 30-39
128, 130, 133, 135, 138, 140, 143, 145, 148, 150, // 40-49
153, 156, 158, 161, 163, 166, 168, 171, 173, 176, // 50-59
179, 181, 184, 186, 189, 191, 194, 196, 199, 201, // 60-69
204, 207, 209, 212, 214, 217, 219, 222, 224, 227, // 70-79
230, 232, 235, 237, 240, 242, 245, 247, 250, 252, // 80-89
253, 254, 254, 254, 255, 255, 255, 255, 255, 255, // 90-99
255 // 100%
};
// 全局选择映射表
const uint8_t* brightnessMap = brightnessMapLinear;
// LED2亮度控制0-255
// 用于控制LED灯带的整体亮度影响模式1、2、4和5
// 模式3使用独立的呼吸算法基于此值计算动态亮度范围
uint8_t led2Brightness = 102; // 默认40%左右102/255≈40%
// 单颗LED颜色数组
CRGB singleLedColors[8] = {
CRGB::Black, // 0: 熄灭
CRGB::Blue, // 1: 蓝色
CRGB::Green, // 2: 绿色
CRGB::Orange, // 3: 橙色
CRGB::Red, // 4: 红色
CRGB::Purple, // 5: 紫色
CRGB::Yellow, // 6: 黄色
CRGB::White // 7: 白色
};
// RFID读取任务
void TaskRFIDcode(void* pvParameters) {
for (;;) {
// 寻找新卡片
if (!rfid.PICC_IsNewCardPresent()) {
delay(10);
continue;
}
// 验证NUID是否可读
if (!rfid.PICC_ReadCardSerial()) {
delay(10);
continue;
}
// 读取卡片数据(用户数据区)
String cardData = "";
MFRC522::MIFARE_Key key;
// 准备认证密钥
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
// 选择卡片
MFRC522::StatusCode status;
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(rfid.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Authentication failed: "));
Serial.println(rfid.GetStatusCodeName(status));
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
delay(100);
continue;
}
// 读取数据块
byte buffer[18];
byte size = sizeof(buffer);
status = rfid.MIFARE_Read(4, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Reading failed: "));
Serial.println(rfid.GetStatusCodeName(status));
} else {
// 转换为ASCII字符串
for (byte i = 0; i < 16; i++) {
if (buffer[i] >= 32 && buffer[i] <= 126) { // 可打印ASCII字符
cardData += (char)buffer[i];
}
}
// 移除空白字符
cardData.trim();
// 卡片数据处理
if (cardData != lastCardData && !cardData.isEmpty()) {
lastCardData = cardData;
Serial.println("SORC_" + cardData);
}
}
// 使放置在读卡区的IC卡进入休眠状态不再重复读卡
rfid.PICC_HaltA();
// 停止加密PCD
rfid.PCD_StopCrypto1();
delay(100);
}
}
// 注意以下两个函数已被TaskLEDUnifiedCode替代保留仅供参考
// 实际运行中不会被调用因为setup()中没有创建对应的任务
// LED1控制任务已废弃由TaskLEDUnifiedCode统一处理
void TaskLED1code(void* pvParameters) {
// 此函数已被废弃,不再使用
// LED1的控制已集成到TaskLEDUnifiedCode中
vTaskDelete(NULL); // 如果意外创建了此任务,立即删除
}
// LED3控制任务已废弃由TaskLEDUnifiedCode统一处理
void TaskLED3code(void* pvParameters) {
// 此函数已被废弃,不再使用
// LED3的控制已集成到TaskLEDUnifiedCode中
vTaskDelete(NULL); // 如果意外创建了此任务,立即删除
}
// PWM控制任务
void TaskPWMcode(void* pvParameters) {
for (;;) {
// 设置PWM占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
delay(100);
}
}
// 按钮0检测任务
void TaskBTN0code(void* pvParameters) {
static unsigned long pressStartTime = 0;
static bool lastState = HIGH;
for (;;) {
bool currentState = digitalRead(BTN0_PIN);
// 检测下降沿(按下)
if (lastState == HIGH && currentState == LOW) {
pressStartTime = millis();
btn0State = LOW;
Serial.println("SO_BT0_HIGH");
btn0LongPress = false;
}
// 检测上升沿(释放)
else if (lastState == LOW && currentState == HIGH) {
btn0State = HIGH;
Serial.println("SO_BT0_LOW");
btn0LongPress = false;
}
// 检测长按
else if (currentState == LOW && millis() - pressStartTime >= 2000 && !btn0LongPress) {
btn0LongPress = true;
Serial.println("SO_BT0_HIGHL");
}
lastState = currentState;
delay(10);
}
}
// WAKEUP1检测任务
void TaskWAKEUP1code(void* pvParameters) {
static bool lastState = LOW;
for (;;) {
bool currentState = digitalRead(WAKEUP1_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
wakeup1State = HIGH;
Serial.println("SO_WAKEUP1");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
wakeup1State = LOW;
Serial.println("SO_WAKEUP0");
}
lastState = currentState;
delay(10);
}
}
// 按钮1检测任务
void TaskBTN1code(void* pvParameters) {
static bool lastState = LOW;
for (;;) {
bool currentState = digitalRead(BTN1_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
btn1State = HIGH;
Serial.println("SO_BT1_HIGH");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
btn1State = LOW;
Serial.println("SO_BT1_LOW");
}
lastState = currentState;
delay(10);
}
}
// 按钮2检测任务
void TaskBTN2code(void* pvParameters) {
static bool lastState = LOW;
for (;;) {
bool currentState = digitalRead(BTN2_PIN);
// 检测上升沿
if (lastState == LOW && currentState == HIGH) {
btn2State = HIGH;
Serial.println("SO_BT2_HIGH");
}
// 检测下降沿
else if (lastState == HIGH && currentState == LOW) {
btn2State = LOW;
Serial.println("SO_BT2_LOW");
}
lastState = currentState;
delay(10);
}
}
// 串口命令处理
void handleSerialCommand() {
static String command = "";
while (Serial.available()) {
// 先检查命令长度(新增的防护代码)
if (command.length() > 64) {
Serial.println("错误: 命令过长最大64字符");
command = ""; // 清空当前命令
while (Serial.available()) Serial.read(); // 清空串口缓冲区
continue;
}
char c = Serial.read();
if (c == '\n') {
// 处理命令
if (command.startsWith("MO_LED_")) {
String modeStr = command.substring(7);
int newMode = modeStr.toInt();
// 控制单颗LED
if (newMode >= 0 && newMode <= 7) {
singleLedMode = newMode;
Serial.print("Single LED set to mode: ");
Serial.println(newMode);
} else {
Serial.println("Invalid single LED mode command");
}
} else if (command.startsWith("MO_LEDN_")) {
String modeStr = command.substring(8);
int newMode = modeStr.toInt();
// 控制灯带只有亮度不为0时才允许
if (newMode >= 0 && newMode <= 5) {
if (led2Brightness == 0) {
Serial.println("当前亮度为0请先将亮度调整至0以上再切换显示模式");
} else {
ledMode = newMode;
// 重置火车灯状态
if (newMode == 4) {
trainPos = -TRAIN_LENGTH;
trainPhase = 0;
rainbowHue = random8();
}
// 新增切换到模式5时复制当前LED2状态和亮度
if (newMode == 5) {
memcpy(frozenLeds2, leds2, sizeof(leds2));
frozenBrightness = led2Brightness; // 保存冻结时的亮度
}
Serial.print("LED strip set to mode: ");
Serial.println(newMode);
}
} else {
Serial.println("Invalid LED strip mode command");
}
} else if (command.startsWith("MO_PWM_")) {
String dutyStr = command.substring(7);
int newDuty = dutyStr.toInt();
// 检查PWM百分比
if (newDuty == 1) {
pwmDuty = 1023; // 100%
} else if (newDuty == 0 || newDuty == 20 || newDuty == 40 || newDuty == 60 || newDuty == 80) {
pwmDuty = (newDuty * 1023) / 100; // 转换为实际占空比
} else {
Serial.println("Invalid PWM command");
}
Serial.print("PWM set to: ");
Serial.print((pwmDuty * 100) / 1023);
Serial.println("%");
}
else if (command.startsWith("MO_BRI_")) {
// 提取亮度参数(跳过"MO_BRI_"前缀)
String levelStr = command.substring(7);
levelStr.trim();
command = ""; // 清空命令缓冲区
// 空参数检查
if (levelStr.length() == 0) {
Serial.println("错误: 缺少亮度值");
return; // 终止处理
}
// 严格数字验证(拒绝非数字字符)
bool isNumeric = true;
for (char c : levelStr) {
if (!isdigit(c)) {
isNumeric = false;
break; // 发现非数字立即退出
}
}
// 非数字错误处理
if (!isNumeric) {
Serial.println("错误: 亮度值必须为整数");
return;
}
// 转换为整数并验证范围
int level = levelStr.toInt();
if (level >= 0 && level <= 100) {
// 更新亮度值映射到PWM范围
led2Brightness = brightnessMap[level]; // 使用预定义映射表
Serial.print("LED亮度: ");
Serial.print(level);
Serial.println("%");
// // 亮度为0时输出警告
// if (level == 0) {
// Serial.println("亮度已设置为0所有灯光将熄灭");
// }
} else {
Serial.println("错误: 亮度值需在0-100之间");
}
command = ""; // 清空命令
}
command = ""; // 清空命令
} else {
// 累积非换行符字符
command += c;
}
}
}
// 统一LED控制任务防闪烁优化版本
// 集中管理LED1单颗、LED2灯带、LED3强制关闭的显示逻辑
// 优化特性:
// 1. 30FPS稳定更新频率防止闪烁
// 2. 修复模式5的双重亮度衰减问题
// 3. 统一亮度处理机制
// 4. 内存优化,减少不必要的数据拷贝
// 5. 防闪烁机制确保LED显示稳定
void TaskLEDUnifiedCode(void* pvParameters) {
static unsigned long lastLEDUpdate = 0;
const unsigned long LED_UPDATE_INTERVAL = 33; // ~30FPS降低更新频率减少闪烁
for (;;) {
unsigned long currentTime = millis();
// 控制更新频率避免过度占用CPU和闪烁问题
if (currentTime - lastLEDUpdate < LED_UPDATE_INTERVAL) {
delay(5); // 增加延时,确保任务调度稳定
continue;
}
lastLEDUpdate = currentTime;
// ---- LED1 控制(单颗 LED----
if (singleLedMode >= 0 && singleLedMode <= 7) {
leds1[0] = singleLedColors[singleLedMode];
} else {
leds1[0] = CRGB::Blue;
}
// ---- LED3 控制(熄灭)----
leds3[0] = CRGB::Black;
// ---- LED2 控制(灯带)----
switch (ledMode) {
case 0: // 模式0全部熄灭关闭所有LED灯珠
fill_solid(leds2, LED_COUNT_2, CRGB::Black);
break;
case 1: // 模式1纯白色静态光亮度可通过led2Brightness调节
fill_solid(leds2, LED_COUNT_2, CHSV(0, 0, led2Brightness));
break;
case 2: // 模式2彩虹流水灯颜色沿灯带流动速度和亮度可调
for (int i = 0; i < LED_COUNT_2; i++) {
leds2[i] = CHSV(rainbowHue + i * 256 / LED_COUNT_2, 255, led2Brightness);
}
rainbowHue++;
break;
case 3: // 模式3彩虹呼吸灯优化版本缓慢变色配合呼吸效果
{
static unsigned long lastHueUpdate = 0;
static unsigned long lastBreathUpdate = 0;
static uint8_t breathingHue = 0;
static uint8_t breathPhase = 0;
unsigned long currentTime = millis();
// 每300ms更新一次色相实现非常缓慢的颜色变化
if (currentTime - lastHueUpdate > 300) {
breathingHue += 1;
lastHueUpdate = currentTime;
}
// 每30ms更新一次呼吸相位控制亮度变化节奏
if (currentTime - lastBreathUpdate > 30) {
breathPhase += 2;
lastBreathUpdate = currentTime;
}
// 计算呼吸亮度基于led2Brightness的60%-100%范围,避免过暗
uint8_t minBrightness = led2Brightness * 60 / 100;
uint8_t maxBrightness = led2Brightness;
uint8_t breathValue = map(sin8(breathPhase), 0, 255, minBrightness, maxBrightness);
for(int i = 0; i < LED_COUNT_2; i++) {
leds2[i] = CHSV(breathingHue, 200, breathValue);
}
}
break;
case 4: // 模式4彩虹火车灯模拟火车往返运行的动态效果
if (millis() - lastUpdate > 30) { // 30ms更新间隔控制火车移动速度
lastUpdate = millis();
fill_solid(leds2, LED_COUNT_2, CRGB::Black);
switch (trainPhase) {
case 0: // 阶段0正向出站火车从起点逐渐显现
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos >= 0) {
trainPhase = 1; // 切换到正向前进阶段
trainPos = 0;
}
break;
case 1: // 阶段1正向前进火车完整显示并向终点移动
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos >= LED_COUNT_2 - TRAIN_LENGTH) {
trainPhase = 2; // 切换到正向进站阶段
trainPos = LED_COUNT_2 - TRAIN_LENGTH;
}
break;
case 2: // 阶段2正向进站火车从尾部开始消失
for (int i = 0; i < TRAIN_LENGTH; i++) {
int displayPos = LED_COUNT_2 - 1 - i;
if (displayPos >= trainPos) {
uint8_t hue = rainbowHue + (i * 256 / TRAIN_LENGTH);
leds2[displayPos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos >= LED_COUNT_2) {
trainPhase = 3; // 切换到反向出站阶段
trainPos = 0;
rainbowHue += 64; // 改变彩虹颜色,增加视觉变化
}
break;
case 3: // 阶段3反向出站火车从终点逐渐显现
for (int i = 0; i < trainPos + 1; i++) {
int pos = LED_COUNT_2 - 1 - i;
if (pos >= 0) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos >= TRAIN_LENGTH) {
trainPhase = 4; // 切换到反向前进阶段
trainPos = TRAIN_LENGTH;
}
break;
case 4: // 阶段4反向前进火车完整显示并向起点移动
for (int i = 0; i < TRAIN_LENGTH; i++) {
int pos = LED_COUNT_2 - trainPos + i;
if (pos >= 0 && pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos >= LED_COUNT_2) {
trainPhase = 5; // 切换到反向进站阶段
trainPos = 0;
}
break;
case 5: // 阶段5反向进站火车从头部开始消失
for (int i = 0; i < TRAIN_LENGTH - trainPos; i++) {
int pos = i;
if (pos < LED_COUNT_2) {
uint8_t hue = rainbowHue + ((TRAIN_LENGTH - 1 - i) * 256 / TRAIN_LENGTH);
leds2[pos] = CHSV(hue, 255, led2Brightness);
}
}
trainPos++;
if (trainPos >= TRAIN_LENGTH) {
trainPhase = 0; // 重新开始正向出站,形成循环
trainPos = -TRAIN_LENGTH;
rainbowHue += 64; // 再次改变彩虹颜色
}
break;
}
}
break;
case 5: // 模式5冻结当前灯效保持切换时的图像但允许调节亮度内存优化版本
if (led2Brightness == 0) {
fill_solid(leds2, LED_COUNT_2, CRGB::Black); // 亮度为0时完全熄灭
} else {
// 计算相对亮度比例,避免双重衰减问题
uint16_t brightnessRatio = (uint16_t)led2Brightness * 255 / frozenBrightness;
if (brightnessRatio > 255) brightnessRatio = 255;
// 直接计算并设置像素颜色内存优化避免使用memcpy
for (int i = 0; i < LED_COUNT_2; i++) {
leds2[i].r = (frozenLeds2[i].r * brightnessRatio) >> 8;
leds2[i].g = (frozenLeds2[i].g * brightnessRatio) >> 8;
leds2[i].b = (frozenLeds2[i].b * brightnessRatio) >> 8;
}
}
break;
}
// ---- 最终统一刷新LED ----
// 添加FastLED刷新保护确保数据稳定后再显示
FastLED.show();
// ---- 稳定的延时机制 ----
// 使用固定延时确保LED显示稳定避免闪烁
delay(10); // 10ms延时确保LED数据传输完成
}
}
void setup() {
// 初始化串口
Serial.begin(115200);
Serial.println("System starting...");
// 初始化SPI总线
SPI.begin(RFID_SCK_PIN, RFID_MISO_PIN, RFID_MOSI_PIN, RFID_SS_PIN);
// 初始化RFID
rfid.PCD_Init();
Serial.println("RFID initialized.");
// 初始化LED
FastLED.addLeds<WS2812, LED_PIN_1, GRB>(leds1, LED_COUNT_1);
FastLED.addLeds<WS2812, LED_PIN_2, GRB>(leds2, LED_COUNT_2);
FastLED.addLeds<WS2812, LED_PIN_3, GRB>(leds3, LED_COUNT_3); // 新增LED3
// 初始化LED状态
fill_solid(leds1, LED_COUNT_1, singleLedColors[singleLedMode]);
fill_solid(leds2, LED_COUNT_2, CHSV(0, 0, led2Brightness)); // 初始化白色
fill_solid(leds3, LED_COUNT_3, CRGB::Black); // 强制GPIO48的灯珠熄灭
FastLED.show();
Serial.println("LED initialized.");
// 初始化PWM
// 创建LED控制器配置
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = (ledc_timer_bit_t)PWM_RESOLUTION,
.timer_num = (ledc_timer_t)PWM_CHANNEL,
.freq_hz = PWM_FREQ,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
// 创建LED通道配置
ledc_channel_config_t ledc_channel = {
.gpio_num = PWM_PIN,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = (ledc_channel_t)PWM_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = (ledc_timer_t)PWM_CHANNEL,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
// 设置初始占空比
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL, pwmDuty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)PWM_CHANNEL);
Serial.println("PWM initialized.");
// 初始化输入引脚
pinMode(BTN0_PIN, INPUT_PULLUP);
pinMode(WAKEUP1_PIN, INPUT);
pinMode(BTN1_PIN, INPUT);
pinMode(BTN2_PIN, INPUT);
Serial.println("Inputs initialized.");
// 创建任务
xTaskCreatePinnedToCore(
TaskRFIDcode, /* 任务函数 */
"TaskRFID", /* 任务名称 */
4096, /* 任务栈大小 */
NULL, /* 传递给任务的参数 */
1, /* 任务优先级 */
&TaskRFID, /* 任务句柄 */
1); /* 运行在核心1上 */
xTaskCreatePinnedToCore(
TaskLEDUnifiedCode,
"TaskLEDUnified",
8192, // 建议栈大一点
NULL,
3, // 提高优先级确保LED更新不被其他任务干扰
NULL,
1);
xTaskCreatePinnedToCore(
TaskPWMcode,
"TaskPWM",
1024,
NULL,
1,
&TaskPWM,
1);
xTaskCreatePinnedToCore(
TaskBTN0code,
"TaskBTN0",
2048,
NULL,
1,
&TaskBTN0,
0);
xTaskCreatePinnedToCore(
TaskWAKEUP1code,
"TaskWAKEUP1",
2048,
NULL,
1,
&TaskWAKEUP1,
0);
xTaskCreatePinnedToCore(
TaskBTN1code,
"TaskBTN1",
2048,
NULL,
1,
&TaskBTN1,
0);
xTaskCreatePinnedToCore(
TaskBTN2code,
"TaskBTN2",
2048,
NULL,
1,
&TaskBTN2,
0);
Serial.println("Tasks created. System ready.");
}
void loop() {
// 处理串口命令
handleSerialCommand();
// 让出CPU时间
delay(1);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
洛天依串口指令.xlsx Normal file

Binary file not shown.

1
环境配置指南.txt Normal file
View File

@ -0,0 +1 @@
Arduino环境搭建指南https://cloud.tencent.com/developer/article/2395361

BIN
项目配置.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB