第十一届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)(大学组)
一.题目分析
(1).题目
(2).题目分析
1.计时分析
只要遇到Vmin,就将计时时间重置为0,直到遇到Vmax结束计时
2.按键功能分析
a.B1显示和功能页面相互切换
b.B2每次按下Vmax加0.1,加到3.3V,再次按下返回3.3V
c.B3每次按下Vmin加0.1,加到3.3V,再次按下返回3.3V
d.设备从参数页面退出要判断数据是否合理,判断是否Vmax>Vmin+1 ,同时Vmax和Vmin 可以设置的范围是0.0V~3.3V
2.按键功能分析
a.若当前触发了计时功能,并且计时没有结束,LD1就点亮,否则就熄灭
b.如果判断按键设置的参数不合理,LD2点亮,直到参数合理才熄灭
(3).逻辑框图
二.CubeMX配置
由于蓝桥杯使用的板子都是STM32G431RBT6,配置都是相同的,模板已经在第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)-CSDN博客配置完成,大家可以前往学习
三.相关代码实现
(1)MAIN
1.全局变量声明
#include "main.h"
#include "RCC\bsp_rcc.h"
#include "KEY_LED\bsp_key_led.h"
#include "LCD\bsp_lcd.h"
#include "ADC\bsp_adc.h"
#include "TIM\bsp_tim.h"//***全局变量声明区
//*减速变量
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的执行速度
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的执行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的执行速度//*按键扫描专用变量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;//*LED专用变量
uint8_t ucLed;//*LCD显示专用变量
uint8_t Lcd_Disp_String[21];//最多显示20个字符//*定时器专用变量
uint16_t Sec;//*主逻辑使用的变量
uint8_t Disp_Flag;//用于显示屏幕的代号,0-数据界面,1-参数界面
uint8_t Vmax_Disp = 30;
uint8_t Vmax_Ctrl = 30;
uint8_t Vmin_Disp = 10;
uint8_t Vmin_Ctrl = 10;
uint16_t ADC_X100_Num;//AD采集的数值,放大了100倍
uint8_t Start_Timer_Key_Point = 0;//开始计时关键点,当小于Vmin时,此点为1,当下一次扫描,大于Vmin小于Vmax,此点为2
uint16_t ADC_Befor_Filter;//AD滤波前的数值
uint8_t Filter_Times;//滤波次数控制
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
2.系统主函数
int main(void)
{/* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/*bsp资源的初始化*/KEY_LED_Init();LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White); ADC2_Init();BASIC_TIM6_Init();ADC_X100_Num = ((uint16_t)((((float)getADC2())/4096)*330));HAL_Delay(1000); while (1){Key_Proc();Led_Proc();Lcd_Proc();}
}
3.子函数
按键扫描子函数
a.逻辑框图
b.程序源码
//***按键扫描子函数
void Key_Proc(void)
{if((uwTick - uwTick_Key_Set_Point)<50) return;//减速函数 uwTick_Key_Set_Point = uwTick;ucKey_Val = Key_Scan();unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val); ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val); ucKey_Old = ucKey_Val;if(unKey_Down == 1)//B1按键调整屏幕显示内容{Disp_Flag ^= 0x01;//完成最低位0和1之间的切换if(Disp_Flag == 0x00)//从参数界面进入到数据界面{if(Vmax_Disp>=(Vmin_Disp+10))//判别参数设置的数据没有bug{Vmax_Ctrl = Vmax_Disp;Vmin_Ctrl = Vmin_Disp;ucLed &= (~0x02);//熄灭LD2小灯}else//判别数据出BUG了{ucLed |= 0x02;//点亮LD2小灯}} if(Disp_Flag == 0x01)//从数据界面进入到参数界面{ Vmax_Disp = Vmax_Ctrl;Vmin_Disp = Vmin_Ctrl; }} if(Disp_Flag == 0x01)//如果在参数界面,可以调整Vmin和Vmax的数值{if(unKey_Down == 2)//B2按键调整Vmax增加0.1{Vmax_Disp += 1;if(Vmax_Disp > 33)Vmax_Disp = 0;} else if(unKey_Down == 3)//B3按键调整Vmin增加0.1{Vmin_Disp += 1;if(Vmin_Disp > 33)Vmin_Disp = 0;} }
}
LED扫描子函数
a.程序源码
void Led_Proc(void)
{if((uwTick - uwTick_Led_Set_Point)<200) return;//减速函数uwTick_Led_Set_Point = uwTick;LED_Disp(ucLed);
}
LCD扫描子函数
a.逻辑框图
b.程序源码
void Lcd_Proc(void)
{if((uwTick - uwTick_Lcd_Set_Point)<100) return;//减速函数uwTick_Lcd_Set_Point = uwTick; for(Filter_Times = 0; Filter_Times<=2; Filter_Times++){ADC_Befor_Filter += getADC2();HAL_Delay(10);}ADC_X100_Num = ((uint16_t)((((float)ADC_Befor_Filter)/4096)*110));ADC_Befor_Filter = 0;//判别1if(ADC_X100_Num < (Vmin_Ctrl*10))//第一次采集,小于Vmin{Start_Timer_Key_Point = 1;//开始计时关键点一半有效。}//判别2if((ADC_X100_Num > (Vmin_Ctrl*10))&&(ADC_X100_Num < (Vmax_Ctrl*10)))//第二次采集,大于Vmin,小于Vmax{if(Start_Timer_Key_Point == 1)//当第一个关键点有效后,第二个关键点产生,置标志位{Start_Timer_Key_Point = 2;//开始计时关键点另一半有效Sec = 0 ; //*打开基本定时器HAL_TIM_Base_Start_IT(&htim6);//每1s触发一次中断 ucLed |= 0x01;//点亮LD1小灯 }} //判别3if(ADC_X100_Num > (Vmax_Ctrl*10))//又一次采集,大于Vmax{ //*停止基本定时器HAL_TIM_Base_Stop_IT(&htim6);//每1s触发一次中断 ucLed &= (~0x01);//熄灭LD1小灯 }if(Disp_Flag == 0)//数据界面{sprintf((char *)Lcd_Disp_String, " Data");LCD_DisplayStringLine(Line0, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " V:%4.2fV ",(ADC_X100_Num*0.01));LCD_DisplayStringLine(Line2, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " T:%02ds ",(unsigned int)Sec);LCD_DisplayStringLine(Line3, Lcd_Disp_String); }else if(Disp_Flag == 1)//参数界面{sprintf((char *)Lcd_Disp_String, " Para");LCD_DisplayStringLine(Line0, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " Vmax:%3.1fV ",(Vmax_Disp*0.1));LCD_DisplayStringLine(Line2, Lcd_Disp_String); sprintf((char *)Lcd_Disp_String, " Vmin:%3.1fV ",(Vmin_Disp*0.1));LCD_DisplayStringLine(Line3, Lcd_Disp_String); }
}
基本定时器6更新回调函数
a.程序源码
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM6){Sec++;}
}
(2)BSP
在第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)-CSDN博客里面有详细的讲解,大家可前往此链接学习