飞道的博客

蓝桥杯嵌入式——第十二届蓝桥杯嵌入式第一场省赛

201人阅读  评论(0)

蓝桥杯嵌入式——第十二届蓝桥杯嵌入式第一场省赛

一、赛题分析

这是刚刚过去的第十二届第一场嵌入式的省赛,也是我刚刚参加的。由于我用的是旧版,我们那个考场只测试了新版的环境,而旧版的软件环境有问题,和新版的存在冲突,耽搁了很久的时间,有点搞人心态。但是最终还是基本上把赛题的功能全部实现完了的,仅仅串口有一个小bug,就是第8辆车进去过后不能出来,其他的都没有什么问题,比赛的时候时间也做的比较久了,实在是不想再调试了,这个bug就没有管了,最后还有点担心进不了国赛,但是成绩下来那一刻,进国赛了,更加没想到还是全省前三,还是不错了。

比赛的时候,拿到赛题,就发现串口部分不是那么简单。所以,就先一步一步的把其他的模块先实现了,除了串口,其他的模块都很简单,非常中规中矩。接下来就搞串口部分,串口其实说难也不是很难,主要是比较麻烦。

我觉得在我们拿到赛题的时候,应该分模块来实现,首先看看用到了哪些模块, 再去看每一个模块,赛题的要求是什么。比如说输出PWM, 题目要求就是PA7输出2kHz,占空比20%,,只用到了一个通道,并且占空比和频率是固定的,所以直接就想到用定时器的PWM模式就行了,就不需要再去用什么OCTOGGLE模式浪费时间了。

我个人觉得,进国赛是比较简单的,只要选择题不要错的太多,就拿这一届来说,串口部分比较难,所以其他部分必须全部实现了,串口实现一部分,不要有太大的逻辑错误, 影响系统运行,应该进国赛都稳了吧。

二、问题总结

其他的模块应该都不会遇到什么大的问题,主要就是串口。我串口使用的是IDLE+RXNE来实现串口的不定长数据的接收的。

在实现串口的部分,首先要实现能够正确识别的进入以及出去,然后再注意一些细节的逻辑错误;

  1. 接收到正确信息的长度为22个字符,冒号的位置等等。
  2. 车型只有CNBR和VNBR两种
  3. 时间格式必须正确,并且不能出现时间的逻辑错误,如年份大于99,小时大于23等。
  4. 进入车辆信息和出去车辆信息要匹配,如进入和出去的车辆的ID相同,但是他们的车型不同是不应该的,因为对于同一个车的ID,它的信息一定全都是相同的。
  5. 出去的时间一定要晚于进入的时间。
  6. 整数,单位为小时, 不足 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
*/

三、代码(完整代码,功能全部实现,附有注释)

码云


转载:https://blog.csdn.net/qq_43715171/article/details/116451070
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场