目录
STM32的定时器概述
通用定时器
通用定时器简介
主要功能
模块框图
时钟来源
通用定时器寄存器
控制寄存器 1(TIMx_CR1)
DMA/中断使能寄存器(TIMx_DIER)
时基单元寄存器
计数器模式
向上计数模式
向下计数模式
定时周期的计算
库函数代码配置定时器
配置步骤
状态查看函数
代码范例
STM32F1有TIME1和TIME8 等高级定时器,也有TIME2~TIME5等通用定时器,还有TIME6和TIME7等基本定时器。
关于高级定时器、通用定时器、基本定时器的区别:
基本定时器:具有最基本的计时功能,与通用和高级定时器的16位自动重装载计数器不同,他的计数器是一个累加计数器!基本定时器独有一个其他定时器没有的DAC的同步电路!
通用定时器:能满足大部分使用需求的定时器。
高级定时器:高级的骚操作比较多的定时器,但是一般不常用到,用到的时候可以再根据参考手册深入研究。
我们一般常用到的就是通用定时器。
加色处理的功能都是非常重要的常用功能!
通用定时器框图如下所示,红色框是计数器部分,当仅使用计数器模式的时候,只涉及这部分。在定时器的基础上,还有下方的捕获/比较通道,输入通道可用于输入捕获(蓝色部分)和输出通道可用于输出PWM(绿色部分),与上面主要功能的颜色对应。本文只涉及到红色部分,也就是定时器的计数单元!输入捕获、PWM和DMA在后文写。
通用定时器的时钟来源有四个,具体选择哪个可以通过 TIMx_SMCR 寄存器的相关位来设置。
不过,一般我们使用内部时钟。
在时钟树可以看到,定时器2~7的内部时钟源是APB1。库函数版本默认使用SystemInit函数初始化系统该时钟的情况下:
SYSCLK=72M
AHB=72M
APB1=36M
也就是说APB1的分频系数为2,所以定时器2~7(包括通用定时器)时钟内部时钟频率为2*36M=72M。
另外需要注意的是定时器1和定时器8的时钟源是APB2!
当使用外部时钟的时候,其框图如下
通用定时器的寄存器有,包括
加黑的几个寄存器是使用定时器基本功能的必须了解的几个寄存器!这里也只叙述这几个寄存器。
DIR:计数方向
0:计数器向上计数
1:计数器向下计数
当计数器配置为中央对齐模式或编码器模式时,该位为只读。
CEN:使能计数器
0:禁止计数器;
1:使能计数器。
CMS[1:0]:选择中央对齐模式
00:边沿对齐模式。计数器依据方向位(DIR)向上或向下计数。
01:中央对齐模式1。计数器交替地向上和向下计数。配置为输出的通道(TIMx_CCMRx寄存器
中CCxS=00)的输出比较中断标志位,只在计数器向下计数时被设置。
10:中央对齐模式2。计数器交替地向上和向下计数。配置为输出的通道(TIMx_CCMRx寄存器
中CCxS=00)的输出比较中断标志位,只在计数器向上计数时被设置。
11:中央对齐模式3。计数器交替地向上和向下计数。配置为输出的通道(TIMx_CCMRx寄存器
中CCxS=00)的输出比较中断标志位,在计数器向上和向下计数时均被设置。
当在计数器开启时(CEN=1),不允许从边沿对齐模式转换到中央对齐模式。
其他的位,请查看《STM32中/英文参考手册》
UIE:允许更新中断
0:禁止更新中断
1:允许更新中断,计数寄存器中的数据更新时触发中断请求。
CCxIE:允许捕获/比较x中断 (Capture/Compare 1 interrupt enable)
0:禁止捕获/比较x中断;
1:允许捕获/比较x中断。
这个寄存器用于使能捕获中断(后面会写)
时基单元包含:
预分频器寄存器(TIMx_PSC)
PSC[15:0]:预分频器的值
该寄存器存放的是预分频器的值。预分频器对定时器的时钟源进行分频,然后提供给计数器。前文已经提到,通用定时器的时钟源有四个,可以通过TIMx_SMCR 寄存器的的相关为进行设置。
为什么要进行分频?
答:因为一般时钟源太快了。以系统时钟源为例,72M的频率,如果不分频的话,那16位定时器的计时周期就65536/72M秒,约等于0.91ms,时间太短了。
自动重装载寄存器(TIMx_ARR)
ARR[15:0]: 自动重装载的值
ARR包含了将要传送至实际的自动重装载寄存器的数值。
计数寄存器(TIMx_CNT)
CNT[15:0]:计数器的值
计数器从0计数到自动加载值(TIMx_ARR计数器的内容),然后重新从0开始计数并且产生一个计数器溢出事件。
计数器从自动装入的值(TIMx_ARR计数器的值)开始向下计数到0,然后从自动装入的值重新开始并且产生一个计数器向下溢出事件。
定时周期与时基单元密切相关,首先确定定时器时钟源的频率Tclk(使用内部时钟源,一般是72M),通过设定分频器的值PSC可以确定最大计时周期,然后通过设定自动重装载寄存器的值ARR,可以确定具体的溢出时间!计算公式如下:
Tout(溢出时间)= (ARR+1)(PSC+1)/Tclk
比如,要定时500ms,Tclk为72M,令PSC=7199,ARR=4999,即可。
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
timer.c
void Tim3_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstructure;
NVIC_InitTypeDef NVIC_Initstructure;
/*************************定时器时钟源使能*********************************/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
/*************************定时器基本配置*********************************/
TIM_TimeBaseInitstructure.TIM_Prescaler = psc;//预分频系数
TIM_TimeBaseInitstructure.TIM_Period = arr;//自动装在值
TIM_TimeBaseInitstructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitstructure.TIM_ClockDivision = TIM_CKD_DIV1;//不知道是什么
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitstructure);
/*************************定时器中断配置使能*********************************/
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
/*************************中断号、优先级配置*********************************/
NVIC_Initstructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_Initstructure);
/*************************使能TIM3计数器*********************************/
TIM_Cmd(TIM3,ENABLE);
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
{
LED0 = !LED0;
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
}
main.c
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LED_Init();
Tim3_Init(TIM3_CRR,TIM3_PSC);
while(1)
{
//其他操作
}
}