查看中文参考手册
定时器简介![在这里插入图片描述](https://img-blog.csdnimg.cn/94d181b8de594e77aa04c000530c0d18.png)
基本定时器有两个TIM6和TIM7,各包含一个16位的自动装载计数器,可以从0计数到2^16-1.
TIM6和TIM7的主要特性
先看图中的时钟部分,只有一个来自RCC的TIMxCLK内部时钟,查看数据手册中结合下图可得该时钟的频率为72MHz。
接着时钟线通过控制器(需要使能),到达预分频器。预分频器PSC的作用是将频率做除法(分频的范围是1~65536),比如二分频就是将72MHz处理成36MHz;最后经过分频后的信号到达CNT计数器开始计数,并由自动装载寄存器在数计满时重装初值,若开启计时器中断则进入中断。
定时器的功能
时基单元
时基单元有三个寄存器,计数器寄存器(TIMx_CNT)、预分频寄存器(TIMx_PSC)、自动重装载寄存器(TIMx_ARR)。
fck_psc就是时钟频率72MHz,那么分频过程就是72MHz/(这个寄存器中的值+1).得到的结果就是分频后的频率。
预加载寄存器
这个自动装载寄存器和前面的系统滴答定时器(SysTick) 相比多了一个预加载寄存器这个预加载寄存器相当于一个缓冲的作用,如果计数器的重装载值为100、当前计到了51且你开启了这个预加载寄存器,这时你更改自动装载寄存器的值为50.那么由于预加载寄存器这个缓冲作用定时器会继续计数到计满100产生更新事件UE(后面讲到),之后你更改的重装值才会生效。当然如果你不开预加载寄存器的话你更改的重装值会立即生效。
如何开启这个寄存器?对TIMx_CR1中的ARPE位(自动重装预加载使能位)写0或1来关闭或开启。
使能定时器
设置TIMx_CR1寄存器中的计数器使能位(CEN)使能计数器
计数。
预分频器
可以看到分频数值从0变到1造成时钟频率的改变,但是预分频器控制寄存器的值改变之后的一段时间内时钟线CK_CNT并未改变频率,当更新事件到来后频率才改变。
计数模式![在这里插入图片描述](https://img-blog.csdnimg.cn/ea538e44c1d84975b0cb2880a6e0548c.png)
EGR时间产生寄存器
这个寄存器UG位由软件写1的话,产生更新事件重新初始化定时器,每次计数器溢出时可以产生更新事件;(通过软件或使用从模式控制器)设置TIMx_EGR寄存器的UG位也可以产生更新事件。
TMX_CR1寄存器
CEN位:写1开计数器
UDIS位:禁止更新事件产生,只能通过写UG位触发硬件复位来产生更新事件。
URS位:选择产生中断的方式。
状态寄存器TIMx_SR
UIF位:产生中段硬件自动置为该位,软件在中断中清除该位。
时钟源
代码
以TIM6为例
1、开时钟
基本定时器TIM6和TIM7挂在APB1时钟线上,那么需要开启APB1 TIM6的时钟。
RCC_APB1ENR寄存器的第4位置1:
RCC_APB1ENR|=(1<<4);
2、根据框图和需求配置定时器
**注意基本定时器只能向上计数!!!!**
配置时基单元
更新事件使能:
TIM6_CR1->UDIS|=0;
TIM6_CR1&=~(0x1<<2);//更新请求源
TIMx_CR1|=0<<3;//OPM更新事件计数器不停止
//设置重装载值有没有缓冲TIMx_CR1的第7位ARPE
//具有缓冲:TIM6_CR1|=1<<7;
//没有缓冲:TIM6_CR1&=~(1<<7);
分频:
TIMx_PSC|=7200;72000000hz/7200=10000hz;也就是0.1ms一个周期
写入重装载值:
TIMx_ARR|=10000;0.1ms*10000=1s,1s进一次中断
3、开中断TIM6_IRQn
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
开启计数器:
TIM6_CR1->CEN|=1;
TIM6中断函数
//定时器6中断服务函数 1s进一次
void TIM6_IRQHandler(void)
{
if(TIMx_SR&1 != 0)//TIMx_SR的UIF位,如果发生更新事件
{
TIMx_SR&=~(0x1)//清除标志位
//你的代码
}
}
库函数版
#include "tim.h"
#include "led.h"
//配置基本定时器 TIM6 1s时间基准
void TIM6_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct={0};
NVIC_InitTypeDef NVIC_InitStructure;
//1,开时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
//2,配置定时器时间基准
TIM_TimeBaseInitStruct.TIM_ClockDivision=0;//输入捕获时才使用
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInitStruct.TIM_Period=10000-1;//重装载值 1S
TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//0-65535 预分频 10Mhz
// TIM_TimeBaseInitStruct.TIM_RepetitionCounter=;//仅在高级定时器中使用
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStruct);
//3,用到中断开中断 开启更新中断请求
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
//配置开启NVIC中断通道和优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//4,使能定时器
TIM_Cmd(TIM6, ENABLE);
}
void TIM7_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct={0};
NVIC_InitTypeDef NVIC_InitStructure;
//1,开时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);
//2,配置定时器时间基准
TIM_TimeBaseInitStruct.TIM_ClockDivision=0;//输入捕获时才使用
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInitStruct.TIM_Period=72-1;//重装载值 1S
TIM_TimeBaseInitStruct.TIM_Prescaler=0;//0-65535 预分频 10Mhz
// TIM_TimeBaseInitStruct.TIM_RepetitionCounter=;//仅在高级定时器中使用
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseInitStruct);
//3,用到中断开中断 开启更新中断请求
TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);
//配置开启NVIC中断通道和优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//4,使能定时器
TIM_Cmd(TIM7, ENABLE);
}
//定时器6中断服务函数 1s进一次
void TIM6_IRQHandler(void)
{
if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
LED4_F();
}
}
//利用基本定时器写的精准延时
uint64_t ustime=0;
uint64_t LED3_Time[2]={0,500000};
void TIM7_IRQHandler(void)
{
TIM7->SR &= ~(0x1);
ustime++;
LED3_Time[0]++;
}
//利用基本定时器写的精准延时
void Tim_Delay(uint64_t time)
{
uint64_t Temp = ustime+time;//计算要延时到那个时间点
while(Temp >= ustime)//systime 会在中断里自加
{}
}