STM32单片机利用定时器实现按键采集
程序员文章站
2022-03-03 19:46:19
源码下载链接:工程项目结构如下图所示:其中画红色方框部分为重要函数来进行讲解TIMx.c#include "TIMx/TIMx.h"#include "LED/LED.h"#include "UART/uart.h"#include "stdio.h"#include "KEY/key.h"extern u8 key_value; // 全局变量/** * 功能:初始化定时器 * 参数: * TIMx:指定待设置的定时器,TIM1-TIM4 *...
源码下载链接:https://taileliekaishi.lanzous.com/ifhJffitozg
工程项目结构如下图所示:
其中画红色方框部分为重要函数来进行讲解
TIMx.c
#include "TIMx/TIMx.h"
#include "LED/LED.h"
#include "UART/uart.h"
#include "stdio.h"
#include "KEY/key.h"
extern u8 key_value; // 全局变量
/**
* 功能:初始化定时器
* 参数:
* TIMx:指定待设置的定时器,TIM1-TIM4
* prescaler:设置预分频值 0-65535
* period:设置中断周期,即设置重装载寄存器的值 0-65535
* IT_Source:中断源,比如更新中断,四个通道的输入比较中断,取值查看:TIM_interrupt_sources
* NewState:是否使能IT_Source参数指定的中断,ENABLE,DISENABLE
* 返回值:None
*/
void initTIMx(TIM_TypeDef* TIMx,u16 prescaler,u16 period,u16 IT_Source,FunctionalState NewState)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
switch((u32)TIMx)
{
case (u32)TIM1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);break; //开启定时器1时钟
case (u32)TIM2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);break; //开启定时器2时钟
case (u32)TIM3: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);break; //开启定时器3时钟
case (u32)TIM4: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);break; //开启定时器4时钟
/*其他密度的单片机对case进行删减即可兼容,本程序针对中密度单片机*/
default : break;
}
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分频因子,该分频不是预分频值,要区分
TIM_TimeBaseStructure.TIM_Period = period; //设置定时器周期
TIM_TimeBaseStructure.TIM_Prescaler =prescaler; //设置预分频值
TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure); //生效更改
TIM_Cmd(TIMx, ENABLE); //开启计数器
TIM_ITConfig(TIMx,IT_Source,NewState); //使能定时器更新中断
}
/**
* 功能:设置定时器周期,即设置重装载寄存器的值
* 参数:
* TIMx:指定待设置的定时器,TIM1-TIM4
* period:设置中断周期,即设置重装载寄存器的值 0-65535
* 返回值:None
*/
void setPeriod(TIM_TypeDef* TIMx,u16 period)
{
TIM_SetAutoreload(TIMx, period); //设置重装载值
}
/**
* 功能:设置定时器预分频值
* 参数:
* TIMx:指定待设置的定时器,TIM1-TIM4
* period:设置中断周期,即设置重装载寄存器的值 0-65535
* 返回值:None
*/
void setPrescaler(TIM_TypeDef* TIMx,u16 prescaler)
{
/*设置预分频值等于fCK_PSC/(PSC[15:0]+1)
*fCK_PSC为内部输入时钟,默认72MHz,假如我们想要72000倍分频,即时钟周期1ms
*则我们传入的值应该是71999*/
TIM_PrescalerConfig(TIMx, prescaler,TIM_PSCReloadMode_Update); //设置定时器周期
}
/****************************************定时器中断服务函数************************************************/
void TIM3_IRQHandler(void)
{
u8 key_cache = 0;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //由于定时器中断源很多,因此要判断是哪个中断源触发的中断
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //软件清除中断挂起位,否则会一直卡死在中断服务函数
key_cache = getKeyValue(KEY_PRESS);
/*在主函数执行Delay_ms延时函数时,在此期间30ms时间按键按下值更新为KEY_UP
在此期间又过了30ms此时按键是没有按下的,但是值被更新为key_No
等100ms执行完成后,明明在这100ms的时间段内按下了按键但是没有改变灯的闪烁的频率
因为我们只需要采集按下的值 所以为了避免没有按下的值影响按下的值就进行下面的判断
*/
if(key_cache != KEY_NO)
{
key_value = key_cache;
}
}
}
main.c
#include "DELAY/Delay.h"
#include "NVIC/NVIC.h"
#include "TIMx/TIMx.h"
#include "KEY/key.h"
#include "LED/LED.h"
u8 key_value = KEY_NO;
int main(void)
{
u16 xms = 100;
/*初始化各外设*/
initSysTick();
initLED();
initKey();
initNVIC(NVIC_PriorityGroup_2);
// 每隔30ms执行一次中断服务函数:采集一次按键的值
initTIMx(TIM3,7199,299,TIM_IT_Update,ENABLE);
TIM_ARRPreloadConfig(TIM3,ENABLE);
while (1)
{
if(key_value==KEY_UP) //UP键按下
{
xms = 100;
}else if(key_value==KEY_DOWN) //DOWN键按下
{
xms = 800;
}else //没有按键按下或全按时不进行任何操作
{
}
toggleLED();
Delay_ms(xms);
}
}
本文地址:https://blog.csdn.net/weixin_39903708/article/details/107944421