第九届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)
一.题目分析
(1).题目
(2).题目分析
-
按键功能分析----存储位置的切换键
a. B1按下切换存储位置,切换后定时时间设定为当前位置存储的时间
b. B2短按切换时分秒+高亮,设置完成后,长按把设置的时间保存到当前位置,如果是临时设置的定时时间则不需要存储,直接按定时器启动按键
c. B3短按单次递增时分秒,长按超过8s开始迅速递增
d. 短按B4,定时器启动,运行期间短按,定时器暂停,再次按下,定时器恢复运行。长按B4超过0.8s,取消定时器运行
(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 "I2C\bsp_i2c.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的执行速度
//全局变量
__IO uint32_t uwTick_Long_Short_Judge = 0;//短长按键判断专用
uint8_t ucState;//系统整体运行状态
uint8_t ucHour_Min_Sec[3];//小时分钟秒
uint8_t Storage_Num = 1;//存储序号
__IO uint32_t Sec_Boss = 0;//全局的秒变量
__IO uint32_t uwTick_Sec_Boss = 0;//控制秒的递减
__IO uint32_t uwTick_LED_BULING = 0;//控制LED闪烁
//***子函数声明区
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
2.系统主函数
int main(void)
{
SystemClock_Config();
/*bsp资源的初始化*/
KEY_LED_Init();
LCD_Init();
LCD_Clear(White);
LCD_SetBackColor(White);
LCD_SetTextColor(Blue);
I2CInit();
PWM_OUTPUT_TIM3_Init();
/*外设使用基本配置*/
iic_24c02_read(ucHour_Min_Sec, 0, 3);
while (1)
{
Key_Proc();
Led_Proc();
Lcd_Proc();
}
}
3.子函数
B3扫描子函数
a.逻辑分析
由于按键3没有长按短按的判断,因此单独写一个函数,此函数的功能是判断是在状态几的时候按下的B3,以此对时分秒进行置零操作(每24小时/每60分钟/ 每60秒就置零)
b.程序源码
#include "main.h"
#include "RCC\bsp_rcc.h"
#include "KEY_LED\bsp_key_led.h"
#include "LCD\bsp_lcd.h"
#include "I2C\bsp_i2c.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的执行速度
//全局变量
__IO uint32_t uwTick_Long_Short_Judge = 0;//短长按键判断专用
uint8_t ucState;//系统整体运行状态
uint8_t ucHour_Min_Sec[3];//小时分钟秒
uint8_t Storage_Num = 1;//存储序号
__IO uint32_t Sec_Boss = 0;//全局的秒变量
__IO uint32_t uwTick_Sec_Boss = 0;//控制秒的递减
__IO uint32_t uwTick_LED_BULING = 0;//控制LED闪烁
//***子函数声明区
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
按键扫描子函数
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)
{
uwTick_Long_Short_Judge = uwTick;
}
if((uwTick - uwTick_Long_Short_Judge) < 800)//短按识别
{
switch(ucKey_Up)
{
case 2://如果B2短按
if( ++ucState == 4)
ucState = 1;
break;
case 4://如果B4短按
if(ucState != 4)
{
ucState = 4;
Sec_Boss = (__IO uint32_t)(3600*ucHour_Min_Sec[0] + 60*ucHour_Min_Sec[1] +ucHour_Min_Sec[2]);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); //PA6,启动PWM的产生
}
else
{
ucLed = 0x00; //关闭LED闪烁
HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_1); //关闭PWM生成
ucState = 5;
}
break;
case 3://如果B3短按,时分秒进行+1操作(一会儿写)
B3_Ctrl();
break;
case 1://如果B1短按,切换存储位置(一会儿写)
if(++Storage_Num == 6) Storage_Num = 1;
iic_24c02_read(ucHour_Min_Sec, (3*(Storage_Num-1)), 3);
break;
}
}
else //长按
{
switch(ucKey_Val)
{
case 2://如果B2长按,进入状态0
if((ucState == 1)||(ucState == 2)||(ucState == 3))
{
iic_24c02_write(ucHour_Min_Sec,(3*(Storage_Num-1)) , 3);
ucState = 0;
}
break;
case 3://如果B3长按,时分秒连续进行+1操作(一会儿写)
B3_Ctrl();
break;
case 4://如果B4长按,运行状态下进入状态0
if(ucState == 4)
{
ucLed = 0x00; //关闭LED闪烁
HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_1); //关闭PWM生成
iic_24c02_read(ucHour_Min_Sec, (3*(Storage_Num-1)), 3);
ucState = 0;
}
break;
}
}
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;
if(ucState == 4)//此状态控制递减操作
{
if((uwTick - uwTick_Sec_Boss) >= 1000)//1s到来了,控制倒计时
{
uwTick_Sec_Boss = uwTick;
Sec_Boss--;
ucHour_Min_Sec[0] = Sec_Boss/3600;
ucHour_Min_Sec[1] = Sec_Boss%3600/60;
ucHour_Min_Sec[2] = Sec_Boss%3600%60;
}
if((uwTick - uwTick_LED_BULING) >= 500)//0.5s到来了,控制LED闪烁
{
uwTick_LED_BULING = uwTick;
ucLed ^= 0x01;
}
}
sprintf((char *)Lcd_Disp_String, " No %1d",Storage_Num);
LCD_DisplayStringLine(Line3, Lcd_Disp_String);
if(ucState == 1) LCD_SetBackColor(Yellow);
LCD_DisplayChar(Line5, 224, (ucHour_Min_Sec[0]/10 + 0x30));
LCD_DisplayChar(Line5, 208, (ucHour_Min_Sec[0]%10 + 0x30));
LCD_SetBackColor(White);
LCD_DisplayChar(Line5, 192, ':');
if(ucState == 2) LCD_SetBackColor(Yellow);
LCD_DisplayChar(Line5, 176, (ucHour_Min_Sec[1]/10 + 0x30));
LCD_DisplayChar(Line5, 160, (ucHour_Min_Sec[1]%10 + 0x30));
LCD_SetBackColor(White);
LCD_DisplayChar(Line5, 144, ':');
if(ucState == 3) LCD_SetBackColor(Yellow);
LCD_DisplayChar(Line5, 128, (ucHour_Min_Sec[2]/10 + 0x30));
LCD_DisplayChar(Line5, 112, (ucHour_Min_Sec[2]%10 + 0x30));
LCD_SetBackColor(White);
switch(ucState)//仅用来表示状态信息
{
case 0:
sprintf((char *)Lcd_Disp_String, " Standby ");
LCD_DisplayStringLine(Line7, Lcd_Disp_String);
break;
case 1:
case 2:
case 3:
sprintf((char *)Lcd_Disp_String, " Setting ");
LCD_DisplayStringLine(Line7, Lcd_Disp_String);
break;
case 4:
sprintf((char *)Lcd_Disp_String, " Running ");
LCD_DisplayStringLine(Line7, Lcd_Disp_String);
break;
case 5:
sprintf((char *)Lcd_Disp_String, " Pause ");
LCD_DisplayStringLine(Line7, Lcd_Disp_String);
break;
}
}
(2)BSP
在第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)-CSDN博客里面有详细的讲解,大家可前往此链接学习