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

news2025/1/12 12:18:44

目录

实验要求:

实验思路:

核心代码:

(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);

}

}

实验结果:

 

 

 

思考或体会

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

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94501.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度理解取模

深度理解取模一.取模概念二.负数取模三.进一步的解释四.取模和取余是一样的吗&#xff1f;一.取模概念 二.负数取模 上面的代码一目了然就不再多少啦&#xff0c;但如果是负数取模又该怎么办呢&#xff1f; 以上a/b-3是很好理解的&#xff0c;那为什么取模后的值是-1呢&#xf…

useEffect 和 useLayoutEffect 的源码解读

文章目录useEffect 和 useLayoutEffect 的源码解读useEffect源码解读mountEffectImplpushEffectupdateEffectImpl疑惑&#xff1a;useLayOutEffect源码解读mountLayoutEffectupdateLayoutEffect总结useEffect 和 useLayoutEffect 的源码解读 useEffect 文件在 packages/react…

毕业设计-基于深度学习的交通标识识别-opencv

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

叠氮-聚乙二醇-羧基,N3-PEG-COOH 异双功能PEG衍生物COOH-PEG-N3又名Azide-PEG-acid,可用于修饰蛋白质

英文名称&#xff1a;N3-PEG-COOH&#xff1b;COOH-PEG-N3 Azide-PEG-acid 中文名称&#xff1a;叠氮-聚乙二醇-羧基&#xff1b;羧基-聚乙二醇-叠氮 存储条件&#xff1a;-20C&#xff0c;避光干燥 用 途&#xff1a;仅用于科学研究&#xff0c;不能用于人体 外观: 固体或…

【OpenFeign】【源码+图解】【一】HelloWorld及其工作原理

目录1. HelloWorld1.1 pom.xml1.2 yml配置1.3 开启OpenFeign1.4 创建Product的FeignClient1.5 Controller2. OpenFeign的工作原理1. HelloWorld 服务中心以及Product微服务继续使用LoadBalance中的HelloWorld&#xff0c;新建一个client作为OpenFeign的例子 1.1 pom.xml 引入…

【视觉高级篇】26 # 如何绘制带宽度的曲线?

说明 【跟月影学可视化】学习笔记。 如何用 Canvas2D 绘制带宽度的曲线&#xff1f; Canvas2D 提供了相应的 API&#xff0c;能够绘制出不同宽度、具有特定连线方式&#xff08;lineJoin&#xff09;和线帽形状&#xff08;lineCap&#xff09;的曲线&#xff0c;绘制曲线非…

力扣(1053.115)补9.13

1053.不相交的线 不会&#xff0c;这题和1143题代码一样&#xff0c;只不过题意不太能懂&#xff0c;难想&#xff0c;难想。 115.不同的子序列 难想&#xff0c;这种题就跟该画dp图去理解&#xff0c;太难了。 跟着图去模拟一下&#xff0c;要不然真的答案都看不懂。 dp[i][j…

Servlet知识

1、什么是Servlet&#xff1f; Servlet&#xff08;Server Applet&#xff09;是Java Servlet的简称&#xff0c;称为小服务程序或服务连接器&#xff0c;用Java编写的服务器端程序&#xff0c;具有独立于平台和协议的特性&#xff0c;主要功能在于交互式地浏览和生成数据&…

机器学习笔记:scikit-learn pipeline使用示例

0. 前言 在机器学习中&#xff0c;管道机制是指将一系列处理步骤串连起来自动地一个接一个地运行的机制。Scikit-Learn提供了pipeline类用于实现机器学习管道&#xff0c;使用起来十分方便。 既然要将不同处理步骤串联起来&#xff0c;首先必须确保每个步骤的输出与下一个步骤的…

java计算机毕业设计基于安卓Android的数字猎头招聘管理APP

项目介绍 网络的广泛应用给生活带来了十分的便利。所以把数字猎头招聘管理与现在网络相结合,利用java技术建设数字猎头招聘管理APP,实现数字猎头招聘管理的信息化。则对于进一步提高数字猎头招聘管理发展,丰富数字猎头招聘管理经验能起到不少的促进作用。 数字猎头招聘管理APP能…

kafka概念及部署

文章目录一.kafka1.kafka的概念2.Kafka的特性3.工作原理4.文件存储5.消息模式5.1点到点5.2订阅模式6.基础架构一.kafka 1.kafka的概念 Kafka是最初由Linkedin公司开发&#xff0c;是一个分布式、支持分区的&#xff08;partition&#xff09;、多副本的&#xff08;replica&a…

第八章会话控制

文章目录为什么需要会话控制带来的问题如何解决无状态的问题——Cookie如果只靠单纯的Cookie存在的问题单纯Cookie导致问题的解决方法——SessionSessionsession的结构一些关于Session的APISession的保存作用域Cookie时效性会话和持久化Cookie对比Cookie的domain和path为什么需…

后端开发框架的具体内容是什么?

在数据化管理越来越规范的今天&#xff0c;低代码开发平台也迎来了重要的发展期。前后端分离已经成为发展趋势&#xff0c;有不少客户朋友想要咨询后端开发框架的定义和内容&#xff0c;为了帮助大家答疑解惑&#xff0c;小编经过整理&#xff0c;组织出了一篇关于该内容的文章…

centos7 安装部署sonarqube 8.9.1(postqresql数据库版)

公司产品sonarqube以最大限度地提高质量并管理软件产品组合中的风险。为开发者软件开发人员最终负责代码质量。 代码质量是所谓的非功能性需求的一部分&#xff0c;因此是开发人员的直接责任。为有追求的程序员写出地道代码提供方向。 一、环境要求 1、centos7 x64 2、jdk11 3…

KT6368A蓝牙芯片用户PC升级_搭配下载器_使用说明

目录 一、下载原理简介 KT6368A双模蓝牙芯片是flash版本&#xff0c;支持重复烧录程序&#xff0c;但是烧录程序必须使用专用的下载工具 这个工具需要由我们来提供。 下载的总体思路是&#xff0c;把芯片和PC电脑相连接&#xff0c;通过USB。然后PC端有上位机工具&#xff0…

Zabbix

一、什么是Zabbix zabbix 是一个基于 Web 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。zabbix 能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 zabbix 由 2 部…

Spring Boot 整合 RabbitMQ

一、工程简介 1、生产者&#xff08;test-11-rabbitmq-producer&#xff0c;spring boot 版本 2.4.1&#xff09; 1&#xff09;pom依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifact…

外汇天眼:分分飞艇──谎称33倍高收益,入金投资获利要不回

在这个万物皆涨、薪水不涨的年代&#xff0c;大多数人都知道投资的重要性&#xff0c;但因为受限于本身的知识与技巧不足&#xff0c;经常看错市场方向或选错标的而亏损&#xff0c;并因此感到苦恼不已。此时若看到人宣称有无风险高获利的赚钱管道&#xff0c;不免会跃跃欲试。…

SM59 事物码里的错误消息 SECSTORE035

系统无法访问全局键值&#xff0c;其存储位置 在配置文件参数 rsec/securestorage/keyfile 中指定。 使用事物码 RZ11&#xff0c;输入 rsec/securestorage/keyfile&#xff0c;点击 Display&#xff1a; 当这个参数路径指向的 .pse 文件包含非法字符或者文件内容小于 48 个字…

Matlab实现|多元宇宙算法求解电力系统多目标优化问题(期刊论文复现)

结果和这几种算法进行比较&#xff1a; 目录 1 概述 2 Matlab完整代码实现 3 结果 1 概述 提出了一种求解电力系统环境经济调度的新方法,该方法利用宇宙空间在随机创建过程中高膨胀率的物体随虫洞在空间移动物体的规律,通过对白洞和黑洞间随机传送物体来实现最优搜索. 算法…