| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- /**
- ******************************************************************************
- * @file battery_display.c
- * @brief 电池电量 LED 显示模块实现
- * 双时间槽分时复用控制反并联 LED, 实现独立闪烁.
- ******************************************************************************
- */
- /* Includes ------------------------------------------------------------------*/
- #include "battery_display.h"
- #include "led_driver.h"
- #include "app_state.h"
- /* Private define ------------------------------------------------------------*/
- /* 充电状态值 */
- #define CHG_CHARGING 0x01u
- #define CHG_ABNORMAL 0xFEu
- /* ========== 电池LED时间槽控制 ========== */
- /* 电池灯闪烁速率: 1s = 500个周期亮 + 500个周期灭 */
- #define BAT_BLINK_ON_CYCLES 500u
- #define BAT_BLINK_OFF_CYCLES 500u
- /* 充电异常闪烁: 100ms = 50个周期亮 + 50个周期灭 */
- #define BAT_ERR_ON_CYCLES 50u
- #define BAT_ERR_OFF_CYCLES 50u
- /* Private variables ---------------------------------------------------------*/
- /* 每颗电池灯(0-3)在各自槽位中的亮灭状态: 0=灭, 1=亮 */
- static volatile uint8_t g_batSlotState[4] = {0u, 0u, 0u, 0u};
- static volatile uint16_t g_batBlinkCnt = 0u; /* 闪烁周期计数器 */
- static volatile uint8_t g_batBlinkPattern = 0u; /* 0=常亮, 1=1s闪烁, 2=异常闪烁 */
- static volatile uint8_t g_batBlinkLed = 0xFFu; /* 闪烁的灯索引(0~3), 0xFF=无 */
- /* ========== LED12/LED13 引脚位偏移 ========== */
- /* PA8 → bit8 → 位偏移 8 → MODER bit 16/17 */
- /* PA11 → bit11 → 位偏移 11 → MODER bit 22/23 */
- #define LED12_PIN_BIT 8u
- #define LED13_PIN_BIT 11u
- /* ========== 函数实现 ========== */
- /**
- * @brief 根据 g_batteryPct / g_chgIng / g_chgFull 更新电池 LED 显示状态
- *
- * 充电闪烁逻辑 (用槽位独立控制):
- * level=1: 灯0 1s闪烁
- * level=2: 灯0常亮, 灯1 1s闪烁
- * level=3: 灯0+1常亮, 灯2 1s闪烁
- * level=4: 灯0+1+2常亮, 灯3 1s闪烁
- * 充满: 4颗灯常亮
- * 充电异常: 灯0 100ms闪烁, 其余灭
- */
- void UpdateBatteryLEDs(void)
- {
- if (!g_batteryReceived) return;
- uint8_t pct = g_batteryPct;
- uint8_t chg = g_chgIng;
- /* 将 1-100% 转换为 4 段 (0-4颗灯亮) */
- uint8_t level;
- if (pct >= 75u) level = 4u; /* 75~100%: 4颗灯 */
- else if (pct >= 50u) level = 3u; /* 50~74%: 3颗灯 */
- else if (pct >= 25u) level = 2u; /* 25~49%: 2颗灯 */
- else if (pct >= 1u) level = 1u; /* 1~24%: 1颗灯 */
- else level = 0u;
- /* 默认: 所有灯灭 */
- for (uint8_t i = 0; i < 4u; i++) g_batSlotState[i] = 0u;
- g_batBlinkPattern = 0u;
- g_batBlinkLed = 0xFFu;
- g_batBlinkCnt = 0u;
- /* 将电池LED从状态3(1kHz翻转)中排除, 由时间槽接管 */
- g_leds[11].state = 0u;
- g_leds[12].state = 0u;
- /* 充电异常: 灯0 100ms闪烁 */
- if (chg == CHG_ABNORMAL)
- {
- g_batBlinkPattern = 2u; /* 100ms闪烁模式 */
- return;
- }
- /* ---- 设置各灯槽状态 ---- */
- switch (level)
- {
- case 4u:
- g_batSlotState[0] = 1u;
- g_batSlotState[1] = 1u;
- g_batSlotState[2] = 1u;
- g_batSlotState[3] = 1u;
- break;
- case 3u:
- g_batSlotState[0] = 1u;
- g_batSlotState[1] = 1u;
- g_batSlotState[2] = 1u;
- /* 灯3灭 */
- break;
- case 2u:
- g_batSlotState[0] = 1u;
- g_batSlotState[1] = 1u;
- break;
- case 1u:
- g_batSlotState[0] = 1u;
- break;
- default: /* 0: 全灭 */
- break;
- }
- /* 充满(100%): 无论是否插充电器, 4颗全亮 */
- if (g_chgFull == 1u && level >= 4u)
- {
- for (uint8_t i = 0; i < 4u; i++) g_batSlotState[i] = 1u;
- return;
- }
- /* 充电中: 冲到哪格就哪格闪 */
- if (chg == CHG_CHARGING && level > 0u)
- {
- g_batBlinkPattern = 1u; /* 1s闪烁 */
- g_batBlinkLed = (uint8_t)(level - 1u); /* 闪烁的灯索引 */
- if (level == 1u)
- {
- g_batSlotState[0] = 1u;
- }
- else
- {
- /* 前面所有灯常亮, 最后一格闪烁 */
- for (uint8_t i = 0; i < level; i++)
- g_batSlotState[i] = 1u;
- }
- }
- }
- /**
- * @brief 双时间槽更新 (TIM3 中断中每 1ms 调用)
- * 前半程(槽A): 正向灯亮/反向灯灭
- * 后半程(槽B): 反向灯亮/正向灯灭
- */
- void BatterySlotUpdate(void)
- {
- static uint8_t s_slotPhase = 0u; /* 0=前半程, 1=后半程 */
- static uint16_t s_cycleCnt = 0u; /* 周期计数(用于闪烁) */
- /* 未收到主板电池数据前, 电池LED由上电全亮状态3控制, 不接管 */
- if (!g_batteryReceived) return;
- s_slotPhase ^= 1u; /* 每 1ms 切换一次槽位 */
- /* 闪烁控制: 每完成一个完整周期(前后半程)计数一次 */
- if (s_slotPhase == 0u)
- {
- s_cycleCnt++;
- }
- /* 判断当前是否在闪烁的"亮"区间 */
- uint8_t blinkOn = 1u;
- if (g_batBlinkPattern == 1u)
- {
- /* 1s闪烁: 500个周期亮, 500个周期灭 */
- uint16_t c = (uint16_t)(s_cycleCnt % (BAT_BLINK_ON_CYCLES + BAT_BLINK_OFF_CYCLES));
- blinkOn = (c < BAT_BLINK_ON_CYCLES) ? 1u : 0u;
- }
- else if (g_batBlinkPattern == 2u)
- {
- /* 100ms闪烁: 50个周期亮, 50个周期灭 */
- uint16_t c = (uint16_t)(s_cycleCnt % (BAT_ERR_ON_CYCLES + BAT_ERR_OFF_CYCLES));
- blinkOn = (c < BAT_ERR_ON_CYCLES) ? 1u : 0u;
- }
- /* ---- LED12(PA8): 灯0(正向) / 灯1(反向) ---- */
- uint8_t needA0 = (g_batBlinkLed == 0u) ? (blinkOn ? g_batSlotState[0] : 0u) : g_batSlotState[0];
- uint8_t needB1 = (g_batBlinkLed == 1u) ? (blinkOn ? g_batSlotState[1] : 0u) : g_batSlotState[1];
- if (s_slotPhase == 0u)
- {
- /* 槽A: 控制灯0 */
- if (needA0)
- {
- GPIOA->MODER = (GPIOA->MODER & ~(3UL << (LED12_PIN_BIT * 2u))) | (1UL << (LED12_PIN_BIT * 2u));
- GPIOA->BSRR = GPIO_PIN_8; /* ODR=1 → 灯0亮 */
- }
- else
- {
- GPIOA->MODER &= ~(3UL << (LED12_PIN_BIT * 2u)); /* 浮空输入 → 灯0灭 */
- GPIOA->PUPDR &= ~(3UL << (LED12_PIN_BIT * 2u));
- }
- }
- else
- {
- /* 槽B: 控制灯1(反向) */
- if (needB1)
- {
- GPIOA->MODER = (GPIOA->MODER & ~(3UL << (LED12_PIN_BIT * 2u))) | (1UL << (LED12_PIN_BIT * 2u));
- GPIOA->BSRR = (GPIO_PIN_8 << 16); /* ODR=0 → 灯1亮 */
- }
- else
- {
- GPIOA->MODER &= ~(3UL << (LED12_PIN_BIT * 2u)); /* 浮空输入 → 灯1灭 */
- GPIOA->PUPDR &= ~(3UL << (LED12_PIN_BIT * 2u));
- }
- }
- /* ---- LED13(PA11): 灯2(正向) / 灯3(反向) ---- */
- uint8_t needA2 = (g_batBlinkLed == 2u) ? (blinkOn ? g_batSlotState[2] : 0u) : g_batSlotState[2];
- uint8_t needB3 = (g_batBlinkLed == 3u) ? (blinkOn ? g_batSlotState[3] : 0u) : g_batSlotState[3];
- if (s_slotPhase == 0u)
- {
- /* 槽A: 控制灯2 */
- if (needA2)
- {
- GPIOA->MODER = (GPIOA->MODER & ~(3UL << (LED13_PIN_BIT * 2u))) | (1UL << (LED13_PIN_BIT * 2u));
- GPIOA->BSRR = GPIO_PIN_11; /* ODR=1 → 灯2亮 */
- }
- else
- {
- GPIOA->MODER &= ~(3UL << (LED13_PIN_BIT * 2u));
- GPIOA->PUPDR &= ~(3UL << (LED13_PIN_BIT * 2u));
- }
- }
- else
- {
- /* 槽B: 控制灯3(反向) */
- if (needB3)
- {
- GPIOA->MODER = (GPIOA->MODER & ~(3UL << (LED13_PIN_BIT * 2u))) | (1UL << (LED13_PIN_BIT * 2u));
- GPIOA->BSRR = (GPIO_PIN_11 << 16); /* ODR=0 → 灯3亮 */
- }
- else
- {
- GPIOA->MODER &= ~(3UL << (LED13_PIN_BIT * 2u));
- GPIOA->PUPDR &= ~(3UL << (LED13_PIN_BIT * 2u));
- }
- }
- }
|