1、洛天依项目ESP32部分业务-项目初始化
This commit is contained in:
commit
8693ee1d29
696
Code_Backup/01_原版代码备份/HOLOMAIN - 副本.ino
Normal file
696
Code_Backup/01_原版代码备份/HOLOMAIN - 副本.ino
Normal 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);
|
||||||
|
}
|
||||||
668
Code_Backup/01_原版代码备份/HOLOMAIN.ino
Normal file
668
Code_Backup/01_原版代码备份/HOLOMAIN.ino
Normal 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);
|
||||||
|
}
|
||||||
55
Code_Backup/01_原版代码备份/多任务需求描述_应用版.txt
Normal file
55
Code_Backup/01_原版代码备份/多任务需求描述_应用版.txt
Normal 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灯珠,默认关闭状态。
|
||||||
668
Code_Backup/01_原版代码备份/源代码.txt
Normal file
668
Code_Backup/01_原版代码备份/源代码.txt
Normal 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);
|
||||||
|
}
|
||||||
784
Code_Backup/02_当前最新烧录版本_V6/源码.ino
Normal file
784
Code_Backup/02_当前最新烧录版本_V6/源码.ino
Normal 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灯带的整体亮度,影响模式1、2、4和5
|
||||||
|
模式3使用独立的呼吸算法,基于此值计算动态亮度范围
|
||||||
|
uint8_t led2Brightness = 102; 默认40%左右(102255≈40%)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
单颗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(当前亮度为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] = CRGBBlue;
|
||||||
|
}
|
||||||
|
|
||||||
|
---- LED3 控制(熄灭)----
|
||||||
|
leds3[0] = CRGBBlack;
|
||||||
|
|
||||||
|
---- LED2 控制(灯带)----
|
||||||
|
switch (ledMode) {
|
||||||
|
case 0 模式0:全部熄灭,关闭所有LED灯珠
|
||||||
|
fill_solid(leds2, LED_COUNT_2, CRGBBlack);
|
||||||
|
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, 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
784
HOLOMAIN.ino
Normal 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);
|
||||||
|
}
|
||||||
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.bin
Normal file
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.bin
Normal file
Binary file not shown.
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.bootloader.bin
Normal file
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.bootloader.bin
Normal file
Binary file not shown.
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.elf
Normal file
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.elf
Normal file
Binary file not shown.
83033
build/esp32.esp32.esp32s3/HOLOMAIN.ino.map
Normal file
83033
build/esp32.esp32.esp32s3/HOLOMAIN.ino.map
Normal file
File diff suppressed because one or more lines are too long
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.merged.bin
Normal file
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.merged.bin
Normal file
Binary file not shown.
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.partitions.bin
Normal file
BIN
build/esp32.esp32.esp32s3/HOLOMAIN.ino.partitions.bin
Normal file
Binary file not shown.
BIN
build/esp32.esp32.esp32s3/烧录说明1.jpg
Normal file
BIN
build/esp32.esp32.esp32s3/烧录说明1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
BIN
build/esp32.esp32.esp32s3/烧录说明2.png
Normal file
BIN
build/esp32.esp32.esp32s3/烧录说明2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
BIN
洛天依串口指令.xlsx
Normal file
BIN
洛天依串口指令.xlsx
Normal file
Binary file not shown.
1
环境配置指南.txt
Normal file
1
环境配置指南.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Arduino环境搭建指南:https://cloud.tencent.com/developer/article/2395361
|
||||||
Loading…
x
Reference in New Issue
Block a user