第十二届省赛嵌入式设计与开发《停车计费系统》

前言

刷了几套蓝桥杯省赛程序题目,心有所感,故写下文章记录一下,本篇文章记录的是第十二届省赛嵌入式设计与开发程序设计题目。
这套题的考察重点和难点在STM32的串口和字符串的处理,难点在于细节方面,对字符串考察很细。其他知识点虽有考察,但比较常规(参考往年题目思路即可)。
文章重点讲解字符串的处理和小算法。

(一) 题目分析:

使用串口获取车辆进、出停车场信息和时间,并能够输出计费信息。
分析:
1.车辆 出车库要计算停车时间,然后根据价格计算并输出计费信息。
2.接下来,我们要考虑如何去判断小车是进车库还是出车库?

有一个办法就是构建一个数据库,进车库的车辆信息必须登记到数据库里。每当串口收到一串字符串信息,就与数据库中的车辆进行对比,如果查询到数据库有这个车,则是出库,随后打印计费信息; 如果没有这辆车, 则是入库,登记车辆信息到数据库。
3.根据题目
在这里插入图片描述
串口接受的字符串是带有固定的格式,所以要先判断串口接受数据的格式和逻辑是否符合要求。
在这里插入图片描述在这里插入图片描述
(1)字符串格式:CNBR : :VNBR: : 这几个字符都是固定。
定义Check_String( )函数对其检查

_Bool Check_String(uint8_t* str)   
{
	
	if(RxCounter1 != 22) //判断收到的字节是否为22个
		return 0;
//	//判断字符是否正确
	if((str[0] == 'C' || str[0] == 'V') && str[1] == 'N' && str[2] == 'B' && str[3] == 'R' && str[4] == ':' && str[9] == ':')
	{
		uint8_t i; 
		for(i=10;i<22;i++)  //for扫描第十位及之后数字是否正确
		{
			if(str[i]>'9'|| str[i]<'0')
			     return 0;	
		}		    
	} 
		 return 1;
}

很多人觉得字符不能比较大小,其实是可以。可以自行百度下。

if(str[i]>'9'|| str[i]<'0')

(2)接下去我们对字符串的逻辑方面进行判断。首先1年只有12月,1月最多31天,1天只有24小时,以及只有59分钟,59秒。

	if((Mouth_temp>12) || (Day_temp>31) || (Hour_temp>23) || (Min_temp>59) || (Sec_temp>59) ) //判断日期和时间是否正确   
	{
	
	}
(二)构建车库(数据库)
//字符串信息的处理
typedef struct  
{
  uint8_t Car_Type[5];  //车辆类型         
  uint8_t Car_ID[5];    //车辆编号ID            
  uint8_t Year;
	uint8_t Month;
	uint8_t Day;
	uint8_t Hour;
	uint8_t Min;
	uint8_t Sec;
	_Bool notEmpty;
}Car_StructureTypeDef;  //定义车辆结构体

Car_StructureTypeDef Car_Structure[8]={0};  //构建数据库

我们通过自行定义一个存储车辆信息的结构体类型,用这个类型定义一个结构体数组Car_Structure[8] ,来存储8辆车的信息(题目规定车库最多有8个车位)

原来的C语言其实没有_Bool布尔类型 , 后来C语言又加上这条规则!

很多新手对结构体不太熟练,其实STM32_Lib3.5有很多规范的写法,可以直接拿来改一下。例如熟知的GPIO_InitTypeDef类型。

typedef struct
{
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;
(3)车辆的出入库判断

首先我们是通过车辆的类型(分为CNBR和VNBR)和编号ID判断车辆的唯一性。程序细节注释都很详细。

/* 判断车辆类型ID是否与数据库中相同,相同则出库,不同则入库
   Car_Structure[8]-->题目中车库最多停八辆车,用for语句依次扫描数据库 */
uint8_t  Car_isExist(uint8_t* str1 , uint8_t* str2)
{
	uint8_t i;
	for(i=0 ; i<8 ;i++)
	{
		if( Buffercmp(str1 , Car_Structure[i].Car_Type ,5)== PASSED) //判断Car_Type是否匹配
		{
			if(Buffercmp(str2 ,Car_Structure[i].Car_ID , 5)==PASSED) //判断Car_ID是否匹配
			      return i;//到这一步说明匹配成功,返回数据库中车辆索引
		}
		
		return 0xFF; //表示匹配失败,车库没有这辆车。
	}
}

Buffercmp()函数比较两个字符串是否相等。若字符串相等,返回PASSED,否则返回FAILED。这个函数是蓝桥杯例程中写好,直接复制粘贴。源码如下:

/* 
  * @brief  Compares two buffers.
  * @param  pBuffer1, pBuffer2: buffers to be compared.
  * @param  BufferLength: buffer's length
  * @retval PASSED: pBuffer1 identical to pBuffer2
  *         FAILED: pBuffer1 differs from pBuffer2
  */
typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
  while(BufferLength--)
  {
    if(*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }

    pBuffer1++;
    pBuffer2++;
  }
  return PASSED;
}

其实还有一种方法就是调用C库函数的strcmp函数。
strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。

好了,加上上面的代码铺垫,现在只需要编写一个串口信息处理函数,放在Main主函数即可。其主要框架是
(1)先检查字符串格式逻辑错误

(2)接着判断车辆入库还是出库

  • 入库则提取串口信息登记到定义的车库存储好
  • 出库则清除车库登记信息,计算费用时间,打印串口输出计费信息

其中车辆入库时,要考虑到车库是否有空闲车位,所以这里要编写一个找车位函数进行判断find_carLocate()

//为入库车辆找一个空闲位置
uint8_t  find_carLocate()
{
	uint8_t i;
	for(i=0 ; i<8 ;i++)
	{
		if(Car_Structure[i].notEmpty == 0)  //说明此位置空闲
		      return i;    
	}
	return 0XFF; //说明车库已满,寻找位置失败
}

void usart_printf()
{
if(Check_String(RxBuffer1)==1) //基本的数据格式正确
{
	uint8_t Car_Type_temp[5]; //数组长度为5个,是因为还要加上'\0'
	uint8_t Car_ID_temp[5];
	uint8_t Year_temp,Mouth_temp,Day_temp,Hour_temp,Min_temp,Sec_temp;
	
	Year_temp  = (RxBuffer1[10]-'0')*10 + (RxBuffer1[11]-'0');   //字符转数字
	Mouth_temp = (RxBuffer1[12]-'0')*10 + (RxBuffer1[13]-'0');
	Day_temp = (RxBuffer1[14]-'0')*10 + (RxBuffer1[15]-'0');
	Hour_temp= (RxBuffer1[16]-'0')*10 + (RxBuffer1[17]-'0');
	Min_temp = (RxBuffer1[18]-'0')*10 + (RxBuffer1[19]-'0');
	Sec_temp = (RxBuffer1[20]-'0')*10 + (RxBuffer1[21]-'0');

	
	if((Mouth_temp>12) || (Day_temp>31) || (Hour_temp>23) || (Min_temp>59) || (Sec_temp>59) ) //判断日期和时间是否正确   
	{
		goto SEND_ERROR;
	}
	//VNBR:D583:200202120000
	substr(Car_Type_temp , RxBuffer1 ,0 ,4);  //截取RxBuffer1中car类型信息 VNBR
	substr(Car_ID_temp , RxBuffer1 ,5 ,4);   //截取RxBuffer1中car类型信息 D583
	 
	
	//此处开始判断车辆是入库还是出库
	if( Car_isExist(Car_Type_temp , Car_ID_temp) == 0XFF) 
	{  //车库没有这辆车,准备入库
		 
     uint8_t Locate = find_carLocate(); //找一个车位
		if(Locate != 0xFF) 
		{
			//登记信息入库
			substr(Car_Structure[Locate].Car_Type , RxBuffer1 ,0 ,4);
			substr(Car_Structure[Locate].Car_ID , RxBuffer1 ,5 ,4); 
//			Car_Structure[Locate].Car_Type = Car_Type_temp;  这种写法是错的,两个数组之间不可以这样赋值
//			Car_Structure[Locate].Car_ID   = Car_ID_temp;
			Car_Structure[Locate].Year  = Year_temp;
			Car_Structure[Locate].Month = Mouth_temp;
			Car_Structure[Locate].Day  = Day_temp;
			Car_Structure[Locate].Hour =Hour_temp;
			Car_Structure[Locate].Min = Min_temp ;
			Car_Structure[Locate].Sec = Sec_temp;
			Car_Structure[Locate].notEmpty = 1;
			//此时LCD记录车位信息应更新
			if(Car_Type_temp[0] == 'C')
			{
				D_Cnbr++;  Idle--;	
			}
			else if(Car_Type_temp[0] == 'V')
			{
			  D_Vnbr++;  Idle--;	
			}
		}
		
	  else goto SEND_ERROR;  //找车位,车位已满
	}
	
	else{ //车库有这辆车,准备出库,计算费用时间
	   uint8_t Locate = Car_isExist(Car_Type_temp, Car_ID_temp);
		// 1.先计算年份 7个月为31日,4个月为30日,1个月为28日(估算平均30天:多出5天) 
		uint16_t year_time , month_time,day_time,hour_time,min_time,sec_time;
		uint32_t all_time;
		
		//全部化为秒为单位
		year_time = (Year_temp - Car_Structure[Locate].Year)*365*24*3600 ;
		month_time = (Mouth_temp - Car_Structure[Locate].Month)*30*24*3600 ;
		day_time = (Day_temp - Car_Structure[Locate].Day)*24*3600;      
	  hour_time = (Hour_temp - Car_Structure[Locate].Hour)*3600;
		min_time = (Min_temp - Car_Structure[Locate].Min)*60;
		sec_time = (Sec_temp - Car_Structure[Locate].Sec);
		
		all_time = year_time+month_time+day_time+hour_time+min_time+sec_time;
		
		all_time = (all_time + 3599) / 3600;	// 换算成小时,并且不足一个小时按一个小时算
		/*这种清空结构体方式不可取*/
		//Car_Structure[Locate] = { {0,0,0,0,0},{0,0,0,0,0}, 0}; 
		/*正解:调用C库函数memset清空结构体*/
		memset(&Car_Structure[Locate] ,0 , sizeof(Car_Structure[Locate]) );
		Car_Structure[Locate].notEmpty = 0; //该车已经出库
		
		//此时LCD记录车位信息应更新
			if(Car_Type_temp[0] == 'C')
			{
					float Money = (float)(all_time * P_Cnbr);
				D_Cnbr--;  	Idle++;	
				
				printf("CNBR:%s:%d:%.2f\r\n" , Car_ID_temp ,all_time ,Money); //打印串口输出计费信息
			}
			else if(Car_Type_temp[0] == 'V')
			{
				float Money = (float)(all_time * P_Vnbr);
			  D_Vnbr--;   Idle++;	
				printf("VNBR:%s:%d:%.2f\r\n" , Car_ID_temp ,all_time ,Money);  //打印串口输出计费信息
			}
	}
	
	
//    sprintf((unsigned char *)testStr , "Car_isExist:%d" , Car_isExist(Car_Type_temp , Car_ID_temp)  );
//		LCD_DisplayStringLine(Line9 ,testStr);
	goto CMD_YES;  
	
	SEND_ERROR: printf("Error\n\r");
	
  CMD_YES:
	RxCounter1=0; 
}
}

这里提一下(一)应该如何正确对结构体变量进行清0操作。

/*这种清空结构体方式不可取*/
//Car_Structure[Locate] = { {0,0,0,0,0},{0,0,0,0,0}, 0}; 
/*正解:调用C库函数memset清空结构体*/
memset(&Car_Structure[Locate] ,0 , sizeof(Car_Structure[Locate]) );

详情见–>void *memset(void *str, int c, size_t n)

(二)以下赋值不可取

int a[5]="abcde";
int b[5];
b = a;  //这种方式是错误的

//题目程序
//Car_Structure[Locate].Car_Type = Car_Type_temp;  
//Car_Structure[Locate].Car_ID   = Car_ID_temp;
//这种写法是错的,两个数组之间不可以这样赋值

/*正解:调用C库函数substr函数*/
substr(Car_Structure[Locate].Car_Type , RxBuffer1 ,0 ,4);
substr(Car_Structure[Locate].Car_ID , RxBuffer1 ,5 ,4); 

好了,对第十二届省赛嵌入式设计与开发程序设计题目中处理字符串的思路到此结束!!!

  • 15
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
### 回答1: 蓝桥杯是全国性的计算机大,旨在提高大学生的计算机技术水平和创新能力。嵌入STM32G431是一款嵌入芯片,具有高性能和低功耗的特点。第十二届第一场停车计费系统是蓝桥杯的一道工程题目,要求参选手设计一个停车计费系统停车计费系统是指通过嵌入技术实现对车辆进入和离开停车场的自动检测、计时和计费系统。对于这个题目,参选手可以根据题目要求,使用STM32G431芯片设计一个具有以下功能的系统: 1. 车辆进入检测:使用车辆传感器检测车辆的进入,触发计时。 2. 车辆离开检测:使用车辆传感器检测车辆的离开,停止计时。 3. 计时功能:使用内部时钟模块获取进入和离开的时间,并计算停车时间。 4. 计费功能:根据停车时间,按照一定的计费规则进行计费。 5. 显示功能:使用液晶显示屏显示当前的停车信息,如车牌号、停车时间、费用等。 6. 数据存储功能:使用闪存等储存介质将停车数据进行存储,以便后续的数据分析和查询。 设计一个停车计费系统涉及到硬件设计和软件编程两个方面。硬件方面,参选手需要选择合适的传感器、显示屏、存储介质等,以及设计电路和接口进行连接。软件方面,需要使用C语言或者汇编语言编写程序,对芯片进行编程,实现各项功能。 通过此次比,选手们可以锻炼嵌入系统设计能力和编程能力,了解实际应用中嵌入系统的工作原理和应用场景。同时,也能提升对STM32G431芯片的理解和运用能力。这对于培养嵌入技术人才,推动物联网技术的发展都具有积极意义。 ### 回答2: 蓝桥杯是面向计算机爱好者的智力竞,而嵌入STM32G431是一款嵌入系统开发板。第十二届第一场停车计费系统真题工程,则是要求参选手设计并实现一个能够进行停车计费系统停车计费系统是一种用于自动计费和管理停车场的系统。这个系统可以通过识别车辆的进出以及停车的时间,自动计算并收费。在这个工程中,选手需要使用嵌入STM32G431开发板以及相关的硬件和软件,来设计一个能够实现停车计费功能的系统。 首先,选手需要使用传感器或摄像头来实现车辆进出的检测。当车辆进入或离开停车场时,传感器会发出信号并通过STM32G431进行检测。接着,选手需要编程实现识别车辆的算法,以便能够识别不同的车辆。当车辆停放时,系统会通过计时器记录停车的时间。 然后,选手需要编写计费算法,根据停车的时间来计算费用。这个算法可以根据停车场的规则来确定费用的计算方,例如按小时计费或按照不同的时间段采用不同的费率。 最后,选手还需要设计一个界面,使得系统能够与用户进行交互。用户可以通过该界面查询停车费用,并进行付款。同时,选手还需要保证系统的稳定性和安全性,确保数据的准确性和保密性。 总而言之,蓝桥杯嵌入STM32G431第十二届第一场停车计费系统真题工程要求选手使用硬件和软件开发能力,设计并实现一个完整的停车计费系统。这需要选手具备嵌入系统开发、传感器技术、算法设计和界面设计等多方面的知识和技能。 ### 回答3: 蓝桥杯嵌入stm32g431——第十二届第一场停车计费系统真题工程是一个基于STM32G431开发板的停车计费系统设计题目。该系统的主要功能是实现停车场的车辆进入、出场的计费管理。 首先,该系统需要实现一个车辆进入检测的功能。当车辆进入停车场时,系统会通过传感器检测到车辆的到达,并记录下进入的时间。 然后,系统需要实现一个车辆出场的功能。当车辆准备离开停车场时,系统会通过传感器检测到车辆的离开,并记录下离开的时间。 接下来,系统需要计算车辆停留的时间。通过进入时间和离开时间的差值计算得出车辆停留的时长。 最后,系统需要计算停车费用。根据停车场的计费规则,根据车辆停留的时长计算出停车费用,并将费用显示在屏幕上。 在实现上述功能的过程中,需要运用STM32G431开发板的各种功能和模块,包括GPIO口、定时器、中断、串口通信等。通过编写相应的代码,实现按钮的控制、传感器检测、时间的计算以及屏幕的显示等功能。 该项目的设计需要考虑多种情况,比如车辆重复进入出场、车辆进入出场顺序错乱等,要充分考虑这些异常情况并进行相应的处理。在代码编写过程中,还需注意代码的优化和资源的合理利用,以提高系统的性能和效率。 通过完成这个项目的设计与实现,可以加深对STM32G431嵌入系统的了解和应用,并提升嵌入系统开发的能力。同时,也能锻炼自己的逻辑思维、问题解决能力和团队合作精神。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式历练者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值