YIE002开发探索04-定时器

(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)
(代码仓库地址:https://gitee.com/luobing4365/yie002-explorer
具体参考博客:YIE002开发探索-Gitee代码仓库说明)



定时器的最基本的功能是用来周期性的定时,当然,它还用来实现如下功能:
1) 输入捕获。脉冲计数,在上升沿或下降沿检测,已经PWM的输入检测;
2) 输出比较。脉冲输出和步进电机的控制;
3) PWM生成。电压输出控制、直流减速电机控制等;
4) 编码器接口、霍尔传感器接口等。

当然,根据所用芯片不同,定时器还能提供更多的功能,比如与DMA的配合等。本篇准备用定时器产生的时间中断,周期性地控制LED灯的亮灭,以期对定时器的编程有基本的理解。

1 STM32的定时器

YIE002-STM32所用的芯片为STM32F103C8T6,属于STM32F1系列,在此系列,STM32提供了大量的定时器:2个基本定时器(TIM6、TIM7)、4个通用定时器(TIM2、TIM3、TIM4、TIM5)、2个高级控制定时器(TIM1和TIM8),以及4个特定功能定时器(SysTick、IWDG、WWDG、RTC),共有12个。另外,超大容量系列的产品中,又增加了5个通用寄存器TIM9~TIM14。

从功能上来说,高级控制通用器的功能是通用定时器的超集、通用定时器的功能是基本定时器的超集。比较通用定时器和高级控制定时器,可知它们的功能非常接近,高级控制定时器只是针对电动机的控制增加了一些功能。

因此,本篇准备使用通用定时器TIM3,构建演示程序。

1.1 定时器的时钟

TIM1和TIM8是高级控制定时器,时钟由APB2输出产生;TIM2至于TIM5是通用定时器,TIM6和TIM7是基本定时器,时钟由APB1输出产生。

从前几篇中可以知道,F103C8T6的系统时钟为72MHZ。如图1所示的时钟树,给出了定时器的时钟频率。
时钟树
图1 定时器的时钟树

图1是以STM32F103C8T6为例绘制的。APB1为36MHZ,APB2为72MHZ。在我们的配置中,APB1 Prescaler是2分频;APB2 Prescaler是1分频。从图中可以看出,不论是通过挂在APB1下、还是挂在APB2下的时钟,其时钟都是72MHZ。

也即TIMxCLK均为72MHZ,与系统时钟等同。

1.2 定时器的中断时间(TIM3)

STM32F1的通用定时器(本例中使用的TIM3)是通过可编程预分频器(PSC)驱动的16位自动装载计数器(CNT)构成,其基本的配置过程包括:
1) TIM3时钟使能;
2) 初始化定时器参数,设置自动重装值、分配系数、计数方式等;
3) 允许TIM3更新中断;
4) 设置TIM3的中断优先级;
5) 使能TIM3;
6) 编写中断服务函数。

使用CubeMX编程,上述6个步骤的前5个都是通过图形配置、自动生成代码的,只有中断服务函数需要编写。

编写代码之前,我们需要考虑定时器以多长的时间定时中断。计算中断时间,与TIMx_PSC寄存器(预分频寄存器)和TIMx_ARR寄存器(自动重装载寄存器)有关。具体的细节可以查看《STM32参考手册》,我们主要关注CubeLibrary中如何操作。在stm32f1xx_hal_tim.h中定义了定时器初始化的数据结构:

/** @defgroup TIM_Exported_Types TIM Exported Types
  * @{
  */

/**
  * @brief  TIM Time base Configuration Structure definition
  */
typedef struct
{
  uint32_t Prescaler;         /*!< Specifies the prescaler value used to divide the TIM clock.
                                   This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */

  uint32_t CounterMode;       /*!< Specifies the counter mode.
                                   This parameter can be a value of @ref TIM_Counter_Mode */

  uint32_t Period;            /*!< Specifies the period value to be loaded into the active
                                   Auto-Reload Register at the next update event.
                                   This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF.  */

  uint32_t ClockDivision;     /*!< Specifies the clock division.
                                   This parameter can be a value of @ref TIM_ClockDivision */

  uint32_t RepetitionCounter;  /*!< Specifies the repetition counter value. Each time the RCR downcounter
                                    reaches zero, an update event is generated and counting restarts
                                    from the RCR value (N).
                                    This means in PWM mode that (N+1) corresponds to:
                                        - the number of PWM periods in edge-aligned mode
                                        - the number of half PWM period in center-aligned mode
                                     GP timers: this parameter must be a number between Min_Data = 0x00 and
                                     Max_Data = 0xFF.
                                     Advanced timers: this parameter must be a number between Min_Data = 0x0000 and
                                     Max_Data = 0xFFFF. */

  uint32_t AutoReloadPreload;  /*!< Specifies the auto-reload preload.
                                   This parameter can be a value of @ref TIM_AutoReloadPreload */
} TIM_Base_InitTypeDef;

数据结构TIM_Base_InitTypeDef的成员变量Prescaler对应预分频寄存器、成员变量Period对应自动重装载寄存器。注意,这两个值可设置的值为[0,65535],注意不要越界。

假设TimClk为定时器时钟频率(单位:MHZ),TimOut为中断时间(也即溢出时间,单位:秒),则计算公式为:

TimOut = ((Prescaler + 1) * (Period + 1)) /TimClk;

TIM3的时钟频率TimClk为72MHZ,如果需要1秒的中断时间,则可以设置

Prescaler=7200-1; 
Period=10000-1;

计算可得TimOut = 1 秒。

常用的几个溢出时间:

Period =9999  Prescaler =7199   1000ms
Period =4999  Prescaler =7199   500ms
Period =2499  Prescaler =7199   250ms
Period =1999  Prescaler =7199   200ms
Period =999   Prescaler =7199   100ms

有了这些基本概念,就可以进入编程步骤了。

2 YIE002-STM32的定时器编程

如之前一样,分为图形配置然后自动生成代码,以及手动编写代码。

2.1 Cube MX的图形配置

本篇的例子,是在03ExtIO上修改的。原来的配置没有修改,主要添加定时器TIM3的配置。如图2所示。
配置TIM3
图2 配置TIM3

在Pinout & Configuration菜单下,选择Timers中的TIM3,将其“Internal Clock”的选项勾选上。同时设置Prescaler值为7200-1,Counter Period值设置为10000-1。

然后设置TIM3中断的优先级,可在System Core的NVIC中设置,如图3所示。

设置TIM3中断优先级
图3 设置TIM3中断优先级

之前设置的外部中断的优先级,可以不必修改,保留即可。

完成设置后,生成代码。

2.2 编写TIM3中断服务函数

定时的中断服务处理函数,在startup_stm32f103xb.s中可以看到。

 EXPORT  TIM1_BRK_IRQHandler        
 EXPORT  TIM1_UP_IRQHandler         
 EXPORT  TIM1_TRG_COM_IRQHandler    
 EXPORT  TIM1_CC_IRQHandler         
 EXPORT  TIM2_IRQHandler            
 EXPORT  TIM3_IRQHandler            
 EXPORT  TIM4_IRQHandler   

我们需要处理的中断函数是TIM3_IRQHandler。跟踪此函数,可以知道,Cube Library提供了回调函数HAL_TIM_PeriodElapsedCallback()供用户处理定时器中断。

因此需要处理的工作包括两项:

一是在初始化函数MX_TIM3_Init()中,添加对TIM3的中断使能函数,代码如下:

/* USER CODE BEGIN TIM3_Init 2 */
	//robin add 20210725
	if(HAL_TIM_Base_Start_IT(&htim3)!=HAL_OK)
	{
		Error_Handler();
	}
 /* USER CODE END TIM3_Init 2 */     

二是添加对回调函数HAL_TIM_PeriodElapsedCallback()的实现,代码如下(添加在USER CODE BEGIN 4中):

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim ==(&htim3))    
        HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_12);
}

编译下载,就可以看到实际效果了。所实现的代码,将以1秒为周期,驱动灯LED1亮灭。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luobing4365

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值