STM32通用定时器时钟源探究
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32通用定时器时钟源探究相关的知识,希望对你有一定的参考价值。
参考技术A 首先我们来看一下定时器的基本框图:不管是做PWM输出、定时中断还是输入捕获都肯定要搞清楚CK_INT 从哪里来,频率是多少?才能正确使用定时器。时钟肯定是来自时钟树,那我们就要去Reference manual里找找:
时钟源确实可以找到,但注意时钟存在翻倍可能性!if APBx PRESC= 1 x1 else x2 : 直接理解是如果APBx PRESC 预分频 设置成1 timer时钟等于APBx 不然 timer时钟为2倍APBx 。可是还是没有找到时钟源和timer时钟具体数值关系,这个就要去Datasheet里找了,找MCU系统框图:
我们发现有2个APB(Advanced Peripheral Bus) ,最大主频还还不一样,分别挂了多个定时器。到这里我们总算找到了timer的具体关联的时钟源了。如何计算频率呢?
举例1:假设使用的是timer2 AHB1=168MHz
// Timer2 On APB1 42MHz(MAX) ==> 可设 APB1 PRESC =4 APB1 =42MHz。
// if APBx PRESC = 1x1 else x2 ==> Timer2_CLK = 42MHz*2 = 84MHz 。
举例2:假设使用的是timer1、timer2 AHB1= 84 MHz
// Timer2 On APB1 42MHz(MAX) ==> 可设 APB1 PRESC =2 APB1 =42MHz。
// if APBx PRESC = 1x1 else x2 ==> Timer2_CLK = 42MHz*2 = 84MHz 。
// Timer1 On APB2 84MHz(MAX) ==> 可设 APB2 PRESC =1 APB2 =84MHz。
// if APBx PRESC = 1x1 else x2 ==> Timer1_CLK = 84MHz*1 = 84MHz 。
参考资料:1. Reference manual 2.Datasheet
STM32学习笔记——通用定时器计数延时
STM32定时器概述
STM32F40x系列总共最多有14个定时器,定时器分为三类:基本定时器、通用定时器和高级定时器。它们的都是通过计数来达到定时的目的,和51的定时器差不多,基本原理都是一样的,就是功能多了一些,这些计数器都是自动重新装载初值的,使用起来非常方便,而且计数时钟频率可以通过分频系数来设置。本文章将介绍使用定时器中断来控制LED间隔1s闪烁。
计数的时钟来源主要有四个:
- 内部时钟CK_INT
- 外部时钟模式1:外部输入脚TIx
- 外部时钟模式2:外部触发输入ETR,仅适用于 TIM2、 TIM3、 TIM4
- 内部触发输入ITRx:使用 A 定时器作为 B 定时器的预分频器(A为B提供时钟)
我们使用定时器内部时钟,即CK_INT作为计数器的时钟源 = 168MHz / 2 = 84MHz
时钟框图如下:
定时器的配置
1.使能定时器时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //定时器3时钟使能
2.初始化定时器参数,设置分频系数和计数初值,计数模式设置等。如果要定时1s定时器溢出,那么可以设置分频系数为8400 ,则分频后的时钟频率为 : 84MHz / 8400 = 10KHz = 0。1ms ,计数初值设置为1s / 0。1 ms = 10000即可。
/*初始化定时器参数,设置自动重装值,分频系数,计数方式*/ TIM_Init。TIM_ClockDivision= TIM_CKD_DIV1; //时钟分频因子 TIM_Init。TIM_CounterMode=TIM_CounterMode_Up; //定时器模式 TIM_Init。TIM_Period=Period; //自动重装值,0-65535 TIM_Init。TIM_Prescaler= Prescaler; // TIM_Init。TIM_Prescaler= 8400; //分频系数-0。1ms // TIM_Init。TIM_Prescaler= 42000; //分频系数-0。5ms // TIM_Init。TIM_RepetitionCounter= TIM_TimeBaseInit(TIM3,&TIM_Init);
TIM_RepetitionCounter是使用高级定时器要进行设置的。我们使用的是定时器3,属于通用定时器,计数模式设置为向上计数,则计数器从0 开始计数,当计数到设置的初值时,然后计数器重新从0开始计数,并将溢出标志位置1,如果设置了溢出中断,则会产生计数器溢出中断。
3.定时器3中断设置,注意优先级的设置,如果程序中开启了多个中断。就要考虑中断优先级的设置,本程序只使用了一个定时器中断,则配置为任何优先级都是可以的。
/*定时器3中断优先级设置*/ NC_Init。NVIC_IRQChannel=TIM3_IRQn; //中断通道指定定时器3 NC_Init。NVIC_IRQChannelCmd= ENABLE; NC_Init。NVIC_IRQChannelPreemptionPriority=0; //设置抢占优先级 NC_Init。NVIC_IRQChannelSubPriority=0; //设置响应优先级 NVIC_Init(&NC_Init);
4.使能定时器,当执行完这一句后,定时器就开始从 0 开始计数了。我们可以通过使能定时器来暂停计数器,或者使能定时器来启动定时器,在开发时钟时可以使用这个。
相当于51中的TR1 = 1 / TR1 = 0
TIM_Cmd(TIM3,ENABLE);
5.中断服务函数,本程序是让LED1间隔1s闪烁,那么中断服务函数的功能就是让LED1的状态反转。
void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3,TIM_IT_Update)) //如果产生溢出中断 { LED1=!LED1; //那么状态反转 // LED0=!LED0; } TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清楚更新中断标志位 }
这里检测的是定时器溢出中断,即计时1s时间到,则将LED1的状态反转,然后将溢出标志位清零。
主函数
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); delay_init(168); LED_Init(); //LED初始化熄灭 Timer3_Config(2000,42000); //0.5ms*2000 = 1s while(1) { LED0=!LED0; delay_ms(1000); } }
这里使用延时函数来延时1s控制LED0闪烁,实际运行效果可以看出两个LED的闪烁在一定的时间内是同步的,但是时间一长还是有点误差。
总结
当学完这一节定时器的时候,我就有一个想法了,那就是写一个LCD电子时钟的程序,通过定时器来达到准确延时的目的,当然还要学习一下LCD1602的驱动方法,哈哈,想想就很有成就感。
参考资料:
STM32F4xx中文参考手册
以上是我学习过程的一些个人理解,有不对或不准确的地方,欢迎各位大神指正。
2017年4月21日21:33:44
以上是关于STM32通用定时器时钟源探究的主要内容,如果未能解决你的问题,请参考以下文章