基本定时器
定时器分类
STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。
基本定时器:
TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部IO。
通用定时器 :
TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。
高级定时器:
TIM1/8 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。
基本定时器功能框图讲解
基本定时器的核心是时基,不仅基本定时器有,通用定时器和高级定时器也有。
时钟源
定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果 APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M。
计数器时钟
定时器时钟经过 PSC 预分频器之后,即 CK_CNT。
PSC 是一个 16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。
计算公式:CK_CNT=TIMxCLK/(PSC+1)。
计数器
计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
自动重装载寄存器
自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
定时时间的计算
定时器的定时时间等于计数器的中断周期乘以中断的次数。
计一个数的时间(计数时钟频率)则是 CK_CLK 的倒数,等于: 1/(TIMxCLK/(PSC+1))= (PSC+1)/(TIMxCLK),那么就可以计算出每一次更新中断的定时时间等于: 1/CK_CLK* (ARR+1)。
即:更新定时周期 = (PSC+1)*(ARR+1)/(TIMxCLK) ,例如:1ms定时周期 = (71+1)*(999+1)/ 72 。
定时器初始化结构体详解
(1) TIM_Prescaler:定时器预分频器设置,时钟源经该预分频器才是定时器时钟,可设置范围为 0 至 65535,实现 1 至 65536 分频。
(2) TIM_CounterMode:定时器计数方式,可是在为向上计数、向下计数以及三种中心对齐模式。基本定时器只能是向上计数,即 TIMx_CNT 只能从 0 开始递增,并且无需初始化。
(3) TIM_Period:定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄存器。可设置范围为 0 至 65535。
(4) TIM_ClockDivision:时钟分频,设置定时器时钟 CK_INT 频率与数字滤波器采样时钟频率分频比,基本定时器没有此功能,不用设置。
(5) TIM_RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出 PWM 的个数。
虽然定时器基本初始化结构体有 5 个成员,但对于基本定时器只需设置其中两个就可以。
基本定时器定时实验
编程要点
(1) 开定时器时钟 TIMx_CLK, x[6,7];
(2) 初始化时基初始化结构体;
(3) 使能 TIMx, x[6,7] update 中断;
(4) 打开定时器;
(5) 编写中断服务程序
time.c
#include "./time/time.h"
//中断优先级配置
void BASIC_TIM_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
//设置中断优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
//设置中断来源
NVIC_InitStruct.NVIC_IRQChannel = BASIC_TIM_IRQ;
//设置优先级
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
//使能中断
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
//初始化中断
NVIC_Init(&NVIC_InitStruct);
}
//基本定时器模式配置
void BASIC_TIM_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
//开启基本定时器时钟 即72M
BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
//自动重装载寄存器的值,TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStruct.TIM_Period = BASIC_TIM_Period;
// 时钟预分频数为
TIM_TimeBaseStruct.TIM_Prescaler= BASIC_TIM_Prescaler;
// 初始化定时器
TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStruct);
// 清除定时器中断标志位
TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
// 开启定时器中断
TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
// 使能定时器器
TIM_Cmd(BASIC_TIM, ENABLE);
}
//初始化基本定时器
void BASIC_TIM_Init(void)
{
BASIC_TIM_NVIC_Config();
BASIC_TIM_Mode_Config();
}
time.h
#ifndef _TIME_H
#define _TIME_H
#include "stm32f10x.h"
//基本定时器只有TIME6和TIME7
#define BASIC_TIM6 //使用TIME7,注释掉即可
#ifdef BASIC_TIM6 //使用TIME6
#define BASIC_TIM TIM6
#define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define BASIC_TIM_CLK RCC_APB1Periph_TIM6
#define BASIC_TIM_Period 1000-1 //每次产生一个更新中断为1ms
#define BASIC_TIM_Prescaler 71
#define BASIC_TIM_IRQ TIM6_IRQn
#define BASIC_TIM_IRQHandler TIM6_IRQHandler
#else // 使用基本定时器TIM7
#define BASIC_TIM TIM7
#define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define BASIC_TIM_CLK RCC_APB1Periph_TIM7
#define BASIC_TIM_Period 1000-1
#define BASIC_TIM_Prescaler 71
#define BASIC_TIM_IRQ TIM7_IRQn
#define BASIC_TIM_IRQHandler TIM7_IRQHandler
#endif
void BASIC_TIM_Init(void);
#endif
中断服务函数
//计时器更新中断服务函数
void BASIC_TIM_IRQHandler (void)
{
if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET )
{
time++;
TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);
}
}
main.c
#include "stm32f10x.h"
#include "led.h"
#include "./time/time.h"
volatile uint32_t time = 0;
int main(void)
{
//LED初始化
LED_Init();
//基本定时器初始化
BASIC_TIM_Init();
while(1)
{
if(time == 500) //也就是500ms
{
time = 0; //把计数值清零
LED_Toggle(LED_G); //LED每500ms翻转一次
}
}
}