| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- /**
- ******************************************************************************
- * @file main.c
- * @author MCU Application Team
- * @brief 音箱控制面板 - 应用主逻辑
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2023 Puya Semiconductor Co.
- * All rights reserved.</center></h2>
- *
- * This software component is licensed by Puya under BSD 3-Clause license,
- * the "License"; You may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- * opensource.org/licenses/BSD-3-Clause
- *
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2016 STMicroelectronics.
- * All rights reserved.</center></h2>
- *
- * This software component is licensed by ST under BSD 3-Clause license,
- * the "License"; You may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- * opensource.org/licenses/BSD-3-Clause
- *
- ******************************************************************************
- */
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include <stdio.h>
- #include "app_state.h"
- #include "led_driver.h"
- #include "battery_display.h"
- #include "input_scan.h"
- #include "uart_protocol.h"
- /* Private define ------------------------------------------------------------*/
- /* ========== TIM3 定时参数 ========== */
- /* 系统时钟 48MHz (PLL), 预分频0 => 48MHz, Period=4799 => 10kHz = 100us */
- #define TIM3_PRESCALER 0
- #define TIM3_PERIOD 4799
- /* 中断内时间基准 */
- #define TICK_1MS 10u /* 1ms = 10 * 100us */
- /* ========== 长按计时 ========== */
- #define BOTH_PRESS_MS 10000u /* 两编码器键同时长按10s软复位 */
- #define IDLE_QUERY_MS 30000u /* 空闲30s后主动查询 */
- /* Private variables ---------------------------------------------------------*/
- TIM_HandleTypeDef TimHandle;
- /* UART2 句柄由 BSP 库在 py32f030xx_Start_Kit.c 中定义 */
- extern UART_HandleTypeDef DebugUartHandle;
- /* ========== 共享状态变量定义 (声明在 app_state.h) ========== */
- /* 主从同步变量 (来自主板) */
- volatile uint8_t g_inputSource = 0u;
- volatile uint8_t g_btConnState = 0u;
- volatile uint8_t g_audioPlaying = 0u;
- volatile uint8_t g_batteryPct = 0u;
- volatile uint8_t g_chgFull = 0u;
- volatile uint8_t g_chgIng = 0u;
- volatile uint8_t g_dacMute = 0u;
- /* 音量等级 (本地操作值) */
- volatile int16_t g_volLRLevel = 0;
- volatile int16_t g_volBassLevel = 0;
- /* 异步发送标志 (由中断置位, 主循环处理) */
- volatile uint8_t g_flagSendVolLR = 0u;
- volatile uint8_t g_flagSendVolBass = 0u;
- volatile uint8_t g_flagSendDacUnmute = 0u;
- /* 面板本地状态 */
- volatile uint8_t g_dataReceived = 0u;
- volatile uint8_t g_mutedByBtn = 0u;
- /* 各状态接收标志 (用于开机全亮无缝切换) */
- volatile uint8_t g_volLRReceived = 0u;
- volatile uint8_t g_volBassReceived = 0u;
- volatile uint8_t g_batteryReceived = 0u;
- volatile uint8_t g_sourceReceived = 0u;
- /* 系统毫秒计时 */
- volatile uint32_t g_sysMs = 0u;
- /* 空闲查询计时 */
- volatile uint16_t g_idleTimer = 0u;
- volatile uint8_t g_userActive = 0u;
- /* Private function prototypes -----------------------------------------------*/
- static void APP_SystemClockConfig(void);
- static void APP_GPIO_Init(void);
- static void APP_UART_Init(void);
- static void APP_TIM3_Init(void);
- static void SystemReadyIndicate(void);
- /* ========== 主函数 ========== */
- /**
- * @brief Main program - 音箱主板控制面板
- */
- int main(void)
- {
- HAL_Init();
- APP_SystemClockConfig();
- APP_GPIO_Init();
- APP_UART_Init();
- LED_InitControlBlock();
- InputScan_Init();
- APP_TIM3_Init();
- /* 上电所有灯全亮3秒, 等待主板开机上报 (LED11除外, 等收到数据再显示) */
- for (uint8_t i = 0; i < 13u; i++)
- {
- if (i == 10u)
- LED_SetState(i, 1u); /* LED11全亮, 收到主板上报后更新 */
- else
- LED_SetState(i, 3u); /* 其他反向并联LED双灯同亮 */
- }
- LED_ApplyAllStates();
- /* 等待3秒让主板启动, 期间每秒查询一次 */
- for (uint8_t i = 0; i < 3u; i++)
- {
- HAL_Delay(1000u);
- /* 处理延时期间收到的帧 */
- while (UART_IsFrameReady())
- {
- UART_ClearFrameReady();
- ProcessReceivedFrame();
- }
- /* 如果还没收到数据, 主动查询 */
- if (!g_dataReceived)
- {
- SendQueryAll();
- HAL_Delay(200u);
- while (UART_IsFrameReady())
- {
- UART_ClearFrameReady();
- ProcessReceivedFrame();
- }
- }
- else
- {
- break; /* 收到数据了, 提前结束等待 */
- }
- }
- /* 系统就绪指示 */
- SystemReadyIndicate();
- while (1)
- {
- /* ---- UART 接收看门狗: 检测并恢复卡死的接收 ---- */
- {
- static uint32_t s_uartWdMs = 0u;
- if ((g_sysMs - s_uartWdMs) >= 200u)
- {
- s_uartWdMs = g_sysMs;
- /* 如果 RxState 不是 BUSY_RX, 说明接收已经停止 */
- if (DebugUartHandle.RxState != HAL_UART_STATE_BUSY_RX)
- {
- /* 清除所有错误标志 */
- __HAL_UART_CLEAR_OREFLAG(&DebugUartHandle);
- __HAL_UART_CLEAR_FEFLAG(&DebugUartHandle);
- __HAL_UART_CLEAR_NEFLAG(&DebugUartHandle);
- __HAL_UART_CLEAR_PEFLAG(&DebugUartHandle);
- /* 强制恢复 RxState 并重启接收 */
- DebugUartHandle.RxState = HAL_UART_STATE_READY;
- HAL_UART_Receive_IT(&DebugUartHandle, &g_rxByte, 1u);
- }
- }
- }
- /* ---- 处理所有待处理协议帧 ---- */
- while (UART_IsFrameReady())
- {
- UART_ClearFrameReady();
- ProcessReceivedFrame();
- }
- /* ---- 异步发送 UART 指令 (脱离中断执行) ---- */
- if (g_flagSendVolLR)
- {
- static int16_t s_dispLRLvl = -1;
- if (s_dispLRLvl != g_volLRLevel)
- {
- s_dispLRLvl = g_volLRLevel;
- UpdateVolumeLEDs(); /* 立即更新本地 UI,保证手感无延迟 */
- }
- /* 限流向主板发送 (50ms) */
- static uint32_t s_lastTxVolLRMs = 0u;
- if ((g_sysMs - s_lastTxVolLRMs) >= 50u)
- {
- g_flagSendVolLR = 0u;
- s_lastTxVolLRMs = g_sysMs;
- SendSetVolLR((uint8_t)g_volLRLevel);
- }
- }
- if (g_flagSendVolBass)
- {
- static int16_t s_dispBassLvl = -1;
- if (s_dispBassLvl != g_volBassLevel)
- {
- s_dispBassLvl = g_volBassLevel;
- UpdateVolumeLEDs();
- }
- static uint32_t s_lastTxVolBassMs = 0u;
- if ((g_sysMs - s_lastTxVolBassMs) >= 50u)
- {
- g_flagSendVolBass = 0u;
- s_lastTxVolBassMs = g_sysMs;
- SendSetVolBass((uint8_t)g_volBassLevel);
- }
- }
- if (g_flagSendDacUnmute)
- {
- g_flagSendDacUnmute = 0u;
- SendSetDacMute(0x01u); /* DAC_UNMUTE */
- }
- /* ---- 处理按键事件 ---- */
- if (g_swKeyEdge)
- {
- g_swKeyEdge = 0u;
- /* SW_KEY(PF3): 切换音源 BT <-> AUX (本地切换, 不等主板上报) */
- if (g_inputSource == 0x01u) /* BT=0x01 */
- g_inputSource = 0x00u; /* AUX=0x00 */
- else
- g_inputSource = 0x01u;
- SendSetInputSrc(g_inputSource);
- UpdateSourceLED();
- g_userActive = 1u;
- g_idleTimer = 0u;
- }
- if (g_swKeyLongPress == 1u)
- {
- g_swKeyLongPress = 2u; /* 标记已处理, 防止重复发送 */
- SendBTDisconnect();
- g_userActive = 1u;
- g_idleTimer = 0u;
- }
- if (g_sw1KeyEdge)
- {
- g_sw1KeyEdge = 0u;
- /* SW1_KEY: 低音静音 */
- g_volBassLevel = 0;
- UpdateVolumeLEDs();
- SendBassMute();
- g_userActive = 1u;
- g_idleTimer = 0u;
- }
- if (g_sw2KeyEdge)
- {
- g_sw2KeyEdge = 0u;
- /* SW2_KEY: 快速静音, 仅第一次按下有效 */
- if (!g_mutedByBtn)
- {
- g_mutedByBtn = 1u;
- SendSetDacMute(0x00u); /* 0x00 is Mute */
- for (uint8_t i = 0; i < 10u; i++)
- LED_SetState(i, 0u);
- LED_ApplyAllStates();
- }
- g_userActive = 1u;
- g_idleTimer = 0u;
- }
- /* ---- 双键同按10s软复位 (500ms防误触 + 10s = 10500ms) ---- */
- if (g_bothPressFlag && g_bothPressMs >= (BOTH_PRESS_MS + 500u))
- {
- g_bothPressFlag = 0u;
- g_bothPressMs = 0u;
- /* 清除可能触发的静音标志 */
- g_sw1KeyEdge = 0u;
- g_sw2KeyEdge = 0u;
- SendSoftReset();
- HAL_Delay(100u);
- NVIC_SystemReset();
- }
- /* ---- 空闲30s后主动查询同步 ---- */
- if (g_dataReceived && g_idleTimer >= IDLE_QUERY_MS)
- {
- g_idleTimer = 0u;
- SendQueryAll();
- }
- }
- }
- /* ========== 系统就绪指示 ========== */
- static void SystemReadyIndicate(void)
- {
- printf("\r\n========================================\r\n");
- printf(" Speaker Control Panel\r\n");
- printf(" Waiting for mainboard data...\r\n");
- printf("========================================\r\n");
- }
- /* ========== 硬件初始化 ========== */
- /**
- * @brief 系统时钟配置: HSI 24MHz -> PLL = 48MHz
- */
- static void APP_SystemClockConfig(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI
- | RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
- RCC_OscInitStruct.HSIState = RCC_HSI_ON;
- #if defined(RCC_HSIDIV_SUPPORT)
- RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
- #endif
- RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_24MHz;
- RCC_OscInitStruct.HSEState = RCC_HSE_OFF;
- RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
- RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- APP_ErrorHandler();
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
- APP_ErrorHandler();
- }
- /**
- * @brief GPIO初始化 (所有引脚初始配置为浮空输入)
- */
- static void APP_GPIO_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- __HAL_RCC_GPIOA_CLK_ENABLE();
- __HAL_RCC_GPIOB_CLK_ENABLE();
- RCC->IOPENR |= RCC_IOPENR_GPIOFEN;
- /* GPIOA: LED + 编码器 + SW2_KEY */
- GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4
- | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_15;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- /* GPIOB: LED + 编码器 + SW1_KEY */
- GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4
- | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- GPIO_InitStruct.Pin = GPIO_PIN_8;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- /* SW1_KEY (PB0) */
- GPIO_InitStruct.Pin = GPIO_PIN_0;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- /* GPIOF: SW_KEY */
- GPIO_InitStruct.Pin = GPIO_PIN_3;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
- }
- /**
- * @brief UART2初始化
- */
- static void APP_UART_Init(void)
- {
- BSP_USART_Config();
- /* 开启UART2中断接收, 缓冲区在 uart_protocol.c 中定义 */
- HAL_UART_Receive_IT(&DebugUartHandle, &g_rxByte, 1u);
- }
- /**
- * @brief TIM3初始化: 100us中断 (10kHz)
- */
- static void APP_TIM3_Init(void)
- {
- TimHandle.Instance = TIM3;
- TimHandle.Init.Period = TIM3_PERIOD;
- TimHandle.Init.Prescaler = TIM3_PRESCALER;
- TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
- TimHandle.Init.RepetitionCounter = 0;
- TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
- if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
- APP_ErrorHandler();
- if (HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
- APP_ErrorHandler();
- }
- /* ========== 中断回调 ========== */
- /**
- * @brief TIM3 周期中断回调: 每 100us 执行一次
- */
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- static uint32_t s_tick = 0u;
- s_tick++;
- /* 每 1ms 更新系统毫秒计数 */
- if ((s_tick % 10u) == 0u) g_sysMs++;
- /* LED 定时翻转 (状态3/4/5) */
- LED_Tick100us();
- /* 每 1ms 扫描按键/编码器/电池时间槽 */
- if ((s_tick % TICK_1MS) == 0u)
- {
- ScanButtons();
- ScanEncoders();
- BatterySlotUpdate();
- /* 双键同按计时: 前500ms防误触 */
- if (g_bothPressFlag)
- {
- if (g_bothPressMs < (BOTH_PRESS_MS + 500u))
- g_bothPressMs++;
- }
- /* 空闲计时 */
- if (g_userActive)
- {
- if (++g_idleTimer >= 200u) /* 200ms无操作认为活动结束 */
- {
- g_userActive = 0u;
- g_idleTimer = 0u;
- }
- }
- else if (g_dataReceived)
- {
- if (g_idleTimer < IDLE_QUERY_MS)
- g_idleTimer++;
- }
- }
- }
- /**
- * @brief USART2 接收完成中断回调 (HAL库)
- * 每次重新开启接收前清除溢出错误标志, 防止 ORE 卡死
- */
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- {
- if (huart->Instance == USART2)
- {
- UART_RxByteCallback(g_rxByte);
- /* 清除可能的溢出错误标志, 防止 ORE 导致接收停止 */
- __HAL_UART_CLEAR_OREFLAG(huart);
- HAL_UART_Receive_IT(&DebugUartHandle, &g_rxByte, 1u);
- }
- }
- /**
- * @brief UART 错误中断回调 (HAL库)
- * 当发生 ORE/FE/NE/PE 错误时, HAL 会调用此函数而非 RxCpltCallback.
- * 必须在此处重新启动接收, 否则 UART 接收将永久停止.
- */
- void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
- {
- if (huart->Instance == USART2)
- {
- /* 清除所有错误标志 */
- __HAL_UART_CLEAR_OREFLAG(huart);
- __HAL_UART_CLEAR_FEFLAG(huart);
- __HAL_UART_CLEAR_NEFLAG(huart);
- __HAL_UART_CLEAR_PEFLAG(huart);
- /* 重新启动中断接收, 恢复通讯 */
- HAL_UART_Receive_IT(&DebugUartHandle, &g_rxByte, 1u);
- }
- }
- /* ========== 错误处理 ========== */
- void APP_ErrorHandler(void)
- {
- while (1)
- {
- }
- }
- #ifdef USE_FULL_ASSERT
- void assert_failed(uint8_t *file, uint32_t line)
- {
- while (1)
- {
- }
- }
- #endif /* USE_FULL_ASSERT */
|