单片机
返回首页

STM32 通用定时器

2024-10-15 来源:cnblogs

STM32 的定时器功能十分强大,有 TIME1 和 TIME8 等高级定时器,也有 TIME2~TIME5 等通用定时器,还有 TIME6 和TIME7 等基本定时器。

STM32 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。   使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。

STM3 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能包括:

1)16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。

2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。

3)4 个独立通道(TIMx_CH1~4),这些通道可以用来作为: 

A.输入捕获 

B.输出比较 

C.PWM 生成(边缘或中间对齐模式) 

D.单脉冲模式输出 

4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。

5)如下事件发生时产生中断/DMA: 

A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) 

B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) 

C.输入捕获 

D.输出比较 

E.支持针对定位的增量(正交)编码器和霍尔传感器电路 

F.触发输入作为外部时钟或者按周期的电流管理

定时器相关的库函数主要集中在固件库文件 stm32f10x_tim.h 和 stm32f10x_tim.c 文件中。

1)TIM3 时钟使能。

TIM3 是挂载在 APB1 之下,所以我们通过 APB1 总线下的使能使能函数来使能 TIM3。调用的函数是:

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

2)初始化定时器参数,设置自动重装值,分频系数,计数方式等。

在库函数中,定时器的初始化参数是通过初始化函数 TIM_TimeBaseInit 实现的:

voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

第一个参数是确定是哪个定时器,这个比较容易理解。第二个参数是定时器初始化参数结构体指针,结构体类型为 TIM_TimeBaseInitTypeDef。针对 TIM3 初始化范例代码格式:

TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;

TIM_TimeBaseStructure.TIM_Period = 5000; //设置自动重载计数周期值

TIM_TimeBaseStructure.TIM_Prescaler =7199;  //设置分频系数

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分频因子

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数方式

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 

3)设置 TIM3_DIER 允许更新中断。

在库函数里面定时器中断使能是通过 TIM_ITConfig 函数来实现的:

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

第一个参数是选择定时器号,这个容易理解,取值为 TIM1~TIM17。

第二个参数非常关键,是用来指明我们使能的定时器中断的类型,定时器中断的类型有很多种,包括更新中断 TIM_IT_Update,触发中断 TIM_IT_Trigger,以及输入捕获中断等等。

第三个参数就很简单了,就是失能还是使能。

例如我们要使能 TIM3 的更新中断,格式为:

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); 

4)TIM3 中断优先级设置。

在定时器中断使能之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,设置中断优先级。

5)允许 TIM3 工作,也就是使能 TIM3。

在配置完后要开启定时器,通过 TIM3_CR1 的 CEN 位来设置。 在固件库里面使能定时器的函数是通过 TIM_Cmd 函数来实现的:

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

这个函数非常简单,比如我们要使能定时器 3,方法为:

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

6)编写中断服务函数。

在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处理完中断之后应该向 TIM3_SR 的最低位写 0,来清除该中断标志。

在固件库函数里面,用来读取中断状态寄存器的值判断中断类型的函数是:

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t)

该函数的作用是,判断定时器 TIMx 的中断类型 TIM_IT 是否发生中断。比如,我们要判断定时器 3 是否发生更新(溢出)中断,方法为:

if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){}

固件库中清除中断标志位的函数是:

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT) 

该函数的作用是,清除定时器 TIMx 的中断 TIM_IT 标志位。使用起来非常简单,比如我们在TIM3 的溢出中断发生后,我们要清除中断标志位,方法是:

TIM_ClearITPendingBit(TIM3, TIM_IT_Update   );


  1. /**

  2.  * 通用定时器3中断初始化

  3.  * 这里时钟选择为APB1的2倍,而APB1为36M

  4.  * arr:自动重装值。

  5.  * psc:时钟预分频数

  6.  * 计算公式如下:

  7.  * Tout= ((arr+1)*(psc+1))/Tclk;

  8.  * 其中:

  9.  * Tclk:TIM3 的输入时钟频率(单位为 Mhz)。

  10.  * Tout:TIM3 溢出时间(单位为 us)。

  11.  */

  12. void TIM3_Int_Init(u16 arr,u16 psc)

  13. {

  14.     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

  15.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* 时钟使能 */


  16.     /*定时器TIM3初始化*/

  17.     TIM_TimeBaseStructure.TIM_Period = arr; /*周期的值*/

  18.     TIM_TimeBaseStructure.TIM_Prescaler = psc; /* 预分频值 */

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

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

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


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

  23.     TIM3_NVIC_Init();


  24.     TIM_Cmd(TIM3,ENABLE);/*使能TIMx*/

  25. }


  26. /**

  27.  * 中断3优先级NVIC设置

  28.  */

  29. void TIM3_NVIC_Init(void)

  30. {

  31.     NVIC_InitTypeDef NVIC_InitStructure;

  32.     NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; /*TIM3中断*/

  33.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; /*先占优先级0级*/

  34.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; /*从优先级3级*/

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

  36.     NVIC_Init(&NVIC_InitStructure);

  37. }


  38. /**

  39.  * 定时器3中断服务程序

  40.  */

  41. void TIM3_IRQHandler(void)

  42. {

  43.     if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET ) /*检查TIM3更新中断发生与否*/

  44.     {

  45.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update); /*清除TIMx更新中断标志 */

  46.         LED0 = !LED0;

  47.     }

  48. }


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 基于IC555的可变PWM振荡器电路

  • 优化电路板布局的简单方法

  • 如何使用LED驱动器LM3915制作振动计

  • 分享一个电网倾角计电路

  • 电谐波图形均衡器示意图

  • 一种构建12V和230V双直流电源的简单方法

    相关电子头条文章