当前位置:首页 > 汽车电子 > 汽车电子
[导读]BMS和仪表盘最怕两件事:CAN报文抖一下,电量百分比乱跳;温度越限瞬间弹红标,下一帧又消失。正确做法是BMS只负责采样和状态估算,仪表HMI只订阅一份“电池状态快照”,渲染层不做算法、不做越权判断,所有阈值和滞回在状态聚合处完成。


BMS和仪表盘最怕两件事:CAN报文抖一下,电量百分比乱跳;温度越限瞬间弹红标,下一帧又消失。正确做法是BMS只负责采样和状态估算,仪表HMI只订阅一份“电池状态快照”,渲染层不做算法、不做越权判断,所有阈值和滞回在状态聚合处完成。

一、数据链路:BMS→CAN→HMI

典型架构分三段:

电芯采样(AFE) → BMS主控(算SOC/SOH)

  → CAN总线(周期报文)

  → 仪表HMI(渲染电压/温度/SOC/故障)

BMS通过CAN周期上报:总压、总电流、单体最高/最低电压及位置、最高/最低温度及位置、SOC、SOH、故障码。仪表是只读消费者,不直接控继电器、不写均衡指令。

二、统一状态结构

HMI先收数据进一份聚合状态,别把原始CAN帧直接塞进控件:

typedef struct {

   uint16_t pack_v;        // 0.1V

   int16_t  pack_i;        // 0.1A,正为放电

   uint8_t  soc;           // 0~100

   uint8_t  soh;

   int8_t   t_max;         // 最高温℃

   int8_t   t_min;

   uint16_t cell_max_mv;

   uint16_t cell_min_mv;

   uint8_t  fault;         // 位域:过压/欠压/过温/绝缘

   uint32_t seq;

   uint64_t ts_ms;

} batt_state_t;


batt_state_t g_batt;

CAN接收线程只做:校验和检查、滚动计数去重、写g_batt,不碰UI。

三、报文解析与信任过滤

现场干扰多,脏数据必须先滤掉再渲染:

void on_can_batt(uint32_t id, uint8_t*data, int len){

   if(can_crc_err(data,len)) return;          // 校验失败丢弃

   if(can_rollover_dup(id, data)) return;     // 滚动计数重复丢弃

   if(id == MSG_BATT_STAT){

       g_batt.pack_v = rd_u16(data+0);

       g_batt.pack_i = (int16_t)rd_u16(data+2);

       g_batt.soc    = data[4];

       g_batt.t_max  = (int8_t)data[5];

       g_batt.t_min  = (int8_t)data[6];

       g_batt.fault  = data[7];

       g_batt.ts_ms  = now_ms();

   }

}

规则:

500ms没新报文→标记“通信丢失”,界面置灰而非显示旧值

电压突变超合理斜率(如单帧跳变>5V)→暂存不渲染,连续3帧一致才采纳

故障位优先于正常数据显示

四、分级显示与滞回

电量条和温度色不是“过线就红”,必须加滞回,否则高速颠簸时告警闪个不停:

typedef struct {

   int warn_hi, warn_lo;

   int alarm_hi, alarm_lo;

   int hyst;

} thresh_t;


thresh_t TEMP_THR = {45,42, 55,52, 2};


int level_eval(int v, thresh_t*t){

   static int lv=0;

   if(lv==0){

       if(v>=t->alarm_hi) lv=2;

       else if(v>=t->warn_hi) lv=1;

   }else if(lv==1){

       if(v>=t->alarm_hi+t->hyst) lv=2;

       else if(v<t->warn_lo) lv=0;

   }else{

       if(v<t->alarm_lo-t->hyst) lv=1;

   }

   return lv;   // 0正常 1预警 2告警

}

显示映射:

SOC:条形图+数字,低于10%变红,高于15%恢复白

温度:绿/黄/红三档,带滞回

单体压差:只显示最大压差,超阈值弹“电池不一致”

故障:过压/过温/绝缘分优先级,绝缘故障最优先

五、渲染节奏与VSync

仪表刷新别跟着CAN周期乱跳:

CAN 100ms一帧,HMI渲染绑VSync(通常60Hz但只按200ms重画一次)

SOC变化<1%不重绘数字,避免肉眼闪烁

温度只显示整数,0.1℃跳动没意义

多屏(中控+仪表+HUD)读同一份g_batt,不各算各的

void hmi_render_battery(void){

   if(now_ms()-g_batt.ts_ms > 500){

       draw_comm_lost();

       return;

   }

   draw_soc_bar(g_batt.soc);

   draw_voltage(g_batt.pack_v/10.0f);

   draw_temp(g_batt.t_max, level_eval(g_batt.t_max, &TEMP_THR));

   if(g_batt.fault & FAULT_INSUL) draw_alarm("绝缘故障");

}

六、故障优先级

多个告警同时来,界面只能突出最要命的那个:

void render_fault(uint8_t f){

   if(f & FAULT_INSUL)   { show_red("绝缘故障"); return; }

   if(f & FAULT_OVT)     { show_red("电池过温"); return; }

   if(f & FAULT_OVV)     { show_red("单体过压"); return; }

   if(f & FAULT_UNDERV)  { show_yellow("电量过低"); return; }

}

BMS侧真正断继电器是它自己的事,HMI只负责把“为什么断”说清楚。

七、落坑清单

把SOC算法写进仪表进程→估算不准还拖慢渲染

CAN帧直接写控件→脏数据让电量乱跳

告警无滞回→过温线来回闪

500ms无报文还显示旧值→用户以为电池正常

多屏各维护一份电池状态→中控和仪表对不上

故障位平级显示→绝缘和低压一起闪分不清

温度显示小数位→读数抖得看不清

SOC每次重绘→数字闪烁刺眼

仪表直接发均衡指令→越权且危险

通信丢帧不降级→假数据继续跑

八、落地顺序

BMS侧算好SOC/SOH,CAN周期上报聚合状态

仪表只维护一份batt_state_t,接收线程做校验去重

电压/温度/电量分级显示,全部带滞回

故障位按优先级渲染,绝缘最高

通信超时置“信号丢失”,不沿用旧值

渲染绑VSync,变化微小不重绘

多屏同源,HMI只读不写控制指令

告警文案对应BMS真实保护动作

BMS与仪表联动的本质是“算归算、传归传、显归显”:BMS把电池状态收敛成一份可信快照,CAN只搬运快照,HMI按阈值和滞回把快照翻译成肉眼可读的条、色、字。仪表程序里最忌讳两件事——把SOC估算挪到HMI里做,以及把原始报文直接绑控件。前者让显示和真实状态逐渐分裂,后者让一根受干扰的CAN线就能把电量条搞成蹦极。做好状态聚合+信任过滤+滞回分级,仪表显示才既跟手又不会吓人一跳。

接下来你更想先看BMS与仪表联动的通信协议设计,还是故障诊断逻辑?



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭