摘要

当前,随着科技的发展,汽车功能的日益增多,汽车仪表系统也变得愈发多元化。传统的机械式指针仪表因为其繁琐的布线方式和点对点的通信方式,已不能满足当前行业的需求。因此,研究一款功能多样,结构简单,安全可靠的仪表系统成为汽车产业技术开发和研究的热点之一[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);
		} 
	}
}

实现效果

在这里插入图片描述

资源获取

下方名片联系我即可!!


博主联系方式:点击我获取资料->->进我个人主页–>获取博主联系方式



大家点赞、收藏、关注、评论啦 、查看👇🏻获取联系方式👇🏻

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐