feat(power): low-battery tip screen and auto power-off below 6.2V
Stop all sound, show UI0902 LOWBAT_TIP fullscreen, then soft-off after 10s. Skip while charging; speed up ADC sampling near empty. Pack new tip bitmap into ExtFlash UI0902 map. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
f740b6fba0
commit
1b1b9b196d
|
|
@ -65,6 +65,18 @@ uint8_t percentage = 0;
|
||||||
//static uint32_t charge_step_tick = 0;
|
//static uint32_t charge_step_tick = 0;
|
||||||
#define VBAT_MIN_RAW 2520
|
#define VBAT_MIN_RAW 2520
|
||||||
#define VBAT_MAX_RAW 3528
|
#define VBAT_MAX_RAW 3528
|
||||||
|
/* 包电压标定:MIN≈6.0V(0%) … MAX≈8.4V(100%);关机阈值 6.2V */
|
||||||
|
#define VBAT_PACK_V_MIN_MV 6000
|
||||||
|
#define VBAT_PACK_V_MAX_MV 8400
|
||||||
|
#define VBAT_SHUTDOWN_MV 6200
|
||||||
|
#define VBAT_SHUTDOWN_RAW \
|
||||||
|
(VBAT_MIN_RAW + (uint32_t)(VBAT_SHUTDOWN_MV - VBAT_PACK_V_MIN_MV) * \
|
||||||
|
(VBAT_MAX_RAW - VBAT_MIN_RAW) / (VBAT_PACK_V_MAX_MV - VBAT_PACK_V_MIN_MV))
|
||||||
|
/* 接近关机阈值时加快采样(约 <6.5V) */
|
||||||
|
#define VBAT_FAST_SAMPLE_RAW \
|
||||||
|
(VBAT_MIN_RAW + (uint32_t)(500) * (VBAT_MAX_RAW - VBAT_MIN_RAW) / \
|
||||||
|
(VBAT_PACK_V_MAX_MV - VBAT_PACK_V_MIN_MV))
|
||||||
|
#define BAT_SAMPLE_INTERVAL_LOW_MS 2000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -72,10 +84,14 @@ uint8_t percentage = 0;
|
||||||
|
|
||||||
static void app_adc_string_process(uint8_t channel)
|
static void app_adc_string_process(uint8_t channel)
|
||||||
{
|
{
|
||||||
|
uint16_t adc_val;
|
||||||
uint16_t adc_val = ADC_ReadChannel(ADC_CHANNEL_0) >> 5;
|
|
||||||
uint8_t vel_out = 80;
|
uint8_t vel_out = 80;
|
||||||
|
|
||||||
|
if (System_LowBat_IsActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
adc_val = ADC_ReadChannel(ADC_CHANNEL_0) >> 5;
|
||||||
|
|
||||||
if (adc_val >= 127) {
|
if (adc_val >= 127) {
|
||||||
/* δ<><CEB4><EFBFBD><EFBFBD> <20><> Note Off */
|
/* δ<><CEB4><EFBFBD><EFBFBD> <20><> Note Off */
|
||||||
if (string_state[channel]) {
|
if (string_state[channel]) {
|
||||||
|
|
@ -114,10 +130,16 @@ pick_state_t app_adc_get_pick_input(void)
|
||||||
|
|
||||||
static void app_adc_pick_process(void)
|
static void app_adc_pick_process(void)
|
||||||
{
|
{
|
||||||
pick_state_t curstate = app_adc_get_pick_input();
|
pick_state_t curstate;
|
||||||
|
uint32_t now;
|
||||||
uint32_t now = rt_tick_get();
|
|
||||||
uint32_t hold_tick;
|
uint32_t hold_tick;
|
||||||
|
|
||||||
|
if (System_LowBat_IsActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
curstate = app_adc_get_pick_input();
|
||||||
|
|
||||||
|
now = rt_tick_get();
|
||||||
switch(pick_fsm)
|
switch(pick_fsm)
|
||||||
{
|
{
|
||||||
case PICK_FSM_STATE_IDLE:
|
case PICK_FSM_STATE_IDLE:
|
||||||
|
|
@ -368,7 +390,7 @@ static void app_adc_battery_do_sample(void)
|
||||||
bat_index = (bat_index + 1) % BAT_SAMPLE_COUNT;
|
bat_index = (bat_index + 1) % BAT_SAMPLE_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 上报:映射成百分比,变化才发消息 */
|
/* 上报:映射成百分比,变化才发消息;低于 6.2V 触发低电量关机流程 */
|
||||||
static void app_adc_battery_report(void)
|
static void app_adc_battery_report(void)
|
||||||
{
|
{
|
||||||
uint16_t filtered = bat_sum / BAT_SAMPLE_COUNT;
|
uint16_t filtered = bat_sum / BAT_SAMPLE_COUNT;
|
||||||
|
|
@ -382,6 +404,15 @@ static void app_adc_battery_report(void)
|
||||||
pct = 100 * (filtered - VBAT_MIN_RAW) / (VBAT_MAX_RAW - VBAT_MIN_RAW);
|
pct = 100 * (filtered - VBAT_MIN_RAW) / (VBAT_MAX_RAW - VBAT_MIN_RAW);
|
||||||
pct = (pct / 10) * 10;
|
pct = (pct / 10) * 10;
|
||||||
|
|
||||||
|
/* 开机且未充电:包电压低于 6.2V → 立即停声并弹关机提示(只触发一次) */
|
||||||
|
if (powon && !usb_charging_state && !System_LowBat_IsActive() &&
|
||||||
|
filtered < (uint16_t)VBAT_SHUTDOWN_RAW)
|
||||||
|
{
|
||||||
|
LOG_W("BAT", "lowbat raw=%u thr=%u → tip+shutdown",
|
||||||
|
(unsigned)filtered, (unsigned)VBAT_SHUTDOWN_RAW);
|
||||||
|
MainTask_Sendmsg(MSG_ID_LOW_BAT_TIP, pct, filtered, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (pct != percentage) { /* 变化才上报 */
|
if (pct != percentage) { /* 变化才上报 */
|
||||||
percentage = pct;
|
percentage = pct;
|
||||||
if(usb_charging_state && !powon)
|
if(usb_charging_state && !powon)
|
||||||
|
|
@ -404,15 +435,20 @@ static void app_adc_battery_process(void)
|
||||||
switch (bat_state)
|
switch (bat_state)
|
||||||
{
|
{
|
||||||
case BAT_IDLE:
|
case BAT_IDLE:
|
||||||
/* 触发:开机后首采,或距上次 ≥30s */
|
/* 触发:开机后首采,或距上次 ≥30s(接近低电时改为 2s) */
|
||||||
if (/*powon && */!bat_poweron_done)
|
if (/*powon && */!bat_poweron_done)
|
||||||
{
|
{
|
||||||
bat_poweron_done = 1;
|
bat_poweron_done = 1;
|
||||||
bat_state = BAT_START;
|
bat_state = BAT_START;
|
||||||
}
|
}
|
||||||
else if (now - bat_last_sample_tick >= BAT_SAMPLE_INTERVAL_MS)
|
else
|
||||||
{
|
{
|
||||||
bat_state = BAT_START;
|
uint32_t interval = BAT_SAMPLE_INTERVAL_MS;
|
||||||
|
uint16_t last_avg = bat_sum / BAT_SAMPLE_COUNT;
|
||||||
|
if (last_avg != 0 && last_avg < (uint16_t)VBAT_FAST_SAMPLE_RAW)
|
||||||
|
interval = BAT_SAMPLE_INTERVAL_LOW_MS;
|
||||||
|
if (now - bat_last_sample_tick >= interval)
|
||||||
|
bat_state = BAT_START;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,11 @@ static volatile uint8_t s_pwr_rails_cut = 0;
|
||||||
/* TMR7:关机长按已触发请求后的紧急倒计时(ms) */
|
/* TMR7:关机长按已触发请求后的紧急倒计时(ms) */
|
||||||
static volatile uint16_t s_pwr_off_grace_ms = 0;
|
static volatile uint16_t s_pwr_off_grace_ms = 0;
|
||||||
|
|
||||||
|
/* 电量 <6.2V:提示界面停留后关机 */
|
||||||
|
#define LOWBAT_SHUTDOWN_DELAY_MS 10000u
|
||||||
|
static volatile uint8_t s_lowbat_active = 0;
|
||||||
|
static volatile uint32_t s_lowbat_deadline_ms = 0;
|
||||||
|
|
||||||
/* ==================== 开机/关机动作 ==================== */
|
/* ==================== 开机/关机动作 ==================== */
|
||||||
|
|
||||||
/* 仅 GPIO/背光:可在 ISR / HardFault 中调用,禁止 RTOS/Flash/日志 */
|
/* 仅 GPIO/背光:可在 ISR / HardFault 中调用,禁止 RTOS/Flash/日志 */
|
||||||
|
|
@ -214,6 +219,8 @@ void System_PowerOn(void)
|
||||||
app_tm1629_reset_key_state();
|
app_tm1629_reset_key_state();
|
||||||
s_pwr_rails_cut = 0u;
|
s_pwr_rails_cut = 0u;
|
||||||
s_pwr_off_grace_ms = 0u;
|
s_pwr_off_grace_ms = 0u;
|
||||||
|
s_lowbat_active = 0u;
|
||||||
|
s_lowbat_deadline_ms = 0u;
|
||||||
/* 本次长按已用于开机:先消耗,再置 powon,防止 TMR7 ISR 把同一按压力即判为关机 */
|
/* 本次长按已用于开机:先消耗,再置 powon,防止 TMR7 ISR 把同一按压力即判为关机 */
|
||||||
Power_Key_ConsumePress();
|
Power_Key_ConsumePress();
|
||||||
/* 控制电源硬件;蓝牙按 NVM/系统设置开关恢复,勿强制常开 */
|
/* 控制电源硬件;蓝牙按 NVM/系统设置开关恢复,勿强制常开 */
|
||||||
|
|
@ -318,6 +325,36 @@ void System_PowerOff_Poll(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 电量 <6.2V:提示界面停留后关机 */
|
||||||
|
void System_LowBat_Arm(void)
|
||||||
|
{
|
||||||
|
if (s_lowbat_active)
|
||||||
|
return;
|
||||||
|
s_lowbat_active = 1;
|
||||||
|
s_lowbat_deadline_ms = rt_tick_get() * 1000u / RT_TICK_PER_SECOND + LOWBAT_SHUTDOWN_DELAY_MS;
|
||||||
|
LOG_I("PWR", "lowbat tip armed, power_off in %ums", (unsigned)LOWBAT_SHUTDOWN_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t System_LowBat_IsActive(void)
|
||||||
|
{
|
||||||
|
return s_lowbat_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void System_LowBat_Poll(void)
|
||||||
|
{
|
||||||
|
uint32_t now;
|
||||||
|
if (!s_lowbat_active || !powon)
|
||||||
|
return;
|
||||||
|
now = rt_tick_get() * 1000u / RT_TICK_PER_SECOND;
|
||||||
|
if ((int32_t)(now - s_lowbat_deadline_ms) >= 0)
|
||||||
|
{
|
||||||
|
s_lowbat_active = 0;
|
||||||
|
LOG_I("PWR", "lowbat tip timeout → power_off");
|
||||||
|
System_RequestPowerOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TMR7 1ms(优先级高于伴奏 TMR6):与主循环解耦的关机键扫描。
|
* TMR7 1ms(优先级高于伴奏 TMR6):与主循环解耦的关机键扫描。
|
||||||
* 正常:请求优雅关机;超时未切轨 → 紧急断电并复位。
|
* 正常:请求优雅关机;超时未切轨 → 紧急断电并复位。
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#define MSG_ID_CHARG 27
|
#define MSG_ID_CHARG 27
|
||||||
#define MSG_ID_BLE_UI_REFRESH 28
|
#define MSG_ID_BLE_UI_REFRESH 28
|
||||||
#define MSG_ID_BLE_STYLE_SET 29
|
#define MSG_ID_BLE_STYLE_SET 29
|
||||||
|
#define MSG_ID_LOW_BAT_TIP 30
|
||||||
|
|
||||||
#define GPIO_PIN_RESET false
|
#define GPIO_PIN_RESET false
|
||||||
#define GPIO_PIN_SET true
|
#define GPIO_PIN_SET true
|
||||||
|
|
@ -177,6 +178,10 @@ void AutoPowerOff_Scan(void);
|
||||||
void System_PowerOn(void);
|
void System_PowerOn(void);
|
||||||
void System_RequestPowerOff(void);
|
void System_RequestPowerOff(void);
|
||||||
void System_PowerOff_Poll(void);
|
void System_PowerOff_Poll(void);
|
||||||
|
/* 低电量:停声+提示后 10s 关机(主循环 Poll) */
|
||||||
|
void System_LowBat_Arm(void);
|
||||||
|
void System_LowBat_Poll(void);
|
||||||
|
uint8_t System_LowBat_IsActive(void);
|
||||||
extern uint8_t Led;
|
extern uint8_t Led;
|
||||||
extern bool PressFlag;
|
extern bool PressFlag;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,11 @@
|
||||||
#define UI0902_FLASH_MODE_W 240
|
#define UI0902_FLASH_MODE_W 240
|
||||||
#define UI0902_FLASH_MODE_H 320
|
#define UI0902_FLASH_MODE_H 320
|
||||||
|
|
||||||
#define UI0902_BTN_CANCEL_BIG_ADDR (UI0902_RES_BASE + 0x0F8000UL) /* 11872 bytes */
|
#define UI0902_LOWBAT_TIP_ADDR (UI0902_RES_BASE + 0x0F8000UL) /* 153600 bytes */
|
||||||
|
#define UI0902_LOWBAT_TIP_W 240
|
||||||
|
#define UI0902_LOWBAT_TIP_H 320
|
||||||
|
|
||||||
|
#define UI0902_BTN_CANCEL_BIG_ADDR (UI0902_RES_BASE + 0x11E000UL) /* 11872 bytes */
|
||||||
#define UI0902_BTN_CANCEL_BIG_W 106
|
#define UI0902_BTN_CANCEL_BIG_W 106
|
||||||
#define UI0902_BTN_CANCEL_BIG_H 56
|
#define UI0902_BTN_CANCEL_BIG_H 56
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ int main(void)
|
||||||
Power_Key_Scan();
|
Power_Key_Scan();
|
||||||
AutoPowerOff_Scan();
|
AutoPowerOff_Scan();
|
||||||
System_PowerOff_Poll();
|
System_PowerOff_Poll();
|
||||||
|
System_LowBat_Poll();
|
||||||
LCD_Dump_Poll();
|
LCD_Dump_Poll();
|
||||||
#if !DEBUG_LCD_DUMP
|
#if !DEBUG_LCD_DUMP
|
||||||
app_log_poll();
|
app_log_poll();
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,28 @@ void TaskUIThread_entry(void* parameter)
|
||||||
StartFlag = 0;
|
StartFlag = 0;
|
||||||
UI_ReloadTonePreset(); /* 内含 Stop_AutoBand */
|
UI_ReloadTonePreset(); /* 内含 Stop_AutoBand */
|
||||||
}
|
}
|
||||||
|
/* 低电量提示:任意页面全屏覆盖;倒计时期间吞掉其它 UI 刷新,避免盖住提示 */
|
||||||
|
if (xEvent.MessageType == MSG_ID_LOW_BAT_TIP)
|
||||||
|
{
|
||||||
|
uint8_t peek[4];
|
||||||
|
LCD_WR_REG(0x29);
|
||||||
|
LCD_BLK_Set();
|
||||||
|
LCD_FillByColor(0, 0, 240, 320, BLACK);
|
||||||
|
W25Q128_Read(peek, UI0902_LOWBAT_TIP_ADDR, 4);
|
||||||
|
if (peek[0] != 0xFF || peek[1] != 0xFF)
|
||||||
|
{
|
||||||
|
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_LOWBAT_TIP_W, UI0902_LOWBAT_TIP_H,
|
||||||
|
UI0902_LOWBAT_TIP_ADDR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_W("UI", "lowbat flash empty @0x%08lX — flash ui0902",
|
||||||
|
(unsigned long)UI0902_LOWBAT_TIP_ADDR);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (System_LowBat_IsActive())
|
||||||
|
continue;
|
||||||
CurrUIProcress(xEvent);
|
CurrUIProcress(xEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -84,15 +106,29 @@ void TaskMainThread_entry(void* parameter)
|
||||||
case MSG_ID_POWER_ON : UITask_Sendmsg(MSG_ID_POWER_ON, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break;
|
case MSG_ID_POWER_ON : UITask_Sendmsg(MSG_ID_POWER_ON, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break;
|
||||||
case MSG_ID_POWER_OFF : break;
|
case MSG_ID_POWER_OFF : break;
|
||||||
//case MSG_ID_ADCIN1KEY : ADC_IN1_KEY_Handle(xEvent.ID);break;
|
//case MSG_ID_ADCIN1KEY : ADC_IN1_KEY_Handle(xEvent.ID);break;
|
||||||
case MSG_ID_BP_KEY : Pick_Handle(); break;
|
case MSG_ID_BP_KEY:
|
||||||
case MSG_ID_LOOP_LIGHT : Loop_Light_Handle(xEvent.ID); break;
|
if (!System_LowBat_IsActive())
|
||||||
|
Pick_Handle();
|
||||||
|
break;
|
||||||
|
case MSG_ID_LOOP_LIGHT:
|
||||||
|
if (!System_LowBat_IsActive())
|
||||||
|
Loop_Light_Handle(xEvent.ID);
|
||||||
|
break;
|
||||||
case MSG_ID_TM1629_KEY : break;
|
case MSG_ID_TM1629_KEY : break;
|
||||||
case MSG_ID_TM1617_KEY : break;
|
case MSG_ID_TM1617_KEY : break;
|
||||||
case MSG_ID_EC_VOL:
|
case MSG_ID_EC_VOL:
|
||||||
/* 任意页面都先下发主音量,避免 UI 未处理导致屏显与实际脱节 */
|
/* 任意页面都先下发主音量,避免 UI 未处理导致屏显与实际脱节 */
|
||||||
Send_volume((uint8_t)xEvent.ID);
|
if (!System_LowBat_IsActive())
|
||||||
|
Send_volume((uint8_t)xEvent.ID);
|
||||||
UITask_Sendmsg(xEvent.MessageType, xEvent.ID, xEvent.HiByte, xEvent.LoByte);
|
UITask_Sendmsg(xEvent.MessageType, xEvent.ID, xEvent.HiByte, xEvent.LoByte);
|
||||||
break;
|
break;
|
||||||
|
case MSG_ID_LOW_BAT_TIP:
|
||||||
|
/* 立即停声,再交给 UI 画提示;主循环 10s 后关机 */
|
||||||
|
Stop_AutoBand();
|
||||||
|
Send_volume(0);
|
||||||
|
System_LowBat_Arm();
|
||||||
|
UITask_Sendmsg(MSG_ID_LOW_BAT_TIP, xEvent.ID, xEvent.HiByte, xEvent.LoByte);
|
||||||
|
break;
|
||||||
case MSG_ID_TOUCH:
|
case MSG_ID_TOUCH:
|
||||||
case MSG_ID_CHARG:
|
case MSG_ID_CHARG:
|
||||||
case MSG_ID_TAP_SPEED:
|
case MSG_ID_TAP_SPEED:
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
|
|
@ -225,6 +225,8 @@ EXTERNAL = [
|
||||||
("BOOT_LOGO", "07_开机/开机界面-20.png"),
|
("BOOT_LOGO", "07_开机/开机界面-20.png"),
|
||||||
("CHARGE_SCREEN", "08_充电界面/充电界面-0902-09.png"), # 0904 最新全屏充电稿;百分比重叠由固件绘制
|
("CHARGE_SCREEN", "08_充电界面/充电界面-0902-09.png"), # 0904 最新全屏充电稿;百分比重叠由固件绘制
|
||||||
("FLASH_MODE", "09_烧录模式/烧录模式-240x320.png"), # Boot IAP 烧录等待画面
|
("FLASH_MODE", "09_烧录模式/烧录模式-240x320.png"), # Boot IAP 烧录等待画面
|
||||||
|
# 低电量关机提示(Doc/UI/K1标准界面图 0904/K1 低电量提醒状态界面.zip 合成全屏)
|
||||||
|
("LOWBAT_TIP", "10_低电量/低电量提醒-240x320.png"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -274,7 +276,7 @@ def main():
|
||||||
if name in ("ROW_UNIVERSAL_NOT", "ROW_UNIVERSAL_SEL", "ROW_NORMAL_NOT", "ROW_NORMAL_SEL", "ROW_EXPERT_NOT", "ROW_EXPERT_SEL"):
|
if name in ("ROW_UNIVERSAL_NOT", "ROW_UNIVERSAL_SEL", "ROW_NORMAL_NOT", "ROW_NORMAL_SEL", "ROW_EXPERT_NOT", "ROW_EXPERT_SEL"):
|
||||||
im = im.resize(ROW_RESIZE, Image.LANCZOS)
|
im = im.resize(ROW_RESIZE, Image.LANCZOS)
|
||||||
data, w, h = rgba_to_rgb565(im)
|
data, w, h = rgba_to_rgb565(im)
|
||||||
elif name in ("BOOT_LOGO", "CHARGE_SCREEN", "FLASH_MODE"):
|
elif name in ("BOOT_LOGO", "CHARGE_SCREEN", "FLASH_MODE", "LOWBAT_TIP"):
|
||||||
if im.size[0] >= 241 and im.size[1] >= 321:
|
if im.size[0] >= 241 and im.size[1] >= 321:
|
||||||
im = im.crop((0, 0, 240, 320))
|
im = im.crop((0, 0, 240, 320))
|
||||||
elif im.size != (240, 320):
|
elif im.size != (240, 320):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue