![](https://i-blog.csdnimg.cn/blog_migrate/dd7386175236b47a33af6221773a2781.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/ad48630c098177a0c27e078608c2dd74.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/b867141905bcbd06fdb33fe0f06056b5.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/f9b781af506783490b57c1fc3dcf0a58.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/8f785357b8e98ac8a7bedda26e529d38.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/b51025570cf0d14b2e3e289b40409963.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/ca84d18ba773d1cba2586c82fc085c0b.jpeg)
本届国赛试题主要包含LCD、LED、按键、EEPROM、串口、模拟电压输入、脉冲输入输出七大部分,其中前面三个部分是蓝桥杯嵌入式的“亲儿子”(必考部分),而剩下的四个部分都为“干儿子”(考频相对较高)。
相对于本届省赛两套试题:
本套试题串口数据接收出现一个较为复杂的问题:如何接收PC端发送变长数据?省赛的两套试题PC发送的数据类型与长度都比较单一,要不发送7个字符的新旧密码,要不直接发送一个"?"号,而本套试题PC发送的数据长度不定,要不是1位数据,要不是3位数据, 那么这就涉及到串口接收不定长度数据,至于到底该怎么处理,此处小编先保密。😁😁😁
本套试题中还出现了一个较为“新鲜的旧知识点”——LCD显示数据翻转,问题新鲜在于可能屏幕前的你是第一次碰到这个操作,旧知识点是因为很多LCD或LED都可以进行翻转。其实,官方提供的LCD显示代码中提供了反向显示的LCD翻转指令: 0x0100、0xA700,具体使用方法大家可以看下文。😜😜😜
本届试题还出现了一个可能困惑大家的地方:SRAM至少记录100条数据。 小编咋一看,还以为是需要将数据存储在一个掉电也不会丢失的内存中呢。(小编忘记ROM与RAM的区别啦😅😅😅)百度后才知道:SRAM,一种静态随机存取存储器存储器只要保持通电,里面储存的数据就可以恒常保持;掉电后,数据还是会消失,这与在断电后还能储存资料的ROM或闪存是不同的。所以,也就是说,将这100条以上的数据存储到数据中就好啦!🤔🤔🤔
本届试题中的模拟电压输入也值得关注,因为本届赛题考察的是ADC多通道采集,而并非十一届赛题那种单通道采集。
至于脉冲输入输出,主要还是定时器配置与使用,只要定时器配置与使用熟练掌握并且合理运用,脉冲输入输出问题不大。
详细题解在正式题解前,大家需要注意以下几点:
由于LCD与LED有部分引脚是共用的,因此初始化完成LCD后最好手动关闭LED或者保存上一次LED的引脚的值;由于每次LCD显示的长度可能不同,因此在本次显示前,要不先清屏,要不跟上次显示一样长;使用CubeMX配置完成串口USART1后需要更改默认引脚为PA9、PA10;LED模块 通过查询产品手册知,LED的引脚为PC8~PC15,外加锁存器74HC573需要用到的引脚PD2。(由于题目要求除LED1、LED2、LED3、LED4外的其他LED都处于熄灭状态,此处特意将所有的LED都初始化以便于管理其他的LED灯) CubeMX配置: 代码样例 由于G431的所有LED都跟锁存器74HC573连接,因此每次更改LED状态时都需要先打开锁存器,写入数据后再关闭锁存器。
试题要求中除了LED3,其他的LED灯要求比较简单,只需要点亮即可;而LED3则需要计时闪烁,每次间隔100ms就需要闪烁,因此,计时最好将其放在定时器中完成。
/*************************************************** 函数功能:LED工作函数* 函数参数:*int mod1:LED3的工作模式*int mod2:LED4的工作模式* 函数返回值:无***************************************************/void ledPro(int mod1,int mod2){// 倍频if(keyB4[0]%2 == 0)changeLedStateByLocation(LED1,1);elsechangeLedStateByLocation(LED1,0);// 分频if(keyB4[0]%2 == 1)changeLedStateByLocation(LED2,1);elsechangeLedStateByLocation(LED2,0);// 电压if(mod1%2 == 1){rollbackLedByLocation(LED3);LED3TimeFlag = 0;}elsechangeLedStateByLocation(LED3,0);// LCD正反if(mod2%2 == 0)changeLedStateByLocation(LED4,1);elsechangeLedStateByLocation(LED4,0);} 按键模块 通过查询产品手册知,开发板上的四个按键引脚为PB0~PB2、PA0。 CubeMX配置 代码样例 本次试题涉及到按键单击以及长按短按,因此,按键扫描时就不能单一的按键按下后就返回按键值;而是在按键按下后,还需要记录按键按下时间,以此来判断按键是长按或者是短按。
本次试题中,串口功能比较简单,但是接收PC发送过来的数据时需要注意:PC发送不定长的数据。这时就需要按位储存PC发送过来的数据,每次处理完成后就清空历史数据。 CubeMX配置 配置时一定一定记得改引脚!!! 代码样例 HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)函数解析:
这里需要注意,下图中的代码句1与代码句2一定不要交换,不然串口接收的数据集就不会是你想要的。😢😢😢
![](https://i-blog.csdnimg.cn/blog_migrate/4f6bd5326b669df2b4f7d4b3c1f270a1.png)
这样,串口数据接收就可以不必每次都接收到数据可能出现的最大值,大大提高了串口数据接收的精确性,但是也降低了串口数据接收的灵活性。
串口数据处理 串口数据处理,是根据PC发送过来的数据进行特殊数据匹配,一旦匹配到合适的数据,就给PC发送数据或者是执行其他的一系列操作。
/*************************************************** 函数功能:串口数据处理函数* 函数参数:无* 函数返回值:无***************************************************/void usartPro(void){char usartTemp[10];// 验证是否收到串口信息以及串口信息长度// 参数if(ucRxbuff[0] == 'X')sprintf(usartTemp,"X:%d\r\n",para[0]);else if(ucRxbuff[0] == 'Y')sprintf(usartTemp,"Y:%d\r\n",para[1]);// 显示切换else if(ucRxbuff[0] == '#')setDisplayMod(++LCDMod%2);// 数据if(ucRxbuff[0] == 'P'){if(strcmp((char*)ucRxbuff,"PA1") == 0)sprintf(usartTemp,"PA1:%d\r\n",P1));else if(strcmp((char*)ucRxbuff,"PA4") == 0)sprintf(usartTemp,"PA4:%.2f\r\n",data[0]);else if(strcmp((char*)ucRxbuff,"PA5") == 0)sprintf(usartTemp,"PA5:%.2f\r\n",data[1]);}// 是否发送数据if(usartTemp[0]=='P' || usartTemp[0]=='X' || usartTemp[0]=='Y')HAL_UART_Transmit(&huart1,(uint8_t*)usartTemp,sizeof(char)*strlen(usartTemp),10);memset(ucRxbuff,0,sizeof(ucRxbuff));} LCD模块LCD模块官方会提供源码,内含初始化,大家会用即可。如下面是一段将LCD初始化成——文字颜色为白色、背景为黑色的LCD屏:
/******************************************************************************* 函数功能:LCD初始化* 函数参数:无* 函数返回值:无*******************************************************************************/void lcdInit(void){//HAL库的初始化LCD_Init();//设置LCD的背景色LCD_Clear(Blue);//设置LCD字体颜色LCD_SetTextColor(White);//设置LCD字体的背景色LCD_SetBackColor(Black);}LCD显示翻转 LCD显示翻转,实质就是改变LCD刷新时数据刷新方向。详细讲解大家可以参考小编的这篇文章【蓝桥杯】讲述蓝桥杯嵌入式开发板的LCD翻转显示。小编在此处就直接给出代码啦:😜😜😜
/**************************************************** 函数功能:设置LCD显示模式* 函数参数:*int mod:显示模式 0-正向显示 1-翻转显示* 函数返回值:无***************************************************/void setDisplayMod(int mod){// 反向显示if(mod == 1){LCD_WriteReg( R1 ,0x0100 );LCD_WriteReg( R96,0xA700 );LCD_Clear(Black);}// 反向显示else{LCD_WriteReg( R1 ,0x0000 );LCD_WriteReg( R96,0x2700 );LCD_Clear(Black);}}不知道大家在LCD与LED同时显示时,有没有碰到LED显示紊乱,这个是因为LCD与LED共用了部分引脚,每次LCD刷新时都有可能改变这些引脚的值,因此LCD显示会出现紊乱。解决这个现象的方案小编放在这篇文章中辣,大家可以参考玩一玩。😁😁😁【蓝桥杯】解决蓝桥杯嵌入式开发板LCD与LED显示冲突问题解决这个问题的实质就是:先保存本次LED显示的值,再刷新LCD显示,最后恢复LED显示。
模拟电压读取(ADC)试题中要求时测量PA4和PA5的模拟电压,咋一看是不是都不知道要干啥?😣😣😣可以先去CubeMX里看看这两个引脚的配置项有没有ADC的通道,如果有直接配置使用就完事啦!
CubeMX配置
![](https://i-blog.csdnimg.cn/blog_migrate/d2448ccb9f2f21f949e92823f53ce3b4.png)
代码样例 通过CubeMX配置咱可以清楚的知道:本次采集需要使用ADC多通道采集,而不是多ADC单通道采集。
/******************************************************************** 函数功能:获取ADC多个通道的值* 函数参数:*ADC_HandleTypeDef *hadc:ADC*double*data:保存ADC的值*int n:ADC通道的个数* 函数返回值:无*******************************************************************/void getManyADC(ADC_HandleTypeDef *hadc,double*data,int n){int i=0;for(i=0;iChannel == HAL_TIM_ACTIVE_CHANNEL_2){//读取定时器的计数值temp = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);//将定时器的计数值设置成0__HAL_TIM_SetCounter(htim,0);//频率 10000)P1 = 10000;//重新开启定时器HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_2);}}脉冲输出 此处的脉冲输出可以理解为PWM输出。 CubeMX配置 代码样例 由于配置完成定时器的PWM输出后,定时器可以周期性工作,因此们可以不用显示调用。题目中要求脉冲输出能够完成分频与倍频操作,也只需要修改定时器的重装载值来完成,具体代码可见下述:
下边是小编个人整理出来免费的蓝桥杯嵌入式福利,有需要的童鞋可以自取哟!🤤🤤🤤
【蓝桥杯嵌入式】第十一届蓝桥杯嵌入式省赛(第二场)程序设计试题及其题解【蓝桥杯嵌入式】第十二届蓝桥杯嵌入式省赛程序设计试题以及详细题解【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式省赛程序设计试题及其详细题解【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式省赛(第二场)程序设计试题及其题解【蓝桥杯】一文解决蓝桥杯嵌入式开发板(STM32G431RBT6)LCD与LED显示冲突问题,并讲述LCD翻转显示也欢迎大家留言或私信交流,共同进步哟!😉😉😉