STM32F429总共有14个:
高级定时器:TIM1 和TIM8
通用定时器:TIM2-TIM5,TIM9-TIM14
基本定时器:TIM6 和 TIM7
挂载的总线:高级定时器及TIM9-TIM11的时钟来自APB2,其他来自APB1;
APB2:TIM1 和 TIM8 、TIM9-TIM11
APB1:TIM2-TIM5、TIM6 和 TIM7、TIM12-TIM14
定时器简介
STM32F429 的通用定时器包含一个 16 位或 32 位自动重载计数器( CNT),该计数器由可编程预分频器( PSC) 驱动。
STM32F429 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。
使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。
STM32F429 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
STM32 的通用 TIMx (TIM2~TIM5 和 TIM9~TIM14)定时器功能包括:
-
16 位/32 位(仅 TIM2 和 TIM5)向上、向下、向上/向下自动装载计数器(TIMx_CNT),注意: TIM9~TIM14 只支持向上(递增)计数方式。
-
16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
-
4 个独立通道(TIMx_CH14TIM9TIM14 最多 2 个通道),这些通道可以用来作为:
A.输入捕获
B.输出比较
C. PWM 生成(边缘或中间对齐模式) ,注意: TIM9~TIM14 不支持中间对齐模式
D.单脉冲模式输出
-
可使用外部信号( TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外
一个定时器)的同步电路。 -
如下事件发生时产生中断/DMA( TIM9~TIM14 不支持 DMA):
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
E.支持针对定位的增量(正交)编码器和霍尔传感器电路( TIM9~TIM14 不支持)
F.触发输入作为外部时钟或者按周期的电流管理( TIM9~TIM14 不支持)
常用的寄存器
TIMx_CR1:(Control Register 1)控制寄存器1
TIM1 和 TIM8:
TIM2-TIM5:
TIM9-TIM12
TIM6 和 TIM7:
qq空间图片
不会做点进去就是图片的链接,好尴尬。
TIMx_CR2:(Control Register 2)控制寄存器2
分类同TIMx_CR1
TIMx_DIER:(DMA Interrupt Enable Register)DMA/中断使能寄存器
TIMx_PSC:(Prescaler)预分频寄存器
TIMx_ARR:(auto-reload register)重装载寄存器
该寄存器在物理上实际对应着 2 个寄存器,一个是程序员可以直接操作的,另外一个是程序员看不到的,这个看不到的寄存器在《 STM32F4xx 中文参考手册》里面被叫做影子寄存器。事实上真正起作用的是影子寄存器。 根
据 TIMx_CR1 寄存器中 APRE 位的设置:APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2 者是连通的;而 PRE=1 时,在每一次更新事件( UEV)时,才把预装载寄存器( ARR) 的内容传送到影子寄存器。
TIMx_SR:(status register)状态寄存器
步骤
- 1) TIM3 时钟使能。
这里我们通过 APB1ENR 的第 1 位来设置 TIM3 的时钟,因为 Stm32_Clock_Init 函数里面
把 APB1的分频设置为 4了,所以我们的 TIM3时钟就是 APB1时钟的 2倍,等于系统时钟 ( 90M)。
- 2) 设置 TIM3_ARR 和 TIM3_PSC 的值。
通过这两个寄存器,我们来设置自动重装的值,以及分频系数。这两个参数加上时钟频率就决定了定时器的溢出时间。
- 3) 设置 TIM3_DIER 允许更新中断。
因为我们要使用 TIM3 的更新中断,所以设置 DIER 的 UIE 位为 1,使能更新中断。
- 4) 允许 TIM3 工作。
光配置好定时器还不行,没有开启定时器,照样不能用。我们在配置完后要开启定时器,通过 TIM3_CR1 的 CEN 位来设置。
- 5) TIM3 中断分组设置。
在定时器配置完了之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,以使能TIM3 中断。
- 6) 编写中断服务函数。
在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处理完中断之后应该向 TIM3_SR 的最低位写 0,来清除该中断标志
示例代码
- 寄存器
/************************/
//C文件内容
#include "tim3.h"
void TIM3_IRQHandler(void)
{
if (TIM3->SR&0x0001) //溢出中断 SR状态寄存器
{
LED0=!LED0;
}
TIM3->SR&=~(1<<0); //状态寄存器清零
}
void TIM4_IRQHandler(void)
{
if (TIM4->SR&0x0001) //溢出中断 SR状态寄存器
{
LED1=!LED1;
}
TIM4->SR&=~(1<<0); //状态寄存器清零
}
//通用定时器 3 中断初始化
//这里时钟选择为 APB1 的 2 倍,而 APB1 为 45M
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//这里使用的是定时器 3!
void TIM3_Int_Init(u16 arr,u16 psc)
{ //0 1 2 3 ...
RCC->APB1ENR|=1<<1; //TIM2 TIM3 TIM4 TIM5 ...
TIM3->ARR=arr; //自动重装载寄存器
TIM3->PSC=psc; //时钟预分频寄存器
TIM3->DIER|=1<<0; //允许更新中断
TIM3->CR1|=0x01; //控制寄存器1 使能定时器3
MY_NVIC_Init(1,3,TIM3_IRQn,2); //抢占1 ,子优先级 3
}
void TIM4_Int_Init(u16 arr,u16 psc)
{ //0 1 2 3 ...
RCC->APB1ENR|=1<<2; //TIM2 TIM3 TIM4 TIM5 ...
TIM4->ARR=arr; //自动重装载寄存器
TIM4->PSC=psc; //时钟预分频寄存器
TIM4->DIER|=1<<0; //允许更新中断
TIM4->CR1|=0x01; //控制寄存器1 使能定时器3
MY_NVIC_Init(2,3,TIM4_IRQn,2); //抢占1 ,子优先级 3
}
/************************/
//头文件内容
#ifndef __TIM3_H_
#define __TIM3_H
#include "sys.h"
#include "led.h"
void TIM3_Int_Init(u16 arr,u16 psc);
void TIM4_Int_Init(u16 arr,u16 psc);
#endif
- 库函数
/*********************/
//c文件
#include "timer.h"
TIM_HandleTypeDef TIM2_Handler;
TIM_HandleTypeDef TIM3_Handler;
//arr:自动重装载
//psc:时钟分频数
void TIM2_Init(u16 arr,u16 psc)
{
TIM2_Handler.Instance=TIM2;
TIM2_Handler.Init.Prescaler=psc;
TIM2_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
TIM2_Handler.Init.Period=arr;
TIM2_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&TIM2_Handler);
//使能
HAL_TIM_Base_Start_IT(&TIM2_Handler);
}
void TIM3_Init(u16 arr,u16 psc)
{
TIM3_Handler.Instance=TIM3;
TIM3_Handler.Init.Prescaler=psc;
TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
TIM3_Handler.Init.Period=arr;
TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&TIM3_Handler);
//使能
HAL_TIM_Base_Start_IT(&TIM3_Handler);
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if (htim==&TIM2_Handler)
{
__HAL_RCC_TIM2_CLK_ENABLE(); //使能 TIM3 时钟
HAL_NVIC_SetPriority(TIM2_IRQn,0,3); //设置中断优先级,抢占 1,子优先级 3
HAL_NVIC_EnableIRQ(TIM2_IRQn); //开启 ITM3 中断
}
if (htim==&TIM3_Handler)
{
__HAL_RCC_TIM3_CLK_ENABLE(); //使能 TIM3 时钟
HAL_NVIC_SetPriority(TIM3_IRQn,1,3); //设置中断优先级,抢占 1,子优先级 3
HAL_NVIC_EnableIRQ(TIM3_IRQn); //开启 ITM3 中断
}
}
//
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TIM2_Handler);
}
//
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TIM3_Handler);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim==&TIM2_Handler)
{
LED1=!LED1;
}
if (htim==&TIM3_Handler)
{
LED0=!LED0;
}
}
/************************************/
//头文件
#ifndef __TIMER_H__
#define __TIMER_H__
#include "sys.h"
#include "led.h"
void TIM2_Init(u16 arr,u16 psc);
void TIM3_Init(u16 arr,u16 psc);
#endif