第12届嵌入式蓝桥杯真题-停车场管理系统的设计与实现

目录

实验要求:

实验思路:

核心代码:

(1)主函数

(2)lcd显示

(3)按键函数

(4)LED显示函数

(5)业务处理函数

(6)PWM函数

实验结果:

思考或体会


实验要求:

1) 设计一个停车计费系统,能够完成费率设置、费用计算等功能。

2) 使用串口(USART获取车辆进、出停车场信息和时间,并能够输出计费信息。

3) 使用按键完成费率设置、调整功能。

4) 按照显示要求,通过 LCD 显示停车状态、费率参数。

5) 通过 PA7(PWM输出固定频率和占空比的脉冲信号或持续低电平。

6) 使用 LED 指示灯完成相关指示功能。

实验思路:

1.涉及到串口中断的相关函数,在CubeMX中也需要相关配置。

2.按键是为LED、LCD服务的,因此最后书写按键状态切换的逻辑。

3.LCD屏幕一共两个屏幕界面,因此要书写两段LCD输出的代码。且板子上电后就有内容显示,默认处于车位显示界面,因此可以首先书写该屏幕的内容保证初始化没问题。

4.PWM输出需要设置时钟,以及降频分频。

5.LED在本题中用到了两处:停车位、PWM状态

核心代码:

(1)主函数

int main(void)

{

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */

HAL_Init();

/* Configure the system clock */

SystemClock_Config();

/* Initialize all configured peripherals */

MX_GPIO_Init();

MX_USART1_UART_Init();

MX_TIM3_Init();

/* Infinite loop */

/* USER CODE BEGIN WHILE */

LCD_Init();//LCD初始化

control_led(LEDALL,OFF);//关闭所有LED灯

ParkingInit();//停车场初始化

HAL_UART_Receive_IT(&huart1, (uint8_t *)usart_rx,RxLen);//接收一次中断

LCD_Clear(Black);//清屏

while (1)

{

lcd_proc();

key_proc();

led_proc();

busi_proc();

pwm_proc();

}

}

(2)lcd显示

void lcd_proc()

{

if(lcd_update_flag==1)//为1时提醒我们要更新lcd了

{

lcd_update_flag=0;

// LCD_Clear(Black);

LCD_SetBackColor(Black);

LCD_SetTextColor(White);

if(lcd_flag == 1)//车位显示界面

{

LCD_DisplayStringLine(Line2,(unsigned char *)"       Data         ");

/*

sprintf函数

用于将我们本应该直接格式化输出的语句内容存储至字符串

位于stdio.h中

*/

sprintf(str,"   CNBR:%d           ",car1);//第四行即将显示的内容

LCD_DisplayStringLine(Line4,(unsigned char *)str);

sprintf(str,"   VNBR:%d           ",car2);//第六行即将显示的内容

LCD_DisplayStringLine(Line6,(unsigned char *)str);

sprintf(str,"   IDLE:%d           ",idle);//第八行即将显示的内容

LCD_DisplayStringLine(Line8,(unsigned char *)str);

}

else//费率设置界面

{

LCD_DisplayStringLine(Line2,(unsigned char *)"       Para         ");

sprintf(str,"   CNBR:%.2f        ",cnbr);

LCD_DisplayStringLine(Line4,(unsigned char *)str);

sprintf(str,"   VNBR:%.2f        ",vnbr);

LCD_DisplayStringLine(Line6,(unsigned char *)str);

LCD_DisplayStringLine(Line8,(unsigned char *)"                    ");

}

}

}

(3)按键函数

void key_proc(void)

{

char value = key_scan();

switch(value)

{

case 1:

/*切换LCD显示屏界面的操作*/

lcd_flag = (lcd_flag == 1 ? 0 : 1);

lcd_update_flag=1;

break;

case 2:

/*CNBR、VNBR费率增加0.5元*/

cnbr += 0.5f;

vnbr += 0.5f;

lcd_update_flag=1;

break;

case 3:

/*CNBR、VNBR费率减少0.5元*/

cnbr -= 0.5f;

vnbr -= 0.5f;

lcd_update_flag=1;

break;

case 4:

/*两种频率输出状态*/

pwm_flag = (pwm_flag == 1 ? 0 : 1);

break;

}

}

(4)LED显示函数

void led_proc(void)

{

if(idle>0)//有车位

{

control_led(LED1,ON);//LED1亮

}

else

{

control_led(LED1,OFF);

}

if(pwm_flag==1)//持续低电平

control_led(LED2,OFF);

else

control_led(LED2,ON);

}

(5)业务处理函数

void busi_proc(void)

{

if(RxEndFlag==1)//串口收到信息则发生中断

{

RxEndFlag = 0;

if(DataSplit())//若传入分割后的字符串合法

{

//初始化结构体

Car car = CarInit(type,id);

Time time = TimeInit(year,month,day,hour,minute,second);

//流程处理

park_proc(park,car,time);

}

if(lcd_flag ==1)//当前是停车信息界面,则需要更新数值

{

lcd_update_flag =1;//lcd屏幕内容要更新了

}

//接收串口传来的信息,然后中断

HAL_UART_Receive_IT(&huart1,(uint8_t*)usart_rx,RxLen);

}

}

(6)PWM函数

void pwm_proc(void)

{

if(pwm_flag)//低电平

{

HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);

__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,0);//占空比0

HAL_Delay(5);

}

else//高电平

{

HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);

__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,100);//占空比100/500=20%

HAL_Delay(5);

}

}

(7)其他函数(与停车场相关函数位于busi.c中)

//车辆信息初始化

Car CarInit(char* type,char* id)

{

Car car;

strcpy(car.type,type);

strcpy(car.id,id);

return car;

}

//时间设置

Time TimeInit(int year,int month,int day,int hour,int minute,int second)

{

Time time;

time.year = year;time.month = month;time.day = day;

time.hour = hour;time.minute = minute;time.second = second;

return time;

}

//停车场初始化

void ParkingInit(void)

{

int i=0;

for(i=0;i<PARKING_SIZE;i++)

{

Car car = CarInit("","");

Time time = TimeInit(0,0,0,0,0,0);

park[i].car = car;

park[i].time = time;

park[i].flag = 1;//1为可以停车,0为不能停车

}

}

//判断传入字符串格式是否正确

int DataSplit(void)

{

/*分割数据:数据来自uart的接收端*/

sscanf((char *)usart_rx,"%4s:%4s:%2d%2d%2d%2d%2d%2d",type,id,&year,&month,&day,&hour,&minute,&second);

/*清空buffer*/

memset(usart_rx,0,sizeof(usart_rx));

/*字符校验*/

//两种车的类型都不属于

if(strcmp(type,"CNBR")!=0 && strcmp(type,"VNBR")!=0)

{

//错误提示给usart发送端

sprintf(usart_tx,"Type Match Error\n");

HAL_UART_Transmit(&huart1,(unsigned char *)usart_tx,strlen(usart_tx),TxLen);

return 0;

}

//时间书写有问题

else if(month>12||day>31||hour>24||minute>60||second>60)

{

sprintf(usart_tx,"Time Format Error\n");

HAL_UART_Transmit(&huart1,(unsigned char *)usart_tx,strlen(usart_tx),TxLen);

return 0;

}

return 1;//正确则返回1

}

//判断当前车位是否是空

int IsEmpty(Parking now)

{

return now.flag;

}

//判断目前的车是进场还是离场(停车场原来就存在则为离场)

int IsExist(Car oldcar,Car newcar)

{

if(strcmp(oldcar.id,newcar.id)==0 && strcmp(oldcar.type,newcar.type)==0)

{

return 1;

}

return 0;

}

//车辆进入停车场

int ParkIn(Parking *park,Car car,Time enter)

{

int i=0;

if(idle==0)//没有空闲车位

{

return 0;

}

for(i=0;i<PARKING_SIZE;i++)

{

if(IsEmpty(park[i]))

{

park[i].car = car;

park[i].time = enter;

park[i].flag = 0;

idle--;

if(strcmp(car.type,"CNBR") == 0)

{

car1++;

}

if(strcmp(car.type,"VNBR")==0)

{

car2++;

}

if(idle == 0)

{

control_led(LED1,OFF);

}

else

{

control_led(LED1,ON);

}

return 1;

}

}

return 0;

}

//车辆离开停车场

float ParkOut(Parking *park,Car car,Time leave)

{

int i,ptime1,ptime2;

i = ptime1 = ptime2 = 0;

float price = 0;

Car oldcar;

Time oldtime;

for(i=0;i<8;i++)

{

oldcar = park[i].car;

oldtime = park[i].time;

//进入if循环则说明是要从这个位置离开停车场

if(IsExist(oldcar,car))

{

//判断时间是否合法

ptime1 = (leave.year - oldtime.year)*365*24 +

(leave.month - oldtime.month)*30*24 +

(leave.day - oldtime.day)*24 +

(leave.hour - oldtime.hour)*1;

ptime2 = (leave.minute - oldtime.minute)*60 +

(leave.second - oldtime.second);

//进入if说明时间不合法

if(ptime1<0 || ptime2<0)

{

return -2;//time error

}

else

{

idle++;

if(strcmp(car.type,"CNBR")==0)

{

price = cnbr;

car1--;

}

if(strcmp(car.type,"VNBR")==0)

{

price = vnbr;

car2--;

}

ClearPark(park,i);

ParkTime = ptime2>0 ? (ptime1+1) : ptime1;

SumMoney = (float)price*ParkTime;

return SumMoney;

}

}

}

return -1;//没有匹配的车位,说明这辆车原本就不在车库里

}

//清空某车位信息

void ClearPark(Parking *park,int location)

{

Car car;

Time time;

car=CarInit("","");

time = TimeInit(0,0,0,0,0,0);

park[location].car = car;

park[location].time = time;

park[location].flag = 1;

return ;

}

//串口通信函数

void park_proc(Parking *park,Car car,Time time)

{

SumMoney = ParkOut(park, car, time);

//没有匹配,就尝试能不能进入停车场

if(SumMoney==-1.0)

{

if(ParkIn(park,car,time))

{

sprintf(usart_tx,"Success Parking Car!\n");

HAL_UART_Transmit(&huart1,(unsigned char*)usart_tx,strlen(usart_tx),TxLen);

}

else

{

sprintf(usart_tx,"Error! Parking is full\n");

HAL_UART_Transmit(&huart1,(unsigned char*)usart_tx,strlen(usart_tx),TxLen);

}

}

//时间非法

if(SumMoney==-2.0)

{

sprintf(usart_tx,"Time Logic Error ! \n");

HAL_UART_Transmit(&huart1,(unsigned char*)usart_tx,strlen(usart_tx),TxLen);

}

//出库成功

if(SumMoney>=0)

{

sprintf(usart_tx,"%s:%s:%d:%.2f\n",car.type,car.id,ParkTime,SumMoney);

HAL_UART_Transmit(&huart1,(unsigned char*)usart_tx,strlen(usart_tx),TxLen);

}

}

实验结果:

第12届嵌入式蓝桥杯真题-停车场管理系统的设计与实现_第1张图片第12届嵌入式蓝桥杯真题-停车场管理系统的设计与实现_第2张图片第12届嵌入式蓝桥杯真题-停车场管理系统的设计与实现_第3张图片

 第12届嵌入式蓝桥杯真题-停车场管理系统的设计与实现_第4张图片

 第12届嵌入式蓝桥杯真题-停车场管理系统的设计与实现_第5张图片

 第12届嵌入式蓝桥杯真题-停车场管理系统的设计与实现_第6张图片

思考或体会

1. 实验的初始化很重要,CubeMX配置一定不能出现差错,特别是配置时钟时频率设置出错会造成很大影响。

2.题目需要我们书写许多额外的头文件和.c文件,例如在书写停车场业务头文件前,我们首先要考虑关于停车场我们都需要有什么:

各种基本属性(车、时间、停车位);进车库出车库操作还有一些基本的异常处理函数。我们就需要围绕以上设想进行书写

3.串口中断一定要在进入while循环前首先调用一次接收函数,否则无法进行Callback回调,造成通讯失败。

4.模块之间关联多用一些状态变量,实现多模块的同步协调通信。

你可能感兴趣的:(嵌入式STM32,蓝桥杯,单片机,stm32)