STM32定时器配置

 

一、定时器基本介绍 

            https://images2018.cnblogs.com/blog/671539/201808/671539-20180816195856553-340078878.png

 

https://images2018.cnblogs.com/blog/671539/201808/671539-20180816194653685-141503018.png

https://images2018.cnblogs.com/blog/671539/201808/671539-20180816194813986-696722352.png

https://images2018.cnblogs.com/blog/671539/201808/671539-20180816194957273-448015297.png

https://images2018.cnblogs.com/blog/671539/201808/671539-20180816195023784-1118130384.png

https://images2018.cnblogs.com/blog/671539/201808/671539-20180816195046984-899206989.png

 

 

二、普通定时器详细介绍TIM2-TIM5

2.1    时钟来源

计数器时钟可以由下列时钟源提供:

·内部时钟(CK_INT)

·外部时钟模式1:外部输入脚(TIx)

·外部时钟模式2:外部触发输入(ETR)

       ·内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。

    由于今天的学习是最基本的定时功能,所以采用内部时钟。TIM2-TIM5的时钟不是直接来自于APB1,而是来自于输入为APB1的一个倍频器。这个倍频器的作用是:当APB1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率(36MHZ);

APB1的预分频系数为其他数值时(即预分频系数为24816),这个倍频器起作用,定时器的时钟频率等于APB1的频率的2倍。

{       

        假如APB1预分频为2(变成36MHZ),则定时器TIM2-5的时钟倍频器起作用,将变成2倍的APB1(2x36MHZ)将为72MHZ给定时器提供时钟脉冲。 一般APB1APB2RCC时钟配置放在初始化函数中例如下面的void RCC_Configuration(void)配置函数所示,将APB1进行2分频,导致TIM2时钟变为72MHZ输入。

如果是1分频则会是36MHZ输入,如果4分频:CKINT=72MHZ/4x2=36MHZ;  8分频:CKINT=72MHZ/8x2=18MHZ;16分频:CKINT=72MHZ/16x2=9MHZ 

   }

 

 1 //系统时钟初始化配置

 2 void RCC_Configuration(void)

 3 {

 4     //定义错误状态变量

 5    ErrorStatus HSEStartUpStatus;

 6    //将RCC寄存器重新设置为默认值

 7    RCC_DeInit();

 8    //打开外部高速时钟晶振

 9    RCC_HSEConfig(RCC_HSE_ON);

10    //等待外部高速时钟晶振工作

11    HSEStartUpStatus = RCC_WaitForHSEStartUp();

12    if(HSEStartUpStatus == SUCCESS)

13    {

14           //设置AHB时钟(HCLK)为系统时钟

15           RCC_HCLKConfig(RCC_SYSCLK_Div1);

16           //设置高速AHB时钟(APB2)为HCLK时钟

17           RCC_PCLK2Config(RCC_HCLK_Div1);

18           //设置低速AHB时钟(APB1)为HCLK的2分频(TIM2-TIM5输入TIMxCLK频率将为72MHZ/2x2=72MHZ输入)

19           RCC_PCLK1Config(RCC_HCLK_Div2);

20           //设置FLASH代码延时

21           FLASH_SetLatency(FLASH_Latency_2);

22           //使能预取指缓存

23           FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

24           //设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHz

25           RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

26           //使能PLL

27           RCC_PLLCmd(ENABLE);

28           //等待PLL准备就绪

29           while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

30           //设置PLL为系统时钟源

31           RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

32           //判断PLL是否是系统时钟

33           while(RCC_GetSYSCLKSource() != 0x08);

34    }

35    //允许TIM2的时钟

36    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

37    //允许GPIO的时钟

38    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

39 }

 

APB1的分频在STM32_SYSTICK的学习笔记中有详细描述。通过倍频器给定时器时钟的好处是:APB1不但要给TIM2-TIM5提供时钟,还要为其他的外设提供时钟;设置这个倍频器可以保证在其他外设使用较低时钟频率时,TIM2-TIM5仍然可以得到较高的时钟频率。

2.2    计数器模式

TIM2-TIM5可以由向上计数、向下计数、向上向下双向计数。向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器内容),然后重新从0开始计数并且产生一个计数器溢出事件。在向下模式中,计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。而中央对齐模式(向上/向下计数)是计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。

2.3    编程步骤

1.       配置系统时钟;

2.       配置NVIC

3.       配置GPIO

4.       配置TIMER

其中,前3项在前面的笔记中已经给出,在此就不再赘述了。第4项配置TIMER有如下配置:

1       利用TIM_DeInit()函数将Timer设置为默认缺省值;

2       TIM_InternalClockConfig()选择TIMx来设置内部时钟源;

3       TIM_Perscaler来设置预分频系数;

4       TIM_ClockDivision来设置时钟分割;

5       TIM_CounterMode来设置计数器模式;

6       TIM_Period来设置自动装入的值

7       TIM_ARRPerloadConfig()来设置是否使用预装载缓冲器

8       TIM_ITConfig()来开启TIMx的中断

其中(3-6)步骤中的参数由TIM_TimerBaseInitTypeDef结构体给出。

步骤(3)中的预分频系数用来确定TIMx所使用的时钟频率,具体计算方法为:CK_INT/(TIM_Perscaler+1)CK_INT是内部时钟源的频率,是根据2.1中所描述的APB1的倍频器送出的时钟,TIM_Perscaler是用户设定的预分频系数,其值范围是从0 – 65535

 

步骤(4)中的时钟分割定义的是在定时器时钟频率(CK_INT)与数字滤波器(ETR,TIx)使用的采样频率之间的分频比例。TIM_ClockDivision的参数如下表:

TIM_ClockDivision

描述

二进制值

TIM_CKD_DIV1

tDTS = Tck_tim

0x00

TIM_CKD_DIV2

tDTS = 2 * Tck_tim

0x01

TIM_CKD_DIV4

tDTS = 4 * Tck_tim

0x10

数字滤波器(ETR,TIx)是为了将ETR进来的分频后的信号滤波,保证通过信号频率不超过某个限定。

步骤(7)中需要禁止使用预装载缓冲器。当预装载缓冲器被禁止时,写入自动装入的值(TIMx_ARR)的数值会直接传送到对应的影子寄存器;如果使能预加载寄存器,则写入ARR的数值会在更新事件时,才会从预加载寄存器传送到对应的影子寄存器。

ARM中,有的逻辑寄存器在物理上对应2个寄存器,一个是程序员可以写入或读出的寄存器,称为preload register(预装载寄存器),另一个是程序员看不见的、但在操作中真正起作用的寄存器,称为shadow register(影子寄存器);设计preload registershadow register的好处是,所有真正需要起作用的寄存器(shadow register)可以在同一个时间(发生更新事件时)被更新为所对应的preload register的内容,这样可以保证多个通道的操作能够准确地同步。如果没有shadow register,或者preload registershadow register是直通的,即软件更新preload register时,同时更新了shadow register,因为软件不可能在一个相同的时刻同时更新多个寄存器,结果造成多个通道的时序不能同步,如果再加上其它因素(例如中断),多个通道的时序关系有可能是不可预知的。

 三、定时器代码实例

 中断优先级就不贴出来了,自己可以配置下

 Tout= ((arr+1)*(psc+1))/Tclk

arr:计数重装值,psc分频数,Tclk系统时钟频率,Tout一个周期的时间。

 Tout= ((arr+1)*(psc+1))/Tclk

 3.1、定时器1使用

这里假设APB2时钟是1分频即72MHZ(如果是4分频则为36MHZ [=72MHZ/4x2=36MHZ] )配置,void RCC_Configuration(void)中配置如下代码: 

1           //设置高速AHB时钟(APB2)为HCLK时钟

2           RCC_PCLK2Config(RCC_HCLK_Div1);

则这里:APB2的时钟为1分频故出来的APB2时钟还是72MHZ,TIM1对系统时钟APB2(72MHZ)再进行7200分频,然后计数重载初值设置为100,则一个定时周期Tout=(100-1+1)*(7200-1+1)/72,000,000=1/10=0.1s,即100ms为一个计数周期

 1 //放到主函数的初始化中初始化

 2 void Timer1CountInitial(void)

 3 {

 4     //定时=36000/72000x2=0.001s=1ms;

 5         TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;

 6         ///

 7         RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

 8        

 9         TIM_TimeBaseStructure.TIM_Period = 100-1;//自动重装值(此时改为100ms)

10         TIM_TimeBaseStructure.TIM_Prescaler = 7200-1;//时钟预分频

11 //        TIM_TimeBaseStructure.TIM_Prescaler = 36000-1;//时钟预分频

12         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数

13 //        TIM_TimeBaseStructure.TIM_Period = 2-1;//自动重装值

14 //        TIM_TimeBaseStructure.TIM_Period = 10-1;//自动重装值(此时改为10ms)

15         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;        //时钟分频1

16         TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;           

17         TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);

18        

19         TIM_ClearFlag(TIM1,TIM_FLAG_Update);

20         TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE); 

21         TIM_Cmd(TIM1, ENABLE);

22 }

23

24

25 void TIM1_UP_IRQHandler(void)

26 {       

27     //TIM_TimeBaseStructure.TIM_Period = 100-1;//自动重装值(此时进中断的周期为100ms)

28     if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)

29     { 

30         //添加行程开关去抖程序

31         if(XingChengTickNum_QuFantan<1000)//

32         {

33             XingChengTickNum_QuFantan++;

34         }             54    

55     TIM_ClearITPendingBit(TIM1,TIM_IT_Update);58 }

 

3.2、定时器2使用

 Tout= ((arr+1)*(psc+1))/Tclk

arr:计数重装值,psc分频数,Tclk系统时钟频率,Tout一个周期的时间。

假设APB1时钟是2分频即72MHZ(如果是1分频则为36MHZ)配置,void RCC_Configuration(void)中配置如下代码:

//设置低速AHB时钟(APB1)为HCLK的2分频(TIM2-TIM5输入TIMxCLK频率将为72MHZ/2x2=72MHZ输入)

 RCC_PCLK1Config(RCC_HCLK_Div2);

这里:APB1的时钟为分频故出来的APB2时钟还是72MHZ,TIM1是对系统时钟APB2(72MHZ)进行7200分频,

则:Tout=(4-1+1)*(36000-1+1)/72,000,000=4/2,000=2ms

 1 void TIM2_Int_Init(void)

 2 {

 3     TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;

 4     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

 5    

 6     TIM_DeInit(TIM2);

 7    

 8     TIM_TimeBaseStructure.TIM_Period = 4 - 1;//2000 - 1;

 9     TIM_TimeBaseStructure.TIM_Prescaler = (36000 - 1);

10     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

11     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

12    

13     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

14    

15     TIM_ClearFlag(TIM2, TIM_FLAG_Update);

16     TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

17    

18     TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

19    

20     TIM_Cmd(TIM2, ENABLE);

21 }

22 void TIM2_IRQHandler(void)

23 {

24    

25     if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)

26     {       

27                 interrupt_rtc();//可以使你自己定义的执行函数

28     }

29      TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);

30 }

 

3.3、定时器3使用

 假设APB1时钟是2分频即72MHZ(如果是1分频则为36MHZ)配置,void RCC_Configuration(void)中配置如下代码:

1           //设置低速AHB时钟(APB1)为HCLK的2分频(TIM2-TIM5输入TIMxCLK频率将为72MHZ/2x2=72MHZ输入)

2           RCC_PCLK1Config(RCC_HCLK_Div2);


TIM3_Int_Init(4-1,36000-1);

则:Tout=(4-1+1)*(36000-1+1)/72,000,000=4/2,000=2ms

 1 //通用定时器3中断初始化

 2 //这里时钟选择为APB1的2倍,而APB1为36M

 3 //arr:自动重装值。

 4 //psc:时钟预分频数

 5 //这里使用的是定时器3!

 6 void TIM3_Int_Init(u16 arr,u16 psc)

 7 {

 8   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

 9     NVIC_InitTypeDef NVIC_InitStructure;

10

11     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

12

13     TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值     计数到5000为500ms

14     TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率 

15     TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim

16     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式

17     TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

18 

19     TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

20

21     NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断

22     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0//先占优先级0级

23     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3//从优先级3级

24     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能

25     NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

26

27     TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设

28                             

29 }

30 //定时器3中断服务程序

31 void TIM3_IRQHandler(void)   //TIM3中断

32 {

33     if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源

34         {

35         TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源

36         LED1=!LED1;

37         }

38 }

 

3.4、定时器4使用

 假设APB1时钟是4分频即72/4=18MHZ(如果是4分频则TIMxCLK=18MHZx2=36MHZ)配置,void RCC_Configuration(void)中配置如下代码:

1 //在void RCC_Configuration(void)中配置APB1时钟4分频或1分频都变为36MHZ

2 //设置低速AHB时钟(APB1)为HCLK的4分频(TIM2-TIM5输入TIMxCLK频率将为72MHZ/4x2=36MHZ输入)

3 RCC_PCLK1Config(RCC_HCLK_Div4);//加入使用4分频

TIM4_Int_Init(4-1,36000-1);

则:Tout=(4-1+1)*(36000-1+1)/36,000,000=4/1,000=4ms

 1 void TIM4_Int_Init(u16 arr,u16 psc)

 2 {

 3     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

 4     NVIC_InitTypeDef NVIC_InitStructure;

 5

 6     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能

 7     //定时器TIM4初始化

 8     TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值

 9     TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值

10     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim

11     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式

12     TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

13     TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断

14

15     //中断优先级NVIC设置

16     NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM3中断

17     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级

18     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级

19     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能

20     NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器

21

22

23     TIM_Cmd(TIM4, ENABLE); //使能TIMx

24 }

25

26

27 //定时器4中断服务程序

28 void TIM4_IRQHandler(void) //TIM3中断

29 {

30     if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //检查TIM4更新中断发生与否

31     {

32         TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIMx更新中断标志

33         LED0=!LED0;

34         // Get_Angle();

35     }

36 }

3.5、定时器5使用

假设APB1时钟是1分频即36MHZ(如果是1分频则TimexCLK=36MHZx1=36MHZ)配置,void RCC_Configuration(void)中配置如下代码:

1 //在void RCC_Configuration(void)中配置APB1时钟4分频或1分频都变为36MHZ

2 //设置低速AHB时钟(APB1)为HCLK的4分频(TIM2-TIM5输入TIMxCLK频率将为72MHZ/4x2=36MHZ输入)

3 RCC_PCLK1Config(RCC_HCLK_Div1);//假如使用1分频

TIM5_Int_Init(4-1,36000-1);

则:Tout=(4-1+1)*(36000-1+1)/36,000,000=4/1,000=4ms

 1 void TIM5_Init(u16 arr,u16 psc)

 2 {

 3     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

 4     NVIC_InitTypeDef NVIC_InitStructure;

 5

 6     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //时钟使能

 7

 8     TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值     计数到5000为500ms

 9     TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率 

10     TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim

11     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式

12     TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

13 

14     TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

15

16     NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;  //TIM3中断

17     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0//先占优先级0级

18     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3//从优先级3级

19     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能

20     NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

21

22     TIM_Cmd(TIM5, ENABLE);  //使能TIMx外?

23 }

24 //定时器5中断服务程序

25 void TIM5_IRQHandler(void)   //TIM3中断

26 {

27     if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源

28         {

29         TIM_ClearITPendingBit(TIM5, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源

30         LED1=!LED1;

31         }

32 }

  • 7
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值