一、 基本概念
定时器是一种计时的工具,它具有延时、频率测量、PWM输出、电机控制及编码接口等功能。
STM32F103微控制器内部集成了多个可编程定时器,可以分为基本定时器(TIM6和TIM7)、通用定时器(TIM2~TIM5)和高级定时器(TIM1、TIM8)3种类型。从功能上看,基本定时器的功能是通用定时器的子集,而通用定时器的功能又是高级定时器的一个子集。
类型 | 编号 | 总线 | 功能 |
---|---|---|---|
高级定时器 | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 |
通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 |
基本定时器 | TIM6、TIM7 | APB1 | 拥有定时中断、主模式触发DAC的功能 |
在STM32F103中,基本定时器TIM6、TIM7各自都包含一个16位自动装载计数器,能够通过各自的可编程预分频器驱动,这两个定时器相互独立,不共享任何资源。
二、 时基单元
上图为基本定时器的结构图,其中红色框线内为时基单元,主要由预分频器、计数器和自动重装载寄存器构成。该模块的时钟源为系统内部时钟CK_INT(72MHz),直接作为预分频器(PSC)的时钟源(CK_PSC),经过预分频后输入至计数器(CNT)对预分频后的时钟进行计数,计时时钟每来一个上升沿,计数器+1,直到达到最大计数值,即65535。最大值后再增加则会回到0,从头开始计数。自动重装寄存器存储了CNT计数器需要计数的值,当计数器计数值等于自动重装值,则会产生中断信号,并重置计数器。
更新中断即为所产生的中断信号UI。更新中断之后就会通往NMIC,再配置好NMIC的定时器通道,更新中断就可得到CPU相应的终端服务程序。更新事件为该模块产生的事件信号U,触发内部其他电路工作。
三、 工作流程
内部时钟CK_INT为唯一时钟源,当TIMx_CR1寄存器的CEN位被置为1时CK_INT为预分频器提供时钟,否则无时钟产生。预分频器的值(PSC)+1为分频数,CK_CNT =CK_PSC/(PSC+1)。预分频可以以系数介于1至65536之间的任意数值对计数器时钟分频。它是通过一个16位寄存器(TIMx_PSC)的计数实现分频。因为TIMx_PSC控制寄存器具有缓冲,可以在运行过程中改变它的数值,新的预分频数值将在下一个更新事件时起作用。
上图为PSC由0变到1的内部时序变化,红线左侧PSC=0,即不分频,右侧PSC=1,即2分频。当CNT_EN为高电平时,CK_CNT开始产生,计数器寄存器开始计数,每次增加1,达到计数设定值时会产生一个更新事件,即计数器清零重新计数。由于预分频器缓冲器(也叫影子寄存器)的存在,虽然在箭头处更改了分频系数,但并没有立即生效,而是在产生更新事件时生效,这样可以保护一个周期自动重装值(ARR+1)数据的完整性,也可以说明实际传输数据就是影子寄存器。
四、 相关寄存器
- TIM6和TIM7控制寄存器1(TIMx_CR1)
CEN:计数器使能
UDIS:禁止更新
URS:更新请求源
OPM:单脉冲模式
ARPE:自动重装载预装载使能
2. TIM6和TIM7控制寄存器2(TIMx_CR2)
MMS:主模式选择
3. TIM6和TIM7 DMA/中断使能寄存器(TIMx_DIER)
UIE:更新中断使能
UDE:更新DMA请求使能
4. TIM6和TIM7状态寄存器(TIMx_SR)
UIF:更新中断标志
5. TIM6和TIM7事件产生寄存器(TIMx_EGR)
UG:产生更新事件
6. TIM6和TIM7计数器(TIMx_CNT)
CNT[15:0]:计数器数值
7. TIM6和TIM7预分频器(TIMx_PSC)
PSC[15:0]:预分频器数值
8. TIM6和TIM7自动重装载寄存器(TIMx_ARR)
ARR[15:0]:自动重装载数值
五、 代码分析
- Timer.c
#include "stm32f10x.h" // Device header
void Tim6_init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);//使能外设时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = 72 - 1;//分频数:72
TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1;//计数值:1000
TIM_TimeBaseInit(TIM6,&TIM_TimeBaseInitStructure);//初始化时基单元
TIM_Cmd(TIM6,ENABLE);//启动定时器
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);//TIM6中断使能
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM6_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=3;//NVIC参数设定
NVIC_Init(&NVIC_InitStruct);
}
- 中断函数(包含在main.c中)
void TIM6_IRQHandler(void)//TIM6中断函数
{
if ( TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET ) //检测是否到达定时数
{
Num ++;
TIM_ClearITPendingBit(TIM6 , TIM_FLAG_Update);//切记要手动清除标志位!!!
}
}
- main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
uint16_t Num;//计次数
int main(void)
{
OLED_Init();
Tim6_init();//TIM6初始化
OLED_ShowString(1, 1, "Num:");//固定显示部分
while (1)
{
OLED_ShowNum(1, 5, Num, 5);//显示次数
}
}
六、 总结
本文是TIM模块的第一部分,围绕基本定时器进行介绍,介绍了该单元的时钟源、工作原理及相关寄存器,并结合例程分析了基本定时器的使用方法。