led_driver.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /**
  2. ******************************************************************************
  3. * @file led_driver.c
  4. * @brief LED 驱动模块实现
  5. * 管理 13 个反向并联 LED 的底层状态机和 GPIO 操作.
  6. * 同时提供基于应用状态的 LED 显示更新函数.
  7. ******************************************************************************
  8. */
  9. /* Includes ------------------------------------------------------------------*/
  10. #include "led_driver.h"
  11. #include "app_state.h"
  12. /* Private define ------------------------------------------------------------*/
  13. /* ========== LED 引脚定义 (13个) ========== */
  14. /* 避免与BSP头文件中 LED3_PIN/LED3_GPIO_PORT 冲突, 使用 GPIO_LEDx_PIN/GPIO_LEDx_PORT 命名 */
  15. #define GPIO_LED1_PIN GPIO_PIN_1
  16. #define GPIO_LED1_PORT GPIOA
  17. #define GPIO_LED2_PIN GPIO_PIN_7
  18. #define GPIO_LED2_PORT GPIOB
  19. #define GPIO_LED3_PIN GPIO_PIN_6
  20. #define GPIO_LED3_PORT GPIOB
  21. #define GPIO_LED4_PIN GPIO_PIN_5
  22. #define GPIO_LED4_PORT GPIOB
  23. #define GPIO_LED5_PIN GPIO_PIN_0
  24. #define GPIO_LED5_PORT GPIOA
  25. #define GPIO_LED6_PIN GPIO_PIN_2
  26. #define GPIO_LED6_PORT GPIOB
  27. #define GPIO_LED7_PIN GPIO_PIN_4
  28. #define GPIO_LED7_PORT GPIOB
  29. #define GPIO_LED8_PIN GPIO_PIN_3
  30. #define GPIO_LED8_PORT GPIOB
  31. #define GPIO_LED9_PIN GPIO_PIN_12
  32. #define GPIO_LED9_PORT GPIOA
  33. #define GPIO_LED10_PIN GPIO_PIN_1
  34. #define GPIO_LED10_PORT GPIOB
  35. #define GPIO_LED11_PIN GPIO_PIN_4
  36. #define GPIO_LED11_PORT GPIOA
  37. #define GPIO_LED12_PIN GPIO_PIN_8
  38. #define GPIO_LED12_PORT GPIOA
  39. #define GPIO_LED13_PIN GPIO_PIN_11
  40. #define GPIO_LED13_PORT GPIOA
  41. /* ========== 闪烁计时参数 (基于TIM3 100us = 0.1ms) ========== */
  42. #define BLINK_500MS_PERIOD_TICKS 2500u /* 500ms周期 (2Hz) = 每250ms翻转 */
  43. #define BLINK_1S_PERIOD_TICKS 5000u /* 1s周期 (1Hz) = 每500ms翻转 */
  44. /* 状态3 (双灯同亮) ~1kHz 翻转: 每 0.5ms (5 ticks) */
  45. #define BLINK_STATE3_TICKS 5u
  46. /* Private variables ---------------------------------------------------------*/
  47. /* 13个LED控制块 */
  48. LED_Control_t g_leds[LED_COUNT];
  49. /* ========== 私有函数声明 ========== */
  50. static void LED_ApplyStateToRegister_Internal(uint8_t ledIdx);
  51. /* ========== 初始化 ========== */
  52. /**
  53. * @brief 初始化 LED 控制块
  54. * 为每颗 LED 填充端口、引脚及引脚序号, 状态默认为 0 (灭).
  55. */
  56. void LED_InitControlBlock(void)
  57. {
  58. /* LED引脚配置表: 索引0-12 */
  59. const struct {
  60. GPIO_TypeDef *port;
  61. uint16_t pin;
  62. } ledcfg[LED_COUNT] = {
  63. {GPIOA, GPIO_PIN_1}, /* 0: LED1 */
  64. {GPIOB, GPIO_PIN_7}, /* 1: LED2 */
  65. {GPIOB, GPIO_PIN_6}, /* 2: LED3 */
  66. {GPIOB, GPIO_PIN_5}, /* 3: LED4 */
  67. {GPIOA, GPIO_PIN_0}, /* 4: LED5 */
  68. {GPIOB, GPIO_PIN_2}, /* 5: LED6 */
  69. {GPIOB, GPIO_PIN_4}, /* 6: LED7 */
  70. {GPIOB, GPIO_PIN_3}, /* 7: LED8 */
  71. {GPIOA, GPIO_PIN_12}, /* 8: LED9 */
  72. {GPIOB, GPIO_PIN_1}, /* 9: LED10 */
  73. {GPIOA, GPIO_PIN_4}, /* 10: LED11 */
  74. {GPIOA, GPIO_PIN_8}, /* 11: LED12 */
  75. {GPIOA, GPIO_PIN_11}, /* 12: LED13 */
  76. };
  77. for (uint8_t i = 0; i < LED_COUNT; i++)
  78. {
  79. g_leds[i].port = ledcfg[i].port;
  80. g_leds[i].pin = ledcfg[i].pin;
  81. g_leds[i].state = 0;
  82. /* 计算引脚序号 (pinNum): 找到位索引 */
  83. uint16_t p = ledcfg[i].pin;
  84. uint8_t n = 0;
  85. while (p > 1) { p >>= 1; n++; }
  86. g_leds[i].pinNum = n;
  87. }
  88. }
  89. /* ========== 状态控制 ========== */
  90. /**
  91. * @brief 设置 LED 状态 (0-5)
  92. * @param ledIdx 索引 (0-12)
  93. * @param state 0=灭, 1=正向, 2=反向, 3=双灯, 4=500ms周期闪烁, 5=1s周期闪烁
  94. */
  95. void LED_SetState(uint8_t ledIdx, uint8_t state)
  96. {
  97. if (ledIdx >= LED_COUNT) return;
  98. if (state > 5u) state = 5u;
  99. g_leds[ledIdx].state = state;
  100. }
  101. /**
  102. * @brief 将单个 LED 当前状态应用到 GPIO 寄存器
  103. * 可在中断内和主循环中安全调用
  104. */
  105. void LED_ApplyStateToRegister(uint8_t ledIdx)
  106. {
  107. if (ledIdx >= LED_COUNT) return;
  108. LED_ApplyStateToRegister_Internal(ledIdx);
  109. }
  110. /**
  111. * @brief 将所有 LED 状态应用到 GPIO 寄存器
  112. */
  113. void LED_ApplyAllStates(void)
  114. {
  115. for (uint8_t i = 0; i < LED_COUNT; i++)
  116. {
  117. LED_ApplyStateToRegister_Internal(i);
  118. }
  119. }
  120. /* ========== 定时器回调 ========== */
  121. /**
  122. * @brief 每 100us 调用一次, 处理所有 LED 的定时翻转
  123. */
  124. void LED_Tick100us(void)
  125. {
  126. static uint32_t s_1kHzTick = 0u; /* 状态3 计数 */
  127. static uint32_t s_blink500ms = 0u; /* 状态4 计数 */
  128. static uint32_t s_blink1s = 0u; /* 状态5 计数 */
  129. /* 状态3 (双灯同亮): 每 0.5ms 翻转 => ~1kHz */
  130. s_1kHzTick++;
  131. if (s_1kHzTick >= BLINK_STATE3_TICKS)
  132. {
  133. s_1kHzTick = 0u;
  134. for (uint8_t i = 0; i < LED_COUNT; i++)
  135. {
  136. if (g_leds[i].state == 3u)
  137. {
  138. g_leds[i].port->ODR ^= (1UL << g_leds[i].pinNum);
  139. }
  140. }
  141. }
  142. /* 状态4 (500ms周期闪烁): 每 2500 ticks 翻转 */
  143. s_blink500ms++;
  144. if (s_blink500ms >= BLINK_500MS_PERIOD_TICKS)
  145. {
  146. s_blink500ms = 0u;
  147. for (uint8_t i = 0; i < LED_COUNT; i++)
  148. {
  149. if (g_leds[i].state == 4u)
  150. {
  151. g_leds[i].port->ODR ^= (1UL << g_leds[i].pinNum);
  152. }
  153. }
  154. }
  155. /* 状态5 (1s周期闪烁): 每 5000 ticks 翻转 */
  156. s_blink1s++;
  157. if (s_blink1s >= BLINK_1S_PERIOD_TICKS)
  158. {
  159. s_blink1s = 0u;
  160. for (uint8_t i = 0; i < LED_COUNT; i++)
  161. {
  162. if (g_leds[i].state == 5u)
  163. {
  164. g_leds[i].port->ODR ^= (1UL << g_leds[i].pinNum);
  165. }
  166. }
  167. }
  168. /* 状态6 (呼吸灯): 纯软件 PWM (针对推挽输出的独立灯如 LED11) */
  169. static uint8_t s_breathPwmCount = 0u; /* PWM 周期计数 (0-99) */
  170. static uint8_t s_breathDuty = 0u; /* 当前占空比 (0-100) */
  171. static int8_t s_breathDir = 1; /* 呼吸方向: 1=渐亮, -1=渐隐 */
  172. static uint8_t s_breathStepCount = 0u; /* 占空比调整分频 */
  173. /* 每 100us 执行一次: 100个tick = 10ms PWM周期 = 100Hz 刷新率 */
  174. s_breathPwmCount++;
  175. if (s_breathPwmCount >= 100u)
  176. {
  177. s_breathPwmCount = 0u;
  178. /* 每 10ms 调整一次亮度, 单程 100 * 10ms = 1秒, 完整呼吸周期 2秒 */
  179. s_breathStepCount++;
  180. if (s_breathStepCount >= 1u)
  181. {
  182. s_breathStepCount = 0u;
  183. /* 更新占空比 */
  184. if (s_breathDir == 1)
  185. {
  186. if (s_breathDuty < 100u) s_breathDuty++;
  187. else s_breathDir = -1;
  188. }
  189. else
  190. {
  191. if (s_breathDuty > 0u) s_breathDuty--;
  192. else s_breathDir = 1;
  193. }
  194. }
  195. }
  196. /* 执行 PWM 输出 */
  197. for (uint8_t i = 0; i < LED_COUNT; i++)
  198. {
  199. if (g_leds[i].state == 6u)
  200. {
  201. if (s_breathPwmCount < s_breathDuty)
  202. {
  203. g_leds[i].port->BSRR = (1UL << g_leds[i].pinNum); /* 亮 (输出高) */
  204. }
  205. else
  206. {
  207. g_leds[i].port->BSRR = (1UL << (g_leds[i].pinNum + 16u)); /* 灭 (输出低) */
  208. }
  209. }
  210. }
  211. }
  212. /* ========== LED 显示更新 ========== */
  213. /**
  214. * @brief 更新音量LED显示 (LED1~LED10, 索引0-9)
  215. * g_volBass → LED1~LED5 (索引0-4, SW1)
  216. * g_volLR → LED6~LED10 (索引5-9, SW2)
  217. * 方向: 倒序从LED5→LED1, LED10→LED6 逐级点亮
  218. * 每颗灯对应2个等级 (正向+反向, 每级10%)
  219. */
  220. void UpdateVolumeLEDs(void)
  221. {
  222. int16_t level;
  223. /* ----- 低音音量 (SW1) LED1~LED5 (索引0-4), 倒序: LED5→LED1 ----- */
  224. if (g_volBassReceived)
  225. {
  226. level = g_volBassLevel;
  227. if (level < 0) level = 0;
  228. if (level > 100) level = 100;
  229. /* 换算10段 */
  230. uint8_t seg = (uint8_t)((level + 9) / 10);
  231. if (seg > 10u) seg = 10u;
  232. for (uint8_t i = 0; i < 5u; i++)
  233. {
  234. uint8_t idx = (uint8_t)(4u - i);
  235. uint8_t rOn = (seg > (i * 2u));
  236. uint8_t fOn = (seg > (i * 2u + 1u));
  237. if (fOn && rOn)
  238. LED_SetState(idx, 3u);
  239. else if (rOn)
  240. LED_SetState(idx, 2u);
  241. else if (fOn)
  242. LED_SetState(idx, 1u);
  243. else
  244. LED_SetState(idx, 0u);
  245. }
  246. }
  247. /* ----- 主音量LR (SW2) LED6~LED10 (索引5-9), 倒序: LED10→LED6 ----- */
  248. if (g_volLRReceived)
  249. {
  250. level = g_volLRLevel;
  251. if (level < 0) level = 0;
  252. if (level > 100) level = 100;
  253. uint8_t seg = (uint8_t)((level + 9) / 10);
  254. if (seg > 10u) seg = 10u;
  255. for (uint8_t i = 0; i < 5u; i++)
  256. {
  257. uint8_t idx = (uint8_t)(9u - i);
  258. uint8_t rOn = (seg > (i * 2u));
  259. uint8_t fOn = (seg > (i * 2u + 1u));
  260. if (fOn && rOn)
  261. LED_SetState(idx, 3u);
  262. else if (rOn)
  263. LED_SetState(idx, 2u);
  264. else if (fOn)
  265. LED_SetState(idx, 1u);
  266. else
  267. LED_SetState(idx, 0u);
  268. }
  269. }
  270. LED_ApplyAllStates();
  271. }
  272. /**
  273. * @brief 更新输入源指示灯 (LED11, 索引10)
  274. * AUX输入: 常亮 (状态1)
  275. * BT已连接: 灭 (状态0)
  276. * BT断开: 1s周期闪烁 (状态5)
  277. */
  278. void UpdateSourceLED(void)
  279. {
  280. if (!g_sourceReceived) return;
  281. uint8_t src = g_inputSource;
  282. uint8_t btCon = g_btConnState;
  283. if (src == 0x00u) /* INPUT_SRC_AUX (V2.0) */
  284. {
  285. g_leds[10].state = 1u; /* 常亮 */
  286. GPIOA->MODER = (GPIOA->MODER & ~(3UL << 8)) | (1UL << 8); /* PA4输出 */
  287. GPIOA->BSRR = GPIO_PIN_4;
  288. }
  289. else if (src == 0x01u) /* INPUT_SRC_BT */
  290. {
  291. /* 已连接 或 正在播放 (Airplay等协议可能无连接状态但有播放状态) -> 长灭 */
  292. if (btCon == 0x01u || g_audioPlaying == 0x01u)
  293. {
  294. g_leds[10].state = 0u; /* 灭 */
  295. GPIOA->BSRR = (GPIO_PIN_4 << 16);
  296. GPIOA->MODER &= ~(3UL << 8);
  297. }
  298. else
  299. {
  300. /* 未连接 且 未播放 -> 呼吸灯渐隐渐亮 */
  301. g_leds[10].state = 6u; /* 状态6: 呼吸灯 */
  302. GPIOA->MODER = (GPIOA->MODER & ~(3UL << 8)) | (1UL << 8);
  303. GPIOA->BSRR = (GPIO_PIN_4 << 16); /* 初始灭 */
  304. }
  305. }
  306. else
  307. {
  308. g_leds[10].state = 0u; /* 未知: 灭 */
  309. GPIOA->BSRR = (GPIO_PIN_4 << 16);
  310. GPIOA->MODER &= ~(3UL << 8);
  311. }
  312. /* 不调 LED_ApplyAllStates, 避免覆盖其他LED */
  313. }
  314. /* ========== 私有函数实现 ========== */
  315. /**
  316. * @brief 直接操作寄存器将单个LED状态应用到GPIO
  317. */
  318. static void LED_ApplyStateToRegister_Internal(uint8_t ledIdx)
  319. {
  320. LED_Control_t *led = &g_leds[ledIdx];
  321. GPIO_TypeDef *gpio = led->port;
  322. uint8_t n = led->pinNum;
  323. uint8_t st = led->state;
  324. uint32_t moderMask = (3UL << (n * 2u));
  325. switch (st)
  326. {
  327. case 0u: /* 全灭: 浮空输入 (高阻态) */
  328. gpio->BSRR = (1UL << (n + 16u)); /* 先确保 ODR=0 */
  329. gpio->MODER &= ~moderMask; /* 00 = 输入模式 */
  330. gpio->PUPDR &= ~(3UL << (n * 2u)); /* 00 = 无上拉 */
  331. gpio->ODR &= ~(1UL << n); /* 再清一次 ODR */
  332. break;
  333. case 1u: /* 正向亮: 推挽输出, 高电平 */
  334. case 4u: /* 500ms周期闪烁: 初始为正向亮 */
  335. case 5u: /* 1s周期闪烁: 初始为正向亮 */
  336. gpio->MODER = (gpio->MODER & ~moderMask) | (1UL << (n * 2u)); /* 01=输出 */
  337. gpio->BSRR = (1UL << n); /* ODR 置 1 */
  338. break;
  339. case 2u: /* 反向亮: 推挽输出, 低电平 */
  340. gpio->MODER = (gpio->MODER & ~moderMask) | (1UL << (n * 2u)); /* 01=输出 */
  341. gpio->BSRR = (1UL << (n + 16u)); /* ODR 清零 */
  342. break;
  343. case 3u: /* 双灯同亮: 推挽输出, 先高电平, 中断中交替翻转 */
  344. gpio->MODER = (gpio->MODER & ~moderMask) | (1UL << (n * 2u)); /* 01=输出 */
  345. gpio->BSRR = (1UL << n); /* ODR 置 1 */
  346. break;
  347. default:
  348. break;
  349. }
  350. }