前言

刷了几套蓝桥杯省赛程序题目,心有所感,故写下文章记录一下,本篇文章记录的是第十二届省赛嵌入式设计与开发程序设计题目。
这套题的考察重点和难点在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:200202120000substr(Car_Type_temp , RxBuffer1 ,0 ,4);  //截取RxBuffer1中car类型信息 VNBRsubstr(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); 

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

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

  1. 最新 2021年 第十二届 蓝桥杯 单片机设计与开发 省赛 客观试题 个人答案

    第十二届蓝桥杯单片机设计与开发项目省赛 第一部分客观试题(30分) 不定项选择(3分/题) (1)MCS-51单片机外部中断1的中断请求标志是( B ).     A.ET1        B.IE1 ...

  2. 第十二届 蓝桥杯 EDA设计与开发项目 省赛

    第十二届 蓝桥杯 EDA设计与开发项目 省赛 在这里插入图片描述

  3. 第十二届蓝桥杯电子类嵌入式设计与开发省、国赛经验分享

    文章目录 前言 一.嵌入式省赛 二.嵌入式国赛 1.前期准备 2.国赛考试 总结 前言 已经考完差不多两周时间了,自己也一直想找个时间写一篇关于蓝桥杯的总结,所以今天就来啦,希望可以帮到后面想参加蓝桥 ...

  4. 蓝桥杯嵌入式——第十二届蓝桥杯嵌入式国赛

    蓝桥杯嵌入式--第十二届蓝桥杯嵌入式国赛 之前准备省赛的时候用的是旧版的STM32F103,从准备国赛开始就用新版STM32G431平台了,主要是想经过新版的准备学习一下HAL库以及CubeMX的使用 ...

  5. 突击蓝桥杯嵌入式(十二)——第十二届省赛第一场真题 停车场

    突击蓝桥杯嵌入式(十二)--第十二届省赛第一场真题 停车场 一.题干 二.题目解析 所需: PA7 PWM LED(锁存器) 串口9600 LCD 按键4个,整体难在逻辑,我们先配置好硬件,进入工程 ...

  6. 蓝桥杯嵌入式第十二届省赛真题

    第十二届蓝桥杯嵌入式-停车计费 文章目录 第十二届蓝桥杯嵌入式-停车计费 1.题目分析 2.项目结构 2.1停车部分整体流程 2.2串口数据解析流程 2.3细节部分 3.代码结构 3.1停车部分 3. ...

  7. 【蓝桥杯嵌入式】第十二届蓝桥杯嵌入式省赛程序设计试题以及详细题解

    原题展示     通读本试题后,可以知本试题所涉及到的模块有LCD显示.LED指示.按键切换.串口收发.定时器的PWM输出五个部分,试题的总体变化不大.在试题要求的所有功能中,串口这部分是侧重点,它既 ...

  8. 蓝桥杯2021年第十二届省赛-杨辉三角形

    蓝桥杯2021年第十二届省赛真题-杨辉三角形 - C语言网 (dotcpp.com)https://www.dotcpp.com/oj/problem2610.html 参考: 2021第十二届蓝桥杯 ...

  9. 【蓝桥杯单片机第十二届国赛真题】

    [蓝桥杯单片机第十二届国赛真题] 文章目录 [蓝桥杯单片机第十二届国赛真题] 前言 一.真题 二.源码 前言 有幸进入国赛,为自己大学最后一个比赛画上完满的句号^@^ 下面为蓝桥杯单片机第十二届国赛程 ...

最新文章

  1. nvJPEG Codec库
  2. OpenCV学习系列教程第五篇:测试和提高代码的效率
  3. hdu A Simple Math Problem
  4. 没看过这条鄙视链,别轻易说你懂区块链!
  5. Java类加载的那些事
  6. mysql sql执行过程_MySQL探秘(二):SQL语句执行过程详解
  7. 为什么我建议每个开发人员都需要学Python?不看会后悔!
  8. 物化视图基础概念、mview跨库迁移表
  9. DM8达梦数据库:sql查询达梦数据库实例的详情
  10. 计算机设计大赛山东,第十届中国大学生计算机设计大赛山东赛区颁奖典礼在我校举办...
  11. Java --> 斗地主案例实现洗牌、随机牌选地主、发牌、存牌、存3张底牌。特此声明:没有实现斗地主规则
  12. 跨境电商平台运营知识:亚马逊日常运营技巧
  13. MySQL日志之错误日志(errorlog)
  14. 值得收藏的 5 款iPhone 数据恢复软件
  15. 分享个弹射世界挂机脚本 worldflipper 弹射世界挂机脚本 自动共斗踢罐子
  16. Eight HDU - 1043
  17. 学习Linux的常见故障(待更新)
  18. setContentView 报错空指针异常
  19. Elasticsearch Search API
  20. 使用scrapy 爬取酷狗音乐歌手及歌曲名并存入mongodb中

热门文章

  1. 恭喜郭霖成为GDE(Google开发者专家)!
  2. 腾讯王者服务器性能,性能不够腾讯来凑 OPPO合作的不止王者荣耀
  3. DLL 反汇编 【其他类文 请到幻影查看】
  4. 基于SSM框架的救援物资的管理与分配系统的设计与实现 毕业设计-附源码291141
  5. 转行!从机械到编程,只因为......
  6. rust货轮什么时候出现_茶壶是什么时候出现的,茶壶的出现是因为什么
  7. 厦门理工c语言程序设计,厦门理工学院+C语言+课程设计
  8. 使用Palm®(奔迈)Mojo 框架开发JavaScript程序 #1
  9. C语言主题作业2答案,北理C语言作业及答案3(2)
  10. 曹云金回应公式相声_曹云金何云伟联袂“公式相声”夫妻,这件事看着有点悬?...