diff --git a/apps/usr_jb_proto/usr_jb_main.c b/apps/usr_jb_proto/usr_jb_main.c index 5efc9c1..bef158c 100644 --- a/apps/usr_jb_proto/usr_jb_main.c +++ b/apps/usr_jb_proto/usr_jb_main.c @@ -3,7 +3,7 @@ * @brief CBC2 业务组合根:只做“先后调用谁、谁通知谁”,不含具体业务算法 * @author cyWu <1917507415@qq.com> * @date 2026.08.25 - * @version V2.0.0 + * @version V2.1.0 * @history * - V1.0.0, 2026.08.21, cyWu, 首次发布 * - V1.1.0, 2026.08.24, cyWu, 收口未接线模块;DP2 仅第 1 字节点动 1s @@ -13,6 +13,11 @@ * - V1.5.0, 2026.08.25, cyWu, LED/按键改充电板事件库,红绿可同时亮 * - V2.0.0, 2026.08.25, cyWu, 重构:电源/配对/开机/功能拆成独立模块, * 本文件只剩初始化顺序、1ms 调度、模块间接线 + * - V2.1.0, 2026.08.26, cyWu, 电机运转期间长期占用 1ms 硬件定时器中断, + * 配网连接后与 BLE 协议栈抢时序触发看门狗复位; + * 换向死区判定改用阈值检查而非精确计时, + * 取消专门的 1ms 高频档,全系统统一 20ms 节拍, + * 只保留"能不能休眠"这一个维度 * * @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData。 * usr_timer_loop 由 BLE 回调,勿再注册第二份。 @@ -61,18 +66,34 @@ const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = { JB_PRODUCT_CODE[3], JB_PRODUCT_CODE[4], JB_PRODUCT_CODE[5] }; -#define USR_TIMER_IDLE_MS 20 /**< 空闲节拍:可 sleep;按键 20ms 消抖对齐 */ +#define USR_TIMER_IDLE_MS 20 /**< 全局统一节拍:按键消抖、换向死区判定都按它对齐 */ + +/** + * @brief 业务节拍档位 + * @note 全系统只用一种节拍周期(USR_TIMER_IDLE_MS),区别只在"能不能休眠", + * 不存在专门的 1ms 高频档——之前为了电机换向死区(BOARD_MOTOR_REVERSE_MS) + * 单独开过 1ms 硬件定时器中断,配网连接后跟 BLE 协议栈自己的收发/ACK + * 处理抢时序,长时间叠加导致看门狗复位。 + * 换向死区的判定是"距上次换向是否已过 switch_ms"这种阈值检查,不是 + * 精确计时:用 20ms 节拍去查,查到时实际已经过了不少于 20ms,天然 + * 满足"至少 1ms"的死区要求,只会让保护更充分,不会失效。所以死区 + * 不需要专门的 1ms 精度,可以和其它业务共用同一个节拍。 + */ +typedef enum { + USR_TICK_IDLE = 0, /**< 可休眠 */ + USR_TICK_BLOCK_SLEEP /**< 禁止休眠(按键按住/玩法中/关机等待/电机运转,含换向死区)*/ +} UsrTickMode_t; /** 调度器状态,替代原来 2 个散落的 static */ typedef struct { - int timer_id; - uint8_t fast; /**< 1=1ms 高优(禁睡),0=空闲可休眠 */ + int timer_id; + UsrTickMode_t mode; } UsrSchedulerCtx_t; static UsrSchedulerCtx_t s_sched; -static void usr_timer_1_ms(void *priv); -static void usr_timer_rearm(uint8_t fast); +static void usr_timer_tick(void *priv); +static void usr_timer_rearm(UsrTickMode_t mode); /** * @brief USB 插拔的联动:插入即停电机,拔出即软关并刷新系统电源图标 @@ -123,50 +144,49 @@ static void usr_poweroff_finalize_hook(void) } /** - * @brief 电机/按键按住时用 1ms 高优定时器;空闲用可休眠节拍 - * @return 1=需要 1ms 高优,0=可休眠 + * @brief 按当前业务状态判断能不能休眠 + * @note 换向死区(bsp_motor_is_busy 已把它算进"忙")、点动、玩法、按键按住、 + * 关机等待,统一都是"不能睡",节拍周期都一样用 USR_TIMER_IDLE_MS, + * 不再区分要不要 1ms + * @return 本次应使用的档位 */ -static uint8_t usr_timer_should_fast(void) +static UsrTickMode_t usr_timer_pick_mode(void) { - if (app_function_is_hand_busy() || bsp_key_is_pressed() || app_power_poweroff_pending()) { - return 1; + if (bsp_key_is_pressed() || app_power_poweroff_pending() + || app_mode_get_active() || bsp_motor_is_busy() + || app_function_is_hand_busy()) { + return USR_TICK_BLOCK_SLEEP; } - if (app_mode_get_active() || bsp_motor_is_busy()) { - return 1; - } - return 0; + return USR_TICK_IDLE; } /** - * @brief 切换业务定时器。priority=1 时系统无法 sleep - * @param fast 1=1ms 高优,0=空闲可休眠 + * @brief 切换业务定时器。priority=1 时系统无法 sleep;节拍周期恒为 USR_TIMER_IDLE_MS + * @param mode 目标档位 * @return 无 */ -static void usr_timer_rearm(uint8_t fast) +static void usr_timer_rearm(UsrTickMode_t mode) { if (s_sched.timer_id) { usr_timer_del((u16)s_sched.timer_id); s_sched.timer_id = 0; } - s_sched.fast = fast; - if (fast) { - s_sched.timer_id = (int)sys_hi_timer_add(NULL, usr_timer_1_ms, 1); - } else { - s_sched.timer_id = (int)sys_s_hi_timer_add(NULL, usr_timer_1_ms, USR_TIMER_IDLE_MS); - } + s_sched.mode = mode; + s_sched.timer_id = (int)usr_timer_add(NULL, usr_timer_tick, USR_TIMER_IDLE_MS, + (mode == USR_TICK_BLOCK_SLEEP) ? 1 : 0); } /** - * @brief 业务定时器:空闲可 sleep;玩法/点动时 1ms 且禁 sleep + * @brief 业务定时器:固定 USR_TIMER_IDLE_MS 一拍;忙时禁睡,空闲可睡 * @param priv 未使用 * @note 禁止在这里直接 sys_enter_soft_poweroff,一律走 app_power 的深睡钩子 * @return 无 */ -static void usr_timer_1_ms(void *priv) +static void usr_timer_tick(void *priv) { - uint16_t dt = s_sched.fast ? 1 : USR_TIMER_IDLE_MS; + uint16_t dt = USR_TIMER_IDLE_MS; uint16_t i; - uint8_t want; + UsrTickMode_t want; AppPowerEvt_t pwr_evt; (void)priv; @@ -191,15 +211,15 @@ static void usr_timer_1_ms(void *priv) app_led_run(dt, app_function_is_power_on()); } - want = usr_timer_should_fast(); - if (want != s_sched.fast) { + want = usr_timer_pick_mode(); + if (want != s_sched.mode) { usr_timer_rearm(want); } } /** * @brief 业务初始化(在 BLE 栈起来之前由 app_main 调用) - * @note 内部会等按键 3s/5s;不足 3s 直接深睡,不会启动 1ms 定时器。 + * @note 内部会等按键 3s/5s;不足 3s 直接深睡,不会启动业务定时器。 * 按键判定只摸 bsp_hw 的裸 GPIO,不经过协议栈/灯效表/电机状态机, * 所以只有 bsp_hw_init() 需要排在它前面——一旦判定要睡回去, * boot_sleep() 原地喂狗不再返回,后面这些初始化不会被浪费。 @@ -224,7 +244,7 @@ void usr_jb_init(void) user_key_lock_if_held(); app_function_power_on_silent(); - usr_timer_rearm(0); + usr_timer_rearm(USR_TICK_IDLE); log_info("timer idle %ums, sleep ok\n", (unsigned)USR_TIMER_IDLE_MS); }