1、运行中空电关机改看显示百分比,到 5% 立刻停电机、关绿灯,红灯闪 5 下后再深睡,避免电压先掉、APP 还没到 5% 就关机

2、充电/放电电量缓冲加快,放电突变拦截先关掉,电量曲线满电点收到 4.12V
3、上电串口打印软硬件版本和编译时间
This commit is contained in:
2026-08-27 11:40:57 +08:00
parent fdb43011b7
commit 215e1be6bb
10 changed files with 205 additions and 68 deletions
+6 -6
View File
@@ -21,8 +21,8 @@
/*========================= 时间/阈值配置 =========================*/
#define BAT_SWITCH_WAIT_CHARGE_MS 60000u /**< 切到充电后等 60s 才记基准 */
#define BAT_SWITCH_WAIT_DISCHARGE_MS 60000u /**< 切到放电后等 60s 才记基准 */
#define BAT_CHARGE_BUFFER_MS 60000u /**< 充电缓冲:1 分钟走 1% */
#define BAT_DISCHARGE_BUFFER_MS 20000u /**< 放电缓冲:20 秒走 1% */
#define BAT_CHARGE_BUFFER_MS 40000u /**< 充电缓冲:40 秒走 1% */
#define BAT_DISCHARGE_BUFFER_MS 10000u /**< 放电缓冲:10 秒走 1% */
#define BAT_DISCHARGE_FILTER_W 90 /**< 放电指数滤波权重(/100),压掉电机拉载噪声 */
#define BAT_SUDDEN_DROP_PCT 1 /**< 突变阈值:单次超过 1% 判定为突变 */
#define BAT_DROP_RECOVERY_MS 60000u /**< 突变超过此时长强制接受新电量 */
@@ -213,10 +213,10 @@ void app_battery_tick(uint16_t dt, uint16_t mv, uint8_t charging)
}
target = (uint8_t)new_percent;
/* 放电时单次跳变过大先当噪声,稳住后再更新 */
if (!b->charging && battery_check_sudden_drop(dt, target)) {
return;
}
// /* 放电时单次跳变过大先当噪声,稳住后再更新 */
// if (!b->charging && battery_check_sudden_drop(dt, target)) {
// return;
// }
if (target != b->target_percent) {
b->target_percent = target;
+3 -3
View File
@@ -10,9 +10,9 @@
*
* @note 本模块只认识"电压(mV) + 是否在充电",不碰 ADC/GPIO,电压采样、
* USB 在位判定由调用方(app_power)负责,保持单向依赖。
* 低电告警迟滞(app_power.c 里的 check_low/check_empty)不受本模块
* 影响,两者各管一段:本模块负责"电量数字怎么变得好看",低电告警/
* 深睡门限仍按原始电压判断
* 低电告警迟滞(app_power.c 里的 check_low)不受本模块影响:
* 本模块负责显示电量怎么变得好看;低电红灯仍按原始电压判断,
* 5% 自动关机则读本模块给出的显示百分比
******************************************************************************/
#ifndef __APP_BATTERY_H__
+36 -3
View File
@@ -11,6 +11,7 @@
* - V2.1.0, 2026.08.25, cyWu, 自己从 app_power/app_pair 取数并内部组装
* - V2.2.0, 2026.08.25, cyWu, 重启/清场逻辑各提一个小函数,把意图写进注释
* - V2.3.0, 2026.08.27, cyWu, 新增 OTA 红绿交替灯效
* - V2.4.0, 2026.08.27, cyWu, 新增空电关机红闪 5 下灯效
******************************************************************************/
#include "app_led.h"
@@ -21,7 +22,8 @@
#include "app_pair.h"
static uint8_t s_initialized;
static uint8_t s_ota; /* 1=OTA 灯效中,app_led_run 不再叠其它灯 */
static uint8_t s_ota; /* 1=OTA 灯效中,app_led_run 不再叠其它灯 */
static uint8_t s_empty_off; /* 1=空电关机红闪中,只跑红灯 5 下 */
static void led_start_pair_result(uint8_t ok);
@@ -89,7 +91,7 @@ AppLed_Ret_t app_led_get_status(void)
*/
void app_led_request_mode_blink(void)
{
if (!s_initialized || s_ota) {
if (!s_initialized || s_ota || s_empty_off) {
return;
}
led_restart(LED_EVENT_MODE);
@@ -101,7 +103,7 @@ void app_led_request_mode_blink(void)
*/
void app_led_hint_power_on(void)
{
if (!s_initialized || s_ota) {
if (!s_initialized || s_ota || s_empty_off) {
return;
}
led_restart(LED_EVENT_STANDBY);
@@ -131,6 +133,30 @@ uint8_t app_led_is_ota(void)
return s_ota;
}
/**
* @brief 空电关机:清掉其它灯(含绿灯),只挂红灯闪 5 下
* @return 无
*/
void app_led_request_empty_off(void)
{
if (!s_initialized || s_ota) {
return; /* OTA 灯效优先,不打断升级提示 */
}
s_empty_off = 1;
LED_EventAllDelete();
bsp_led_all_off(); /* 先关绿灯 */
LED_EventAdd(LED_EVENT_EMPTY);
}
/**
* @brief 查询是否处于空电关机灯效
* @return 1=空电红闪中,0=否
*/
uint8_t app_led_is_empty_off(void)
{
return s_empty_off;
}
/**
* @brief 播放一次性配对结果灯
* @param ok 1=成功常绿,0=失败红绿交替
@@ -186,6 +212,13 @@ void app_led_run(uint16_t dt, uint8_t app_power)
return;
}
/* 空电关机:绿灯已关,只跑红灯闪 5 下;事件在 request 时已挂上,这里不要再 Add,
* 否则闪完被删后又会重新开始闪。 */
if (s_empty_off) {
user_led_handle();
return;
}
/* 配对成功/失败是边沿事件,只在那一拍切灯效 */
pair_evt = app_pair_tick_1ms(dt);
if (pair_evt == APP_PAIR_EVT_OK) {
+13
View File
@@ -11,6 +11,7 @@
* - V2.1.0, 2026.08.25, cyWu, 改为自己从 app_power/app_pair 取数,
* 调用方不用再手填 AppLedCtx_t
* - V2.3.0, 2026.08.27, cyWu, 新增 OTA 红绿交替灯效
* - V2.4.0, 2026.08.27, cyWu, 新增空电关机红灯闪 5 下
******************************************************************************/
#ifndef __APP_LED_H__
@@ -62,6 +63,18 @@ void app_led_request_ota(void);
*/
uint8_t app_led_is_ota(void);
/**
* @brief 空电关机灯效:关掉绿灯,只闪红灯 5 下
* @return 无
*/
void app_led_request_empty_off(void);
/**
* @brief 查询是否处于空电关机灯效
* @return 1=空电红闪中,0=否
*/
uint8_t app_led_is_empty_off(void);
/**
* @brief 清空全部灯事件并灭灯(关机前调用)
* @return 无
+54 -33
View File
@@ -2,13 +2,15 @@
* @file app_power.c
* @brief USB / 充电检测、电量采样与低电策略、深睡请求生命周期实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.26
* @version V1.1.0
* @date 2026.08.27
* @version V1.2.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现 USB/充电检测、电量采样与深睡请求
* - V1.1.0, 2026.08.26, cyWu, 取消低电闪烁 1 分钟后自动关机;自动关机门限
* 改为约 5%BOARD_VBAT_SHUTDOWN_MV),与开机
* 低电拦截(app_boot)共用同一门限
* - V1.2.0, 2026.08.27, cyWu, 运行中空电关机改用显示百分比,到 5% 立即停电机
* 并请求空电灯效后再掉电,不再做连续次数窗口
******************************************************************************/
#include "app_power.h"
@@ -34,7 +36,6 @@
#define BAT_BOOT_MS 3000 /* 上电 3s 内不因低电深睡 */
#define BAT_LOG_MS 10000
#define BAT_LOW_WIN 3 /* 连续约 2.4s 才进低电告警(仅闪灯,不关机) */
#define BAT_EMPTY_WIN 5 /* 连续约 4s 才判定 <=5%,自动关机 */
/** 充电检测:CHG/VPWR 消抖后的结果 */
typedef struct {
@@ -57,11 +58,10 @@ typedef struct {
/** 低电告警:进入/退出都要连续窗口消抖,避免电机拉压降误报
* @note 低电(BOARD_VBAT_LOW_MV)只负责红灯闪烁提示,不再有超时自动关机;
* 真正的自动关机改由 power_battery_check_empty 在电量约 5%
* BOARD_VBAT_SHUTDOWN_MV)时触发 */
* 真正的自动关机改由 power_battery_check_empty 在显示电量
* <= BOARD_BATTERY_SHUTDOWN_PCT5%)时立刻触发 */
typedef struct {
uint8_t low_bat;
uint8_t empty_win;
uint8_t enter_win;
uint8_t exit_win;
} AppBatteryAlarm_t;
@@ -72,6 +72,7 @@ typedef struct {
AppBatterySample_t sample;
AppBatteryAlarm_t alarm;
uint8_t req_poweroff;
uint8_t empty_off; /**< 1=空电路径:闪完红灯再掉电 */
AppPowerHook_t on_request;
AppPowerHook_t on_finalize;
} AppPowerCtx_t;
@@ -83,7 +84,7 @@ static AppPowerEvt_t power_charge_tick(uint16_t dt);
static void power_battery_tick(uint16_t dt);
static uint8_t power_battery_sample_ready(uint16_t dt, uint16_t *out_mv);
static void power_battery_update_percent(uint16_t mv);
static void power_battery_check_empty(uint16_t mv);
static void power_battery_check_empty(void);
static void power_battery_check_low(uint16_t mv);
static void power_battery_periodic_log(uint16_t dt);
@@ -100,8 +101,8 @@ void app_power_init(void)
/**
* @brief 注册深睡请求的两段式回调
* @param on_request 刚请求深睡时调用(停电机、灯全灭
* @param on_finalize 50ms 后调用(真正进深睡,不会返回)
* @param on_request 刚请求深睡时调用(停电机;灯效由调用方按关机类型决定
* @param on_finalize 延时到点后调用(真正进深睡,不会返回)
* @return 无
*/
void app_power_set_hooks(AppPowerHook_t on_request, AppPowerHook_t on_finalize)
@@ -151,15 +152,16 @@ uint8_t app_power_low_bat(void)
}
/**
* @brief 请求深睡:立即触发 on_request 钩子,50ms 后触发 on_finalize
* @brief 请求深睡(按键 3s 等):立即触发 on_request 钩子,50ms 后触发 on_finalize
* @return 无
*/
void app_power_request_poweroff(void)
{
if (s_power.req_poweroff) {
return; /* 已经在关机流程里,不要重复挂 50ms 定时器 */
return; /* 已经在关机流程里,不要重复挂定时器 */
}
s_power.req_poweroff = 1;
s_power.empty_off = 0;
log_info("request deep off\n");
if (s_power.on_request) {
s_power.on_request(); /* 立刻停电机、灯全灭 */
@@ -167,6 +169,24 @@ void app_power_request_poweroff(void)
sys_timeout_add(NULL, power_do_poweroff, 50); /* 给 GPIO 落稳一点再真正掉电 */
}
/**
* @brief 空电关机:立刻停电机,等红灯闪完 5 下后再真正掉电
* @return 无
*/
void app_power_request_empty_poweroff(void)
{
if (s_power.req_poweroff) {
return;
}
s_power.req_poweroff = 1;
s_power.empty_off = 1;
log_info("request empty off, wait %ums\n", (unsigned)BOARD_LED_EMPTY_OFF_WAIT_MS);
if (s_power.on_request) {
s_power.on_request(); /* 立刻停电机,调用方挂空电红闪 */
}
sys_timeout_add(NULL, power_do_poweroff, BOARD_LED_EMPTY_OFF_WAIT_MS);
}
/**
* @brief 查询深睡请求是否已发起
* @return 1=已发起,0=未发起
@@ -176,6 +196,15 @@ uint8_t app_power_poweroff_pending(void)
return s_power.req_poweroff;
}
/**
* @brief 当前这次关机是否为空电路径
* @return 1=空电关机,0=普通关机
*/
uint8_t app_power_empty_off_pending(void)
{
return s_power.empty_off;
}
/**
* @brief 50ms 延时到点:真正进入深睡
* @param priv 未使用
@@ -304,31 +333,24 @@ static void power_battery_update_percent(uint16_t mv)
}
/**
* @brief 低电自动关机判定:连续 BAT_EMPTY_WIN 次采样都 <= SHUTDOWN_MV(约 5%)才认定,直接请求深睡
* @note 充电中不判定;用连续窗口而非单次采样,避免电机拉压降瞬间跌破误报
* 对应“电量低于 5% 自动关机”,与开机时的低电拦截(app_boot)用同一门限
* @param mv 本次均值电压,单位 mV
* @brief 空电关机判定:显示电量一到 <= 5% 立刻停电机并请求空电关机
* @note 充电中不判定。百分比已经在 app_battery 做过滤波/缓冲,这里不再做连续次数窗口
* 开机拦截(app_boot)仍用 BOARD_VBAT_SHUTDOWN_MV,因为那时电量算法还没跑
* @return 无
*/
static void power_battery_check_empty(uint16_t mv)
static void power_battery_check_empty(void)
{
AppBatteryAlarm_t *a = &s_power.alarm;
uint8_t pct = s_power.sample.pct;
if (s_power.charge.usb_online || mv > BOARD_VBAT_SHUTDOWN_MV) {
a->empty_win = 0; /* 充电中或电压还够,窗口清零 */
if (s_power.charge.usb_online || pct > BOARD_BATTERY_SHUTDOWN_PCT) {
return;
}
if (a->empty_win < 0xFF) {
a->empty_win++;
}
if (a->empty_win < BAT_EMPTY_WIN) {
return; /* 还没连续够次数,可能是电机拉压降的瞬间 */
}
a->low_bat = 1;
s_power.alarm.low_bat = 1;
gDevData.alm_low_battery = 1;
if (!s_power.req_poweroff) {
log_info("vbat %dmV <=5%%, deep off\n", mv);
app_power_request_poweroff();
log_info("battery %d%% <=%d%%, stop motor + blink red then off\n",
pct, BOARD_BATTERY_SHUTDOWN_PCT);
app_power_request_empty_poweroff();
}
}
@@ -391,10 +413,9 @@ static void power_battery_periodic_log(uint16_t dt)
/**
* @brief 电量采样与低电策略,每个业务 tick 调用一次
* @note 显示用的百分比(滤波/充放电基准/突变防抖/缓冲平滑)交给 app_battery
* 模块处理;这里的 check_empty/check_low 是另一套基于原始电压的
* 低电告警迟滞,直接判 mv 阈值,跟 app_battery 各管一段、互不干扰。
* check_low(3.7V)只负责红灯闪烁提示,不再有超时自动关机
* check_empty(约 5%/3.25V)才是真正触发自动关机的判定。
* 模块处理。check_low 仍按原始电压做 3.7V 红灯提示;check_empty
* 按显示电量 <= BOARD_BATTERY_SHUTDOWN_PCT5%)关机,跟 APP 看到
* 的数字对齐,避免电压先掉、百分比还没到 5% 就关机
* @param dt 距上次调用的毫秒数
* @return 无
*/
@@ -411,7 +432,7 @@ static void power_battery_tick(uint16_t dt)
power_battery_update_percent(mv);
/* 开机保护期内只更新百分比,不判定任何告警 */
if (s->boot_ms >= BAT_BOOT_MS) {
power_battery_check_empty(mv);
power_battery_check_empty();
power_battery_check_low(mv);
}
}
+21 -6
View File
@@ -2,10 +2,11 @@
* @file app_power.h
* @brief USB / 充电检测、电量采样与低电策略、深睡请求生命周期
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
* @date 2026.08.27
* @version V1.2.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现 USB/充电检测、电量采样与深睡请求
* - V1.2.0, 2026.08.27, cyWu, 显示电量到 5% 立即走空电关机(停电机、红灯闪 5 下再掉电)
*
* @note 本模块只管“电从哪来、还剩多少、要不要关机”,不认识电机/灯/按键。
* 需要在 USB 插拔 / 深睡时联动其它模块的地方,一律走 app_power_set_hooks
@@ -24,7 +25,7 @@ typedef enum {
APP_POWER_EVT_USB_OUT
} AppPowerEvt_t;
/** 深睡请求的钩子:on_request 用于立即停机(马达/灯),on_finalize 用于真正掉电 */
/** 深睡请求的钩子:on_request 立刻停电机并按关机类型处理灯;on_finalize 真正掉电 */
typedef void (*AppPowerHook_t)(void);
/**
@@ -35,8 +36,8 @@ void app_power_init(void);
/**
* @brief 注册深睡请求的两段式回调
* @param on_request 刚请求深睡时调用(停电机、灯全灭
* @param on_finalize 50ms 后调用(真正进深睡,不会返回)
* @param on_request 刚请求深睡时调用(停电机;灯效由调用方按关机类型决定
* @param on_finalize 延时到点后调用(真正进深睡,不会返回)
* @return 无
*/
void app_power_set_hooks(AppPowerHook_t on_request, AppPowerHook_t on_finalize);
@@ -67,15 +68,29 @@ uint8_t app_power_charge_led(void);
uint8_t app_power_low_bat(void);
/**
* @brief 请求深睡:立即触发 on_request 钩子,50ms 后触发 on_finalize
* @brief 请求深睡(按键 3s 等):立即触发 on_request 钩子,50ms 后触发 on_finalize
* @return 无
*/
void app_power_request_poweroff(void);
/**
* @brief 空电关机:立刻停电机,等红灯闪完 5 下后再真正掉电
* @note 调用方在 on_request 里根据 app_power_empty_off_pending() 挂空电灯效,
* 不要立刻灭灯。延时为 BOARD_LED_EMPTY_OFF_WAIT_MS。
* @return 无
*/
void app_power_request_empty_poweroff(void);
/**
* @brief 查询深睡请求是否已发起(发起后其它模块应停止响应新操作)
* @return 1=已发起,0=未发起
*/
uint8_t app_power_poweroff_pending(void);
/**
* @brief 当前这次关机是否为空电路径(红灯闪 5 下再掉电)
* @return 1=空电关机,0=普通关机
*/
uint8_t app_power_empty_off_pending(void);
#endif /* __APP_POWER_H__ */
+2 -1
View File
@@ -52,6 +52,7 @@ typedef enum {
LED_EVENT_PAIR_OK, /**< 配对成功常绿若干秒 */
LED_EVENT_PAIR_FAIL, /**< 配对失败红绿交替 */
LED_EVENT_OTA, /**< OTA:红绿交替闪,直到升级结束/复位 */
LED_EVENT_EMPTY, /**< 电量 5% 关机:关绿灯,红灯闪 5 下 */
LED_EVENT_MAX
} LED_Event_t;
@@ -62,7 +63,7 @@ typedef enum {
PRIORITY_1 = 0, /**< 待机绿灯 */
PRIORITY_2, /**< 低电红闪 */
PRIORITY_3, /**< 充电红 / 充满绿 */
PRIORITY_4, /**< 配对 / 切模式 / 配对结果 / OTA */
PRIORITY_4, /**< 配对 / 切模式 / 配对结果 / OTA / 5% 关机红闪 */
PRIORITY_MAX
} LED_EventPriority_t;
+27
View File
@@ -20,6 +20,7 @@ static uint8_t led_mode_handler(LED_Config_t *led_config);
static uint8_t led_pair_ok_handler(LED_Config_t *led_config);
static uint8_t led_pair_fail_handler(LED_Config_t *led_config);
static uint8_t led_ota_handler(LED_Config_t *led_config);
static uint8_t led_empty_handler(LED_Config_t *led_config);
/**
* @brief 只改掩码里的通道,其它灯保持原样
@@ -124,6 +125,20 @@ static uint8_t led_ota_handler(LED_Config_t *led_config)
return 1;
}
/**
* @brief 空电关机红闪:拦住其它灯,绿灯已关,只剩红灯闪 5 下
* @param led_config 配置
* @return 1=还在闪(拦住更低优先级),0=闪完已删事件
*/
static uint8_t led_empty_handler(LED_Config_t *led_config)
{
if (LED_Update(led_config) == 0) {
LED_EventDelete(LED_EVENT_EMPTY); /* 闪完 5 下后删,灯保持灭直到真正掉电 */
return 0;
}
return 1;
}
/**
* @brief 注册回调并装载 CBC2 事件表(GPIO 已在 bsp_hw_init
* @return 无
@@ -232,6 +247,18 @@ void user_led_init(void)
.config.runNum = 0, /* 0=无限 */
.ledEventHandler = led_ota_handler,
},
[LED_EVENT_EMPTY] = {
/* 电量 5%:关绿灯后只闪红灯 5 下,然后掉电 */
.event = LED_EVENT_EMPTY,
.priority = PRIORITY_4,
.config.ledMask = LED_CHANNEL(LED_CH_RED),
.config.state = LED_BLINKING,
.config.blinkParams.orDer = 0, /* 先亮后灭 */
.config.blinkParams.onTime = BOARD_LED_EMPTY_ON_MS,
.config.blinkParams.offTime = BOARD_LED_EMPTY_OFF_MS,
.config.runNum = BOARD_LED_EMPTY_BLINK_N,
.ledEventHandler = led_empty_handler,
},
};
LED_SetStateInit(set_led_multi);
+24 -4
View File
@@ -94,6 +94,7 @@ static UsrSchedulerCtx_t s_sched;
static void usr_timer_tick(void *priv);
static void usr_timer_rearm(UsrTickMode_t mode);
static void usr_log_boot_version(void);
/**
* @brief USB 插拔的联动:插入即停电机,拔出即软关并刷新系统电源图标
@@ -116,13 +117,18 @@ static void usr_on_power_evt(AppPowerEvt_t evt)
}
/**
* @brief 深睡请求钩子:立停电机、灯全灭(真正掉电在 50ms 后)
* @brief 深睡请求钩子:立停电机;空电路径挂红闪,按键关机则灯全灭
* @return 无
*/
static void usr_poweroff_request_hook(void)
{
app_function_stop_all();
app_led_clear();
if (app_power_empty_off_pending()) {
/* 电量到 5%:关绿灯,红灯闪 5 下,真正掉电等闪完 */
app_led_request_empty_off();
} else {
app_led_clear();
}
}
/**
@@ -220,8 +226,8 @@ static void usr_timer_tick(void *priv)
/* 重新查询而非复用上面的判断:user_key_handle() 可能在本拍内刚请求关机,
* 要用最新状态决定这一拍还要不要播灯效,否则会多播一帧才熄灭。
* OTA 期间灯效优先:关机钩子不要把红绿交替清掉。 */
if (app_led_is_ota()) {
* OTA / 空电红闪期间灯效优先:关机钩子不要把提示灯清掉。 */
if (app_led_is_ota() || app_led_is_empty_off()) {
app_led_run(dt, app_function_is_power_on());
} else if (app_power_poweroff_pending()) {
app_led_clear();
@@ -235,6 +241,18 @@ static void usr_timer_tick(void *priv)
}
}
/**
* @brief 上电打印固件版本与编译时间,方便串口对应当前是哪一包
* @return 无
*/
static void usr_log_boot_version(void)
{
log_info("sw V%d.%d.%d hw V%d.%d.%d build %s %s\n",
JB_MCU_SW_VERSION_MAJOR, JB_MCU_SW_VERSION_MINOR, JB_MCU_SW_VERSION_PATCH,
JB_MCU_HW_VERSION_MAJOR, JB_MCU_HW_VERSION_MINOR, JB_MCU_HW_VERSION_PATCH,
__DATE__, __TIME__);
}
/**
* @brief 业务初始化(在 BLE 栈起来之前由 app_main 调用)
* @note 内部会等按键 3s/5s;不足 3s 直接深睡,不会启动业务定时器。
@@ -245,6 +263,8 @@ static void usr_timer_tick(void *priv)
*/
void usr_jb_init(void)
{
usr_log_boot_version(); /* UART 已在 app_main 起来,按键判定前就能看到版本 */
bsp_hw_init();
app_boot_wait_key(); /* 深睡分支不会返回;返回即代表确定要开机 */
+19 -12
View File
@@ -2,8 +2,8 @@
* @file board_pin.h
* @brief CBC2 门夹弹力绳板级引脚、电平与时序(换板只改本文件)
* @author cyWu <1917507415@qq.com>
* @date 2026.08.26
* @version V1.4.0
* @date 2026.08.27
* @version V1.5.0
* @history
* - V1.0.0, 2026.08.21, cyWu, 首次发布
* - V1.1.0, 2026.08.24, cyWu, 收口:去掉实验开关与未贴件限位
@@ -12,6 +12,7 @@
* - V1.4.0, 2026.08.26, cyWu, 新增 5% 自动关机门限、开机低电闪灯拦截、
* 12s 长按 OTA、自动模式单次最长运行时长;
* 取消低电闪烁 1 分钟后自动关机门限
* - V1.5.0, 2026.08.27, cyWu, 运行中空电关机红闪 5 下时序宏
******************************************************************************/
#ifndef __BOARD_PIN_H__
@@ -54,16 +55,17 @@
/* 电量 / 充电 */
/*============================================================================*/
#define BOARD_VBAT_FULL_MV 4200 /**< 100% */
#define BOARD_VBAT_EMPTY_MV 3200 /**< 0%,电量曲线下限(仅用于百分比换算) */
#define BOARD_VBAT_CHARGE_FULL_MV 4250 /**< 充电基准未记录时 100%(充电内阻压降,比放电阈值高)*/
#define BOARD_VBAT_CHARGE_EMPTY_MV 3350 /**< 充电基准未记录时 0% */
#define BOARD_VBAT_LOW_MV 3700 /**< 低电预警阈值:只闪红灯提示,不关机 */
#define BOARD_VBAT_LOW_HYST_MV 50 /**< 低电恢复回差 */
#define BOARD_VBAT_SHUTDOWN_MV 3250 /**< 约 5%运行中低于此值自动关机;关机时低于此值拒绝开机 */
#define BOARD_VPWR_ONLINE_MV 4000 /**< VPWR 判定 USB 插入 */
#define BOARD_VPWR_OFF_MV 1500 /**< 低于此值认定已拔出 */
#define BOARD_CHG_FULL_MS 1000 /**< CHG 已高且 VPWR 在,满 1s 认充满 */
#define BOARD_VBAT_FULL_MV 4120 /**< 100% */
#define BOARD_VBAT_EMPTY_MV 3200 /**< 0%,电量曲线下限(仅用于百分比换算) */
#define BOARD_VBAT_CHARGE_FULL_MV 4200 /**< 充电基准未记录时 100%(充电内阻压降,比放电阈值高)*/
#define BOARD_VBAT_CHARGE_EMPTY_MV 3400 /**< 充电基准未记录时 0% */
#define BOARD_VBAT_LOW_MV 3700 /**< 低电预警阈值:只闪红灯提示,不关机 */
#define BOARD_VBAT_LOW_HYST_MV 50 /**< 低电恢复回差 */
#define BOARD_VBAT_SHUTDOWN_MV 3250 /**< 约 5%仅开机拦截用:关机状态下 app_battery 尚未运行,只能摸裸电压 */
#define BOARD_BATTERY_SHUTDOWN_PCT 5 /**< 运行中显示电量 <= 此值才自动关机,跟 APP 看到的百分比对齐 */
#define BOARD_VPWR_ONLINE_MV 4000 /**< VPWR 判定 USB 插入 */
#define BOARD_VPWR_OFF_MV 1500 /**< 低于此值认定已拔出 */
#define BOARD_CHG_FULL_MS 1000 /**< CHG 已高且 VPWR 在,满 1s 认充满 */
/*============================================================================*/
/* 按键 / 灯效 */
@@ -79,6 +81,11 @@
#define BOARD_BOOT_LOWBAT_BLINK_N 5 /**< 关机时电量过低:拒绝开机前红灯闪烁次数 */
#define BOARD_BOOT_LOWBAT_ON_MS 200 /**< 拒绝开机提示:闪烁亮时间 */
#define BOARD_BOOT_LOWBAT_OFF_MS 200 /**< 拒绝开机提示:闪烁灭时间 */
#define BOARD_LED_EMPTY_BLINK_N 5 /**< 运行中电量到 5%:红灯闪烁次数 */
#define BOARD_LED_EMPTY_ON_MS 200 /**< 5% 关机提示:闪烁亮时间 */
#define BOARD_LED_EMPTY_OFF_MS 200 /**< 5% 关机提示:闪烁灭时间 */
#define BOARD_LED_EMPTY_OFF_WAIT_MS ((BOARD_LED_EMPTY_ON_MS + BOARD_LED_EMPTY_OFF_MS) \
* BOARD_LED_EMPTY_BLINK_N + 50u) /**< 闪完再掉电,多留 50ms 让 GPIO 落稳 */
#define BOARD_LED_FAST_ON_MS 100 /**< 配对绿快闪:亮 */
#define BOARD_LED_FAST_OFF_MS 100 /**< 配对绿快闪:灭 */