电动车整车控制器的设计与开发
电动车整车控制器的设计与开发
本文主要围绕作者在长沙理工大学方程式赛车队中所设计的电动车整车控制器的软硬件及整车控制策略进行介绍,具体内容如下:
1. 根据对电动汽车功能的需求,研究设计整车控制器的硬件电路。
2. 分析电动汽车的控制需求,设计整车的控制策略和软件代码,包括高压电的上电策略、扭矩管理、CAN报文优先级的设计和CAN通信软件设计等。
关键词:整车控制器;STM32;控制策略;CAN通信协议
1. 电动车整车控制器整体功能
电动车整车控制器采用了STM32F407作为主控芯片进行设计,主频最高可达168MHz,主要功能有(本文主要针对基础功能进行介绍):
1.模拟量信号采集、开关量信号采集、频率量信号采集。(基础功能)
2.用电器控制、高压电上电控制、电机扭矩控制。(基础功能)
3.与仪表进行通信,实现数据显示及人机交互等相关功能。(扩展功能)
如图1.1所示,仪表采用4.7寸串口屏,主要用于显示车速,高压电池电量,低压电池电量,水温,最高电芯温度,油门开度,电池箱总电流等关键参数,同时还可以在一定范围内对相关参数进行调节以实现人机交互的功能。
图1.1 仪表界面示意图
4.作为下位机通过4G-LTE模块进行远程数据传输并与上位机共同组成远程实时监控系统。(扩展功能)
如图1.2所示,远程实时监控系统(上位机)采用C#语言进行编写,可支持串口(nRF24L01)和TCP(4G网络透传)两种模式进行任意地切换。画面简洁明了,使队员对赛车运动时的状况有更好的了解,也为后期的调试带来了极大的便利。
图1.2 上位机界面示意图
2. 电动车整车控制器硬件设计
图2 整车控制器硬件电路设计架构
2.1 主控芯片的选型
对于纯电动汽车整车控制器,其输入、输出量多,对数据处理的实时性要求极高,因此,主控芯片的处理速度成为了最重要的选型标准。目前市场上主流的电动汽车整车控制器主控芯片为32位MCU。根据这一标准,本文采用了STM32F407作为主控芯片,其主频高达168MHZ,处理速度完全达到我们整车控制的要求,且其功能强大,具有两路CAN通信接口,I2C总线、SPI总线、串行通信接口、12位ADC和12位DAC等片内外设。
2.2 最小系统的设计
2.2.1 时钟电路
时钟电路是单片机正常运作必不可少的电路,其相当于人的心脏一样,提供生命信号,没有了时钟信号,单片机就处于瘫痪状态。STM32F407是通过外部晶振与内部振荡器共同作用产生时钟信号的,本文选用的外部晶振为8MHz石英晶振,滤波电容选用两个22pF的陶瓷电容。电路图如图2.2.1所示
图2.2.1 时钟电路
2.2.2 复位电路
主控芯片工作开始于复位,复位后,寄存器和端口状态复位至默认值,之后程序从默认起始地址开始执行。复位可把单片机状态强制恢复值默认状态。STM32F407有四种常用复位方式:上电复位、手动复位、软件复位、内核复位函数复位。下面介绍手动复位电路的设计与复位原理。STM32的RESET引脚电平被拉低即可以使单片机复位,上电复位原理是通过一个RC延时电路,上电时,由于电容电压不能突变,因此,上电时,RESET为低电平,电容开始充电,慢慢的,电容电压达到3.3V,RESET变为高电平,退出复位。若要手动复位,则需要将RESET位手动拉低,因此,在电容两端并联一个可自动复位的按钮,当按钮按下时,RESET被拉低,单片机复位。电路如图2.2.2所示。
图2.2.2 手动复位电路
2.2.3 电源电路
电动汽车电源分高压与低压两部分,整车控制器的电源来自低压12V电瓶。由于大多数芯片供电是5V,主控芯片供电是3.3V。因此,12V是不能直接给芯片供电的,需要先进行DC-DC降压。本文选用的降压芯片为TI公司生产的LM2576S-5.0,其使用负反馈方式能稳定输出5V电压,并能有限抑制电源纹波,最大输出电流可达3A,完全满足低压系统5V供电的器件使用。12V降到5V后,再通过LDO芯片AMS1117-3.3,由于该款芯片为线性稳压,因此,当输入和输出电压的压差过大,并且输出电流输出较大时,芯片的发热量将会增加,5V输入和3.3V输出,降5V降至3.3V供单片机使用,满足芯片的设计需求。电路图如图2.2.3所示。
图2.2.3 电源电路
2.3 传感器信号采集电路
2.3.1 油门踏板传感器信号采集
油门踏板传感器是电动汽车动力系统中的一个重要部件,用于采集油门踏板的开度信息,其信号为模拟信号,该信号通过ADC采集,整车控制器经过处理与分析后,将给电机控制器发送目标扭矩请求,控制汽车加速、减速、前进或后退。
为了识别油门踏板传感器信号的微小变化,在AD采集前加一个电压跟随器,用于阻抗变换。电压跟随器如图2.3.1.1所示。
图2.3.1.1 电压跟随器
其中R30的作用是消反射的,运放的2、3脚理论上是电压相同的,且输入阻抗是无穷大!那么输入信号的电流主要是通过R27流入地,也就是输入点的电压在同相输入端形成,理论上不会有电流流入R30,如果没有R30那么信号就会100%反射到同相输入端,如果信号源的内阻非常的大,也就是带载的能力很差,反射的信号就会在R27的输入点附近形成很强的发射震荡也就是"回音"这样的噪声经过放大就会使输出信号质量很差,R30和C22的接入可以把在3pin的反射信号有效地吸收,高频的反射信号通过C22泄放到地(GND)R30把反射的信号阻隔在3pin的输入端。R27、R30、R41的选取和运放的工作阻抗有关。D4、D10静电钳位,防止输出电压过大或者过小,通常的电路都有内阻,一般的数字电路的普遍内阻在100ohm左右, VCC 5V的情况下,最大输出电流50mA,所以电路中使用100ohm的电阻来消反射。为了验证电路的有效性,使用Multisim对该电路进行了仿真,仿真结果如图2.3.1.2所示。
图2.3.1.2 电压跟随器仿真结果
2.3.2 制动压力传感器信号采集
汽车的制动系统多为液压式,制动踏板踩下后,制动油管内的制动液被压缩,由于液体几乎无法被压缩,制动液的将压力传递到每个车轮的制动卡钳的活塞上,活塞驱动制动卡钳夹紧制动盘,从而产生巨大的摩擦力令汽车减速。
制动压力传感器被安装在制动油管内,油管内的的压力发生变化,制动压力传感器的电荷分布也发生变化,微弱的电压变化经过放大后形成传感器的信号输出,被整车控制器采集。
制动压力传感器的输出信号为模拟信号,因此也需要在输入到单片机前经过一个电压跟随器。制动压力传感器实物如图2.3.2所示。
图2.3.2 制动压力传感器实物图
2.4 开关量信号采集电路
汽车上许多地方会使用到开关量信号,如:钥匙信号、空调开关、各种灯光信号、挡位信号等。这些开关量信号通常为5V,有些为12V,若这么高的电压不经处理,直接输入单片机,很可能会直接烧毁单片机。开关量信号也有一些是按钮提高,按钮在按下时,会出现抖动,若没有经过消抖处理,单片机可能会连续处理几次该信号,造成一些不必要的错误。因此,开关量信号输入单片机前,应该经过一些处理,将输入电压变成单片机能接收的电压,并经过消抖处理。本文的处理是经过一个光耦隔离,将前级的输入转变成3.3V后,输入单片机。开关量信号处理电路如图2.4所示。
图2.4 开关量信号处理电路
如图所示,当开关量输入信号为低电平的时候,光耦的发光二极管导通,使光敏晶体管导通,PC2被拉低,即输入到单片机的信号为低电平。相反,当开关量输入信号为高电平的时候,光耦截止,PC2为高电平。
2.5 车上用电器控制电路设计
汽车上有许多用电器,如灯光、水泵、风扇、喇叭等。这些用电器都需要整车控制器来控制。而这些用电器其功率一半都比较大,控制器无法直接驱动,因此,必须设计一些驱动电路来驱动。通常单片机输出的信号为数字信号,即高低电平的形式。因此,本文使用大功率MOS管驱动车上的用电器。经过调查用电器的功率,功率最大的水泵为24W。因此,MOS管最大功率必须满足并大于24W。本文选用的MOS管为光宇睿芯公司生产的SE4020B,该MOS管为N沟道,漏极持续电流可达20A,漏源电压为40V,栅源极阈值电压为2V。部分参数如图2.5.1所示。
图2.5.1 SE4020B部分参数表
如图2.5.2所示,该电路图位喇叭驱动电路,喇叭的正极接12V电源,负极接MOS管的漏极,MOS管源极接地,栅极被一个10k电阻下拉到地。当speaker为高电平时,MOS管导通,因为12V电源与整车控制器共地,所以MOS导通,speaker工作。水泵、风扇等用电器驱动电路和喇叭驱动电路同理。
图2.5.2 喇叭驱动电路
2.6 CAN通信硬件设计
本文使用的CAN控制芯片为TJA1050,其供电电压为5V,在电源与地之间并联一个100nf的陶瓷电容,用于滤除电源上的纹波高频干扰。其输出端CAN_H与CAN_L间并联一个120Ω终端电阻,用于匹配总线阻抗,吸收信号反射以及回波,提高数据通信的抗干扰性及可靠性。电路图如图2.6所示。
图2.6 CAN总线硬件原理图
2.7 PCB板设计
在原理图设计完成后,就要进入PCB绘制的环节了。随着集成芯片的发展,市面上的微处理器的工作频率越来越快,对PCB板的抗干扰能力的要求也越来越高。因此,PCB绘制的规范性也变得越来越重要。下面总结了几点PCB绘制的规范:
- 布局合理:将板子上的高压和低压部分分开,高频和低频分开,电源尽量原理高频电路。这能提高板子的抗干扰能力,防止电源的纹波对高频线路的干扰。
- 线宽合理:不同电流应该选用不同的线宽,大电流的电源线至少要1mm,而电流小的信号线也不能用太小,一般不小于6mil,因为太小了生产工艺无法满足设计要求。
- 走线应该尽量最短,不能绕的太远。走线不能出现锐角和直角,因为锐角和直角的走线会造成信号的反射还会使线宽发生变化造成阻抗的不连续性。
- 合理选用多点接地和单点接地。工作频率低时可用单点接地,而工作频率高的时候应该使用多点接地。
绘制完PCB图后的PCB效果图如图2.7.1所示,实物图如图2.7.2所示。
图2.7.1 整车控制器PCB图
图2.7.2 整车控制器实物图
3. 电动车整车控制器控制策略及软件设计
3.1 上电策略
电动汽车由于分为低压电路和高压电路两部分,因此上电必须要有必要的策略。由低压电路控制高压电路。当驾驶员将钥匙钮到on的位置时,整车的低压系统上电,整车控制器(VCU)首先会进行自检,检测模拟输入输出、CAN总线等是否有故障。自检完成后并且无故障情况下,整车控制器会向电池管理系统发送上电指令,BMS收到指令后首先进行自检,自检无故障后,闭合预充继电器,预充完成后闭合正极和负极两个高压继电器,此时高压系统已经闭合,但没有电流输出给电机。BMS将上电完成的信息反馈给VCU,VCU收到BMS的反馈后,将发送指令给电机控制器,告诉电机控制器此时可以激活。但是此时也不能起步,还必须要有驾驶员的操作。就是驾驶员必须用力踩下制动踏板,并且将档把从P档推到D档,当VCU采集到制动压力的值达到设定值并且挡位处于D档时,VCU向电机控制器发送扭矩请求指令,若驾驶员没有踩下加速踏板或者一直踩下制动踏板,VCU发送的扭矩请求为0。上电策略流程图如图3.1所示。
图3.1 上电策略流程图
3.2 扭矩管理
电动汽车电机扭矩输出通常由油门踏板开度、扭矩系数和电机转速共同决定,不同的电机有着不同的电机特性,根据电机的特性曲线,可以设计相对应的MAP。汽车在不同工况下,其转矩系数也会不同。通常的扭矩变化有三种,如图3.2.1所示。
图3.2.1 三种工况扭矩系数图
第一种工况是追求汽车的动力性,踏板开度不大,但扭矩上升速度快,汽车的加速度相应的也大,适合用于竞速或者爬坡,但是这种情况下会损失其经济性。
第二种工况是线性变化的,这种情况下驾驶员更容易控制,因为其扭矩大小随踏板开度变化是线性的,因此驾驶员在起步加速时,不会出现轻踩踏板汽车快速弹出的情况。
第三种工况则是追求经济性,踏板开度大但是扭矩变化不大,因此汽车消耗的功率也相对较小,这种模式可用于电量不足时需要节省电量的情况。本文主要研究了上述第一和第二两种工况下的扭矩控制策略。
如图3.2.2所示,想要保持电机的动力不损失,需要将电机转速保持在6000转以下,此时电机可以达到最大扭矩输出,随着电机转速的增加,电机的扭矩输出越来越小。当汽车速度上来后,电机转速超过6000转,电机功率随着转速增加而下降。因此电机在高转之后呈现出来的是经济性,在6000转以下呈现的是动力
图3.2.2 电机特性曲线图
图3.2.3 扭矩与车速关系图
而第二种为线性工况,该种情况相对较简单,只需要将油门踏板与扭矩输出设置为线性比例关系即可。比例关系公式为:扭矩=1.4*踏板开度。比例系数为1.4。扭矩请求计算程序如程序3.2.4所示。
1 u8 Get_Torque(float pedal,u16 Motor_Speed) 2 { 3 static int torque_last=0; 4 u8 torque_1,torque_2,torque_num,torque_last_num,Motor_Speed_num; 5 torque_1=1.4*pedal; //计算目标扭矩 6 vTaskDelay(50); 7 torque_num=torque_1/2; 8 if(torque_num>=85) torque_num=85; 9 torque_last_num=torque_last/10; 10 if(torque_last_num>=18) torque_last_num=18; 11 Motor_Speed_num=Motor_Speed/250; 12 if(Motor_Speed_num>=28) Motor_Speed_num=28; 13 torque_2=torque_filter[torque_last_num][torque_num]; //扭矩查表滤波 14 torque=torque_2*Motor_speed_cor[Motor_Speed_num]; //MOTOR转速修正 15 torque_last=torque; 16 return torque; 17 }
程序3.2.4 扭矩请求计算程序
3.3 CAN报文优先级设计
汽车在行驶过程中,CAN通讯时刻在进行着。一共有多达上百条报文。这么多的报文,有些是强实时性消息,有些是弱实时性消息,还有软实时性消息。强实时性消息一般是会对行车安全造成严重影响的,这些信息不能由于被别的报文抢占或者发送时间等待太长。因此必须能被及时处理,这些报文的优先级应该属于最高优先级。而弱实时性消息,则可安排相对低一级的优先级。而软实时性消息则是发送一些反馈电机状态或者电池状态的信息,对行车安全不会造成影响的信息。表3-1列举了强实时性消息和弱实时性消息的报文还有发送周期等。
表3-1
消息类别 |
报文名称 |
发送节点 |
发送周期(ms) |
截止期(ms) |
数据字节 |
|||||
强实时性消息 |
VCU紧急呼叫 |
VCU |
事件触发 |
5 |
8 |
|||||
MCU紧急呼叫 |
MCU |
事件触发 |
5 |
8 |
||||||
BMS紧急呼叫 |
BMS |
事件触发 |
5 |
8 |
||||||
弱实时性消息 |
电机控制指令 |
VCU |
10 |
10 |
8 |
|||||
电池控制指令 |
VCU |
10 |
10 |
8 |
||||||
总线状态 |
VCU |
10 |
10 |
8 |
||||||
制动踏板 |
VCU |
10 |
10 |
8 |
||||||
整车故障 |
VCU |
事件触发 |
50 |
8 |
||||||
电机故障 |
MCU |
事件触发 |
50 |
8 |
||||||
电池故障 |
BMS |
事件触发 |
50 |
8 |
||||||
电机状态 |
MCU |
50 |
50 |
8 |
||||||
软实时性消息 |
生命信号 |
VCU |
200 |
200 |
8 |
|||||
电池状态 |
BMS |
200 |
200 |
8 |
||||||
电机反馈 |
MCU |
500 |
500 |
8 |
3.4 CAN通信软件设计
要实现CAN通信,还需要对MCU进行代码编写。首先要对CAN总线控制器进行初始化配置,即使能对应的I/O口。初始化配置程序代码如程序3.4.1所示。CAN1使用过滤器0,CAN2使用过滤器14,优先级由报文ID来决定,CAN通信波特率设置为250k,接收所有FIFO。
1 //CAN单元设置 2 CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式 3 CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理 4 CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位) 5 CAN_InitStructure.CAN_NART=ENABLE; //禁止报文自动传送 6 CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的 7 CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定 8 CAN_InitStructure.CAN_Mode= mode; //模式设置 9 CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq 10 CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq 11 CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~ CAN_BS2_8tq 12 CAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为brp+1 13 CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1 14 15 //配置过滤器 16 CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0 17 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 18 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 19 CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;////32位ID 20 CAN_FilterInitStructure.CAN_FilterIdLow=0x0000; 21 CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK 22 CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000; 23 CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0 24 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0 25 CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
程序3.4.1 CAN总线初始化配置代码
接下来是编写CAN总线的接收程序和发送程序。如程序3.4.2所示,接收程序思路为:首先判断是否有接收到数据,若没有,则直接跳出程序。接收到数据后,读取数据,读取数据子函数会将数据存放到结构体的RxMessage.Data数组中,然后通过一个循环,将数据从RxMessage.Data数组中存放到自己规定的数组中。最后返回数据长度并退出函数。
1 u8 CAN1_Receive_Msg(u8 *buf) 2 { 3 u32 i; 4 CanRxMsg RxMessage; 5 if(CAN_MessagePending(CAN1,CAN_FIFO0)==0) return 0;//没有接收到数据,直接退出 6 CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据 7 extID=RxMessage.ExtId; 8 printf("ID:%d\r\n",RxMessage.ExtId); 9 for(i=0;i<RxMessage.DLC;i++) 10 { 11 buf[i]=RxMessage.Data[i]; 12 printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]); 13 } 14 Get_data(buf,extID);//数据解析 15 return RxMessage.DLC; 16 }
程序3.4.2 CAN总线接收程序代码
如程序3.4.3所示,发送程序思路为:首先输入要发送的报文标识符,将标识符存放到对应的结构体变量中。将IDE和RTR分别配置成1、0,即使用扩展帧,消息类型为数据帧,一帧8位。配置好后,将要发送的数组通过一个for循环,存放到结构体数组TxMessage.Data中,然后发送,等待发送成功后返回0,直接退出函数。
1 u8 CAN1_Send_Msg(u8* msg,u8 len) 2 { 3 u8 mbox; 4 u16 i=0; 5 CanTxMsg TxMessage; 6 TxMessage.StdId=0x00; // 标准标识符为0 7 TxMessage.ExtId=0xCFF08EF;// 设置扩展标示符(29位) 8 TxMessage.IDE=1; // 使用扩展标识符 9 TxMessage.RTR=0; // 消息类型为数据帧,一帧8位 10 TxMessage.DLC=len; // 发送两帧信息 11 for(i=0;i<len;i++) 12 TxMessage.Data[i]=msg[i];// 第一帧信息 13 mbox= CAN_Transmit(CAN1, &TxMessage); 14 i=0; 15 while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;//等待发送结束 16 if(i>=0XFFF)return 1; 17 return 0; 18 }
程序3.4.3 CAN总线发送程序代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结