1、简介
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断。
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时。 2的16次方是65536 这里最大定时是 1 /(72M/65536/65536 中断频率)
· 如果要增加定时时间可以级联定时器 72M = 72000000
不仅具备基本的定时中断,还包括内外时钟源的选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能。
根据不同的运用场景分为了高级定时器、通用定时器、基本定时器三种类型。
2、定时器类型
3、基本定时器
带影子的寄存器都是有缓存寄存器功能的
1)PSC预分频
当预分频为0时,就是1分频 输出频率 = 输入频率 / 1 = 72MHz,
当预分频为1时,就是2分频 输出频率 = 输入频率 / 2 = 36MHz,
当预分频为3时,就是3分频 输出频率 = 输入频率 / 3 = 24MHz。
16位的预分频器就可以写65535,也就是65536分频。
2)计数器
计数时钟每次产生上升沿计数器就加一。
16位的计数器器就可以计数到65535,再计数就回到0重新开始。
3)自动重装载寄存器
计数器不断自增,到篮圈位置和自动重装载寄存器值相同时产生一个中断信号和中断事件,计数器清零,自动开始下个计数。
UI为中断信号 U为中断事件
4)主从模式触发DAC
用途
在使用DAC的时候,可能会用DAC输出一段波形,需要每隔一段时间来触发一次DAC,让它输入下一个电压点。主模式可以直接把更新事件通过主模式映射到TRGO,然后TRGO就直接去触发DAC了,不需要软件参与,直接硬件触发,减少了CPU的处理任务数量。
4、通用定时器
1)CNT计数器三种计数模式
向上计数、向下计数 、中央对齐计数模式。
2)内外部时钟源触发方式
上部分
外部触发方式
1、两种用途
一种为了定时器的级联。
比如可以初始化TIM3,将更新事件和TIGO连起来,再初始化TIM2和TIM3相连对应的就是TIM3的TIGO,这样TIM3的更新事件就可以驱动TIM2的实基单元。
下面一部分是输入捕获和测频率时会用到的情况。
2、对外部时钟的整形
下部分
右边输出比较电路,用于输出PWM波形,驱动电机。
左边输入捕获电路,用于测输入方波的频率等。
中间这个捕获/比较寄存器,是左右两个公用的。
5、高级定时器
1、重复次数计数器
可以每隔几个周期更新一次,最大计数时间还可以多乘个65536,计数时间增加了。
2、死区生成电路(DTG)
右边输出引脚变成两个互补的输出,比如互补的PWM波。
可以驱动三相无刷电机。
三相无刷电机有三个桥臂,6个大功率开关管控制。
由于开关切换的瞬间产生了短暂直通现象,所以死区生成电路可以产生死区,防止直通现象。
3、刹车输入
给电机驱动提高安全保障。
6、定时中断基本结构图
7、时序图——结合手册254,255
8、实例
内部时钟
1、开启RCC时钟,定时器的基准时钟和整个外设的工作时钟就会同时打开了。
2、选择时基单元的时钟源,对于定时中断就选择内部时钟源。
3、配置时基单元。
4、配置输出中断控制,允许更新中断输出到NVIC。
5、配置NVIC,在NVIC中打开定时器中断通道,并分配一个优先级。
6、允许控制,使能定时器。
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //打开定时器
TIM_InternalClockConfig(TIM2); //选择为内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //滤波的选择
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //分频选择
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数模式
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //setcounter getcounter操作计数器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //手动清除标志位
//计数器是在出现更新事件发生后产生计数
//防止更新事件和中断一起响应导致计数从1开始加而不是0
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能中断 到NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //定时器2在NVIC里的通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE); //启动定时器
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //获取中断标志位
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除标志位
}
}
外部时钟
0、开启GPIO口,配置GPIO。
1、开启RCC时钟,定时器的基准时钟和整个外设的工作时钟就会同时打开了。
2、选择时基单元的时钟源,对于定时中断就选择内部时钟源。
3、配置时基单元。
4、配置输出中断控制,允许更新中断输出到NVIC。
5、配置NVIC,在NVIC中打开定时器中断通道,并分配一个优先级。
6、允许控制,使能定时器。
(这里是用对射红外线做的,挡光10次,计数器加一)
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //TIM2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //也可以浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F); //定时器,预分频,外部触发级性,外部触发滤波器(手册284)
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
uint16_t Timer_GetCounter(void)
{
return TIM_GetCounter(TIM2);
}
/*
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
*/
9、心得
其中 ARR 决定分辨率 PSC决定频率 CCR决定占空比