在按键的使用过程中,很多人使用delay延时函数进行按键的消抖,delay函数可能会堵塞程序的运行,而使用定时器TIM进行按键的使用能够有效的避免程序堵塞的问题,下面就是有关于使用TIM实现按键的使用
1.硬件连接
按键的一端 | PB0 |
按键的另一端 | GND |
LED长脚(+) | PA1 |
LED短脚(-) | GND |
2.TIM、按键以及LED的cubemx配置
定时器TIM
开启Internal Clock以及中断使能TIM3
配置TIM中断时间为T=10ms,PSC=72-1,ARR=10000-1
TIM的中断时间T计算
T=1/F
F=时钟源频率/(预分频系数+1)/(自动重装载值+1)=72 000 000/(PSC+1)/(ARR+1)
时钟源频率:stm32f103c8t6一般默认为72KHz,我们配置的时钟树是多少就是多少(如下图)
预分频系数PSC:
降低计数频率:将定时器的输入时钟源分频,得到更低的计数频率
扩展定时范围: 通过降低计数频率,定时器计数器(Counter)的每个“步进”时间变长,从而允许在有限的计数器位数(如16位)下实现更长的定时周期。
自动重装载值ARR:
定义计数周期:定时器从 0 开始计数,当达到 ARR 值时触发中断或更新事件,随后自动重置为 0。
控制中断频率:ARR 直接决定了定时器中断的间隔时间。较小的 ARR 值会频繁触发中断,较大的 ARR 值则减少中断频率。
按键
按键PB0设置为上拉输入,在stm32f103c8t6系统板上一部分IO内部自带上、下拉电阻。
LED灯
LED灯PA1设置为推挽输出,初始电平为Low
3.LED和KEY的封装函数以及main.c
LED的封装函数void led_p(uint8_t mode)
void led_p(uint8_t mode)//LED封装函数 mode=0灯灭 mode=1灯亮
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);//将PA1输出低电平,灯熄灭
if(mode)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);//将PA1输出高电平,灯点亮
}
else
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);//将PA1输出低电平,灯熄灭
}
}
KEY的封装函数调用TIM的中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
volatile uint8_t j = 0;//变量j和key_number声明为volatile,防止可能主循环中读取错误的值
volatile uint8_t key_number = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM3) {
uint8_t k = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
switch (j) {
case 0:
if (k == 0) j = 1; // 首次检测到按下
break;
case 1:
if (k == 0) j = 2; // 二次确认,去抖
else j = 0;
break;
case 2:
if (k == 1) { // 释放时触发
key_number = 1;
j = 0; // 立即复位
}
break;
}
}
}
中断回调函数:当中断触发时,系统调用预先注册的回调函数来处理中断逻辑。
主函数main.c
HAL_TIM_Base_Start_IT(&htim3);
开启定时器中断,一定不要忘记
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(key_number==1)//按键按下之后LED灯点亮1S
{
led_p(1);
HAL_Delay(1000);
led_p(0);
key_number=0;
}
}
烧录代码即可实现相应内容:按键按下之后LED灯点亮1S