目录
本篇通过按键中断检测,来学习如何用CubeMX配置定时器,编写中断回调函数,实现按键检测。
为了让大家更直观的看到按键按下的状态,本次我们采用LCD显示按键按下的状态,我们直接在官方HAL库的LCD例程的基础上进行配置。
在CubeMX使用教程(3)——GPIO中,我们也用到了按键,当时是用按键控制LED,但是和这次定时器中断按键检测是不一样的。当时用的按键扫描函数Key_Scan()是通过延时函数实现的,按键中断是通过定时器中断实现的。按键扫描是用CPU对按键的情况进行不断扫描,检测到按键变化执行按键控制。按键中断是一但出现IO口的变化就触发中断,执行中断内的程序。相比按键扫描,按键中断可以大幅节省CPU资源,提高系统运行效率。
1、GPIO配置
通过G431RBT6开发板的按键原理图可知,我们需要把PB0、PB1、PB2、PA0配置为上拉输入,上拉输入的好处就是输入的电平不会上下浮动而导致输入信号不稳定,在没有信号输入的情况下可以稳定在高电平,即默认低电平有效。
2、定时器配置
配置完四个按键的GPIO后,接下来我们进行定时器的配置
在时钟配置时,主要就是配置分频系数(psc)和重装载值(counter)这两个参数,他们分别决定系统的定时工作频率和定时频率
定时工作频率=外部总线频率/(psc+1)
定时频率=定时工作频率/counter
通过这两个等式,我们可以配置psc=80-1;counter=10000-1
CubeMX的时钟配置完成,点击GENERATE CODE即可生成代码
3、编写中断回调函数
interrupt.c
#include "interrupt.h"
struct keys key[4]={0,0,0,0};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM3)
{
key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++)
{
switch (key[i].judge_sta)
{
case 0:
{
if(key[i].key_sta==0) key[i].judge_sta=1;
}
break;
case 1:
{
if(key[i].key_sta==0)
{
key[i].judge_sta=1;
key[i].single_flag=1;
}
else key[i].judge_sta=0;
}
break;
case 2:
{
if(key[i].key_sta==1)
{
key[i].judge_sta=0;
}
}
break;
}
}
}
};
interrupt.h
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_
#include "main.h"
#include "stdbool.h"
void HAL_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
struct keys
{
char judge_sta;
bool key_sta;
bool single_flag;
};
#endif
4、完善main.c
在编写完中断回调函数之后,在main.c中添加#include "interrupt.h"头文件
同时在main.c中引用interrupt.c中的变量struct keys key[],具体方法为添加extern struct keys key[];语句
最后在主函数中添加HAL_TIM_Base_Start_IT(&htim3); 以便打开中断3
主函数while(1)中添加以下功能函数
if(key[0].single_flag==1)
{
LCD_DisplayStringLine(Line5, (uint8_t *)" B1_ Down ");
key[0].single_flag=0;
}
if(key[1].single_flag==1)
{
LCD_DisplayStringLine(Line5, (uint8_t *)" B2_ Down ");
key[1].single_flag=0;
}
if(key[2].single_flag==1)
{
LCD_DisplayStringLine(Line5, (uint8_t *)" B3_ Down ");
key[2].single_flag=0;
}
if(key[3].single_flag==1)
{
LCD_DisplayStringLine(Line5, (uint8_t *)" B4_ Down ");
key[3].single_flag=0;
}
5、最终效果
按下按键1(B1)
按下按键2(B2)
按下按键3(B3)
按下按键4(B4)