基于STM32的汽车仪表系统设计
摘要
当前,随着科技的发展,汽车功能的日益增多,汽车仪表系统也变得愈发多元化。传统的机械式指针仪表因为其繁琐的布线方式和点对点的通信方式,已不能满足当前行业的需求。因此,研究一款功能多样,结构简单,安全可靠的仪表系统成为汽车产业技术开发和研究的热点之一[1]。
本次课题基于STM32F407微型控制器以及CAN总线通信技术,设计一款新型全液晶汽车仪表。相比于传统的机械式指针仪表,本设计的汽车仪表具有简单的接线方式,快速的模块之间通讯以及全液晶显示等特点。同时,该课题中采用emWin技术进行LCD液晶显示屏的设计,具有更直观美化的人机交互界面,而且由于采用了CAN总线通信方式,元器件与控制元件(ECU)之间信息传递性将会更好。本次课题,采用CAN分析仪开发测试工具,通过定义好相关模拟变量,模拟实际汽车中的情况输入CAN信号报文并利用Simulink建模进行汽车仪表灯的逻辑处理。同时将FreeRTOS实时操作系统移植到STM32F407上,利用STM32芯片输入输出信号,进而达到点亮汽车仪表的目的。
通过软件与硬件方面的调试,该课题达到了预期研究要求,证明了课题技术上的可行性以及延展性。
设计内容
本项目基于STM32F407设计的汽车仪表系统由:主控芯片,CAN通讯模块,按键模块,LCD显示模块和报警模块组成。STM32主控制芯片负责在接收到CAN通信传来的信号或者按键按下时的系统任务调度,经过主控芯片处理后,会输送到LCD显示模块和报警模块,执行点亮或熄灭相关指示灯,蜂鸣器警报,同步水温表,车速表等操作。系统功能框图如图1.1所示。

图1.1 系统功能框图
该项目分为两种控制方式:CAN总线通信以及按键硬线通信。通过使用CAN收发器实时发送CAN报文给STM32芯片,STM32芯片会判断是否满足相关条件,执行点亮/闪烁/熄灭相关仪表灯或报警。由于在STM32中移植FreeRTOS实时操作系统,会在一个循环周期内不停检测是否接收到CAN报文,执行多个任务调度,实现多个仪表灯的控制。按键控制则是通过定义好的I/O口与仪表灯,当按键按下或取消时,仪表灯和报警会有对应的显示。至此为该项目的流程与功能。
程序函数
#include "GUI.h"
#include "JPGResource.h"
#include "displayapp.h"
#include "sys.h"
#include "delay.h"
#include "key.h"
#include "Beep.h"
uint16_t gEngCoolantValue = 0;
uint16_t gFuelResistanceValue = 0;
uint16_t gESCVehSpeed = 0; //0-170km/h
uint32_t gEMSEngSpd = 0; //0-8000
uint32_t gODOMeter = 0;
uint8_t gturnleft = 0;
uint8_t gturnright = 0;
uint32_t flag = 0;
uint8_t gAir = 0;
uint8_t gseatbelt = 0;
uint8_t gseatbelt1 = 0;
uint8_t gABSwarning = 0;
uint8_t gPark = 0;
uint8_t gposition = 0;
static const GUI_POINT aPointer[] = {
{ 0, 10 },
{ 150, 0 },
{ 0, -10 },
{ -20, 0 },
};
static const GUI_POINT aSmallPointer[] = {
{ 0, 5 },
{ 40, 0 },
{ 0, -5 },
{ -10, 0 },
};
static GUI_POINT aPointerHiRes[countof(aPointer)];
static GUI_POINT aSmallPointerHiRes[countof(aSmallPointer)];
typedef struct {
GUI_AUTODEV_INFO AutoInfo;
GUI_POINT aPoints[countof(aPointer)];
GUI_POINT aSmallPoints[countof(aSmallPointer)];
int Factor;
}PARAMPolygon;
#define HMI_POS_Y 25
static void DrawSpeed(void * p)
{
int posX = 25, posY = HMI_POS_Y;
PARAMPolygon * pParam = (PARAMPolygon *)p;
if (pParam->AutoInfo.DrawFixed) {
GUI_ClearRect(posX, posY, bmspeed.XSize + posX, bmspeed.YSize + posY);
GUI_DrawBitmap(&bmspeed,posX,posY);
}
GUI_AA_FillPolygon(pParam->aPoints, countof(aPointer), (posX + 160)*pParam->Factor, (posY + 160)* pParam->Factor );//车速针
GUI_AA_FillPolygon(pParam->aSmallPoints, countof(aSmallPointer), (posX + 170)*pParam->Factor, (posY + 305)* pParam->Factor);//油表针
}
static void DrawVelocity(void * p)
{
int posX = 425, posY = HMI_POS_Y;
PARAMPolygon * pParam = (PARAMPolygon *)p;
if (pParam->AutoInfo.DrawFixed) {
GUI_ClearRect(posX, posY, bmvelocity.XSize + posX, bmvelocity.YSize + posY);
GUI_DrawBitmap(&bmvelocity,posX,posY);
}
GUI_AA_FillPolygon(pParam->aPoints, countof(aPointer), posX + 160, posY + 160);//转速针
GUI_AA_FillPolygon(pParam->aSmallPoints, countof(aSmallPointer), posX + 170, posY + 305);//水温
}
void keyBeam()
{
u8 key;
key=KEY_Scan(0);
if(key)
{
if(key == WKUP_PRES)
{
GUI_DrawBitmap(&bmHigh_Beam,610,380);
}
else
{
GUI_ClearRect(610, 380, bmHigh_Beam.XSize + 610, bmHigh_Beam.YSize + 380);
}
if(key == KEY0_PRES)
{
GUI_DrawBitmap(&bmlow_beam,530,380);
}
else
{
GUI_ClearRect(530, 380, bmlow_beam.XSize + 530, bmlow_beam.YSize + 380);
}
}else delay_ms(10);
}
void show()
{
if( gturnleft == 1)
{
if( flag == 1)
{
GUI_DrawBitmap(&bmTurn_left,255,380);
BEEP = 1;
delay_ms(100);
BEEP = 0;
}
else
{
GUI_ClearRect(255, 380, bmTurn_left.XSize + 255, bmTurn_left.YSize + 380);
}
}
if( gturnright == 1)
{
if( flag == 1)
{
GUI_DrawBitmap(&bmTurn_right,445,380);
BEEP = 1;
delay_ms(100);
BEEP = 0;
}
else
{
GUI_ClearRect(445, 380, bmTurn_right.XSize + 445, bmTurn_right.YSize + 380);
}
}
if( gABSwarning == 1)
{
GUI_DrawBitmap(&bmABS_warning,310,5);
}
else
{
GUI_ClearRect(310, 5, bmABS_warning.XSize + 310, bmABS_warning.YSize + 5);
}
if( gPark == 1)
{
static int t = 0;
GUI_DrawBitmap(&bmParkingIndication_green,400,10);
if( t == 0)
{
BEEP = 1;
delay_ms(100);
BEEP = 0;
delay_ms(100);
BEEP = 1;
delay_ms(100);
BEEP = 0;
t = 1;
}
}
else
{
GUI_ClearRect(400, 10, bmParkingIndication_green.XSize + 400, bmParkingIndication_green.YSize + 10);
}
if( gposition == 1)
{
GUI_DrawBitmap(&bmPosition_lamp,690,380);
}
else
{
GUI_ClearRect(690, 380, bmPosition_lamp.XSize + 690, bmPosition_lamp.YSize + 380);
}
if( gAir == 1)
{
GUI_DrawBitmap(&bmAirbag_warning,35,380);
}
else
{
GUI_ClearRect(35, 380, bmAirbag_warning.XSize + 35, bmAirbag_warning.YSize + 380);
}
if( gseatbelt == 1)
{
GUI_DrawBitmap(&bmseatblet,105,380);//显示
BEEP = 1;
delay_ms(50);
BEEP = 0;
delay_ms(50);
BEEP = 1;
delay_ms(50);
BEEP = 0;
delay_ms(1000);
}
else
{
GUI_ClearRect(105, 380, bmseatblet.XSize + 105, bmseatblet.YSize + 380);//清除
}
if( gseatbelt1 == 1)
{
GUI_DrawBitmap(&bmseatblet_1,185,380);//显示
BEEP = 1;
delay_ms(50);
BEEP = 0;
delay_ms(50);
BEEP = 1;
delay_ms(50);
BEEP = 0;
delay_ms(1000);
}
else
{
GUI_ClearRect(185, 380, bmseatblet_1.XSize + 185, bmseatblet_1.YSize + 380);//清除
}
}
#define PI 3.1415
float GetAngleSpeed(uint32_t val)
{
float frange = 1.22 * PI + 0.22 * PI;//车速表
float leftRange = 1.28 * PI;
uint16_t maxSpeed = 170, minSpeed = 0;
float temp;
if ( val > maxSpeed )val = 170;
temp = (float)val / 170 * (frange);
if( temp >0.5 * PI)
{
if ( temp > 1.22 * PI )
{
temp = 2 * PI - ( temp - 1.22 * PI);
}
else
{
temp = 1.22 * PI - temp;
}
}
else
{
temp = leftRange - temp;
}
return temp;
}
float GetAngleEngSpeed(uint32_t val)
{
float frange = 1.22 * PI + 0.19 * PI;
float leftRange = 1.21 * PI;
uint16_t maxSpeed = 8000, minSpeed = 0;
float temp;
if ( val > maxSpeed )val = 8000;
temp = (float)val / (maxSpeed - minSpeed) * (frange);
if ( temp > 1.21 * PI )
{
temp = 2 * PI - (temp - 1.21 * PI);
}
else
{
temp = leftRange - temp;
}
return temp;
}
float GetAngleTempature(uint32_t val)
{
float frange = 1.25 * PI - 0.3 * PI;
float leftRange = 1.25 * PI;
uint16_t maxTempature = 120, minTempature = 0x00;
float temp;
if ( val > maxTempature )val = 120;
temp = (float)val / (maxTempature - minTempature) * (frange);
temp = leftRange - temp;
return temp;
}
float GetAngleFuel(uint32_t val)
{
float frange = 0.93 * PI - 0.07 * PI;
float leftRange = 0.93 * PI;
uint16_t maxFuel = 0x0029, minFuel = 0x00;
float temp;
if ( val > maxFuel )val = 0x0029;
temp = (float)val / (maxFuel - minFuel) * (frange);
temp = leftRange - temp;
return temp;
}
void HMIDisplay(void)
{
GUI_AUTODEV aAuto[10];
PARAMPolygon Param;
int i;
Param.Factor = 3;
for (i = 0; i < countof(aAuto); i++)
{
GUI_MEMDEV_CreateAuto(&aAuto[i]);
}
for (i = 0; i < countof(aPointer); i++)
{
aPointerHiRes[i].x = aPointer[i].x * Param.Factor;
aPointerHiRes[i].y = aPointer[i].y * Param.Factor;
}
for (i = 0; i < countof(aSmallPointer); i++)
{
aSmallPointerHiRes[i].x = aSmallPointer[i].x * Param.Factor;
aSmallPointerHiRes[i].y = aSmallPointer[i].y * Param.Factor;
}
GUI_AA_SetFactor(Param.Factor);
while(1)
{
keyBeam();
show();
for (i = 0; i < 10; i++)
{
GUI_AA_EnableHiRes();
GUI_RotatePolygon(Param.aPoints, aPointerHiRes, countof(aPointer), GetAngleSpeed(gESCVehSpeed));//速度
GUI_RotatePolygon(Param.aSmallPoints, aSmallPointerHiRes, countof(aSmallPointer), GetAngleFuel(gFuelResistanceValue));//油耗
GUI_MEMDEV_DrawAuto(&aAuto[0], &Param.AutoInfo, DrawSpeed, &Param);
GUI_AA_DisableHiRes();
GUI_RotatePolygon(Param.aPoints, aPointer, countof(aPointer), GetAngleEngSpeed(gEMSEngSpd));//转速
GUI_RotatePolygon(Param.aSmallPoints, aSmallPointer, countof(aSmallPointer), GetAngleTempature(gEngCoolantValue));//水温
GUI_MEMDEV_DrawAuto(&aAuto[1], &Param.AutoInfo, DrawVelocity, &Param);
GUI_SetFont(GUI_FONT_D24X32);
GUI_SetTextAlign(GUI_TA_RIGHT);
GUI_GotoXY(425,405);
GUI_DispDecMin(gODOMeter);
GUI_Delay(20);
}
}
}
实现效果

资源获取
下方名片联系我即可!!
博主联系方式:点击我获取资料->->进我个人主页–>获取博主联系方式
大家点赞、收藏、关注、评论啦 、查看👇🏻获取联系方式👇🏻
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)