STM32F103ZET6+TIMx定时器
STM32定时器种类多,功能强大,这些定时器完全独立、互不干扰,可以同步操作。
1、 SysTick定时器
SysTick系统时钟位于Cortex-M3内核,是一个24位的递减计数器,主要用于:
• 精确延时,在多任务操作系统中为系统提供时间基准(时基);
• 任务切换,为每个任务分配时间片。
2、 看门狗定时器
作用:当微控制器受到外部干扰或程序中出现不可预知的逻辑故障导致应用程序脱离正常的执行流程时(俗称程序跑飞),在一定的时间间隔内使系统复位,回到初始状态;
看门狗设计是用来监视MCU程序运行状态的,是确保系统可靠稳定运行的一种有效措施。
高级定时器的功能强于通用定时器,通用定时器的功能强于基本定时器。
定时器的主要功能
1、 计数
脉冲计数,使用使用微控制器内部的外部时钟(PCLK)来计数,是对固定周期的脉冲信号计数。
2、 定时
时间控制,通过对微控制器内部的时钟脉冲进行计数实现定时功能。
3、 输入捕获
对输入信号进行捕获,实现对脉冲的频率测量,可用于对外部输入信号脉冲宽度的测量,比如测量电机转速。
4、 输出比较
将计数器计数值和设定值进行比较,根据比较结果输出不同电平,用于控制输出波形,比如直流电机的调速。
基本定时器
STM32有2个基本定时器TIM6和TIM7,可用作:
通用的16位计数器:
产生DAC触发信号
基本定时器的计数模式只有向上计数模式。
通用定时器
TIM2、TIM3、TIM4、TIM5为STM32的4个独立的16位通用定时器,具有定时、测量输入信号的脉冲长度(输入捕获)、输出所需波形(输出比较、产生PWM、单脉冲输出等)等功能。
1、时钟源
当定时器使用内部时钟时,定时器的时钟源统称为TIMxCLK。虽然在系统默认的配置中,TIMxCLK的时钟频率都是72MHz,但其时钟来源并不相同。
定时器TIM2~TIM7挂接在APB1上
定时器TIM1和TIM8挂接在APB2上
若外部晶振的频率为8MHz,则系统默认的时钟频率为72MHz
APB1预分频器的分频系数设置为2,则PCLK1=36MHz;
APB2预分频系数设置为1,则PCLK2=72MHz,TIM1和TIM8的时钟频率TIMxCLK=72MHz;
Cortex系统时钟由AHB时钟(HCLK)8分频得到,即SysTick的频率为9MHz。
2、预分频器PSC
可以以1~65535之间的任意数值对时钟源CK_PSC的时钟频率进行分频,输出CK_CNT脉冲供计数器CNT进行计数。
3、计数器CNT
TIMxCNT是一个16位的寄存器,计数范围为1~65535,可以向上计数、向下计数或向下向上双向计数。
要得到想要的计数值,需要对输入时钟频率进行分频。
当计数值达到设定值时,便产生溢出事件,溢出时产生中断或DMA请求,然后再由自动装载寄存器进行重新加载或更新。
计数器溢出中断属于软件中断,执行相应的定时器中断服务程序。
4、自动装载寄存器ARR
定时器的定时时间主要取决于定时周期和预分频因子,计算公式为:
定时时间=(ARR+1)×(预分频值PSC+1)/输入时钟频率
或 T=(TIM_Period +1)*(TIM_Prescaler +1)/TIMxCLK
这里ARR+1是因为计数器都是从0开始计数的。
高级定时器
TIM1和TIM8是STM32的2个16位的高级定时器,高级定时器相比基本定时器、通用定时器,功能更为强大。
作用:通用定时功能。TIM1还提供控制三相六步电机的接口,具有刹车功能、死区时间控制等功能,主要用于电机控制。
定时器标准外设库配置过程
定时器的标准外设库配置步骤如下:
- 使能TIM2
TIM2时钟使能代码如下:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
- 初始化定时器参数,设置自动重装值、预分频系数、计数方式等
使用TIM_TimeBaseInit()函数初始化定时器,其原型如下:
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
第1个参数是选择的具体定时器TIMx(x为2,3,4),第2个参数为TimeBaseInitStruct结构体指针。
以初始化通用定时器TIM2为例,配置如下:
3.设置TIM2允许更新中断
为了避免在初始化定时器时进入中断,需要在初始化过程中清除中断标志。若设置定时器为向上计数模式,则调用库函数TIM_ClearFlag(TIM2, TIM_FLAG_Update)来清除向上溢出中断标志。
中断在使用前必须先使能再使用,若使能定时器TIM2的更新模式中断,则调用库函数TIM_ITConfig(),函数原型如下:
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
第1个参数是选择的具体定时器TIMx(x=2,3,4)
第2个参数用来指明使能定时器的中断类型
第3个参数为TIMx的中断状态,该参数可取值为ENANLE(使能)或者DISABLE(失能)
4.设置TIM2中断优先级的相关代码如下:
5.使能TIM2
使用TIM_Cmd()函数使能相应的定时器,其函数原型如下:
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
第1个参数为TIMx(x=2,3,4);第2个参数为TIMx的状态,该参数可取值为ENABLE(使能)或者DISABLE(失能)
6.编写中断服务函数
STM32标准外设库函数中用来读取中断状态的库函数如下:
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t);
清除定时器相应中断标志位的函数如下:
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
在之前的LED灯工程上,新建两个文件,一个是timer.h文件,另一个是timer.c文件
timer.h文件的代码如下:
#ifndef __TIMER_H
#define __TIMER_H
#include "stm32f10x.h"
void Timer_Init(void);
void TIM2_NVIC_Configuration(void);
#endif
timer.c文件的代码如下:
#include "timer.h"
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定义TIM初始化类型结构体变量
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启TIM2时钟
TIM_TimeBaseStructure.TIM_Period = (36000-1); //设置自动重装计数周期值
TIM_TimeBaseStructure.TIM_Prescaler = (2000-1); //设置分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分频因子
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置为向上计数方式
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //初始化定时器TIM2
TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清除中断,避免系统启动中断后会立即产生中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能TIM2的更新中断
TIM_Cmd(TIM2,ENABLE); //使能TIM2定时器
}
void TIM2_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择中断优先级分组2
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //设置中断通道为TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //设置响应优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能引脚为中断源
NVIC_Init(&NVIC_InitStructure); //初始化NVIC
}
//中断处理函数
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_5,(BitAction)((1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5)))); //PE5的电平状态翻转
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清除中断标志位
}
}
main.c文件的代码如下:
#include "stm32f10x.h"
#include "led.h"
#include "Timer.h"
int main(void)
{
LED_Init();
Timer_Init();
TIM2_NVIC_Configuration();
while(1)
{
}
}
总结: 在系统初始化即开启系统时钟后,要对LED灯进行初始化操作,同时还需要配置通用定时器TIM2的相关参数,配置NVIC中断,最后编写中断处理函数。