第十一届蓝桥杯嵌入式省赛程序设计题解析(基于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;
//判别1
if(ADC_X100_Num < (Vmin_Ctrl*10))//第一次采集,小于Vmin
{
Start_Timer_Key_Point = 1;//开始计时关键点一半有效。
}
//判别2
if((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小灯
}
}
//判别3
if(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博客里面有详细的讲解,大家可前往此链接学习