通用定时器
一、定时器的作用
时钟系统与定时器的关系
学习了一段时间以后,我们再回头看这张图会更清晰的读懂这张图片。我们选择了时钟源(5个时钟源,分别为HSI、HSE、LSI、LSE、PLL。)后再选择进行定时器的选择。
定时器TIM2~TIM7挂载在APB1分频器上,TIM1和TIM8挂载在APB2分频器上;APB1上面挂载的是低速外设,APB2上挂载高速外设。APB2可以工作在72MHz下,而APB1最大是36MHz。
定时器的产生路线:系统时钟 -> AHB预分频 -> APB2预分频 -> TIM1倍频器 -> 产生TIM1的时钟系统
在默认情况下,系统的各个时钟频率如下:
SYSCLK:72M
AHB:72M
APB1(PCLK1):36M
APB2(PCLK2):72M
PLL:72M
- stm32定时器可分为基本定时器(TIM6、TIM7)、通用定时器(TIM2-TIM5)、高级定时器(TIM1、TIM8)
- 基本定时器的功能最为简单,类似于 51 单片机内定时器。
- 在基本定时器的基础上扩展而来,增加了输入捕获与输出比较等功能。
- 高级定时器不但具有基本,通用定时器的所有的功能,还具有控制交直流电动机所有的功能,你比如它可以输出6路互补带死区的信号,刹车功能等等
通用TIMx (TIM2、 TIM3、 TIM4和TIM5)定时器功能
-
16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
-
16位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
4个独立通道(TIMx_CH1-4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C. PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出
- 可使用外部信号(TIMx_ETR)控制定时器,且可实现多个定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
发生如下事件时产生中断/DMA 请求:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/ 外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
- 支持针对定位的增量(正交)编码器和霍尔传感器电路
- 触发输入作为外部时钟或者按周期的电流管理
使用的寄存器
A.计数器寄存器(TIMx_CNT)
B. 预分频器寄存器 (TIMx_PSC)
C. 自动装载寄存器 (TIMx_ARR)
二、定时器的原理
详细的定时器设定如下:
首先要搞清楚定时器的计数时钟频率,在预分频系数≠1的时候,TIM2~7的时钟频率为APB1的频率的2倍,即72MHz,预分频系数的默认值不是1。
定时器的设置主要包括定时器的初始化和中断的初始化。
定时器的时钟不是直接来自APB1或APB2,而是来自输入为APB1或APB2的一个倍频器,当APB1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其它数值(即预分频系数为2、4、8或16)时,这个倍频器起作用,定时器的时钟频率等于APB1的频率的两倍。
假定AHB=36MHz,因为APB1允许的最大频率为36MHz,所以APB1的预分频系数可以取任意数值;
当预分频系数=1时,APB1=36MHz,TIM2~7的时钟频率=36MHz(倍频器不起作用);
当预分频系数=2时,APB1=36MHz/2=18MHz,在倍频器的作用下,TIM2~7的时钟频率=36MHz;
当预分频系数=4时,APB1=36MHz/4=9MHz,在倍频器的作用下,TIM2~7的时钟频率=18MHz;
当预分频系数=8时,APB1=36MHz/8=4.5MHz,在倍频器的作用下,TIM2~7的时钟频率=9MHz;
当预分频系数=16时,APB1=36MHz/16=2.25MHz,在倍频器的作用下,TIM2~7的时钟频率=4.5MHz;
既然需要TIM2-7的时钟频率=36MHz,为什么不直接取APB1的预分频系数=1呢?这是因为APB1不但要为TIM2-7提供时钟,而且还要为其它外设提供时钟,设置这个倍频器可以在保证其它外设使用较低时钟频率时,TIM2-7仍能得到较高的时钟频率。例如当AHB=72MHz时,APB1的预分频系数必须大于2,因为APB1的最大频率只能为36MHz。如果APB1的预分频系数=2,则因为这个倍频器,TIM2-7仍然能够得到72MHz的时钟频率。能够使用更高的时钟频率,无疑提高了定时器的分辨率,这也正是设计这个倍频器的初衷。
三、关于定时器的代码
1.定时器中断函数
在学习了一段时间stm32的代码后,我总结出来自己的一些经验
//通用定时器3中断初始化
***************************************************************
//函数说明:初始化时钟与中断
//函数参数:arr psc
//arr:自动重装值
//psc:时钟预分频数
//附加说明:用户需修改TIMX的地方为自己所需要的时钟,且补充初始化值
//函数返回:无返回
***************************************************************
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue; //时钟配置
//TIM_TimeBaseInitStrue.TIM_ClockDivision //设置时钟分割:TDTS = Tck_tim
//TIM_TimeBaseInitStrue.TIM_CounterMode //TIM向上计数模式
//TIM_TimeBaseInitStrue.TIM_Period //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
//TIM_TimeBaseInitStrue.TIM_Prescaler //设置用来作为TIMx时钟频率除数的预分频值
//TIM_TimeBaseInit(TIMX,&TIM_TimeBaseInitStrue);
NVIC_InitTypeDef NVIC_InitStructure;//中断配置
//NVIC_InitStructure.NVIC_IRQChannel //中断通道
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority //抢占优先级3
//NVIC_InitStructure.NVIC_IRQChannelSubPriority //子优先级3
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE //IRQ通道使能
//NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
TIM_Cmd(TIMX, ENABLE); //使能TIMx
}
再结合结构体我们不难发现出,这一类我们理解为定义单片机的模式(可以理解为初始化)
***************************************************************
//函数说明:定时器中断服务程序
//函数参数:无
//附加说明:函数需修改TIMX后使用 还需加入使能LED函数
//函数返回:无返回
***************************************************************
void TIMX_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIMX, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIMX, TIM_IT_Update ); //清除TIMx更新中断标志
LED1=!LED1;//亮灯
}
}
时钟中断函数需要自己去编写所需要实现的内容
//主函数
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
TIM3_Int_Init(9999,7199);//10Khz的计数频率,计数到5000为500ms
//计算公式Tout=(arr+1)*(psc+1) /Tclk
//例如定时1秒:1s=(9999 + 1)*(7199 + 1)/72M
while(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
delay_ms(500);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
delay_ms(500);
}
}