From 90105a60eacc591ab7c3f61000b385c8c2a6948a Mon Sep 17 00:00:00 2001 From: Rdzleo Date: Tue, 21 Apr 2026 17:22:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=97=A7=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E6=9D=BF=E4=BB=A3=E7=A0=81=E5=A4=87=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01_HOLOMAIN_旧开发板代码.ino | 145 ++++++++--------------------------- 1 file changed, 30 insertions(+), 115 deletions(-) diff --git a/01_HOLOMAIN_旧开发板代码.ino b/01_HOLOMAIN_旧开发板代码.ino index 2c786b0..6578fcf 100644 --- a/01_HOLOMAIN_旧开发板代码.ino +++ b/01_HOLOMAIN_旧开发板代码.ino @@ -35,43 +35,6 @@ // 任务句柄 TaskHandle_t TaskRFID, TaskLED1, TaskLED2, TaskLED3, TaskPWM, TaskBTN0, TaskWAKEUP1, TaskBTN1, TaskBTN2; -// 双串口架构: -// - Serial = USB-Serial-JTAG (USB2 口),连 Windows 做调试日志 -// - SerialLinux = UART0 (CH343/USB1 口),连 Linux 开发板接收业务数据 -// UART0 默认引脚:TX=GPIO43、RX=GPIO44(对应 CH343P 的 RXD/TXD) -HardwareSerial SerialLinux(0); - -// Serial 输出互斥锁:防止多任务并发写串口导致数据交错/截断 -SemaphoreHandle_t serialMutex = NULL; - -// 带互斥保护的双串口输出:同时发到 USB CDC (Windows) 和 UART0 (Linux) -// 调用方:RFID 任务发 SORC_xxx,按键任务发 SO_xxx -// 机制:1) 互斥锁避免多任务交错 2) 两个串口并发传输 3) flush 等待传输完成 -void serialPrintlnSafe(const String& msg) { - if (serialMutex && xSemaphoreTake(serialMutex, pdMS_TO_TICKS(100)) == pdTRUE) { - // ---- 发到 USB CDC (Windows 调试) ---- - // 等待 TX 缓冲区有足够空间,避免 USB CDC 缓冲区满导致截断(最多等 50ms) - size_t needed = msg.length() + 2; - uint32_t waitStart = millis(); - while ((size_t)Serial.availableForWrite() < needed && (millis() - waitStart) < 50) { - vTaskDelay(pdMS_TO_TICKS(2)); - } - Serial.println(msg); - Serial.flush(); - - // ---- 发到 UART0 (Linux 业务) ---- - // UART0 硬件有独立 128 字节 FIFO,115200 波特率下发送 12 字节约 1ms,几乎不阻塞 - SerialLinux.println(msg); - SerialLinux.flush(); - - xSemaphoreGive(serialMutex); - } else { - // 拿不到锁的降级路径(正常情况下几乎不触发) - Serial.println(msg); - SerialLinux.println(msg); - } -} - // 全局变量 MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN); // 创建RFID实例 CRGB leds1[LED_COUNT_1]; // 1颗灯珠数组 @@ -170,12 +133,11 @@ void TaskRFIDcode(void* pvParameters) { MFRC522::StatusCode status; status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { - // 调试日志用普通 Serial.println:失败频率较高时,避免 flush 阻塞拖慢 RFID 响应 - // 偶尔截断可接受(Linux 端用正则 ^SORC_HA\d+$ 过滤业务数据即可) - Serial.println(String("Authentication failed: ") + rfid.GetStatusCodeName(status)); + Serial.print(F("Authentication failed: ")); + Serial.println(rfid.GetStatusCodeName(status)); rfid.PICC_HaltA(); rfid.PCD_StopCrypto1(); - delay(30); // 从 100ms 降到 30ms,提升刷卡响应速度 + delay(100); continue; } @@ -184,47 +146,23 @@ void TaskRFIDcode(void* pvParameters) { byte size = sizeof(buffer); status = rfid.MIFARE_Read(4, buffer, &size); if (status != MFRC522::STATUS_OK) { - Serial.println(String("Reading failed: ") + rfid.GetStatusCodeName(status)); - rfid.PICC_HaltA(); - rfid.PCD_StopCrypto1(); - delay(30); // 从 100ms 降到 30ms - continue; - } - - // 转换为ASCII字符串 - for (byte i = 0; i < 16; i++) { - if (buffer[i] >= 32 && buffer[i] <= 126) { // 可打印ASCII字符 - cardData += (char)buffer[i]; + 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(); + // 移除空白字符 + cardData.trim(); - // 卡片数据格式校验:规则 "HA" + 阿拉伯数字 - // 过滤掉卡片读取异常或数据损坏的情况,避免发送无效数据给 Linux - auto isValidCardData = [](const String& d) -> bool { - if (d.length() < 3) return false; // 至少 "HA" + 1 位数字 - if (!d.startsWith("HA")) return false; // 必须以 HA 开头 - for (size_t i = 2; i < d.length(); i++) { - if (!isdigit(d[i])) return false; // HA 后面必须全是数字 - } - return true; - }; - - // 3 秒去重窗口:同一张卡 3 秒内只发送一次,超过后允许重发 - // 切换到不同卡立即发送 - static String lastSentCard = ""; - static unsigned long lastSentTime = 0; - const unsigned long DUPLICATE_WINDOW_MS = 3000; - - if (!cardData.isEmpty() && isValidCardData(cardData)) { - unsigned long now = millis(); - bool isDuplicate = (cardData == lastSentCard) && (now - lastSentTime < DUPLICATE_WINDOW_MS); - if (!isDuplicate) { - serialPrintlnSafe("SORC_" + cardData); - lastSentCard = cardData; - lastSentTime = now; + // 卡片数据处理 + if (cardData != lastCardData && !cardData.isEmpty()) { + lastCardData = cardData; + Serial.println("SORC_" + cardData); } } @@ -278,19 +216,19 @@ void TaskBTN0code(void* pvParameters) { if (lastState == HIGH && currentState == LOW) { pressStartTime = millis(); btn0State = LOW; - serialPrintlnSafe("SO_BT0_HIGH"); + Serial.println("SO_BT0_HIGH"); btn0LongPress = false; } // 检测上升沿(释放) else if (lastState == LOW && currentState == HIGH) { btn0State = HIGH; - serialPrintlnSafe("SO_BT0_LOW"); + Serial.println("SO_BT0_LOW"); btn0LongPress = false; } // 检测长按 else if (currentState == LOW && millis() - pressStartTime >= 2000 && !btn0LongPress) { btn0LongPress = true; - serialPrintlnSafe("SO_BT0_HIGHL"); + Serial.println("SO_BT0_HIGHL"); } lastState = currentState; @@ -308,12 +246,12 @@ void TaskWAKEUP1code(void* pvParameters) { // 检测上升沿 if (lastState == LOW && currentState == HIGH) { wakeup1State = HIGH; - serialPrintlnSafe("SO_WAKEUP1"); + Serial.println("SO_WAKEUP1"); } // 检测下降沿 else if (lastState == HIGH && currentState == LOW) { wakeup1State = LOW; - serialPrintlnSafe("SO_WAKEUP0"); + Serial.println("SO_WAKEUP0"); } lastState = currentState; @@ -331,12 +269,12 @@ void TaskBTN1code(void* pvParameters) { // 检测上升沿 if (lastState == LOW && currentState == HIGH) { btn1State = HIGH; - serialPrintlnSafe("SO_BT1_HIGH"); + Serial.println("SO_BT1_HIGH"); } // 检测下降沿 else if (lastState == HIGH && currentState == LOW) { btn1State = LOW; - serialPrintlnSafe("SO_BT1_LOW"); + Serial.println("SO_BT1_LOW"); } lastState = currentState; @@ -354,12 +292,12 @@ void TaskBTN2code(void* pvParameters) { // 检测上升沿 if (lastState == LOW && currentState == HIGH) { btn2State = HIGH; - serialPrintlnSafe("SO_BT2_HIGH"); + Serial.println("SO_BT2_HIGH"); } // 检测下降沿 else if (lastState == HIGH && currentState == LOW) { btn2State = LOW; - serialPrintlnSafe("SO_BT2_LOW"); + Serial.println("SO_BT2_LOW"); } lastState = currentState; @@ -382,8 +320,6 @@ void handleSerialCommand() { char c = Serial.read(); if (c == '\n') { - // 去掉命令末尾可能的 \r,兼容不同行尾符设置(\n 或 \r\n) - command.trim(); // 处理命令 if (command.startsWith("MO_LED_")) { String modeStr = command.substring(7); @@ -489,13 +425,6 @@ void handleSerialCommand() { } command = ""; // 清空命令 } - // 软复位命令:串口发送 "RESET" 触发 ESP32 重启 - else if (command == "RESET") { - Serial.println("System resetting..."); - Serial.flush(); // 等待串口数据发送完成 - delay(100); // 留时间让串口打印完 - ESP.restart(); // 触发软复位 - } command = ""; // 清空命令 } else { @@ -518,9 +447,7 @@ void handleSerialCommand() { // 5. 防闪烁机制,确保LED显示稳定 void TaskLEDUnifiedCode(void* pvParameters) { static unsigned long lastLEDUpdate = 0; - // 20FPS 更新频率:兼顾视觉流畅度和 RFID 稳定性 - // 每秒 20 次 WS2812 传输(每次 ~5.6ms 关中断),相比 30FPS 减少 33% 干扰窗口 - const unsigned long LED_UPDATE_INTERVAL = 50; + const unsigned long LED_UPDATE_INTERVAL = 33; // ~30FPS,降低更新频率减少闪烁 for (;;) { unsigned long currentTime = millis(); @@ -722,20 +649,9 @@ void TaskLEDUnifiedCode(void* pvParameters) { void setup() { - // 初始化 USB CDC 串口(Windows 调试) - // 增大 TX 缓冲区到 4KB:防止多任务并发写串口时 USB CDC 默认缓冲区溢出导致数据截断 - Serial.setTxBufferSize(4096); + // 初始化串口 Serial.begin(115200); - - // 初始化 UART0(CH343/USB1 → Linux 业务通讯) - // 默认引脚:TX=GPIO43、RX=GPIO44,波特率与 Linux 端保持一致 - SerialLinux.begin(115200); - - // 创建 Serial 输出互斥锁 - serialMutex = xSemaphoreCreateMutex(); - Serial.println("System starting..."); - SerialLinux.println("System starting..."); // 初始化SPI总线 SPI.begin(RFID_SCK_PIN, RFID_MISO_PIN, RFID_MOSI_PIN, RFID_SS_PIN); @@ -793,15 +709,14 @@ void setup() { Serial.println("Inputs initialized."); // 创建任务 - // TaskRFID 放 Core 0:避开 Core 1 上 WS2812 bit-banging 关中断窗口,SPI 通讯更稳定 xTaskCreatePinnedToCore( TaskRFIDcode, /* 任务函数 */ "TaskRFID", /* 任务名称 */ 4096, /* 任务栈大小 */ NULL, /* 传递给任务的参数 */ - 2, /* 任务优先级(提高到 2,避免被按键任务频繁抢占)*/ + 1, /* 任务优先级 */ &TaskRFID, /* 任务句柄 */ - 0); /* 运行在核心0上(与 LED 任务物理隔离)*/ + 1); /* 运行在核心1上 */ xTaskCreatePinnedToCore( TaskLEDUnifiedCode,