一、基本定时器的功能介绍:
STM32F103的基本定时器有:TIM6、TIM7。基本定时器TIM6和TIM7各包含一个16位递增自动装载计数器,最大计数到2^16也就是65536,计数值为0~65535,其拥有的功能有:定时中断、主模式触发DAC的功能。没有输入输出通道,常作为时基,即作为定时功能使用。
二、基本定时器框图介绍:
时钟源来源于APB1总线(不懂的可以看看时钟树,这里先不做过多详细介绍,一般都为72MHZ)当然,通用定时器和基本定时器都来自这个总线。
计数器时钟CK_CNT:每来一个时钟,先经过控制器,通过预分频器的分频,0为1分频,也就是不分频,1为2分频,如果时钟为72MHZ的话到达计数器则为36MHZ(预分频器为16位,最大可以写65535,也就是65536分频),即经过预分频器后的时钟为计数器时钟CK_CNT。
公式CK_CNT = TIMxCLK/(PSC + 1)
计数器CNT:对预分频的时钟计数,每来一个时钟上升沿计数器加1,当等于自动重装载寄存器时的值时,产生溢出中断或DMA请求和更新事件(注:基本定时器只能向上计数递增)。
可以从图中看见更新事件U回到了自动重装载寄存器了,作用是什么呢?是为了将预装载寄存器的值加载到对应影子寄存器,即实现了自动重装载的功能。自动重装载寄存器起到缓冲的作用,真正其作用的是它的影子寄存器(图中有方框阴影的都有影子寄存器)。
定时时间的计算:其中有两个寄存器决定着计时的时间,分别是预分频值和自动重装载的值。时间可以看成预分频后的时间乘上自动重装载的值,假如为71分频,此时时钟为1MHz,也就是1us,如果我们要定时500ms,那么自动重装载值也就为500000,因为计数器计一个数代表过了1us,记上500000个数就是500ms了。那么真的可以这样吗?显然不行,自动重装在寄存器也是16位的,最大值依旧为65535,所以我们可以试试719分频,此时计数器记一个数也就过了10us,我们设置自动重装载值为50000就可以了。
总结一下,定时器定时时间:T =((PSC+1)(ARR+1))/TIMxCLK
三、基本定时器的使用
其使用方法和通用定时器一样,首先就是开启定时器的时钟,然后是时基单元的初始化,给预分频值和计数值;至于时钟分频因子和计数模式和重复计数器的值都不用管,这些基本定时器都没有,基本定时器只能向上计数。
如果要开启相应中断还得进行中断的初始化配置,中断来源设置为定时器6;代码如下:注意,F1系列通用型并没有定时器6和7,也就是F103C8没有这个定时器,这里用到的是STM32F103ZET6!!!
#include "stm32f10x.h" // Device header
#include "led.h"
uint8_t led_state;
int main(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);//开启定时器6的时钟
TIM_TimeBaseInitStructure.TIM_Period = 500000-1;//设置计数值
TIM_TimeBaseInitStructure.TIM_Prescaler = 710;//设置预分频值
TIM_TimeBaseInit(TIM6,&TIM_TimeBaseInitStructure);//时基单元初始化
TIM_ClearFlag(TIM6,TIM_FLAG_Update);//清除中断标志位
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);//开启中断
TIM_Cmd(TIM6,ENABLE);//定时器使能
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//设置中断分组
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;//中断来源于定时器6
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//主优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//抢占优先级3
NVIC_Init(&NVIC_InitStructure);//中断初始化
LED_Init();//led的初始化
while (1)
{
LED(led_state);//LED500ms闪烁
}
}
void TIM6_IRQHandler(void)
{
if(TIM_GetITStatus(TIM6,TIM_IT_Update) == SET)//判断中断标志位
{
TIM_ClearITPendingBit(TIM6,TIM_IT_Update);//清除中断标志位
led_state = 1 - led_state;
}
}