目录
0.前言
这套教程针对于蓝桥杯嵌入式比赛的底层模块调试,针对于比赛进行每个模块的调试,低层模块调试好,对于赛题的实现就会方便很多,虽然有一些应试教育的意味,不过准备这个比赛对于程序整体实现思维还是有着很大帮助,我也从中受益颇多!
1.功能要求
实现按键的消抖、长按等功能,并能够使用按键实现一些基础功能,创建计时函数,对执行函数频率进行调节。
电路原理图
2.STM32Cubemx初始化
将PB0~PB2、PA0设置为GPIO_Input,其他执行默认操作即可,之后生成代码。
3.程序实现
创建实现按键功能所需要的变量
/*main.c*/
typedef enum
{
Key_Check,
Key_Press,
Key_Release,
Key_Over,
}Key_State;
Key_State KeyState=Key_Check;//按键状态
uint16_t Key_tt=0;//按键扫描计时标志位
uint16_t Key_Ref=0;//按键扫描标志位
uint16_t Key_Value=0;//按键标志
uint16_t Key_Flag=0;//按键任务执行标志位
uint16_t Key_Press_Time=20;//按键按下时间计时
对按键读取函数函数进行宏定义
/*main.c*/
#define B1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define B2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define B3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define B4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
创建按键扫描函数 Key_Scan()
函数详细解释在注释中
/*main.c*/
void Key_Scan(void)
{
switch(KeyState)
{
case Key_Check:
Key_Press_Time=20;//初始化按键按下时间
//判断是否有按键被按下
if((B1==GPIO_PIN_RESET)||(B2==GPIO_PIN_RESET)||(B3==GPIO_PIN_RESET)||(B4==GPIO_PIN_RESET))
{
KeyState=Key_Press;
}
break;
case Key_Press:
//判断按键是否仍然被按下(消抖操作)
if(B1==GPIO_PIN_RESET){Key_Value=1;}//检测是哪个按键被按下
else if(B2==GPIO_PIN_RESET){Key_Value=2;}
else if(B3==GPIO_PIN_RESET){Key_Value=3;}
else if(B4==GPIO_PIN_RESET){Key_Value=4;}
KeyState=Key_Release;
break;
case Key_Release:
if((B1==GPIO_PIN_RESET)||(B2==GPIO_PIN_RESET)||(B3==GPIO_PIN_RESET)||(B4==GPIO_PIN_RESET))
{
Key_Press_Time+=20;//对按键按下时间进行计时(判断按键是否长按)
}
else
{
KeyState=Key_Check;
Key_Flag=1;//置一个标志位,判断是否执行按键任务
}
break;
default:break;
}
}
创建计时函数Task_Time()
该函数用于计时,控制任务执行的频率。该函数非常重要,在之后的程序编写中,也会扩充该函数,以实现更多的任务计时(在main.h中声明该函数)
/*main.c*/
void Task_Time(void)
{
if(++Key_tt==10) {Key_tt=0;Key_Ref=1;}
}
在stm32g4xx_it.c中引入Task_Time()
这里使用滴答定时器进行计时,滴答定时器每1ms执行一次SysTick_Handler()函数,所以我们将Task_Time()放在SysTick_Handler()中,使用Key_tt进行计时,每次增加一个数,当Key_tt等于10之后,清空Key_tt,然后将Key_Ref置1,从而进行后续判断
/*stm32g4xx_it.c*/
extern void Task_Time(void);
/*‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
Task_Time();//计时函数(用户自行添加位置)
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
按键扫描标志位Key_Ref使用
在主循环中判断Key_Ref标志位,当标志位置1后,执行一次Key_Scan()扫描一次按键,即可以实现每10ms执行一次按键的扫描,以达到对按键的消抖和计时
/*main.c*/
while (1)
{
if(Key_Ref==1)
{
Key_Ref=0;//清除标志位
Key_Scan();
}
}
创建按键任务执行函数Key_Task()
这里检测 Key_Value、Key_Press_Time的值即可判断哪个按键被按下,并且可以判断按下时间来判断长按与短按。
void Key_Task(void)
{
if((Key_Value==1)&(Key_Press_Time>=500))//长按
{
Key_Value=0;
/*按键B1长按执行操作*/
}
else if(Key_Value==1)//短按
{
Key_Value=0;
/*按键B1短按执行操作*/
}
if(Key_Value==2)
{
Key_Value=0;
/*按键B2短按执行操作*/
}
if(Key_Value==3)
{
Key_Value=0;
/*按键B3短按执行操作*/
}
if(Key_Value==4)
{
Key_Value=0;
/*按键B4短按执行操作*/
}
}
按键任务执行标志位Key_Flag使用
在主循环中添加以下代码即可
/*main.c*/
while (1)
{
if(Key_Flag==1)
{
Key_Flag=0;//清除标志位
Key_Task();
}
}
所有函数书写完毕就可以在按键任务执行函数Key_Task()中编写自己的用户函数啦!
注:main.c中定义的函数请务必在main.h中声明,为方便后续模块的调用!!!
/*main.h*/
void Task_Time(void);
void Key_Scan(void);
相关函数定义位置stm43g4xx_hal_gpio.c
/*stm43g4xx_hal_gpio.c*/
HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
4.工程文件
该工程文件为全10讲所有内容,可以作为参考,不过还是希望读者能够自己手敲一遍,加深记忆
链接:https://pan.baidu.com/s/1LcNszc7_oHWvXcucCezlxg?pwd=hw07
提取码:hw07
自己做的笔记,也希望能对你有帮助!