目录
目录
通用定时器简介
STM32 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)
构成。STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波
形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形
周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相
共享的任何资源。
STM3 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能包括:
1)16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~
65535 之间的任意数值。
3)4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C.PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出
4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外
一个定时器)的同步电路。
5)如下事件发生时产生中断/DMA:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
E.支持针对定位的增量(正交)编码器和霍尔传感器电路
F.触发输入作为外部时钟或者按周期的电流管理
寄存器
控制寄存器 (TIMx_CR1)
在本实验中,只用到了 TIMx_CR1 的最低位,也就是计数器使能位,该位必须置 1,
才能让定时器开始计数
DMA/中断使能寄存器(TIMx_DIER)
同样仅关心它的第 0 位,该位是更新中断允许位,本章用到的是定时器的更新中断,所以该位要设置为 1,来允许由于更新事件所产生的中断。
预分频寄存器(TIMx_PSC)
该寄存器用设置对时钟进行分频,然后提供给计数器
这里,定时器的时钟来源有 4 个:
1)内部时钟(CK_INT)
2)外部时钟模式 1:外部输入脚(TIx)
3)外部时钟模式 2:外部触发输入(ETR)
4)内部触发输入(ITRx):使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟)。
这些时钟,具体选择哪个可以通过 TIMx_SMCR 寄存器的相关位来设置。这里的 CK_INT
时钟是从APB1倍频的来的,STM32中除非APB1的时钟分频数设置为1,否则通用定时器TIMx
的时钟是 APB1 时钟的 2 倍,当 APB1 的时钟不分频的时候,通用定时器 TIMx 的时钟就等于
APB1 的时钟。这里还要注意的就是高级定时器的时钟不是来自 APB1,而是来自 APB2 的。
TIMx_CNT 寄存器
该寄存器是定时器的计数器,该寄存器存储了当前定时器的计数值。
自动重装载寄存器(TIMx_ARR)
状态寄存器(TIMx_SR)
该寄存器用来标记当前与定时器相关的各种事件/中断是否发生。
设置定时器中断步骤
1 )TIM3 时钟使能
TIM3 是挂载在 APB1 之下,所以我们通过 APB1 总线下的时钟使能函数来使能 TIM3。调用的函数是:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
2 )初始化定时器参数 , 设置 自动重装值 , 分频系数 ,计数方式 等。
voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct);
第一个参数是确定是哪个定时器,第二个参数是定时器初始化参数结构体指针,结构体类型为TIM_TimeBaseInitTypeDef,下面我们看看这个结构体的定义:
typedef struct
{
uint16_t TIM_Prescaler;
uint16_t TIM_CounterMode;
uint16_t TIM_Period;
uint16_t TIM_ClockDivision;
uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;
对于通用定时器只有前面四个参数有用,最后一个参数 TIM_RepetitionCounter 是高级定时器才有用的,
第一个参数 TIM_Prescaler 是用来设置分频系数第二个参数 TIM_CounterMode 是用来设置计数方式,可以设置为向上计数,向下计数方式还有中央对齐计数方式,比较常用的是向上计数模式 TIM_CounterMode_Up 和向下计数模式 TIM_CounterMode_Down。
第三个参数是设置自动重载计数周期值
第四个参数是用来设置时钟分频因子。
针对 TIM3 初始化范例代码格式:TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 5000;
TIM_TimeBaseStructure.TIM_Prescaler =7199;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
3 )设置 TIM3_DIER 允许更新中断。
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
第一个参数是选择定时器号,取值为 TIM1~TIM17。
第二个参数指明我们使能的定时器中断的类型,定时器中断的类型有很多种,包括更新中断 TIM_IT_Update,触发中断 TIM_IT_Trigger,以及输入捕获中断等等。
第三个参数就是失能还是使能。
例如我们要使能 TIM3 的更新中断,格式为:TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );
4 )TIM3 中断优先级设置。
在定时器中断使能之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,设置中
断优先级。
5 )允许 TIM3 工作,也就是使能 TIM3 。
我们在配置完后要开启定时器,通过 TIM3_CR1 的 CEN 位来设置。在固件库里面使能定时器 的函数是通过 TIM_Cmd 函数来实现的:
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
6)用来读取中断状态寄存器的值判断中断类型的函数是:
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t)
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){ }
清除中断标志位,
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
TIM_ClearITPendingBit(TIM3, TIM_IT_Update );
代码块
#include "timer.h"
#include "led.h"
//通用定时器 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 使能
//定时器 TIM3 初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //②初始化 TIM3
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //③允许更新中断
//中断优先级 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); //⑤使能 TIM3
}
/定时器 3 中断服务程序⑥
void TIM3_IRQHandler(void) //TIM3 中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除 TIM3 更新中断标志
LED1=!LED1;
}
}
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置 NVIC 中断分组 2:2 位
抢占优先级,2 位响应优先级
uart_init(9600); //串口初始化波特率为 9600
LED_Init(); //LED 端口初始化
TIM3_Int_Init(4999,7199); //10Khz 的计数频率,计数到 5000 为 500ms
while(1)
{
LED0=!LED0;
delay_ms(200);
}
}
此上内容均为从官方资料中查找的