【蓝桥杯嵌入式】【复盘】第15届省赛真题
1. 前言
最近在准备16届的蓝桥杯嵌入式赛道的国赛,打算出一个系列的博客,记录STM32G431RBT6这块比赛用板上所有模块可能涉及到的所有考点,如果有错误或者遗漏欢迎各位大佬斧正。
本系列博客会分为以下两大类:
1.1. 单独模块的讲解
在这部分,我会分享自己总结的各个模块的相关配置、代码书写模板,涉及到的大致框架如下:
这个框架后续可能会不断更新,欢迎各位给出建议。
这一大类相关的文章链接如下(持续补充中):
【蓝桥杯嵌入式】【模块】一、系统初始化-CSDN博客
【蓝桥杯嵌入式】【模块】二、LED相关配置及代码模板-CSDN博客
【蓝桥杯嵌入式】【模块】三、LCD相关配置及代码模板-CSDN博客
【蓝桥杯嵌入式】【模块】四、按键相关配置及代码模板-CSDN博客
【蓝桥杯嵌入式】【模块】五、ADC相关配置及代码模板-CSDN博客
【蓝桥杯嵌入式】【模块】六、PWM相关配置及代码模板-CSDN博客
【蓝桥杯嵌入式】【模块】七、IIC相关配置及代码模板-CSDN博客
【蓝桥杯嵌入式】【模块】八、UART相关配置及代码模板-CSDN博客
1.2. 蓝桥杯各届的真题、模拟题复盘及个人答案
在这一部分,我会分享个人练过的所有题的复盘思路及代码,每篇文章结构如下:
这一大类相关的文章链接如下(持续补充中):
【蓝桥杯嵌入式】【复盘】第13届国赛真题_蓝桥杯嵌入式13届国赛题-CSDN博客
【蓝桥杯嵌入式】【复盘】第14届国赛真题-CSDN博客
【蓝桥杯嵌入式】【复盘】第15届省赛真题-CSDN博客
以下是本篇博客正文内容:
2. 4t评测结果
4t平台网址:学单片机,上4T - 4T评测网
测试拿到了满分。
3. 个人解答代码
仓库地址:lanqiao/15_true_shengsai at main · Dukiyaaa/lanqiao
如果不嫌麻烦的话,可以点个star~
4. 重点和易错点
这一套题,根据我个人的做题经历,我认为应该关注的有以下几点:
1. pwm相关的超限报警、频率突变测量。
2. 按键长按。
4.1. pwm超限报警、频率突变测量
我的核心代码如下:
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){uint32_t tmp = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);if(tmp != 0){freA = 8000000.0f / (float)tmp;}if(freA > 20000){freA = 20000;}if(freA < 400){freA = 400;}freA += PX;__HAL_TIM_SET_COUNTER(&htim2, 0);HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);}if(htim->Instance == TIM3){uint32_t tmp = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_1);if(tmp != 0){freB = 8000000.0f / (float)tmp;}if(freB > 20000){freB = 20000;}if(freB < 400){freB = 400;}freB += PX;__HAL_TIM_SET_COUNTER(&htim3, 0);HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);}
}
float faMAX, fbMAX, faMIN, fbMIN;bool NHA_lock = 1, NHB_lock = 1;
void pwm_task(void)
{ // 超限if((NHA_lock == 0) && ((freA - (float)PH) > 10)){NHA++;NHA_lock = 1;}else if((NHA_lock == 1) && (((float)PH - freA) > 10)){NHA_lock = 0;}if((NHB_lock == 0) && ((freB - (float)PH) > 10)){NHB++;NHB_lock = 1;}else if((NHB_lock == 1) && (((float)PH - freB) > 10)){NHB_lock = 0;}// 突变,3s判断一次if(freA > faMAX){faMAX = freA;}if(freB > fbMAX){fbMAX = freB;}if((freA >= 0) && (freA < faMIN)){faMIN = freA;}if((freB >= 0) && (freB < fbMIN)){fbMIN = freB;}if(is_3s == 1){if(((faMAX - faMIN) - PD) >= 5){NDA++;}if(((fbMAX - fbMIN) - PD) >= 5){NDB++;}faMAX = -1;faMIN = 40000;fbMAX = -1;fbMIN = 40000;is_3s = 0;}}
1. 关于超限预警,需要注意的是防抖的处理,蓝桥杯的要求默认情况下都是如果一直超限的话,超限次数不累加,所以建立一个flag用于控制超限次数的增加。
2. 关于频率突变,我的处理方法就是单纯每3s判断一次这3s内测到的最大最小值,根据要求做一下比较就行。之前想过很多种方法,比如滑动窗口,最后发现像现在这样处理就够了。
3. 可以发现,边界值部分我基本都采用的是做差比较,这种方法用于防止边界情况下的计数抖动。
4.2. 按键长按
我的核心代码如下:
void key_scan(void)
{key_buf[0].key_pin_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);key_buf[1].key_pin_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);key_buf[2].key_pin_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);key_buf[3].key_pin_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);for(uint8_t i = 0;i < 4;i++){switch(key_buf[i].key_step){case 0:if(key_buf[i].key_pin_state == 0){key_buf[i].key_step = 1;} else{key_buf[i].key_step = 0;key_buf[i].key_is_down = 0;key_buf[i].key_time = 0;key_buf[i].key_is_long = 0;}break;case 1:if(key_buf[i].key_pin_state == 0){key_buf[i].key_step = 2;key_buf[i].key_is_down = 1;} else{key_buf[i].key_step = 0;key_buf[i].key_is_down = 0;key_buf[i].key_time = 0;key_buf[i].key_is_long = 0;}break;case 2:if(key_buf[i].key_pin_state == 0){key_buf[i].key_time++;if(key_buf[i].key_time >= 100){key_buf[i].key_is_long = 1;} } else{key_buf[i].key_step = 0;key_buf[i].key_is_down = 0;key_buf[i].key_time = 0;key_buf[i].key_is_long = 0;}break;}}
}
void key_task(void)
{for(uint8_t i = 0;i < 4;i++){if(key_buf[i].key_is_down == 1){switch(i){case 0:key_buf[i].key_is_down = 0;if(lcd_num == 1){switch(is_select){case 0:PD += 100;if(PD > 1000){PD = 1000;}break;case 1:PH += 100;if(PH > 10000){PH = 10000;}break;case 2:PX += 100;if(PX > 1000){PX = 1000;}break;}}break;case 1:key_buf[i].key_is_down = 0;if(lcd_num == 1){switch(is_select){case 0:PD -= 100;if(PD < 100){PD = 100;}break;case 1:PH -= 100;if(PH < 1000){PH = 1000;}break;case 2:PX -= 100;if(PX < -1000){PX = -1000;}break;}}break;case 2:// 短按if(lcd_num == 1){key_buf[i].key_is_down = 0;is_select++;if(is_select > 2){is_select = 0;}}else if(lcd_num == 0){key_buf[i].key_is_down = 0;is_fre ^= 1; // 切换显示模式}else if(lcd_num == 2){if(key_buf[2].key_is_long == 1){key3_flag = 1;}}break;case 3:key_buf[i].key_is_down = 0;lcd_num++;if(lcd_num > 2){lcd_num = 0;}if(lcd_num == 0){is_fre = 1;}if(lcd_num == 1){is_select = 0;}break;}}if(key3_flag == 1){if(key_buf[2].key_is_long == 0){key3_flag = 0;if(lcd_num == 2){NHA = 0;NHB = 0;NDA = 0;NDB = 0;}}}}
}
其实比较常规,关于短按的逻辑直接处理就行,但是关于长按,则需要建立标志位,用于实现在松开之后再做处理的逻辑。
5. 总结
本文总结了个人在练习13届省赛过程中的复盘及易错点、重难点分析,主要内容在pwm超限与突变测量、按键长按。