EMS 知识库
首页 / knowledge/代码解析/hmi/led

app_led.c

源文件路径:hmi/led/app_led.c 所属模块:hmi/led(人机界面 - WS2812 灯带应用层) 代码行数:232

1. 文件职责

本文件是 WS2812 灯带模块的应用层(策略层),负责把 EMS 的业务状态翻译成 121 颗灯珠的颜色数组,具体位流编码由下层 led_dev.c 完成。它是"系统状态 → 灯带颜色"这条链路的中间环节:下游是 led_dev.c 的 ws2812_set_color_hex()/ws2812_update()。

数据来源有三个:电池 SOC(bms_read_total_soc())、联网登录状态(g_stEMSInfo.bIsLogin)、系统运行状态色(全局 sys_current_status_color,由 hmi/led.c:654 的 DISPLAY_LCD_RKP_E 分支写入);亮度档位来自全局 u8_led_brightness_value。

驱动方式:设计上由 uCOS-II 任务周期调用 led_display_task()(hmi/led/app_led.h:20 的 LED_TASK_PERIOD 定义为 10 ms),函数内部采用"脏标志 + 1 s 强制刷新"策略,只有输入变化或超过 1 秒未刷新时才重新编码整个灯带。但当前工程中没有任何任务或代码调用 led_display_task(),因此本文件在运行期实际未被驱动(详见第 7 节)。

本文件同时定义并维护全局变量 sys_current_status_color,供 hmi/led.c 写入、本文件读取,是 hmi/led.c 与灯带模块之间唯一的状态传递通道。

2. 关键数据结构与宏

名称类型(结构体/枚举/宏/联合体)说明
STATUS_LED_COLOR_E枚举(定义于 hmi/led/app_led_cfg.h:48-54)长灯带系统状态色:0 灭 / 1 绿 / 2 红 / 3 黄;本文件用它声明并读取 sys_current_status_color
SOC_LED_COLOR_E枚举(定义于 hmi/led/app_led_cfg.h:58-62)短灯带颜色:SOC_LED_BLUE(0,未联网) / SOC_LED_WHITE(1,已联网);本文件用 s_current_soc_color 保存
LED_TEST宏(局部,hmi/led/app_led.c:30)空宏,无任何条件编译或代码引用,属调试遗留
brightness[]静态 const 数组(float[12],hmi/led/app_led.c:135-148)亮度档位→缩放系数映射表:索引 0=0.0(熄灭)、1=0.05、2=0.1、3=0.2、4=0.3、5=0.4、6=0.5、7=0.6、8=0.7、9=0.8、10=0.9、11=1.0
LED_SOC_NUM / LED_LONG_NUM / RKP_LED_NUM宏(hmi/led/led_dev.h:21/27/32)短灯带 20 颗、长灯带 101 颗、总数 121 颗;本文件用 LED_SOC_NUM 分段、用 RKP_LED_NUM 作循环上限
TRUE / FALSE宏(UCOSII/uCOS-CONFIG/includes.h)布尔常量,本文件大量用于脏标志比较

本文件定义的全局变量

名称类型说明
sys_current_status_colorSTATUS_LED_COLOR_E(全局,非 static,hmi/led/app_led.c:44)长灯带系统状态色,初值 SYS_STATUS_NOT_RUN_LED_OFF。由 hmi/led.c:654 写入,本文件只读。声明在 hmi/led/app_led_cfg.h:71
u8_led_brightness_valueu8(全局,初值 8,hmi/led/app_led.c:49)灯带亮度档位 0~11,默认 70%。除本文件外无任何读写点,也没有 Modbus/界面写入路径
u16_led_test_numu16(全局,初值 121,hmi/led/app_led.c:50)灯珠数量测试值,全工程无任何引用,死变量
s_current_soc_colorstatic SOC_LED_COLOR_E(初值 SOC_LED_BLUE,hmi/led/app_led.c:47)短灯带颜色缓存;注意它保存的其实是联网状态对应的颜色,变量名与语义不一致

3. 函数清单

函数名作用域(static/全局)说明(一句话)
get_bms_socstatic(前向声明 hmi/led/app_led.c:24,定义 hmi/led/app_led.c:210)读 BMS 总 SOC(0~1000,即 0.00%~100.00%)并折算成 0~10 的档位数(每档 10%)
get_network_statusstatic(前向声明 hmi/led/app_led.c:25,定义 hmi/led/app_led.c:221)返回云端登录标志 g_stEMSInfo.bIsLogin(0/1),用作短灯带颜色选择
led_build_full_bufferstatic(前向声明 hmi/led/app_led.c:26,定义 hmi/led/app_led.c:127)按当前 SOC/联网/系统状态/亮度重新编码全部 121 颗灯珠并启动一次发送
apply_brightnessstatic(定义 hmi/led/app_led.c:60,无前向声明)把 0xRRGGBB 颜色按 float 系数逐通道缩放后重新打包
led_display_task全局(定义 hmi/led/app_led.c:68)灯带刷新任务主体:聚合 5 路输入变化,置脏标志后调用 led_build_full_buffer()

本文件共 5 个函数(含 3 个前向声明对应的 static 函数),已全部列出。

4. 核心逻辑解析

4.1 led_display_task() 的脏标志聚合(hmi/led/app_led.c:68-124)

函数内维护 5 个 static 缓存,每轮比较一次,任一变化即置 s_u8_need_update = TRUE:

步骤输入缓存变量行号
1OSTimeGet()s_u32_last_tick82-87:if((current_tick - s_u32_last_tick) > 1000) → 每 1 秒强制刷新一次(无条件)
2sys_current_status_colors_u8_sys_run_state89-93
3get_bms_soc()s_u8_bms_soc96-102
4get_network_status()(同时写入 s_current_soc_color)s_u8_network_status105-110
5u8_led_brightness_values_u8_led_brightness_value112-116

全部比较完成后统一执行(hmi/led/app_led.c:119-123):

if(s_u8_need_update == TRUE)
{ led_build_full_buffer(); s_u8_need_update = FALSE; }

注意事项:

4.2 led_build_full_buffer() 的灯带编码(hmi/led/app_led.c:127-208)

执行顺序:

  1. 取亮度系数:s_u8_brightness_index = u8_led_brightness_value; bright_factor = brightness[s_u8_brightness_index];(150-153)——没有做 0~11 的边界钳位。
  2. 取两种颜色:short_color = get_soc_color_to_rgb(s_current_soc_color)(短灯带 = 联网状态色),long_color = get_sys_color_status(sys_current_status_color)(长灯带 = 系统状态色)(156-157)。
  3. 清屏:ws2812_set_color_buffer_clear()(160)。
  4. 逐颗编码(#if 0 ... #else ... #endif,实际生效的是 #else 分支,hmi/led/app_led.c:182-205):
for(u8 i = 0; i < RKP_LED_NUM; i++)          // 121 颗
{
    if(i < LED_SOC_NUM)                       // 前 20 颗 = 短灯带(SOC 柱)
    {
        if( i < get_bms_soc() * 2)            // 点亮左侧 soc*2 颗
            ws2812_set_color_hex(i, apply_brightness(short_color, bright_factor));
        else
            ws2812_set_color_hex(i, 0);       // 其余熄灭
    }
    else                                      // 后 101 颗 = 长灯带(系统状态)
        ws2812_set_color_hex(i, apply_brightness(long_color, bright_factor));
}
  1. ws2812_update() 启动一次 DMA 发送(hmi/led/app_led.c:207)。

被编译屏蔽的 #if 0 分支(hmi/led/app_led.c:161-181)用的是另一种点亮规则 i >= LED_SOC_NUM - get_bms_soc()(点亮右侧 soc 颗),说明 SOC 柱的方向与每档颗数曾反复调整(#else 分支上方注释只有一个"昌"字,为现场调试遗留)。

亮度缩放公式(hmi/led/app_led.c:60-66):

r = (u8)(((color >> 16) & 0xFF) * brightness);
g = (u8)(((color >> 8)  & 0xFF) * brightness);
b = (u8)(( color        & 0xFF) * brightness);
return (r << 16) | (g << 8) | b;

系数为 float,运算结果直接截断取整(非四舍五入),因此 100% 档(1.0)不会改变颜色,0 档(0.0)会使颜色全 0。

4.3 get_bms_soc() 的 SOC 折算(hmi/led/app_led.c:210-220)

u16 soc = bms_read_total_soc();   // 0~1000,单位 0.1%
u8  percent = (u8)(soc / 10);     // 0~100
if (percent == 0) return 0;
return (percent + 9) / 10;        // 向上取整到 0~10 档

即返回值 = ⌈percent/10⌉,配合 led_build_full_buffer() 的 soc * 2 得到 0~20 颗点亮的 SOC 柱,每颗灯珠代表 5%(hmi/led/led_dev.h:28 的注释写"精度为10%",与实现不符)。

bms_read_total_soc() 数据类型为 u16(midware/bms/bms.h:1190),若上游异常返回 > 1000,percent 会超过 100,(percent+9)/10 可能大于 10,进而 get_bms_soc()*2 > LED_SOC_NUM,短灯带全亮(不会越界,因为循环本身受 i < LED_SOC_NUM 限制),但 SOC 指示会失真。注意 get_bms_soc() 的返回类型是 u8,(percent + 9) 在 percent=255 时为 264,未溢出 u8 计算(C 语言提升为 int),但强转返回仍会截断。

4.4 get_network_status()(hmi/led/app_led.c:221-225)

static u8 get_network_status(void)
{
    extern STEMSTab g_stEMSInfo;      // 函数内局部 extern 声明
    return g_stEMSInfo.bIsLogin;
}

直接返回 EMS 云端登录标志(net/ems.h:285 的 BOOLEAN bIsLogin),返回 0/1 正好与 SOC_LED_COLOR_E 的 SOC_LED_BLUE(0)/SOC_LED_WHITE(1) 数值一一对应,因此调用点用 (SOC_LED_COLOR_E)get_network_status() 强转(hmi/led/app_led.c:105)。

注意:这里只用 bIsLogin,没有考虑 bIsBuiltSocket、路由(g_t_wireless_info)等中间态,与 hmi/led.c:345-383 五级优先级的联网判定相比信息量更少;函数内 extern 声明绕过了头文件(ems.h 已 include,此写法多余)。

4.5 与 uCOS-II 的配合

本文件不创建任务、不申请信号量/邮箱,也不调用 OSTimeDly*;唯一的 OS 调用是 OSTimeGet()(hmi/led/app_led.c:82、84)。任务与调度周期完全由外部调用者决定。与中断的交互发生在下层 led_dev.c/hardware/dma/dma.c:296-303(DMA 传输完成中断清除 g_u_ws2812_flag.bit.write_flag)。

5. 对外接口

本文件导出

名称类型使用方
led_display_task全局函数(声明于 hmi/led/app_led.h:43)无调用点
sys_current_status_color全局变量(声明于 hmi/led/app_led_cfg.h:71)由 hmi/led.c:654 写入,本文件 hmi/led/app_led.c:89 读取
u8_led_brightness_value全局变量(无头文件声明)仅本文件读写;因无 extern 声明,外部模块即使想写也会与 midware/interface/modbus/modbus.c:45 的 include 声明不匹配
u16_led_test_num全局变量(无头文件声明)无任何引用

本文件调用的外部函数/变量

名称来源模块
bms_read_total_socmidware/bms/bms.c(声明 midware/bms/bms.h:1190)
get_soc_color_to_rgb、get_sys_color_statushmi/led/app_led_cfg.c
ws2812_set_color_hex、ws2812_set_color_buffer_clear、ws2812_updatehmi/led/led_dev.c
OSTimeGetuCOS-II
g_stEMSInfo(STEMSTab)net/ems.c(声明 net/ems.h:467)
sys_current_status_color定义在本文件;写入方为 hmi/led.c

6. 依赖关系

依赖(本文件 include):app_led.h(13)、ems.h(14)、bms.h(15)、meter.h(16)、logic.h(17)、inverter.h(18)。

其中 meter.h、logic.h、inverter.h 在本文件正文中没有任何符号被使用,属于多余 include。

被依赖:

7. 备注与风险点