蓝桥杯嵌入式——第十二届蓝桥杯嵌入式第一场省赛
一、赛题分析
这是刚刚过去的第十二届第一场嵌入式的省赛,也是我刚刚参加的。由于我用的是旧版,我们那个考场只测试了新版的环境,而旧版的软件环境有问题,和新版的存在冲突,耽搁了很久的时间,有点搞人心态。但是最终还是基本上把赛题的功能全部实现完了的,仅仅串口有一个小bug,就是第8辆车进去过后不能出来,其他的都没有什么问题,比赛的时候时间也做的比较久了,实在是不想再调试了,这个bug就没有管了,最后还有点担心进不了国赛,但是成绩下来那一刻,进国赛了,更加没想到还是全省前三,还是不错了。
比赛的时候,拿到赛题,就发现串口部分不是那么简单。所以,就先一步一步的把其他的模块先实现了,除了串口,其他的模块都很简单,非常中规中矩。接下来就搞串口部分,串口其实说难也不是很难,主要是比较麻烦。
我觉得在我们拿到赛题的时候,应该分模块来实现,首先看看用到了哪些模块, 再去看每一个模块,赛题的要求是什么。比如说输出PWM, 题目要求就是PA7输出2kHz,占空比20%,,只用到了一个通道,并且占空比和频率是固定的,所以直接就想到用定时器的PWM模式就行了,就不需要再去用什么OCTOGGLE模式浪费时间了。
我个人觉得,进国赛是比较简单的,只要选择题不要错的太多,就拿这一届来说,串口部分比较难,所以其他部分必须全部实现了,串口实现一部分,不要有太大的逻辑错误, 影响系统运行,应该进国赛都稳了吧。
二、问题总结
其他的模块应该都不会遇到什么大的问题,主要就是串口。我串口使用的是IDLE+RXNE来实现串口的不定长数据的接收的。
在实现串口的部分,首先要实现能够正确识别的进入以及出去,然后再注意一些细节的逻辑错误;
- 接收到正确信息的长度为22个字符,冒号的位置等等。
- 车型只有CNBR和VNBR两种
- 时间格式必须正确,并且不能出现时间的逻辑错误,如年份大于99,小时大于23等。
- 进入车辆信息和出去车辆信息要匹配,如进入和出去的车辆的ID相同,但是他们的车型不同是不应该的,因为对于同一个车的ID,它的信息一定全都是相同的。
- 出去的时间一定要晚于进入的时间。
- 整数,单位为小时, 不足 1 小时,按 1 小时统计。
下面附上串口部分的关键代码:
void substr(uint8_t* d_str,uint8_t* s_str,uint8_t locate,uint8_t length)
{
uint8_t i = 0;
for(i = 0; i < length; i++)
{
d_str[i] = s_str[locate + i];
}
d_str[length] = '\0';
}
uint8_t findLocate(void) // 找一个空闲的位置
{
uint8_t i = 0;
for(i = 0; i < 8; i++)
{
if(!car[i].notEmpty) // 如果是空闲
return i;
}
return 0xFF;
}
uint8_t isExist(uint8_t* str) // 判断车辆是否存在
{
uint8_t i = 0;
for(i = 0; i < 8; i++)
{
if(strcmp((const char*)str,(const char*)car[i].id) == 0)
{
return i; // 如果这辆车存在,则返回这辆车所在的车位i
}
}
return 0xFF; // 返回0xFF表示这辆车不存在
}
_Bool checkCmd(uint8_t* str)
{
// VNBR:D583:200202120000
// 0123456789012345678901
if(RxCounter != 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++)
{
if(str[i] > '9' || str[i] < '0')
return 0;
}
}
return 1;
}
void usart_proc(void)
{
if(RxFlag)
{
RxFlag = 0;
// 将接收到的字符串显示到LCD上面
// memset(lcd_str,0,sizeof(lcd_str));
// sprintf((char*)lcd_str,"%-20.20s",RxBuffer);
// LCD_DisplayStringLine(Line9,lcd_str);
// VNBR:D583:200202120000
// 0123456789012345678901
if(checkCmd(RxBuffer)) // 接收到的标准信息应该是22个字符,并且只有在有空闲车位的时候有效
{
uint8_t car_id[5];
uint8_t car_type[5];
uint8_t locate = 0xFF;
uint8_t year_temp,month_temp,day_temp,hour_temp,min_temp,sec_temp;
// 将字符串中时间的信息提取出来
year_temp = (RxBuffer[10] - '0') * 10 + (RxBuffer[11] - '0');
month_temp = (RxBuffer[12] - '0') * 10 + (RxBuffer[13] - '0');
day_temp = (RxBuffer[14] - '0') * 10 + (RxBuffer[15] - '0');
hour_temp = (RxBuffer[16] - '0') * 10 + (RxBuffer[17] - '0');
min_temp = (RxBuffer[18] - '0') * 10 + (RxBuffer[19] - '0');
sec_temp = (RxBuffer[20] - '0') * 10 + (RxBuffer[21] - '0');
if(year_temp > 99 || month_temp > 12 || day_temp > 31 || hour_temp > 23 || min_temp > 59 || sec_temp > 59)
{
// printf("shi jian ge shi error!\r\n");
goto SEND_ERROR;
}
substr(car_id,RxBuffer,5,4); // 将车辆的编号信息提取到car_id
substr(car_type,RxBuffer,0,4); // 将车辆的类型信息提取到car_type
locate = isExist(car_id); // 查询这辆车是否在车库从存在
if(locate != 0xFF) // 这辆车在车库中存在
{
int time_val;
printf("locate:%d,type:%s,id:%s\r\n",locate,car[locate].type,car[locate].id);
if(strcmp((const char *)car_type,(const char *)car[locate].type)) // 如果车辆的id和车辆的类型不同,则表示信息错误
{
// printf("id and type pi pei error!\r\n");
goto SEND_ERROR;
}
// 假设一年365天,一个月30天,秒为单位
time_val = (year_temp - car[locate].year_in) * 365 * 24 * 3600 + (month_temp - car[locate].month_in) * 30 * 24 * 3600 + (day_temp - car[locate].day_in) * 24 * 3600 + \
(hour_temp - car[locate].hour_in) * 3600 + (min_temp - car[locate].min_in) * 60 + (sec_temp - car[locate].sec_in);
if(time_val < 0)
{
// printf("time_val error!\r\n");
goto SEND_ERROR;
}
time_val = (time_val + 3599) / 3600; // 换算成小时,并且不足一个小时按一个小时算
// 输出计费信息
printf("%s:%s:%d:%.2f\r\n",car[locate].type,car[locate].id,time_val,time_val / 10.0 * (RxBuffer[0] == 'C'?CNBR_fee:VNBR_fee));
if(RxBuffer[0] == 'C')
CNBR_cnt--;
else if(RxBuffer[0] == 'V')
VNBR_cnt--;
memset(&car[locate],0,sizeof(car[locate])); // 将当前结构体清空
}
else // 这辆车在车库中不存在
{
uint8_t locate = findLocate(); // 找一个空闲的车位
if(locate == 0xFF) // 没有找到空闲车位
{
goto SEND_ERROR;
}
// printf("locate:%d,type:%s\r\n",locate,car[locate].type);
// 保存车辆信息
substr(car[locate].type,RxBuffer,0,4);
substr(car[locate].id,RxBuffer,5,4);
car[locate].year_in = year_temp;
car[locate].month_in = month_temp;
car[locate].day_in = day_temp;
car[locate].hour_in = hour_temp;
car[locate].min_in = min_temp;
car[locate].sec_in = sec_temp;
car[locate].notEmpty = 1; // 标记为非空闲
if(RxBuffer[0] == 'C')
CNBR_cnt++;
else if(RxBuffer[0] == 'V')
VNBR_cnt++;
}
goto CMD_YES;
}
SEND_ERROR:printf("ERROR\r\n");
CMD_YES: memset(RxBuffer,0,sizeof(RxBuffer));
RxCounter = 0;
}
}
/* 测试数据,用来测试逻辑是否有错误
1. *
VNBR:D583:200202120000
VNBR:D583:200202213205
2. *
CNBR:D593:200202120000
CNBR:D593:200203213205
3. *
VNBR:D883:200202120000
VNBR:D883:200202223205
4. *
CNBR:D588:200202120000
CNBR:D588:200202313205 会提示时间设置错误
CNBR:D588:200202223205 时间设置正确
5. *
CNBR:D580:200202120000
CNBR:D580:200202215205
6. *
VNBR:D58S:200202120000
VNBR:D58S:200203213205
7. *
CNBR:D58E:200202120000
CNBR:D58E:200204213205
8. *
CNBR:D58B:200202120000
CNBR:D58B:200205213205
9.
CNBR:D555:200202120000
CNBR:D555:200205213205
*/
三、代码(完整代码,功能全部实现,附有注释)
版权声明:本文为CSDN博主「FILWY_M」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43715171/article/details/116451070
暂无评论