696 lines
19 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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