当前位置:   article > 正文

STM32(五):TIMER定时器 (标准库函数)_stm32 timer

stm32 timer

前言

上一篇文章已经介绍了如何用STM32单片机中的Systick嘀嗒定时器来控制LED灯的交替闪烁,实现了点灯的第四种方式。这篇文章我们来介绍一下如何用STM32单片机中的TIMER定时器来控制LED灯的交替闪烁。

一、实验原理

1.定时器的功能

STM32的定时器是一种强大的外设,具有以下几种主要功能:

  • 定时功能:可以设置定时时间,用于在特定时刻执行任务。
  • 计数功能:对输入的时钟脉冲进行计数。
  • PWM信号产生:用于控制电机速度、灯光亮度等。
  • 输入捕获:捕获并记录外部信号的时间参数。
  • 定时器中断:在计数值达到设定值时触发中断,进行相应处理。

2.定时器的类型

STM32中的定时器根据功能和复杂度分为三种类型:

  • 高级定时器:TIM1和TIM8,支持更复杂的控制需求和高精度的操作。
  • 通用定时器:TIM2、TIM3、TIM4、TIM5,适用于常规的定时和计数任务。
  • 基本定时器:TIM6和TIM7,主要用于简单的定时任务,没有高级控制功能。

3.定时器工作原理

以下是定时器的工作原理图,主要分为5个部分,分别是时钟产生、定时器、输入、输出和寄存器部分。

时钟产生来源:
1. 内部时钟     PB1(CLK_INT) (*)
2. TIMx_ETR       外部引脚输入
3. ITRx            内部触发输入,定时器集联
4. TL1FP1/2        来自于定时器外部通道
主要是内部时钟,最后输出 [ CK_PSC ]

输出比较:
比如说现在定时器是从 0-100 向上计数
如果把 [ 捕获比较寄存器 ] 的值设置为 v = 50;
如果 当前值 < v 则输出高电平, 当前值 > v 则输出低电平
那么效果就是 0-50 输出高电平, 50-100 输出低电平, 实现通道输出
通过控制 V 的值 就能改变占空比,  实现PWM。

定时器主要分为3种计数模式,向上计数、向下计数以及中央对齐模式。

1.向上计数模式

2.向下计数模式

3.中央对齐模式

 3.定时器系统框图

以下是定时器的系统框图:

主要有4块组成部分:

1.振荡器

  • HSI RC:内部高速时钟,8MHz。

  • HSE Osc:外部高速时钟,频率依赖于外部晶振。

  • LSI RC:内部低速时钟。

  • LSE Osc:外部低速时钟,通常是32.768kHz,用于实时时钟(RTC)。

2.时钟源选择和配置

  • PLL(相位锁环):可以将HSI或HSE的频率乘以一个系数(如图中所示,最高可达72MHz)。

  • SYSCLK(系统时钟):可以选择HSI、HSE或PLLCLK作为源。

  • MCO(微控制器时钟输出):可以输出不同源的时钟,如HSI、HSE或PLLCLK的一部分。

3.总线和接口时钟

  • AHB Prescaler:高性能总线预分频器,可对HCLK进行分频。

  • APB1 Prescaler和APB2 Prescaler:两个外设总线预分频器,分别对PCLK1和PCLK2进行分频。

  • ADC Prescaler:模数转换器预分频器,提供给ADC的时钟。

4.定时器

  • TIM1、TIM8(高级定时器):接收PCLK2时钟,可以选择直接时钟或通过倍增器增倍(x1或x2)。

  • TIM2、TIM3、TIM4(通用定时器):接收PCLK1时钟,同样有倍增器选择。

  • 系统时钟与这些定时器的关系,决定了定时器的计数速度和精度。

二、实验步骤

1.时钟初始化

首先是对时钟的初始化,其中我们要知道以下计算的式子

定时器频率 =((1+TIM_Prescaler )/72M)*(1+TIM_Period )
例:如果想要设置定时器频率为 1秒,可以设置
TIM_Prescaler=35999,TIM_Period=1999 //2Khz的频率,计数到
2000
TIM_Prescaler=7199,TIM_Period=9999 //10KHz的频率,计数到
10000

参数如下所示:

  • TIM_Prescaler  用来设置分频系数
  • TIM_CounterMode  用来设置计数方式
  • TIM_Period 设置自动重载计数周期值
  • TIM_ClockDivision 用来设置时钟分频因子
  1. void GENERAL_TIMx_Configuration(void)
  2. {
  3. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  4. /* 开启TIMx_CLK,x[2,3,4,5],即内部时钟CK_INT=72M */
  5. GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK, ENABLE);
  6. /* 通用定时器 TIMx,x[2,3,4,5]中断优先级配置 */
  7. GENERAL_TIMx_NVIC_Configuration();
  8. /* 自动重装载寄存器周的值(计数值) */
  9. TIM_TimeBaseStructure.TIM_Period=1000;
  10. /* 累计 TIM_Period个频率后产生一个更新或者中断
  11. 时钟预分频数为71,则驱动计数器的时钟CK_CNT = CK_INT / (71+1)=1M */
  12. TIM_TimeBaseStructure.TIM_Prescaler= 71;
  13. /* 时钟分频因子 ,没有用到,不用管 */
  14. //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  15. /* 计数器计数模式,基本定时器TIM6和TIM7只能向上计数,没有计数模式的设置,不用管 */
  16. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  17. /* 重复计数器的值,通用定时器没有,不用管 */
  18. //TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
  19. /* 初始化定时器TIMx, x[2,3,4,5] */
  20. TIM_TimeBaseInit(GENERAL_TIMx, &TIM_TimeBaseStructure);
  21. /* 清除计数器中断标志位 */
  22. TIM_ClearITPendingBit(GENERAL_TIMx, TIM_IT_Update);
  23. /* 开启计数器中断 */
  24. TIM_ITConfig(GENERAL_TIMx,TIM_IT_Update,ENABLE);
  25. /* 使能计数器: */
  26. TIM_Cmd(GENERAL_TIMx, ENABLE);
  27. }

2.时钟中断

时钟中断函数GENERAL_TIMx_NVIC_Configuration(void),这边是对中断来源以及优先级的配置,前面在Systick中有所介绍,可以看一下之前的连接:STM32(四):Systick (标准库函数)-CSDN博客

  1. void GENERAL_TIMx_NVIC_Configuration(void)
  2. {
  3. NVIC_InitTypeDef NVIC_InitStructure;
  4. /* 设置中断组为0 */
  5. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  6. /* 设置中断来源 */
  7. NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM_IRQ;
  8. /* 设置主优先级为 0 */
  9. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  10. /* 设置抢占优先级为3 */
  11. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  12. /*定时器使能 */
  13. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  14. NVIC_Init(&NVIC_InitStructure);
  15. }

但到这里我们的中断配置还没结束!!重点!!易踩坑!!

我们还需要在stm32f10x_it.c的文件里面加上新的中断服务函数 GENERAL_TIM_INT_FUN (),记得加上头文件,例如:

  1. #include "bsp/GeneralTIM/bsp_GeneralTIM.h"
  2. extern __IO uint16_t timer_count;
  3. void GENERAL_TIM_INT_FUN (void)
  4. {
  5. if ( TIM_GetITStatus(GENERAL_TIMx,TIM_IT_Update) != RESET )
  6. {
  7. timer_count++;
  8. TIM_ClearITPendingBit(GENERAL_TIMx , TIM_IT_Update);
  9. }
  10. }

三、实操代码

程序分为3个文件:bsp_GeneralTIM.c、bsp_GeneralTIM.h、main.c

1.bsp_GeneralTIM.c

  1. /* 包含头文件 ----------------------------------------------------------------*/
  2. #include "bsp/GeneralTIM/bsp_GeneralTIM.h"
  3. /**
  4. * 函数功能: 通用定时器 TIMx,x[2,3,4,5]中断优先级配置
  5. * 输入参数: 无
  6. * 返 回 值: 无
  7. * 说 明:无
  8. */
  9. void GENERAL_TIMx_NVIC_Configuration(void)
  10. {
  11. NVIC_InitTypeDef NVIC_InitStructure;
  12. /* 设置中断组为0 */
  13. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  14. /* 设置中断来源 */
  15. NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM_IRQ;
  16. /* 设置主优先级为 0 */
  17. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  18. /* 设置抢占优先级为3 */
  19. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  20. /*定时器使能 */
  21. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  22. NVIC_Init(&NVIC_InitStructure);
  23. }
  24. void GENERAL_TIMx_Configuration(void)
  25. {
  26. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  27. /* 开启TIMx_CLK,x[2,3,4,5],即内部时钟CK_INT=72M */
  28. GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK, ENABLE);
  29. /* 通用定时器 TIMx,x[2,3,4,5]中断优先级配置 */
  30. GENERAL_TIMx_NVIC_Configuration();
  31. /* 自动重装载寄存器周的值(计数值) */
  32. TIM_TimeBaseStructure.TIM_Period=1000;
  33. /* 累计 TIM_Period个频率后产生一个更新或者中断
  34. 时钟预分频数为71,则驱动计数器的时钟CK_CNT = CK_INT / (71+1)=1M */
  35. TIM_TimeBaseStructure.TIM_Prescaler= 71;
  36. /* 时钟分频因子 ,没有用到,不用管 */
  37. //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  38. /* 计数器计数模式,基本定时器TIM6和TIM7只能向上计数,没有计数模式的设置,不用管 */
  39. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  40. /* 重复计数器的值,通用定时器没有,不用管 */
  41. //TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
  42. /* 初始化定时器TIMx, x[2,3,4,5] */
  43. TIM_TimeBaseInit(GENERAL_TIMx, &TIM_TimeBaseStructure);
  44. /* 清除计数器中断标志位 */
  45. TIM_ClearITPendingBit(GENERAL_TIMx, TIM_IT_Update);
  46. /* 开启计数器中断 */
  47. TIM_ITConfig(GENERAL_TIMx,TIM_IT_Update,ENABLE);
  48. /* 使能计数器: */
  49. TIM_Cmd(GENERAL_TIMx, ENABLE);
  50. }

2.bsp_GeneralTIM.h

  1. #ifndef __GENERAL_TIM_H__
  2. #define __GENERAL_TIM_H__
  3. /* 包含头文件 ----------------------------------------------------------------*/
  4. #include <stm32f10x.h>
  5. /* 类型定义 ------------------------------------------------------------------*/
  6. /* 宏定义 --------------------------------------------------------------------*/
  7. /********************通用定时器TIM参数定义,只限TIM2 & TIM3 & TIM4 & TIM5************/
  8. #define GENERAL_TIMx TIM2
  9. #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
  10. #define GENERAL_TIM_CLK RCC_APB1Periph_TIM2
  11. #define GENERAL_TIM_IRQ TIM2_IRQn
  12. #define GENERAL_TIM_INT_FUN TIM2_IRQHandler
  13. //#define GENERAL_TIMx TIM3
  14. //#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
  15. //#define GENERAL_TIM_CLK RCC_APB1Periph_TIM3
  16. //#define GENERAL_TIM_IRQ TIM3_IRQn
  17. //#define GENERAL_TIM_INT_FUN TIM3_IRQHandler
  18. //#define GENERAL_TIMx TIM4
  19. //#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
  20. //#define GENERAL_TIM_CLK RCC_APB1Periph_TIM4
  21. //#define GENERAL_TIM_IRQ TIM4_IRQn
  22. //#define GENERAL_TIM_INT_FUN TIM4_IRQHandler
  23. //#define GENERAL_TIMx TIM5
  24. //#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
  25. //#define GENERAL_TIM_CLK RCC_APB1Periph_TIM5
  26. //#define GENERAL_TIM_IRQ TIM5_IRQn
  27. //#define GENERAL_TIM_INT_FUN TIM5_IRQHandler
  28. /* 扩展变量 ------------------------------------------------------------------*/
  29. /* 函数声明 ------------------------------------------------------------------*/
  30. void GENERAL_TIMx_Configuration(void);
  31. #endif /* __GENERAL_TIM_H__ */

3.main.c

  1. /* 包含头文件 ----------------------------------------------------------------*/
  2. #include "stm32f10x.h"
  3. #include "bsp/led/bsp_led.h"
  4. #include "bsp/key/bsp_key.h"
  5. #include "bsp/delay/delay.h"
  6. #include "bsp/systick/bsp_SysTick.h"
  7. #include "bsp/GeneralTIM/bsp_GeneralTIM.h"
  8. /* 函数体 --------------------------------------------------------------------*/
  9. __IO uint16_t timer_count=0;
  10. /**
  11. * 函数功能: 主函数.
  12. * 输入参数: 无
  13. * 返 回 值: 无
  14. * 说 明: 无
  15. */
  16. int main(void)
  17. {
  18. LED_GPIO_Init();
  19. //KEY_GPIO_Init();
  20. // KEY1_EXIT_Config();
  21. // KEY2_EXIT_Config();
  22. // KEY3_EXIT_Config();
  23. /* 初始化系统滴答定时器 */
  24. // SysTick_Init();
  25. /* 通用定时器初始化:1ms中断一次 */
  26. GENERAL_TIMx_Configuration();
  27. while (1)
  28. {
  29. if(timer_count==500)
  30. {
  31. LED1_ON;
  32. LED2_OFF;
  33. LED3_OFF;
  34. }
  35. if(timer_count==1000)
  36. {
  37. LED1_OFF;
  38. LED2_ON;
  39. LED3_OFF;
  40. }
  41. if(timer_count==1500)
  42. {
  43. timer_count=0;
  44. LED1_OFF;
  45. LED2_OFF;
  46. LED3_ON;
  47. }
  48. }
  49. }

四、实验效果

Timer定时器点灯

结束语

本文以STM32VET6为例讲解了用TIMER定时器控制LED灯的交替闪烁的实现方法,并指出其中的易坑点。希望对大家有所帮助!如果还有什么问题,欢迎评论区留言,谢谢!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/754006
推荐阅读
相关标签
  

闽ICP备14008679号