本篇博客主要学习了解定时器的标准库函数,以及定时器中断进行LED灯的反转,还有定时器外部时钟获取脉冲计数功能。本篇博客大部分是自己收集和整理,如有侵权请联系我删除。
本篇博客主要是对通用定时器来讲解,功能适中比较常用。
本次博客开发板使用的是正点原子精英版,芯片是STM32F103ZET6,需要资料可以@我拿取。
本博客内容原创,创作不易,转载请注明
————————————————
对定时器不了解的可以先去看看: TIM定时器详解
在学习库函数之前,首先我们得先了解定时器的基本机构和框图来进行分析:
1.首先定时器的基本作用就是定时的功能,还有对外部脉冲检测
2.然后就是四个输入捕获通道,四个输出比较通道,获取预分频和重装载值,标志位等等
3.高级定时器的高级功能死区和刹车生成暂时不需要了解
4.时钟选择函数
由此可见,细分之后的定时器库函数并不多,接下来主要讲下新手常用的库函数了解就行。
接下来借鉴一下我群友做的笔记来了解一下常用标准库函数的组成和作用吧!
针对开发板的例子,本次说明使用通用定时器TIM3来控制LED定时翻转
如图所示,本次需要用到的就是前四个参数,最后一个是高级定时器才用到的,这里暂时不了解。
TIM_InternalClockConfig(TIM3);
可以不选,芯片内部自动上电选择就是RCC时钟,但是用到外部时钟要配置。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM3 是挂载在 APB1 之下,所以我们通过 APB1 总线下的使能使能函数来使能 TIM3。
TIM_TimeBaseStructure.TIM_Prescaler = 7199;
默认定时器时钟频率为72M,那么预分频器设置为7199,那么一次计数为1S
设置为9999,那么产生一次定时器中断的时间为1ms
TIM_TimeBaseStructure.TIM_Period = 10000 - 1;
//自动重装载寄存器为9999,则产生一次中断时间为1s
时钟分频因子:一般选择1分频,就是不分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 计数器计数模式,选择向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//允许更新中断
TIM_Cmd(TIM3, ENABLE);
在初始化之后,开启中断之前
再次执行TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim,不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
LED1=!LED1;
}
}
1.既然是通过外部输入的,我们的模块就选择一个输入引脚,本篇博客参考江科大的代码,实现对射红外传感器实现获取外部脉冲。
2.然后就是不选择内部时钟源了,我们可以选择外部时钟1或者外部时钟2,本次我们选择外部时钟2_ETR
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);
核心代码是通过选择外部时钟,然后最后一个参数根据实际情况选择,因为有些人可能获取数据比较快,不稳定,就可以修改这个参数来滤波。
然后其他代码和中断基本相似,就贴代码看看就行了
最后一个滤波参数说明
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1; //获取十次之后计数器清0
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //每获取一次记一个数
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //高级定时器才用这个,所以给0,
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //事件更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //定时器2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
uint16_t Timer_GetCounter(void)
{
return TIM_GetCounter(TIM2); //获取脉冲计次
}
以上就是本次博客的定时器中断和外部时钟的介绍和例程代码,具体都是通过预分频和重装载值来玩这个定时器,难度不高,属于定时器的基础内容,如有错误,欢迎各位交流指正。
点赞收藏关注双击博主,不定期分享单片机知识,互相学习交流。
————————————————