From 93c19439920a9a77a314ac557abaa10b12f91889 Mon Sep 17 00:00:00 2001 From: Wuchuyuan <1917507415@qq.com> Date: Tue, 25 Aug 2026 20:05:59 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=85=85=E7=94=B5=E6=97=B6=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E5=8F=A0=E5=BE=85=E6=9C=BA=E7=BB=BF=E7=81=AF=EF=BC=9B?= =?UTF-8?q?=E6=84=8F=E5=A4=96=E5=A4=8D=E4=BD=8D=E4=B8=8D=E5=86=8D=E8=B7=B3?= =?UTF-8?q?=E8=BF=87=203s=20=E5=BC=80=E6=9C=BA=E6=8C=89=E9=94=AE=E5=88=A4?= =?UTF-8?q?=E5=AE=9A=202=E3=80=81=E7=94=B5=E6=9C=BA=E5=81=9C=E8=BD=AC?= =?UTF-8?q?=E5=8E=BB=E6=8E=89=E5=8F=8D=E6=8E=A5=E5=88=B9=E8=BD=A6=E6=94=B9?= =?UTF-8?q?=E8=87=AA=E7=94=B1=E6=BB=91=E8=A1=8C=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E7=94=B5=E6=B5=81=E5=86=B2=E5=87=BB=E8=A7=A6=E5=8F=91=20LVD=20?= =?UTF-8?q?=E5=A4=8D=E4=BD=8D=EF=BC=9B=203=E3=80=81=E5=85=B3=E6=9C=BA?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=20power=5Fset=5Fsoft=5Fpoweroff=EF=BC=8C?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E8=80=B3=E6=9C=BA=20SDK=20=E4=BC=98=E9=9B=85?= =?UTF-8?q?=E5=85=B3=E6=9C=BA=E6=B5=81=E7=A8=8B=EF=BC=8C=E6=8C=89=E9=94=AE?= =?UTF-8?q?=E5=85=B3=E6=9C=BA=E4=BB=8E=E5=8D=81=E5=87=A0=E7=A7=92=E5=8E=8B?= =?UTF-8?q?=E5=88=B0=E7=9E=AC=E9=97=B4=E6=8E=89=E7=94=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/usr_app/app_boot.c | 20 ++++---- apps/usr_app/app_function.c | 2 +- apps/usr_app/app_led.c | 3 +- apps/usr_app/app_mode.c | 2 +- apps/usr_jb_proto/usr_jb_main.c | 15 ++++-- apps/usr_periph/board_pin.h | 1 - apps/usr_periph/bsp_hw.c | 82 ++++++++++++++++----------------- apps/usr_periph/bsp_hw.h | 14 +++--- 8 files changed, 72 insertions(+), 67 deletions(-) diff --git a/apps/usr_app/app_boot.c b/apps/usr_app/app_boot.c index c2d745b..fabe96e 100644 --- a/apps/usr_app/app_boot.c +++ b/apps/usr_app/app_boot.c @@ -80,16 +80,16 @@ static uint8_t boot_skip_key_wait(void) boot_delay_ms(5); } - /* 以下都是“芯片自己意外重启了一下”,不是用户主动按开机键, - * 不能因此逼用户重新按键,否则相当于设备无故“关机”了一次 */ - if (cpu_reset_by_soft() /* SDK 综合判断:是否软件复位 */ - || is_reset_source(MSYS_SOFT_RST) /* 主系统软件复位(断言/异常/OTA 后重启等) */ - || is_reset_source(P33_SOFT_RST) /* P33 软件复位,最常见的软复位入口 */ - || is_reset_source(P33_VDDIO_LVD_RST) /* VDDIO 低压复位(电机启动拉低电压误触发) */ - || is_reset_source(P11_WDT_RST)) { /* 看门狗复位(程序卡死被强制重启) */ - log_info("boot reset-keep, skip key wait\n"); - return 1; - } + // /* 以下都是“芯片自己意外重启了一下”,不是用户主动按开机键, + // * 不能因此逼用户重新按键,否则相当于设备无故“关机”了一次 */ + // if (cpu_reset_by_soft() /* SDK 综合判断:是否软件复位 */ + // || is_reset_source(MSYS_SOFT_RST) /* 主系统软件复位(断言/异常/OTA 后重启等) */ + // || is_reset_source(P33_SOFT_RST) /* P33 软件复位,最常见的软复位入口 */ + // || is_reset_source(P33_VDDIO_LVD_RST) /* VDDIO 低压复位(电机启动拉低电压误触发) */ + // || is_reset_source(P11_WDT_RST)) { /* 看门狗复位(程序卡死被强制重启) */ + // log_info("boot reset-keep, skip key wait\n"); + // return 1; + // } return 0; } diff --git a/apps/usr_app/app_function.c b/apps/usr_app/app_function.c index c2dadaf..ada33c3 100644 --- a/apps/usr_app/app_function.c +++ b/apps/usr_app/app_function.c @@ -91,7 +91,7 @@ void app_function_poll(void) void app_function_tick_1ms(uint16_t dt) { if (s_func.hand_busy) { - bsp_motor_brake_tick(); + bsp_motor_switch_tick(); s_func.hand_ms = app_add_ms(s_func.hand_ms, dt); } else { app_mode_run(); diff --git a/apps/usr_app/app_led.c b/apps/usr_app/app_led.c index 69b43df..55a2e4c 100644 --- a/apps/usr_app/app_led.c +++ b/apps/usr_app/app_led.c @@ -193,7 +193,8 @@ void app_led_run(uint16_t dt, uint8_t app_power) led_clear_function_events(); } else { #if BOARD_LED_STANDBY_ON - if ((charge_led != 2) && !pairing && !green_busy()) { + /* 正在充电(红)或已充满(绿)时都不叠加待机绿,只有完全没接电才显示待机 */ + if ((charge_led == 0) && !pairing && !green_busy()) { LED_EventAdd(LED_EVENT_STANDBY); } else { LED_EventDelete(LED_EVENT_STANDBY); diff --git a/apps/usr_app/app_mode.c b/apps/usr_app/app_mode.c index 084b3bf..644b627 100644 --- a/apps/usr_app/app_mode.c +++ b/apps/usr_app/app_mode.c @@ -201,7 +201,7 @@ void app_mode_run(void) { const AppModeStep_t *tbl; - bsp_motor_brake_tick(); + bsp_motor_switch_tick(); if (!s_mode.initialized || s_mode.active == 0) { return; } diff --git a/apps/usr_jb_proto/usr_jb_main.c b/apps/usr_jb_proto/usr_jb_main.c index 287f40e..5efc9c1 100644 --- a/apps/usr_jb_proto/usr_jb_main.c +++ b/apps/usr_jb_proto/usr_jb_main.c @@ -44,14 +44,13 @@ #include "app_mode.h" #include "app_led.h" #include "key_manager.h" +#include "asm/power/power_api.h" #define LOG_TAG_CONST APP #define LOG_TAG "[USR_JB]" #define LOG_INFO_ENABLE #include "debug.h" -extern void sys_enter_soft_poweroff(void *priv); - /* 向 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], @@ -106,13 +105,21 @@ static void usr_poweroff_request_hook(void) } /** - * @brief 深睡请求钩子:50ms 到点,真正进入深睡(不会返回) + * @brief 深睡请求钩子:50ms 到点,真正进入深睡 + * @note 不走 sys_enter_soft_poweroff():那是耳机 SDK 给"蓝牙耳机"设计的优雅关机流程 + * (BLE 断连握手 + 任务切换到 idle + 尝试放关机音效),实测哪怕已经砍掉了灯效 + * 动画和广播空转,走完还是要 2.5s 左右,供应商确认这对按键关机的玩具不正常。 + * 本产品不用 DAC/音频(没有 dac_power_on 过),跳过 dac_power_off()—— + * 它在从未打开过 DAC 的情况下会直接调 audio_dac_close() 关一个没开过的 + * 句柄,没必要也没好处。跳过 BLE 优雅断连的代价是手机 App 端不会收到 + * 断连通知,只能等连接超时(标准 BLE 行为,等同于直接拔电池,App 端会 + * 自行处理,不影响下次重连配对)。 * @return 无 */ static void usr_poweroff_finalize_hook(void) { bsp_hw_enter_sleep_io(); - sys_enter_soft_poweroff(NULL); + power_set_soft_poweroff(); } /** diff --git a/apps/usr_periph/board_pin.h b/apps/usr_periph/board_pin.h index 65084dc..d5f6fcc 100644 --- a/apps/usr_periph/board_pin.h +++ b/apps/usr_periph/board_pin.h @@ -88,7 +88,6 @@ /*============================================================================*/ #define BOARD_MOTOR_REVERSE_MS 1 /**< 换向前先松开,防 H 桥直通 */ -#define BOARD_MOTOR_STOP_BRAKE_MS 30 /**< 停转先反转刹车(ms),太长会倒转 */ #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% */ diff --git a/apps/usr_periph/bsp_hw.c b/apps/usr_periph/bsp_hw.c index c6305db..4762d46 100644 --- a/apps/usr_periph/bsp_hw.c +++ b/apps/usr_periph/bsp_hw.c @@ -10,6 +10,8 @@ * - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 占空比降速 * - V1.4.0, 2026.08.24, cyWu, 增加按占空比驱动,供玩法变速 * - V1.5.0, 2026.08.25, cyWu, 空闲关闭 MCPWM 时钟 + * - V1.6.0, 2026.08.25, cyWu, 去掉停转反接刹车,改自由滑行停止,避免刹车 + * 电流冲击拉垮供电轨触发 LVD 复位 ******************************************************************************/ #include "system/includes.h" @@ -29,12 +31,12 @@ static uint8_t s_initialized; /** 电机状态,替代原来散落的 7 个 static */ typedef struct { - BspMotorDir_t dir; /**< 当前实际方向(含正在刹车时的反向) */ - BspMotorDir_t pending; /**< 死区/刹车结束后要切到的方向 */ + BspMotorDir_t dir; /**< 当前实际方向 */ + BspMotorDir_t pending; /**< 换向死区结束后要切到的方向 */ uint16_t duty; /**< 当前实际占空比 */ - uint16_t pending_duty; /**< 死区/刹车结束后要用的占空比 */ - uint16_t brake_ms; /**< 换向死区/反转刹车剩余时长,0=空闲 */ - u32 brake_t0; /**< 死区/刹车起始时间戳 */ + uint16_t pending_duty; /**< 换向死区结束后要用的占空比 */ + uint16_t switch_ms; /**< 换向死区剩余时长,0=空闲/不在换向中 */ + u32 switch_t0; /**< 换向死区起始时间戳 */ uint8_t pwm_clk_on; /**< 1=MCPWM 时钟已打开 */ } BspMotorCtx_t; @@ -180,13 +182,17 @@ 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(); + /* 换向死区(BOARD_MOTOR_REVERSE_MS)、刹车瞬间也会短暂占空比为 0, + * 但马上(1~30ms 内)还要再驱动,不能当成“真空闲”去关时钟: + * 频繁 close/open MCPWM 外设比单纯调占空比激进得多,玩法换向越快 + * 关得越勤,有卡死风险。这里只清占空比(两脚拉低,电气效果一样), + * 真正的空闲关时钟统一交给 bsp_hw_sleep_pwm_off()——它在系统真的 + * 要进轻睡前才调用,并且会先查 bsp_motor_is_busy()。 */ + mcpwm_set_duty(pwm_ch0, 0); + mcpwm_set_duty(pwm_ch1, 0); return; -#endif - } else { - bsp_motor_pwm_clock_on(); } + bsp_motor_pwm_clock_on(); mcpwm_set_duty(pwm_ch0, ina_duty); mcpwm_set_duty(pwm_ch1, inb_duty); } @@ -229,7 +235,7 @@ BspHw_Ret_t bsp_hw_init(void) s_motor.pending = BSP_MOTOR_STOP; s_motor.duty = 0; s_motor.pending_duty = 0; - s_motor.brake_ms = 0; + s_motor.switch_ms = 0; #if BOARD_MOTOR_PWM_IDLE_CLOSE bsp_motor_pwm_clock_off(); #endif @@ -290,7 +296,7 @@ void bsp_led_all_off(void) } /** - * @brief 设置电机方向。STOP 时若正在转,先反转刹车再滑行 + * @brief 设置电机方向。STOP 时直接切断驱动,自由滑行到停(不做反接刹车) * @param dir 收绳 / 放绳 / 停转 * @return 无 */ @@ -320,7 +326,7 @@ void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty) } /* 同向只改占空比:直接改 PWM,不走换向死区 */ - if (dir == s_motor.dir && s_motor.brake_ms == 0) { + if (dir == s_motor.dir && s_motor.switch_ms == 0) { if (duty == s_motor.duty) { return; } @@ -331,42 +337,32 @@ void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty) return; } - /* 已经在反转刹车等到停,忽略重复 STOP */ - if (dir == BSP_MOTOR_STOP && s_motor.pending == BSP_MOTOR_STOP && s_motor.brake_ms) { - return; - } - - /* 正在转时要停:先反向驱动再滑行,短接对此驱动无效 */ - if (dir == BSP_MOTOR_STOP - && (s_motor.dir == BSP_MOTOR_IN || s_motor.dir == BSP_MOTOR_OUT)) { - BspMotorDir_t rev = (s_motor.dir == BSP_MOTOR_OUT) ? BSP_MOTOR_IN : BSP_MOTOR_OUT; - uint16_t brake_duty = s_motor.duty ? s_motor.duty : BOARD_MOTOR_PWM_DUTY; - - bsp_motor_gpio(rev, brake_duty); - s_motor.dir = rev; - s_motor.duty = brake_duty; + /* 停转:直接切断驱动,让电机自由滑行到停,不做反接刹车——反接刹车电流比 + * 正常驱动大(电池要同时顶住反向驱动电流和电机反电动势),实测会把供电轨 + * 拉低触发 LVD 复位。哪怕正在换向死区里,也直接取消死区改成停。 */ + if (dir == BSP_MOTOR_STOP) { + s_motor.switch_ms = 0; + s_motor.dir = BSP_MOTOR_STOP; s_motor.pending = BSP_MOTOR_STOP; + s_motor.duty = 0; s_motor.pending_duty = 0; - s_motor.brake_ms = BOARD_MOTOR_STOP_BRAKE_MS; - s_motor.brake_t0 = timer_get_ms(); - log_info("motor rev-brake %ums duty=%u\n", - (unsigned)BOARD_MOTOR_STOP_BRAKE_MS, (unsigned)brake_duty); + bsp_motor_gpio(BSP_MOTOR_STOP, 0); return; } /* 换向:先松开再输出,避免 H 桥直通 */ - if (dir != BSP_MOTOR_STOP && s_motor.dir != BSP_MOTOR_STOP && dir != s_motor.dir) { + if (s_motor.dir != BSP_MOTOR_STOP && dir != s_motor.dir) { bsp_motor_gpio(BSP_MOTOR_STOP, 0); s_motor.pending = dir; s_motor.pending_duty = duty; - s_motor.brake_ms = BOARD_MOTOR_REVERSE_MS; - s_motor.brake_t0 = timer_get_ms(); + s_motor.switch_ms = BOARD_MOTOR_REVERSE_MS; + s_motor.switch_t0 = timer_get_ms(); s_motor.dir = BSP_MOTOR_STOP; s_motor.duty = 0; return; } - s_motor.brake_ms = 0; + s_motor.switch_ms = 0; s_motor.dir = dir; s_motor.pending = dir; s_motor.duty = duty; @@ -376,21 +372,21 @@ void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty) } /** - * @brief 推进换向死区与停转反转刹车,按真实毫秒计时 + * @brief 推进换向死区计时,按真实毫秒计时;死区结束后切到目标方向/占空比 * @return 无 */ -void bsp_motor_brake_tick(void) +void bsp_motor_switch_tick(void) { #if !BOARD_MOTOR_ENABLE return; #else - if (s_motor.brake_ms == 0) { + if (s_motor.switch_ms == 0) { return; } - if ((timer_get_ms() - s_motor.brake_t0) < s_motor.brake_ms) { + if ((timer_get_ms() - s_motor.switch_t0) < s_motor.switch_ms) { return; } - s_motor.brake_ms = 0; + s_motor.switch_ms = 0; s_motor.dir = s_motor.pending; s_motor.duty = s_motor.pending_duty; bsp_motor_gpio(s_motor.dir, s_motor.duty); @@ -484,7 +480,7 @@ void bsp_hw_sleep_pwm_off(void) } /** - * @brief 电机是否还在转或刹车 + * @brief 电机是否还在转或处于换向死区 * @return 1=忙碌,0=已停且 PWM 已关 */ uint8_t bsp_motor_is_busy(void) @@ -492,7 +488,7 @@ uint8_t bsp_motor_is_busy(void) #if !BOARD_MOTOR_ENABLE return 0; #else - if (s_motor.brake_ms) { + if (s_motor.switch_ms) { return 1; } if (s_motor.dir != BSP_MOTOR_STOP) { @@ -513,7 +509,7 @@ void bsp_hw_enter_sleep_io(void) { bsp_motor_set(BSP_MOTOR_STOP); #if BOARD_MOTOR_ENABLE - s_motor.brake_ms = 0; + s_motor.switch_ms = 0; s_motor.dir = BSP_MOTOR_STOP; s_motor.pending = BSP_MOTOR_STOP; s_motor.duty = 0; diff --git a/apps/usr_periph/bsp_hw.h b/apps/usr_periph/bsp_hw.h index 5f11759..d3b4eb1 100644 --- a/apps/usr_periph/bsp_hw.h +++ b/apps/usr_periph/bsp_hw.h @@ -2,14 +2,16 @@ * @file bsp_hw.h * @brief CBC2 板级硬件:电机 / LED / 按键 / 充电 / 电量 * @author cyWu <1917507415@qq.com> - * @date 2026.08.24 - * @version V1.5.0 + * @date 2026.08.25 + * @version V1.6.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 时钟,避免待机空转耗电 + * - V1.6.0, 2026.08.25, cyWu, 去掉停转反接刹车,改自由滑行停止,避免刹车 + * 电流冲击拉垮供电轨触发 LVD 复位 ******************************************************************************/ #ifndef __BSP_HW_H__ @@ -63,7 +65,7 @@ void bsp_led_green_set(uint8_t on); void bsp_led_all_off(void); /** - * @brief 设置电机方向。STOP 时若正在转,先反转刹车再滑行 + * @brief 设置电机方向。STOP 时直接切断驱动,自由滑行到停(不做反接刹车) * @note 占空比用 BOARD_MOTOR_PWM_DUTY(手动点动) * @param dir 收绳 / 放绳 / 停转 * @return 无 @@ -79,13 +81,13 @@ void bsp_motor_set(BspMotorDir_t dir); void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty); /** - * @brief 推进换向死区与停转反转刹车,按真实毫秒计时 + * @brief 推进换向死区计时,按真实毫秒计时;死区结束后切到目标方向/占空比 * @return 无 */ -void bsp_motor_brake_tick(void); +void bsp_motor_switch_tick(void); /** - * @brief 电机是否还在转或刹车 + * @brief 电机是否还在转或处于换向死区 * @return 1=忙碌,0=已停且 PWM 已关 */ uint8_t bsp_motor_is_busy(void);