Stm32之TIM-定时器的使用
- 开发环境:Window 10
- 开发工具:Keil uVision5 MDK
- 硬件:STM32F103
资料参考:
1、【正点原子】STM32F103开发板资料(A盘);
2、stm32之TIM-基本定时器应用实例
https://blog.csdn.net/weixin_42653531/article/details/88527405
3、stm32的抢占优先级和响应优先级
https://blog.csdn.net/baidu_38988793/article/details/89522107
文章目录
STM32F103ZE 简介
内核:ARM Cortex-M3,72MHz
内存:64kB RAM,512kB ROM
时钟和电源:2.00V—3.60V,72 MHz
通信 :SPI、I2C、UART、I2S、CAN、USART、USB、Device
定时器/计数器/PWM :8 × 16 位定时器
模拟:2通道 12位DAC,21通道 12位ADC
I/O 和封装: -40℃—85℃,144-QFP,144-BGA
官网:https://www.keil.com/dd2/stmicroelectronics/stm32f103ze/
一、定时器的概述
定时器最基本的功能就是定时处理事情。比如定时发送USART数据、定时采集AD数据、测量输入脉冲的频率(输入捕获)、产生输出波形(比较输出或PWM)等。
STM32系列的定时器分为基本定时器、通用定时器、高级定时器。高级定时器包括前者的全部功能。
通常地,STM32包括高级定时器TIM1、TIM8,通用定时器TIM2、TIM3、TIM4、TIM5,基本定时器TIM6、TIM7,具体详见各芯片的数据手册。
- 基本定时器(TIM6、TIM7)
- 通用定时器(TIM2、TIM3、TIM4、TIM5)
- 高级定时器(TIM1、TIM8)
注释:STM32F103系列有8个16位的定时器,且均采用72MHz的内部时钟;而F407系列则有14个且每个定时器的时钟也不同,具体使用需结合数据手册,如下图。
二、定时器的使用步骤
1)TIMx时钟使能
2)初始化定时器参数,设置自动重装值,分频系数,计数方式等
3)设置TIMx_DIER允许中断
4)TIMx中断优先级设置
5)允许TIMx工作,即使能TIMx
6)编写中断服务函数
1)TIMx时钟使能
基本、通用定时器的时钟来自于APB1总线;
高级定时器(TIM1、TIM8)的时钟来自于APB2总线。
针对 TIM3 时钟使能范例:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 时钟使能
2)初始化定时器参数
库函数中定时器的初始化通过TIM_TimeBaseInit()实现
TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
第一个参数:确定哪个定时器;
第二个参数:定时器初始化参数结构体指针,即用结构体形式对定时器的相关参数进行配置。
typedef struct
{
u16 TIM_Period;
u16 TIM_Prescaler;
u8 TIM_ClockDivision;
u16 TIM_CounterMode;
u8 TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;
- TIM_Period:定时器自动重装载计数周期值,当计数寄存器的值递增到等于该值时,将相关事件标志位置位,范围0~65535。
- TIM_Prescaler:定时器预分频设置。时钟源经该预分频器才是定时器时钟,范围0~65535。
- TIM_ClockDivision:时钟分频。有不分频、二分频、四分频。基本定时器没有这个功能。
- TIM_CounterMode:定时器计数方式设置,有向上计数、向下计数、对齐模式等,基本定时器只能向上计数。
- TIM_RepetitionCounter :重复计数器,只有高级定时器才有用。
针对 TIM3 初始化范例代码格式:
定时时间=(计数值)*(定时器预分频+1)/内部时钟
STM32F103的内部时钟为72MHz,为实现0.5s定时,预分频Prescaler设置为7200-1,定时器可以得到10KHz(72MHz/((7200-1)+1))的时钟频率,计数值Period设置为5000-1,可以得到定时为0.5s(5000*(1/10kHz))的定时器。
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 5000;//设置自动重装载计数值
TIM_TimeBaseStructure.TIM_Prescaler =7199;//设置预分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟不分频
TIM_TimeBaseStruc ture.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//根据指定参数初始化TIMx
3)设置TIMx_DIER允许中断
在库函数里面定时器中断使能是通过 TIM_ITConfig 函数来实现
使能TIM3 的更新中断,格式为:
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );
4)TIMx中断优先级设置
用 NVIC_Init()函数实现中断优先级的设置
NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
NVIC_InitTypeDef定义于文件“misc.h”
typedef struct
{
u8 NVIC_IRQChannel;
u8 NVIC_IRQChannelPreemptionPriority;
u8 NVIC_IRQChannelSubPriority;
FunctionalState NVIC_IRQChannelCmd;
} NVIC_InitTypeDef;
- NVIC_IRQChannel:定义初始化哪个中断
- NVIC_IRQChannelPreemptionPriority:定义中断的抢占优先级别
- NVIC_IRQChannelSubPriority:定义这个中断的子优先级别
- NVIC_IRQChannelCmd:该中断是否使能
针对 TIM3 中断设置范例代码格式:
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寄存器
NVIC 的优先级组
STM32用4位寄存器位的表示中断优先级,其的分组方式如下:
第0组:所有4位用于指定响应优先级
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级,抢占级有2^1 =2 级;子优先级2^3=8级,共2*8=16级嵌套
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级,抢占级有2^2 =4 级;子优先级2^2=4级,共4*4=16级嵌套
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级,抢占级有2^3 =8 级;子优先级2^1=2级,共8*2=16级嵌套
第4组:所有4位用于指定抢占式优先级
中断响应的优先级由抢占优先级和响应优先级(子优先级)确定,若抢占优先级相同,则看响应优先级,数字越小优先级越高。
1.抢占相同,子优先级不同:按照子优先级顺序排序
2.抢占和子优先级都相同但有先后:此时无抢占剥夺,依照FIFO(先进先出),前一个执行完了再执行后者;
3.抢占和子优先级都相同且同时到达:按照中断向量表顺序排先后
5)允许TIMx工作,即使能TIMx
使能定时器的函数通过 TIM_Cmd 函数来实现
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
针对 TIM3 中断设置范例代码格式:
TIM_Cmd(TIM3, ENABLE); // 使能 TIMx 外设
6)编写中断服务函数
- 库函数中,用TIM_GetITStatus()来判断中断类型
比如要判断定时器3是否发生更新(溢出)中断,方法为:
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
- 固件库中使用TIM_ClearITPendingBit()清除中断标志位
比如在TIM3的溢出中断发生后,要清除中断标志位,方法是:
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
针对 TIM3 实现定时0.5s闪烁的中断服务函数范例:
/*注意:中断处理的事情要尽可能精简,避免过长时间停留在中断里面*/
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //判断TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
LED1=!LED1; //翻转LED1的状态,实现闪烁
}
}