Compare commits

..
2 Commits
Author SHA1 Message Date
wuchuyuan c2c0a169cf 调整自动模式顺序,调整版本号为1.0.1 2026-09-10 14:38:00 +08:00
wuchuyuanandCursor c7adda3711 修复切模式闪完多一闪,以及配对失败灯因休眠又慢又少。
切模式/配对快闪用优先级拦住待机绿,闪完同一拍衔上常亮;短灯效播完前禁睡,避免节拍被拉长。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 14:16:42 +08:00
10 changed files with 92 additions and 71 deletions
+23 -15
View File
@@ -2,8 +2,8 @@
* @file app_led.c
* @brief CBC2 灯效适配:充电红与待机绿可同时亮,不再 if-else 互斥
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V2.0.0
* @date 2026.09.10
* @version V2.5.0
* @history
* - V1.0.0, 2026.08.21, cyWu, 首次发布
* - V1.1.0, 2026.08.25, cyWu, 开机绿灯只提示几秒
@@ -12,6 +12,7 @@
* - V2.2.0, 2026.08.25, cyWu, 重启/清场逻辑各提一个小函数,把意图写进注释
* - V2.3.0, 2026.08.27, cyWu, 新增 OTA 红绿交替灯效
* - V2.4.0, 2026.08.27, cyWu, 新增空电关机红闪 5 下灯效
* - V2.5.0, 2026.09.10, cyWu, 切模式时保留待机绿,闪完不再多一闪
******************************************************************************/
#include "app_led.h"
@@ -53,15 +54,6 @@ static uint8_t green_pattern_busy(void)
|| LED_IsEventExist(LED_EVENT_PAIR_FAIL));
}
/**
* @brief 绿灯正被配对/切模式/结果占用时,不要再挂待机绿
* @return 1=绿灯忙
*/
static uint8_t green_busy(void)
{
return (uint8_t)(LED_IsEventExist(LED_EVENT_PAIRING) || green_pattern_busy());
}
/**
* @brief 灯效初始化
* @return APP_LED_OK=成功
@@ -157,6 +149,20 @@ uint8_t app_led_is_empty_off(void)
return s_empty_off;
}
/**
* @brief 短灯效还在播时不要进休眠
* @return 1=应禁睡,0=可以睡
*/
uint8_t app_led_need_nosleep(void)
{
if (s_ota || s_empty_off) {
return 1;
}
return (uint8_t)(LED_IsEventExist(LED_EVENT_PAIR_FAIL)
|| LED_IsEventExist(LED_EVENT_PAIR_OK)
|| LED_IsEventExist(LED_EVENT_MODE));
}
/**
* @brief 播放一次性配对结果灯
* @param ok 1=成功常绿,0=失败红绿交替
@@ -263,11 +269,13 @@ void app_led_run(uint16_t dt, uint8_t app_power)
led_clear_function_events();
} else {
#if BOARD_LED_STANDBY_ON
/* 正在充电(红)或已充满(绿)时都不叠加待机绿,只有完全没接电才显示待机 */
if ((charge_led == 0) && !pairing && !green_busy()) {
LED_EventAdd(LED_EVENT_STANDBY);
} else {
/* 配对/切模式/配对失败用 return 1 拦住待机,这里不用删。
* 充电红不占用绿灯:拦截只是不跑待机 handler,绿灯会停在上次的亮。
* 所以充电时要删待机,把绿灯掐灭。 */
if (charge_led == 1) {
LED_EventDelete(LED_EVENT_STANDBY);
} else {
LED_EventAdd(LED_EVENT_STANDBY);
}
#endif
}
+7
View File
@@ -75,6 +75,13 @@ void app_led_request_empty_off(void);
*/
uint8_t app_led_is_empty_off(void);
/**
* @brief 短灯效还在播时不要进休眠(配对失败/成功、切模式闪)
* @note 灯刷新跟业务定时器走;休眠后节拍被拉长,交替闪会又慢又少。
* @return 1=应禁睡,0=可以睡
*/
uint8_t app_led_need_nosleep(void);
/**
* @brief 清空全部灯事件并灭灯(关机前调用)
* @return 无
+25 -24
View File
@@ -2,12 +2,13 @@
* @file app_mode.c
* @brief 自动模式 1~6:按节拍改方向与 PWM 占空比
* @author cyWu <1917507415@qq.com>
* @date 2026.08.24
* @version V1.2.0
* @date 2026.09.10
* @version V1.3.0
* @history
* - V1.0.0, 2026.08.21, cyWu, 首次发布
* - V1.1.0, 2026.08.24, cyWu, 接入 H 桥往返节拍
* - V1.2.0, 2026.08.24, cyWu, 节拍带占空比;六档波形加花样
* - V1.3.0, 2026.09.10, cyWu, 调整 1~6 玩法顺序
******************************************************************************/
#include "system/includes.h"
@@ -37,10 +38,10 @@ typedef struct {
/* 节拍以 ms=0 结尾,循环播放。同向连续步进只改占空比,换向才刹车。 */
static const AppModeStep_t s_mode1[] = { /* 弹力呼吸:慢加速放、慢加速收,最长 2s */
STEP_OUT(500, DUTY_MID), STEP_OUT(1200, DUTY_RUN), STEP_OUT(500, DUTY_PUNCH),
static const AppModeStep_t s_mode1[] = { /* 起伏攻防:2s 慢逗再猛收 */
STEP_OUT(500, DUTY_SOFT), STEP_OUT(1200, DUTY_MID), STEP_OUT(500, DUTY_RUN),
STEP_STOP(400),
STEP_IN(500, DUTY_MID), STEP_IN(1200, DUTY_RUN), STEP_IN(500, DUTY_PUNCH),
STEP_IN(500, DUTY_PUNCH), STEP_IN(500, DUTY_MID),
STEP_STOP(400),
STEP_END
};
@@ -53,7 +54,24 @@ static const AppModeStep_t s_mode2[] = { /* 飞鸟俯冲:快冲出去,2s 慢
STEP_END
};
static const AppModeStep_t s_mode3[] = { /* 云阶陀螺:短步往返加长,力度一档档加 */
static const AppModeStep_t s_mode3[] = { /* 闪电快闪:两下轻、两下重,短停防 LVD */
STEP_OUT(400, DUTY_MID), STEP_IN(400, DUTY_MID),
STEP_OUT(800, DUTY_RUN), STEP_IN(800, DUTY_RUN),
STEP_OUT(500, DUTY_PUNCH), STEP_IN(500, DUTY_PUNCH),
STEP_OUT(700, DUTY_PUNCH), STEP_IN(700, DUTY_PUNCH),
STEP_STOP(300),
STEP_END
};
static const AppModeStep_t s_mode4[] = { /* 弹力伪装:慢加速放、慢加速收,最长 2s */
STEP_OUT(500, DUTY_MID), STEP_OUT(1200, DUTY_RUN), STEP_OUT(500, DUTY_PUNCH),
STEP_STOP(400),
STEP_IN(500, DUTY_MID), STEP_IN(1200, DUTY_RUN), STEP_IN(500, DUTY_PUNCH),
STEP_STOP(400),
STEP_END
};
static const AppModeStep_t s_mode5[] = { /* 云阶陀螺:短步往返加长,力度一档档加 */
STEP_OUT(800, DUTY_SOFT), STEP_IN(800, DUTY_SOFT),
STEP_OUT(800, DUTY_MID), STEP_IN(800, DUTY_MID),
STEP_OUT(800, DUTY_RUN), STEP_IN(800, DUTY_RUN),
@@ -61,15 +79,7 @@ static const AppModeStep_t s_mode3[] = { /* 云阶陀螺:短步往返加长,
STEP_END
};
static const AppModeStep_t s_mode4[] = { /* 起伏攻防:2s 慢逗再猛收 */
STEP_OUT(500, DUTY_SOFT), STEP_OUT(1200, DUTY_MID), STEP_OUT(500, DUTY_RUN),
STEP_STOP(400),
STEP_IN(500, DUTY_PUNCH), STEP_IN(500, DUTY_MID),
STEP_STOP(400),
STEP_END
};
static const AppModeStep_t s_mode5[] = { /* 微风拂动:轻点后歇 2s */
static const AppModeStep_t s_mode6[] = { /* 微风拂动:轻点后歇 2s */
STEP_OUT(500, DUTY_MID), STEP_STOP(1000),
STEP_IN(500, DUTY_MID), STEP_STOP(1200),
STEP_OUT(500, DUTY_RUN), STEP_STOP(800),
@@ -77,15 +87,6 @@ static const AppModeStep_t s_mode5[] = { /* 微风拂动:轻点后歇 2s */
STEP_END
};
static const AppModeStep_t s_mode6[] = { /* 闪电快闪:两下轻、两下重,短停防 LVD */
STEP_OUT(400, DUTY_MID), STEP_IN(400, DUTY_MID),
STEP_OUT(800, DUTY_RUN), STEP_IN(800, DUTY_RUN),
STEP_OUT(500, DUTY_PUNCH), STEP_IN(500, DUTY_PUNCH),
STEP_OUT(700, DUTY_PUNCH), STEP_IN(700, DUTY_PUNCH),
STEP_STOP(300),
STEP_END
};
static const AppModeStep_t *const s_tables[7] = {
0, s_mode1, s_mode2, s_mode3, s_mode4, s_mode5, s_mode6
};
+11 -8
View File
@@ -2,12 +2,13 @@
* @file led_manager.c
* @brief CBC2 灯事件:充电红与待机绿走不同通道,可同时亮
* @author cyWu <1917507415@qq.com>
* @date 2026.08.27
* @version V1.1.0
* @date 2026.09.10
* @version V1.2.0
* @history
* - V1.0.0, 2026.08.25, cyWu, 首次发布,实现红绿独立通道灯事件表
* - V1.1.0, 2026.08.27, cyWu, 新增 LED_EVENT_BOOT_REJECT:拒绝开机低电闪,
* 供 app_boot 在按键判定阶段直接复用事件库
* - V1.2.0, 2026.09.10, cyWu, 切模式闪时待机绿不写灯,闪完同一拍衔上常亮
******************************************************************************/
#include "led_manager.h"
@@ -67,26 +68,29 @@ static uint8_t led_standby_handler(LED_Config_t *led_config)
/**
* @brief 配对绿快闪(无限)
* @note 返回 1 拦住待机绿,否则待机会把快闪盖成常亮
* @param led_config 配置
* @return 0
* @return 1
*/
static uint8_t led_pairing_handler(LED_Config_t *led_config)
{
(void)LED_Update(led_config);
return 0;
return 1;
}
/**
* @brief 切模式闪完两下后删事件
* @note 还在闪时返回 1,拦住待机绿,避免把闪烁盖成常亮
* @param led_config 配置
* @return 0
* @return 1=还在闪,0=闪完已删
*/
static uint8_t led_mode_handler(LED_Config_t *led_config)
{
if (LED_Update(led_config) == 0) {
LED_EventDelete(LED_EVENT_MODE); /* 闪完两下后删,绿灯还给待机/配对 */
}
return 0;
}
return 1;
}
/**
@@ -248,8 +252,7 @@ void user_led_init(void)
.config.alternatingBlinkParams.Group[0] = LED_CHANNEL(LED_CH_RED),
.config.alternatingBlinkParams.Group[1] = LED_CHANNEL(LED_CH_GREEN),
.config.alternatingBlinkParams.Cycle = (uint32_t)(BOARD_LED_ALT_MS * 2u),
.config.runNum = (uint16_t)((BOARD_LED_PAIR_FAIL_MS + (BOARD_LED_ALT_MS * 2u) - 1u)
/ (BOARD_LED_ALT_MS * 2u)),
.config.runNum = (uint16_t)((BOARD_LED_PAIR_FAIL_MS + (BOARD_LED_ALT_MS * 2u) - 1u)/ (BOARD_LED_ALT_MS * 2u)),
.ledEventHandler = led_pair_fail_handler,
},
[LED_EVENT_OTA] = {
+10 -10
View File
@@ -106,24 +106,24 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
case PLAY_MODE_0: /* 停止复位 */
// TODO: 处理 停止复位
break;
case PLAY_MODE_1: /* 弹力伪装 */
// TODO: 处理 弹力伪装
case PLAY_MODE_1: /* 起伏攻防 */
// TODO: 处理 起伏攻防
break;
case PLAY_MODE_2: /* 飞鸟俯冲 */
// TODO: 处理 飞鸟俯冲
break;
case PLAY_MODE_3: /* 云阶小陀螺 */
case PLAY_MODE_3: /* 闪电快闪 */
// TODO: 处理 闪电快闪
break;
case PLAY_MODE_4: /* 弹力伪装 */
// TODO: 处理 弹力伪装
break;
case PLAY_MODE_5: /* 云阶小陀螺 */
// TODO: 处理 云阶小陀螺
break;
case PLAY_MODE_4: /* 起伏攻防战 */
// TODO: 处理 起伏攻防战
break;
case PLAY_MODE_5: /* 微风拂动 */
case PLAY_MODE_6: /* 微风拂动 */
// TODO: 处理 微风拂动
break;
case PLAY_MODE_6: /* 闪电快闪 */
// TODO: 处理 闪电快闪
break;
default:
break;
}
+1 -1
View File
@@ -22,7 +22,7 @@
/* MCU software version: Vmajor.minor.patch */
#define JB_MCU_SW_VERSION_MAJOR 1
#define JB_MCU_SW_VERSION_MINOR 0
#define JB_MCU_SW_VERSION_PATCH 0
#define JB_MCU_SW_VERSION_PATCH 1
/* MCU hardware version: Vmajor.minor.patch */
#define JB_MCU_HW_VERSION_MAJOR 1
+5 -5
View File
@@ -154,12 +154,12 @@ typedef enum
typedef enum
{
PLAY_MODE_0 = 0, /* 停止复位 */
PLAY_MODE_1 = 1, /* 弹力伪装 */
PLAY_MODE_1 = 1, /* 起伏攻防 */
PLAY_MODE_2 = 2, /* 飞鸟俯冲 */
PLAY_MODE_3 = 3, /* 云阶小陀螺 */
PLAY_MODE_4 = 4, /* 起伏攻防战 */
PLAY_MODE_5 = 5, /* 微风拂动 */
PLAY_MODE_6 = 6, /* 闪电快闪 */
PLAY_MODE_3 = 3, /* 闪电快闪 */
PLAY_MODE_4 = 4, /* 弹力伪装 */
PLAY_MODE_5 = 5, /* 云阶小陀螺 */
PLAY_MODE_6 = 6, /* 微风拂动 */
} PLAY_MODE_t;
/* 充电状态 */
+5 -3
View File
@@ -159,8 +159,9 @@ static void usr_poweroff_finalize_hook(void)
* @brief 按当前业务状态判断能不能休眠
* @note 换向死区(bsp_motor_is_busy 已把它算进"忙")、点动、玩法、按键按住、
* 关机等待、配网窗口,统一都是"不能睡",节拍周期都一样用 USR_TIMER_IDLE_MS。
* 配网只跟 120s 配对窗口(app_pair_is_active):窗口内禁睡,保证广播
* 节拍不被低功耗拉长;成功或超时后恢复可休眠。
* 配网只跟 120s 配对窗口(app_pair_is_active):窗口内禁睡
* 超时后配对失败灯还要再闪约 3s,这段也禁睡,否则节拍被拉长,
* 红绿交替会又慢又少。
* @return 本次应使用的档位
*/
static UsrTickMode_t usr_timer_pick_mode(void)
@@ -168,7 +169,8 @@ static UsrTickMode_t usr_timer_pick_mode(void)
if (bsp_key_is_pressed() || app_power_poweroff_pending()
|| app_mode_get_active() || bsp_motor_is_busy()
|| app_function_is_hand_busy()
|| app_pair_is_active()) {
|| app_pair_is_active()
|| app_led_need_nosleep()) {
return USR_TICK_BLOCK_SLEEP;
}
return USR_TICK_IDLE;
+4 -4
View File
@@ -53,12 +53,12 @@
| 玩法 | 效果 |
| --- | --- |
| 停止复位 | 停转 |
| 弹力伪装 | 绳子慢慢放出去再慢慢收回来,来回一次 |
| 起伏攻防 | 慢慢逗弄两秒,突然猛收一下 |
| 飞鸟俯冲 | 快速冲出去,再慢慢收回,模拟小鸟飞扑 |
| 云阶小陀螺 | 小幅度来回抖动,力度逐渐加大,像陀螺转动 |
| 起伏攻防战 | 慢慢逗弄两秒,突然猛收一下 |
| 微风拂动 | 轻轻动一下,歇两秒,像被风吹动 |
| 闪电快闪 | 快速连续来回抽动,动作急促 |
| 弹力伪装 | 绳子慢慢放出去再慢慢收回来,来回一次 |
| 云阶小陀螺 | 小幅度来回抖动,力度逐渐加大,像陀螺转动 |
| 微风拂动 | 轻轻动一下,歇两秒,像被风吹动 |
- 玩法会循环播放,直到切换或停止。
- 运行中可随时切换到其他玩法或停止。
+1 -1
View File
@@ -9,7 +9,7 @@
[CmdletBinding()]
param(
[string]$ProjectName = "PICBC2",
[string]$ProjectName = "JBao_Door_Clamp",
[string]$SdkRoot = ""
)