一、VCU概述与系统架构

大家好,我是老张。在VCU这个领域摸爬滚打了十几年,今天咱们聊聊VCU的基础架构。说实话,很多新手工程师一上来就扎进代码里,结果连VCU在车上到底管什么都搞不清楚。我个人习惯,先看全局,再抠细节。

1.1 VCU在电动汽车中的角色

VCU是什么?说白了,它就是整车的“大脑”。

你想想看,电动汽车里那么多控制器——BMS管电池、MCU管电机、OBC管充电。谁来协调它们?就是VCU。

具体来说,VCU干这几件事:

  • 驾驶员意图解析:你踩油门踩了多少?踩刹车踩了多少?VCU得读懂你的想法。
  • 扭矩分配:前驱后驱?四驱?每个电机给多少扭矩?VCU说了算。
  • 能量管理:什么时候回收能量?回收多少?不能把电池充爆了。
  • 故障诊断与保护:哪个传感器坏了?哪个执行器不听话?VCU得及时发现并处理。
  • 网络管理与状态机:上电、下电、休眠、唤醒,整个流程VCU来调度。

核心观点:没有VCU,电动汽车就是一盘散沙。各个控制器各自为战,根本跑不起来。

我在项目中遇到过一件事。有一次,某款车的BMS和MCU直接通信,跳过了VCU。结果呢?急加速时电池过放,MCU还在傻乎乎地要扭矩。从那以后,我坚持所有关键路径必须经过VCU仲裁。

1.2 VCU硬件架构

VCU的硬件,其实没那么神秘。它本质上就是一个高性能的微控制器,加上一堆外围电路。

我给大家拆解一下:

模块 说明 选型建议
主控芯片 MCU核心,运行控制算法 Infineon TC2xx/TC3xx, NXP S32K, TI TMS570
电源管理 将车载12V/24V转为芯片所需电压 带SBC的系统基础芯片,如TLE926x
CAN收发器 物理层信号转换 TJA1043, TJA1145(带唤醒功能)
数字输入 采集钥匙信号、刹车开关等 带滤波功能的输入接口
模拟输入 采集加速踏板位置、温度等 12位以上ADC,带过压保护
高边驱动 驱动继电器、指示灯等 带诊断功能的智能开关
低边驱动 驱动电磁阀、风扇等 带电流检测的驱动芯片

个人经验:选主控芯片时,别光看主频。我建议重点关注CAN模块的数量和SRAM大小。CAN模块少了,后期扩展麻烦;SRAM小了,跑复杂算法会卡死。

嗯,这里要注意。VCU的硬件设计,最关键的是可靠性。车规级芯片、宽温范围、抗振动设计,这些一个都不能少。我曾经见过一个项目,为了省成本用了工业级芯片,结果夏天高温测试时,VCU直接罢工了。

1.3 VCU软件分层

软件架构这块,我习惯用分层的思想来设计。为什么?因为分层之后,每一层各司其职,出了问题也好定位。

典型的VCU软件分层如下:

  1. 硬件抽象层(HAL):屏蔽硬件差异。换芯片时,只需要改这一层。
  2. 基础软件层(BSW):包括操作系统、CAN协议栈、诊断协议栈等。
  3. 应用层(ASW):核心控制算法,扭矩控制、能量回收都在这里。
  4. 标定层:可标定参数,方便调试和匹配。

我给大家画个图,这样更直观:

VCU软件分层架构 应用层(ASW) 扭矩控制 | 能量回收 | 状态管理 | 故障诊断 标定层(Calibration) 基础软件层(BSW) CAN协议栈 | 诊断协议 | 操作系统 | 存储管理 硬件抽象层(HAL) 硬件层(MCU + 外围电路)

你看,每一层都只跟相邻层打交道。应用层不需要知道CAN报文是怎么发出去的,它只管把数据丢给BSW就行。

避坑指南:我曾经见过一个团队,把CAN驱动代码和应用逻辑混在一起写。结果换了个CAN收发器芯片,整个应用层代码都得重写。这就是不分层的代价。

代码示例,我给大家看一个简单的分层调用:

/* 应用层:扭矩计算 */
float App_CalcTorque(float pedalPos, float speed)
{
    /* 调用标定层获取参数 */
    float maxTorque = Cal_GetParam("MaxTorque");
    
    /* 核心算法 */
    float torque = pedalPos * maxTorque * speed_factor;
    
    /* 调用BSW层发送CAN报文 */
    BSW_SendCanMessage(0x123, (uint8_t*)&torque, 4);
    
    return torque;
}

/* 硬件抽象层:读取踏板 */
float HAL_ReadPedal(void)
{
    /* 屏蔽不同ADC芯片的差异 */
    uint16_t adcVal = ADC_ReadChannel(0);
    return (float)adcVal * 5.0f / 4096.0f;
}

1.4 CAN通信基础

CAN通信,是VCU的命脉。没有CAN,VCU就是个孤岛。

为什么电动汽车都用CAN?说白了,就三个字:稳、快、省

  • :差分信号,抗干扰能力强。车上那么多电机、逆变器,电磁环境恶劣,CAN扛得住。
  • :最高1Mbps的速率,对于控制信号来说足够了。
  • :双线制,布线简单,成本低。

CAN通信的几个关键概念,我给大家捋一捋:

概念 说明 实际应用
CAN ID 报文标识符,决定优先级 ID越小,优先级越高。0x000最高
数据帧 携带数据的报文 扭矩指令、状态信息都用数据帧
远程帧 请求数据的报文 VCU可以发远程帧请求BMS上报SOC
错误帧 总线出错时自动发送 节点检测到错误,主动发送错误帧
位填充 连续5个相同电平后插入反码 保证时钟同步,防止误判

你想想看,VCU要发一个扭矩指令给MCU,流程是这样的:

  1. VCU应用层计算出目标扭矩值
  2. 将扭矩值打包成CAN数据帧,填上CAN ID
  3. CAN控制器自动添加CRC、ACK等位
  4. 通过CAN收发器发送到总线上
  5. MCU收到后,解析数据帧,执行扭矩控制

个人习惯:我设计CAN通信矩阵时,会预留一些备用ID。为什么?因为后期肯定要加功能。我曾经吃过这个亏,矩阵定死了,结果加个功能就得重新分配ID,麻烦得很。

嗯,这里还要提一下CAN的波特率。常见的车载CAN波特率是250kbps和500kbps。我个人建议,动力相关的信号用500kbps,车身控制类的用250kbps。为什么?动力信号实时性要求高,500kbps延迟更小。

核心要点:CAN通信看似简单,但坑很多。总线负载率别超过30%,否则丢帧风险大增。我见过一个项目,负载率干到60%,结果急加速时扭矩指令丢了,车直接没动力。这就是血的教训。

最后,给大家一个CAN报文解析的代码片段:

/* CAN报文解析示例 */
typedef struct {
    uint16_t canId;
    uint8_t data[8];
    uint8_t dlc;
} CanMessage_t;

/* 解析扭矩指令 */
void ParseTorqueCmd(CanMessage_t *msg)
{
    if (msg->canId == 0x0C1)  /* 扭矩指令ID */
    {
        /* 数据格式:Byte0-1为扭矩值,Byte2为方向 */
        int16_t torque = (msg->data[0] << 8) | msg->data[1];
        uint8_t dir = msg->data[2];
        
        if (dir == 0x01)  /* 正向 */
        {
            App_SetTargetTorque(torque);
        }
        else  /* 反向(能量回收) */
        {
            App_SetTargetTorque(-torque);
        }
    }
}

好了,VCU的基础架构就聊到这儿。记住,万丈高楼平地起,基础打牢了,后面学扭矩控制和能量回收才不费劲。


公众号:蓝海资料掘金营,微信deep3321