diff --git a/apps/earphone/board/br28/board_jl701n_demo.c b/apps/earphone/board/br28/board_jl701n_demo.c index fb938e1..ffc2626 100644 --- a/apps/earphone/board/br28/board_jl701n_demo.c +++ b/apps/earphone/board/br28/board_jl701n_demo.c @@ -24,6 +24,7 @@ #endif #include "norflash_sfc.h" #include "asm/power/power_port.h" +#include "bsp_hw.h" //#include "app_umidigi_chargestore.h" #if TCFG_AUDIO_ANC_ENABLE #include "audio_anc.h" @@ -1022,6 +1023,7 @@ void sleep_enter_callback(u8 step) { /* 此函数禁止添加打印 */ if (step == 1) { + bsp_hw_sleep_pwm_off(); putchar('<'); } else { gpio_set_pull_up(TCFG_CHARGESTORE_PORT, 0); diff --git a/apps/usr_app/app_cbc2.c b/apps/usr_app/app_cbc2.c index 5908a1d..7c9c28a 100644 --- a/apps/usr_app/app_cbc2.c +++ b/apps/usr_app/app_cbc2.c @@ -472,7 +472,7 @@ void app_cbc2_tick_1ms(void) led.app_power = s_app.power; led.low_bat = s_app.alm_low; led.life_on = (uint8_t)(s_app.life != APP_LIFE_CHARGE_ONLY); - app_led_tick_1ms(&led); + app_led_tick_1ms(&led, 1); } void app_cbc2_run(void *priv) diff --git a/apps/usr_app/app_led.c b/apps/usr_app/app_led.c index 2f12981..5280bda 100644 --- a/apps/usr_app/app_led.c +++ b/apps/usr_app/app_led.c @@ -1,11 +1,12 @@ /****************************************************************************** * @file app_led.c - * @brief CBC2 灯效:充电 > 配对 > APP 暂停 > 低电 > 切模式闪 > 开机常亮 + * @brief CBC2 灯效:充电 > 配对 > APP 暂停 > 低电 > 切模式闪 > 开机绿灯提示后灭 * @author cyWu <1917507415@qq.com> - * @date 2026.08.21 - * @version V1.0.0 + * @date 2026.08.25 + * @version V1.1.0 * @history * - V1.0.0, 2026.08.21, cyWu, 首次发布 + * - V1.1.0, 2026.08.25, cyWu, 开机绿灯只提示几秒,避免待机常亮耗电 ******************************************************************************/ #include "app_led.h" @@ -19,6 +20,7 @@ static uint16_t s_mode_ms; static uint8_t s_mode_on; static uint16_t s_pair_res_ms; static uint8_t s_pair_res; /* 0 none 1 ok 2 fail */ +static uint16_t s_power_green_ms; /* 开机绿灯剩余 ms,0 则待机灭灯 */ /** * @brief 灯效初始化,先全灭 @@ -30,6 +32,7 @@ AppLed_Ret_t app_led_init(void) return APP_LED_OK; } bsp_led_all_off(); + s_power_green_ms = BOARD_LED_POWER_ON_MS; s_initialized = 1; return APP_LED_OK; } @@ -54,6 +57,15 @@ void app_led_request_mode_blink(void) s_mode_on = 0; } +/** + * @brief 重新亮几秒开机绿灯(上电 / APP 再开) + * @return 无 + */ +void app_led_hint_power_on(void) +{ + s_power_green_ms = BOARD_LED_POWER_ON_MS; +} + /** * @brief 播放一次性配对结果灯:成功常绿,失败红绿交替 * @param ok 1=成功,0=失败 @@ -67,11 +79,12 @@ void app_led_start_pair_result(uint8_t ok) } /** - * @brief 按优先级刷新灯,1ms 调用 + * @brief 按优先级刷新灯 * @param ctx 当前充电/配对/开关/低电;为空则直接返回 + * @param dt 距上次调用的毫秒数 * @return 无 */ -void app_led_tick_1ms(const AppLedCtx_t *ctx) +void app_led_tick_1ms(const AppLedCtx_t *ctx, uint16_t dt) { uint8_t red = 0; uint8_t green = 0; @@ -79,8 +92,11 @@ void app_led_tick_1ms(const AppLedCtx_t *ctx) if (!s_initialized || !ctx) { return; } + if (dt == 0) { + dt = 1; + } - s_phase_ms++; + s_phase_ms = (uint16_t)(s_phase_ms + dt); /* 1-2 充电独占 */ if (ctx->charge_led == 1) { @@ -117,11 +133,11 @@ void app_led_tick_1ms(const AppLedCtx_t *ctx) green = 1; } } - if (s_pair_res_ms > 0) { - s_pair_res_ms--; - if (s_pair_res_ms == 0) { - s_pair_res = 0; - } + if (s_pair_res_ms > dt) { + s_pair_res_ms = (uint16_t)(s_pair_res_ms - dt); + } else { + s_pair_res_ms = 0; + s_pair_res = 0; } bsp_led_red_set(red); bsp_led_green_set(green); @@ -145,7 +161,7 @@ void app_led_tick_1ms(const AppLedCtx_t *ctx) /* 7 切模式闪 2 下 */ if (s_mode_left) { - s_mode_ms++; + s_mode_ms = (uint16_t)(s_mode_ms + dt); if (!s_mode_on) { if (s_mode_ms >= BOARD_LED_MODE_OFF_MS) { s_mode_ms = 0; @@ -165,12 +181,26 @@ void app_led_tick_1ms(const AppLedCtx_t *ctx) return; } - /* 8 开机绿灯常亮 */ +#if BOARD_LED_STANDBY_ON + /* 待机绿灯常亮 */ if (ctx->life_on && ctx->app_power) { bsp_led_red_set(0); bsp_led_green_set(1); return; } +#else + /* 开机绿灯只亮几秒,用来对比灭灯待机电流 */ + if (ctx->life_on && ctx->app_power && s_power_green_ms) { + if (s_power_green_ms > dt) { + s_power_green_ms = (uint16_t)(s_power_green_ms - dt); + } else { + s_power_green_ms = 0; + } + bsp_led_red_set(0); + bsp_led_green_set(1); + return; + } +#endif bsp_led_all_off(); } diff --git a/apps/usr_app/app_led.h b/apps/usr_app/app_led.h index 42383c6..1612ab1 100644 --- a/apps/usr_app/app_led.h +++ b/apps/usr_app/app_led.h @@ -1,11 +1,12 @@ /****************************************************************************** * @file app_led.h - * @brief CBC2 灯效优先级:充电 > 配对 > 软关 > 低电 > 切模式闪 > 绿灯 + * @brief CBC2 灯效优先级:充电 > 配对 > 软关 > 低电 > 切模式闪 > 开机绿灯提示后灭 * @author cyWu <1917507415@qq.com> - * @date 2026.08.21 - * @version V1.0.0 + * @date 2026.08.25 + * @version V1.1.0 * @history * - V1.0.0, 2026.08.21, cyWu, 首次发布 + * - V1.1.0, 2026.08.25, cyWu, 开机绿灯只提示几秒,避免待机常亮耗电 ******************************************************************************/ #ifndef __APP_LED_H__ @@ -33,11 +34,12 @@ typedef struct { AppLed_Ret_t app_led_init(void); /** - * @brief 1ms 按优先级刷新灯 + * @brief 按优先级刷新灯 * @param ctx 充电/配对/开关/低电状态,不可为空 + * @param dt 距上次调用的毫秒数 * @return 无 */ -void app_led_tick_1ms(const AppLedCtx_t *ctx); +void app_led_tick_1ms(const AppLedCtx_t *ctx, uint16_t dt); /** * @brief 请求切模式绿灯闪两下 @@ -45,6 +47,12 @@ void app_led_tick_1ms(const AppLedCtx_t *ctx); */ void app_led_request_mode_blink(void); +/** + * @brief 重新亮几秒开机绿灯 + * @return 无 + */ +void app_led_hint_power_on(void); + /** * @brief 播放一次性配对结果灯 * @param ok 1=成功常绿,0=失败红绿交替 diff --git a/apps/usr_jb_proto/usr_jb_main.c b/apps/usr_jb_proto/usr_jb_main.c index 3724c39..ce9c7ef 100644 --- a/apps/usr_jb_proto/usr_jb_main.c +++ b/apps/usr_jb_proto/usr_jb_main.c @@ -2,16 +2,17 @@ * @file usr_jb_main.c * @brief CBC2 业务主循环:按键 / 充电 / 电量 / 灯 / 6 档玩法 / 手动点动 * @author cyWu <1917507415@qq.com> - * @date 2026.08.24 - * @version V1.3.0 + * @date 2026.08.25 + * @version V1.4.0 * @history * - V1.0.0, 2026.08.21, cyWu, 首次发布 * - V1.1.0, 2026.08.24, cyWu, 收口未接线模块;DP2 仅第 1 字节点动 1s * - V1.2.0, 2026.08.24, cyWu, 按键:深睡 3s 开机、5s 开机+配对;开机中 3s 深睡 * - V1.3.0, 2026.08.24, cyWu, DP2:00=空闲,01/02 转,03 停 + * - V1.4.0, 2026.08.25, cyWu, 空闲改可休眠定时器,系统才能进 sleep * - * @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData, - * 本文件 1ms 轮询执行。usr_timer_loop 由 BLE 库回调,勿再注册第二份。 + * @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData。 + * usr_timer_loop 由 BLE 回调,勿再注册第二份。 ******************************************************************************/ #include "system/includes.h" @@ -39,7 +40,7 @@ #define LOG_INFO_ENABLE #include "debug.h" -/* 向 usr_le_code 库提供产品身份(换产品只改 jb_protocol.h 宏即可) */ +/* 向 usr_le_code 提供产品身份(换产品只改 jb_protocol.h 宏即可) */ const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN] = { JB_CATEGORY_CODE[0], JB_CATEGORY_CODE[1], JB_CATEGORY_CODE[2], JB_CATEGORY_CODE[3] @@ -50,11 +51,13 @@ const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = { }; static void usr_timer_1_ms(void *priv); +static void usr_timer_rearm(uint8_t fast); void usr_timer_loop(void); extern void clr_wdt(void); extern u32 timer_get_ms(void); static int jb_timer_id; +static uint8_t s_timer_fast; /**< 1=1ms 高优(禁睡),0=空闲可休眠 */ static uint8_t s_pairing; /**< 1=深睡 5s 进入配对中 */ static uint8_t s_play_mode; /**< 当前自动模式 0~6 */ static uint8_t s_key_raw; @@ -88,10 +91,24 @@ static volatile uint8_t s_hand_write_pending; /**< DP2 刚写入(03 停转要 static volatile uint8_t s_hand_write_cmd; static uint32_t s_pair_ms; /**< 配对已持续 ms,满 60s 判失败 */ +/** + * @brief 毫秒累加,饱和到 0xFFFF + * @param v 当前值 + * @param dt 增加量 + * @return 累加结果 + */ +static uint16_t usr_add_ms(uint16_t v, uint16_t dt) +{ + uint32_t n = (uint32_t)v + dt; + + return (n > 0xffffu) ? 0xffffu : (uint16_t)n; +} + #define BAT_SAMPLE_MS 100 #define BAT_AVG_N 8 #define BAT_BOOT_MS 3000 /* 上电 3s 内不因低电深睡 */ #define BAT_LOG_MS 10000 +#define USR_TIMER_IDLE_MS 20 /* 空闲节拍:可 sleep;按键 20ms 消抖对齐 */ #define BAT_LOW_WIN 3 /* 连续约 2.4s 才进低电告警 */ #define BAT_EMPTY_WIN 5 /* 连续约 4s 才 3.2V 深睡 */ @@ -313,6 +330,7 @@ static void usr_app_power_poll(void) } if (gDevData.power && !s_app_power) { s_app_power = 1; + app_led_hint_power_on(); log_info("APP power on\n"); } else if (!gDevData.power && s_app_power) { usr_app_soft_off(); @@ -376,15 +394,13 @@ static void usr_hand_poll(void) * @brief 手动运行时推进刹车;停转改由 DP2 写 03 * @return 无 */ -static void usr_hand_tick_1ms(void) +static void usr_hand_tick_1ms(uint16_t dt) { if (!s_hand_busy) { return; } bsp_motor_brake_tick(); - if (s_hand_ms < 0xffff) { - s_hand_ms++; - } + s_hand_ms = usr_add_ms(s_hand_ms, dt); } /** @@ -450,17 +466,18 @@ static uint8_t usr_bat_percent(uint16_t mv) * @note 电机运转时只记电压、不改百分比/告警,避免电流拉垮 VBAT 误报 * @return 无 */ -static void usr_bat_tick_1ms(void) +static void usr_bat_tick_1ms(uint16_t dt) { uint16_t mv; uint8_t pct; uint8_t motor_busy; if (s_bat_boot_ms < BAT_BOOT_MS) { - s_bat_boot_ms++; + s_bat_boot_ms = usr_add_ms(s_bat_boot_ms, dt); } - if (++s_bat_tick >= BAT_SAMPLE_MS) { + s_bat_tick = usr_add_ms(s_bat_tick, dt); + if (s_bat_tick >= BAT_SAMPLE_MS) { s_bat_tick = 0; s_bat_acc += bsp_vbat_mv(); s_bat_n++; @@ -531,14 +548,16 @@ static void usr_bat_tick_1ms(void) if (s_usb_online || s_req_poweroff || (s_bat_boot_ms < BAT_BOOT_MS)) { s_low_ms = 0; } else if (s_low_bat && (s_low_ms < BOARD_LOWBAT_SLEEP_MS)) { - s_low_ms++; - if (s_low_ms == BOARD_LOWBAT_SLEEP_MS) { + s_low_ms += dt; + if (s_low_ms >= BOARD_LOWBAT_SLEEP_MS) { + s_low_ms = BOARD_LOWBAT_SLEEP_MS; log_info("low battery 1min, deep off\n"); usr_key_request_poweroff(); } } - if (++s_bat_log_ms >= BAT_LOG_MS) { + s_bat_log_ms = usr_add_ms(s_bat_log_ms, dt); + if (s_bat_log_ms >= BAT_LOG_MS) { s_bat_log_ms = 0; log_info("bat %d%% %dmV alm=%d\n", s_bat_pct, s_bat_mv, s_low_bat); } @@ -583,9 +602,10 @@ static void usr_key_init(void) * @note 开机中即使按满 5s 也不进配对。配对只在深睡长按 5s、BLE 起来前判定 * @return 无 */ -static void usr_key_tick_1ms(void) +static void usr_key_tick_1ms(uint16_t dt) { uint8_t raw; + uint16_t hold_old; if (s_req_poweroff) { return; @@ -595,7 +615,10 @@ static void usr_key_tick_1ms(void) if (raw == s_key_raw) { if (s_key_cnt < BOARD_KEY_DEBOUNCE_MS) { - s_key_cnt++; + s_key_cnt = (uint8_t)usr_add_ms(s_key_cnt, dt); + if (s_key_cnt > BOARD_KEY_DEBOUNCE_MS) { + s_key_cnt = BOARD_KEY_DEBOUNCE_MS; + } } } else { s_key_raw = raw; @@ -604,7 +627,7 @@ static void usr_key_tick_1ms(void) if (s_key_cnt != BOARD_KEY_DEBOUNCE_MS) { if (s_key_pressed && !s_boot_key_lock) { - s_key_hold_ms++; + s_key_hold_ms = usr_add_ms(s_key_hold_ms, dt); } return; } @@ -624,6 +647,7 @@ static void usr_key_tick_1ms(void) } else if (!s_app_power) { s_app_power = 1; gDevData.power = 1; + app_led_hint_power_on(); log_info("key click cancel soft off\n"); } else { usr_key_on_click(); @@ -634,8 +658,9 @@ static void usr_key_tick_1ms(void) } if (s_key_pressed && !s_boot_key_lock) { - s_key_hold_ms++; - if (s_key_hold_ms == BOARD_KEY_POWER_MS) { + hold_old = s_key_hold_ms; + s_key_hold_ms = usr_add_ms(s_key_hold_ms, dt); + if ((hold_old < BOARD_KEY_POWER_MS) && (s_key_hold_ms >= BOARD_KEY_POWER_MS)) { if (s_usb_online) { log_info("key hold 3s ignored, charging\n"); } else if (s_pairing) { @@ -652,7 +677,7 @@ static void usr_key_tick_1ms(void) * @brief 充电检测:CHG 低=充电中;VPWR 在且 CHG 高满 1s=充满;拔电软关 * @return 无 */ -static void usr_chg_tick_1ms(void) +static void usr_chg_tick_1ms(uint16_t dt) { uint8_t chg_low = bsp_chg_is_low(); uint8_t vpwr = bsp_vpwr_is_online(); @@ -665,9 +690,7 @@ static void usr_chg_tick_1ms(void) usb = 1; } else if (vpwr) { /* 拔电时 CHG 先变高、VPWR 还没掉,不能立刻当充满 */ - if (s_full_ms < 0xFFFF) { - s_full_ms++; - } + s_full_ms = usr_add_ms(s_full_ms, dt); if (s_full_ms >= BOARD_CHG_FULL_MS) { s_charge_led = 2; } @@ -710,7 +733,7 @@ static void usr_chg_tick_1ms(void) * @brief 组装灯效上下文:充电 > 配对 > 软关灭灯 > 低电 > 切模式闪 > 绿灯 * @return 无 */ -static void usr_led_tick_1ms(void) +static void usr_led_tick_1ms(uint16_t dt) { AppLedCtx_t led; uint8_t paired; @@ -728,16 +751,23 @@ static void usr_led_tick_1ms(void) s_pairing = 0; s_pair_ms = 0; log_info("pair ok\n"); - } else if (++s_pair_ms >= BOARD_PAIR_TIMEOUT_MS) { - s_pairing = 0; - s_pair_ms = 0; - app_led_start_pair_result(0); - log_info("pair timeout 60s, stay on\n"); + } else { + s_pair_ms += dt; + if (s_pair_ms >= BOARD_PAIR_TIMEOUT_MS) { + s_pairing = 0; + s_pair_ms = 0; + app_led_start_pair_result(0); + log_info("pair timeout 60s, stay on\n"); + } } } if (s_key_led_override_ms) { - s_key_led_override_ms--; + if (s_key_led_override_ms > dt) { + s_key_led_override_ms = (uint16_t)(s_key_led_override_ms - dt); + } else { + s_key_led_override_ms = 0; + } } memset(&led, 0, sizeof(led)); @@ -746,7 +776,7 @@ static void usr_led_tick_1ms(void) led.app_power = s_app_power; led.low_bat = s_low_bat; led.life_on = 1; - app_led_tick_1ms(&led); + app_led_tick_1ms(&led, dt); } /** @@ -773,33 +803,77 @@ void usr_jb_init(void) s_hand_write_cmd = 0; s_charge_led_last = 0xff; - if (jb_timer_id == 0) { - jb_timer_id = sys_hi_timer_add(NULL, usr_timer_1_ms, TIMER_PERIOD_MS); + usr_timer_rearm(0); + log_info("timer idle %ums, sleep ok\n", (unsigned)USR_TIMER_IDLE_MS); +} + +/** + * @brief 电机/按键按住时用 1ms 高优定时器;空闲用可休眠节拍 + * @return 1=需要 1ms 高优,0=可休眠 + */ +static uint8_t usr_timer_should_fast(void) +{ + if (s_hand_busy || s_key_pressed || s_req_poweroff) { + return 1; + } + if (app_mode_get_active() || bsp_motor_is_busy()) { + return 1; + } + return 0; +} + +/** + * @brief 切换业务定时器。priority=1 时系统无法 sleep + * @param fast 1=1ms 高优,0=空闲可休眠 + * @return 无 + */ +static void usr_timer_rearm(uint8_t fast) +{ + if (jb_timer_id) { + usr_timer_del((u16)jb_timer_id); + jb_timer_id = 0; + } + s_timer_fast = fast; + if (fast) { + jb_timer_id = (int)sys_hi_timer_add(NULL, usr_timer_1_ms, 1); + } else { + jb_timer_id = (int)sys_s_hi_timer_add(NULL, usr_timer_1_ms, USR_TIMER_IDLE_MS); } } /** - * @brief 约 1ms 高优定时器:按键/充电/电量/DP 轮询/电机节拍/灯 + * @brief 业务定时器:空闲可 sleep;玩法/点动时 1ms 且禁 sleep * @param priv 未使用 - * @note 用 sys_hi_timer(priority=1)避免休眠把节拍拉长。禁止在这里直接 sys_enter_soft_poweroff + * @note 禁止在这里直接 sys_enter_soft_poweroff * @return 无 */ static void usr_timer_1_ms(void *priv) { + uint16_t dt = s_timer_fast ? 1 : USR_TIMER_IDLE_MS; + uint16_t i; + uint8_t want; + (void)priv; - jbTimerIrq(); - usr_key_tick_1ms(); - usr_chg_tick_1ms(); - usr_bat_tick_1ms(); + for (i = 0; i < dt; i++) { + jbTimerIrq(); + } + usr_key_tick_1ms(dt); + usr_chg_tick_1ms(dt); + usr_bat_tick_1ms(dt); usr_app_power_poll(); usr_hand_poll(); usr_play_mode_poll(); if (s_hand_busy) { - usr_hand_tick_1ms(); + usr_hand_tick_1ms(dt); } else { app_mode_run(); } - usr_led_tick_1ms(); + usr_led_tick_1ms(dt); + + want = usr_timer_should_fast(); + if (want != s_timer_fast) { + usr_timer_rearm(want); + } } /** @@ -814,7 +888,7 @@ void usr_jb_le_recieve_data(u8 *data, u16 len) } /** - * @brief 约 500ms:协议收包与 DP 上报(由 usr_le_code 库回调,不要再注册一份) + * @brief 约 500ms:协议收包与 DP 上报(由 usr_le_code 回调,不要再注册一份) * @return 无 */ void usr_timer_loop(void) diff --git a/apps/usr_periph/board_pin.h b/apps/usr_periph/board_pin.h index 00ef301..65084dc 100644 --- a/apps/usr_periph/board_pin.h +++ b/apps/usr_periph/board_pin.h @@ -80,6 +80,8 @@ #define BOARD_LED_MODE_OFF_MS 150 /**< 切模式闪:灭 */ #define BOARD_LED_MODE_ON_MS 150 /**< 切模式闪:亮 */ #define BOARD_LED_MODE_BLINK_N 2 /**< 切模式闪次数 */ +#define BOARD_LED_STANDBY_ON 1 /**< 1=待机绿灯常亮;0=亮完 BOARD_LED_POWER_ON_MS 后灭(对比电流) */ +#define BOARD_LED_POWER_ON_MS 3000 /**< BOARD_LED_STANDBY_ON=0 时的开机绿灯时长 */ /*============================================================================*/ /* 电机 */ @@ -90,5 +92,6 @@ #define BOARD_HAND_PULSE_MS 1000 /**< 预留;手动 1/2 一直转到写 03 停止 */ #define BOARD_MOTOR_PWM_HZ 20000 /**< MCPWM 频率(Hz),20k 避开可听啸叫 */ #define BOARD_MOTOR_PWM_DUTY 8000 /**< 占空比 0~10000=0%~100%,80% */ +#define BOARD_MOTOR_PWM_IDLE_CLOSE 1 /**< 1=空闲/轻睡关 MCPWM;0=保持开着,方便对比待机电流 */ #endif /* __BOARD_PIN_H__ */ diff --git a/apps/usr_periph/bsp_hw.c b/apps/usr_periph/bsp_hw.c index 425c3c3..74cca6b 100644 --- a/apps/usr_periph/bsp_hw.c +++ b/apps/usr_periph/bsp_hw.c @@ -3,12 +3,13 @@ * @brief CBC2 板级 GPIO / ADC:电机 H 桥、LED、按键、充电检测 * @author cyWu <1917507415@qq.com> * @date 2026.08.24 - * @version V1.4.0 + * @version V1.5.0 * @history * - V1.0.0, 2026.08.21, cyWu, 首次发布 * - V1.1.0, 2026.08.24, cyWu, 停转反转刹车;去掉限位脚 * - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 占空比降速 * - V1.4.0, 2026.08.24, cyWu, 增加按占空比驱动,供玩法变速 + * - V1.5.0, 2026.08.25, cyWu, 空闲关闭 MCPWM 时钟 ******************************************************************************/ #include "system/includes.h" @@ -31,6 +32,7 @@ static uint16_t s_motor_duty; static uint16_t s_pending_duty; static uint16_t s_brake_ms; static u32 s_brake_t0; +static uint8_t s_pwm_clk_on; /**< 1=MCPWM 已打开 */ extern u32 timer_get_ms(void); @@ -99,10 +101,49 @@ static void bsp_motor_pwm_init(void) mcpwm_set_duty(pwm_ch0, 0); mcpwm_set_duty(pwm_ch1, 0); + s_pwm_clk_on = 1; log_info("motor pwm %uHz duty=%u/10000\n", (unsigned)BOARD_MOTOR_PWM_HZ, (unsigned)BOARD_MOTOR_PWM_DUTY); } +/** + * @brief 打开 MCPWM 并绑回 INA/INB + * @return 无 + */ +static void bsp_motor_pwm_clock_on(void) +{ + if (s_pwm_clk_on) { + return; + } + mcpwm_open(pwm_ch0); + mcpwm_open(pwm_ch1); + gpio_och_sel_output_signal(BOARD_MOTOR_INA_PIN, OUTPUT_CH_SIGNAL_MC_PWM0_H); + gpio_och_sel_output_signal(BOARD_MOTOR_INB_PIN, OUTPUT_CH_SIGNAL_MC_PWM1_H); + gpio_set_direction(BOARD_MOTOR_INA_PIN, 0); + gpio_set_direction(BOARD_MOTOR_INB_PIN, 0); + s_pwm_clk_on = 1; +} + +/** + * @brief 关闭 MCPWM 时钟,INA/INB 拉低(待机必关) + * @return 无 + */ +static void bsp_motor_pwm_clock_off(void) +{ + mcpwm_set_duty(pwm_ch0, 0); + mcpwm_set_duty(pwm_ch1, 0); + if (s_pwm_clk_on) { + mcpwm_close(pwm_ch0); + mcpwm_close(pwm_ch1); + gpio_och_disable_output_signal(BOARD_MOTOR_INA_PIN, OUTPUT_CH_SIGNAL_MC_PWM0_H); + gpio_och_disable_output_signal(BOARD_MOTOR_INB_PIN, OUTPUT_CH_SIGNAL_MC_PWM1_H); + JL_MCPWM->MCPWM_CON0 = 0; + s_pwm_clk_on = 0; + } + gpio_direction_output(BOARD_MOTOR_INA_PIN, 0); + gpio_direction_output(BOARD_MOTOR_INB_PIN, 0); +} + /** * @brief 立刻改 INA/INB PWM。运转脚输出 duty,另一脚 0%;STOP=两路 0% * @param dir 目标方向 @@ -132,6 +173,14 @@ static void bsp_motor_gpio(BspMotorDir_t dir, uint16_t duty) } } + if ((ina_duty == 0) && (inb_duty == 0)) { +#if BOARD_MOTOR_PWM_IDLE_CLOSE + bsp_motor_pwm_clock_off(); + return; +#endif + } else { + bsp_motor_pwm_clock_on(); + } mcpwm_set_duty(pwm_ch0, ina_duty); mcpwm_set_duty(pwm_ch1, inb_duty); } @@ -175,6 +224,9 @@ BspHw_Ret_t bsp_hw_init(void) s_motor_duty = 0; s_pending_duty = 0; s_brake_ms = 0; +#if BOARD_MOTOR_PWM_IDLE_CLOSE + bsp_motor_pwm_clock_off(); +#endif #endif s_initialized = 1; @@ -408,6 +460,45 @@ uint8_t bsp_vpwr_is_online(void) #endif } +/** + * @brief 轻睡前关掉空闲电机 PWM(电机忙碌时不关,避免玩法被掐断) + * @return 无 + */ +void bsp_hw_sleep_pwm_off(void) +{ +#if BOARD_MOTOR_ENABLE && BOARD_MOTOR_PWM_IDLE_CLOSE + if (!s_initialized) { + return; + } + if (bsp_motor_is_busy()) { + return; + } + bsp_motor_pwm_clock_off(); +#endif +} + +/** + * @brief 电机是否还在转或刹车 + * @return 1=忙碌,0=已停且 PWM 已关 + */ +uint8_t bsp_motor_is_busy(void) +{ +#if !BOARD_MOTOR_ENABLE + return 0; +#else + if (s_brake_ms) { + return 1; + } + if (s_motor_dir != BSP_MOTOR_STOP) { + return 1; + } + if (s_motor_pending != BSP_MOTOR_STOP) { + return 1; + } + return 0; +#endif +} + /** * @brief 进深睡前把电机 PWM 关掉并拉低,灯全灭 * @return 无 @@ -416,14 +507,11 @@ void bsp_hw_enter_sleep_io(void) { bsp_motor_set(BSP_MOTOR_STOP); #if BOARD_MOTOR_ENABLE - mcpwm_set_duty(pwm_ch0, 0); - mcpwm_set_duty(pwm_ch1, 0); - mcpwm_close(pwm_ch0); - mcpwm_close(pwm_ch1); - gpio_och_disable_output_signal(BOARD_MOTOR_INA_PIN, OUTPUT_CH_SIGNAL_MC_PWM0_H); - gpio_och_disable_output_signal(BOARD_MOTOR_INB_PIN, OUTPUT_CH_SIGNAL_MC_PWM1_H); - gpio_direction_output(BOARD_MOTOR_INA_PIN, 0); - gpio_direction_output(BOARD_MOTOR_INB_PIN, 0); + s_brake_ms = 0; + s_motor_dir = BSP_MOTOR_STOP; + s_motor_pending = BSP_MOTOR_STOP; + s_motor_duty = 0; + bsp_motor_pwm_clock_off(); #endif bsp_led_all_off(); } diff --git a/apps/usr_periph/bsp_hw.h b/apps/usr_periph/bsp_hw.h index d7c7287..5f11759 100644 --- a/apps/usr_periph/bsp_hw.h +++ b/apps/usr_periph/bsp_hw.h @@ -3,12 +3,13 @@ * @brief CBC2 板级硬件:电机 / LED / 按键 / 充电 / 电量 * @author cyWu <1917507415@qq.com> * @date 2026.08.24 - * @version V1.4.0 + * @version V1.5.0 * @history * - V1.0.0, 2026.08.21, cyWu, 首次发布 * - V1.1.0, 2026.08.24, cyWu, 停转改为反转刹车;去掉未贴件限位 * - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 50% 占空比降速 * - V1.4.0, 2026.08.24, cyWu, 增加按占空比驱动,供玩法变速 + * - V1.5.0, 2026.08.25, cyWu, 空闲关闭 MCPWM 时钟,避免待机空转耗电 ******************************************************************************/ #ifndef __BSP_HW_H__ @@ -83,6 +84,12 @@ void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty); */ void bsp_motor_brake_tick(void); +/** + * @brief 电机是否还在转或刹车 + * @return 1=忙碌,0=已停且 PWM 已关 + */ +uint8_t bsp_motor_is_busy(void); + /** * @brief 读取按键 * @return 1=按下,0=未按下 @@ -113,6 +120,12 @@ uint16_t bsp_vpwr_mv(void); */ uint8_t bsp_vpwr_is_online(void); +/** + * @brief 轻睡前关掉空闲电机 PWM(电机忙碌时不关) + * @return 无 + */ +void bsp_hw_sleep_pwm_off(void); + /** * @brief 进深睡前把电机 PWM 关掉并拉低,灯全灭 * @return 无