定时器是微控制器重要的功能模块之一,在监测、控制领域广泛应用

定时器的基本概念

定时器是对周期固定的脉冲信号进行计数,如MCU内部的外设时钟(APB)。

计数器是对周期固定或者不固定的脉冲信号进行计数,如MCU的I/O引脚所引入的外部脉冲信号。

所以,定时器和计数器本质上都是计数器,定时器是计数器的一种特例。

STM32 定时器家族

STM32定时器大家族
STM32定时器大家族

在这里我们会逐步更新关于各个定时器的介绍:

内核定时器 - 系统节拍定时器(SysTick)

SysTick 是一个24位的系统节拍定时器(System Tick Timer),具有自动重载和溢出中断功能,所有基于 Cortex_M3 处理器的微控制器都可以由这个定时器获得一定的时间间隔。这个定时器是专用于实时操作系统,也可当成一个标准的递减计数器。

SysTick 的定义

SysTick 定时器被捆绑在 NVIC 中,用于产生 SYSTICK 异常(异常号:15)。Cortex-M3 处理器内部包含了一个 SysTick 定时器,因此所有的 Cortex-M3 芯片都带有这个定时器,所以 SysTick 能用于Cortex-M3 芯片的快速移植,软件在不同的 Cortex-M3 芯片的移植工作大为化简。

特性 描述
计数器 24 位递减计数器
加载 自动重加载功能
中断 当计数器为0时能产生一个可屏蔽中断
时钟源 可编程时钟源

系统时基定时器的时钟源,来自于AHB总线,不分频为等于AHB频率和AHB/8两种分频情况。它可以是内部时钟(FCLK,Cortex上的自由运行时钟),或者是外部时钟(Cortex处理器上的SYSCLK信号)。

SysTick 的作用

在单任务引用程序中,因为其架构就决定了它执行任务的串行性,使用实时操作系统(RTOS)。因为 RTOS 以并行的架构处理任务,单一任务的崩溃并不会牵连到整个系统。这样用户出于可靠性的考虑可能就会基于 RTOS 来设计自己的应用程序。 SYSTICK 存在的意义就是提供必要的时钟节拍,为 RTOS 的任务调度提供一个有节奏的“心跳”。SysTick定时器除了能服务于操作系统之外,还能用于作为一个闹铃,用于测量时间等。当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。
以及 HAL 库的库函数 - HAL_Delay() 使用息息相关。可以利用 HAL_Delay() 来达到系统等待的效果。

专用定时器 - 看门狗定时器(IWDG)

IWDG 简介

STM32F10x有两个嵌入的看门狗外围设备,能够提供高度的安全、准确的计时和灵活的运用。所有的看门狗外围设备(独立的或视窗的)都是用来检测和解决由于软件运行失败而引起的故障,当定时器到达一个给定的超时值时,看门狗就会触发一个中断或者重启系统。独立看门狗是由它自身所带的专门的低速时钟(32KHZ)计时的,因此即使主时钟不工作时它也能正常运行。视窗看门狗的时钟由APB1时钟分频而来,并拥有一个可配置可编程的定时窗口,能够检测到不正常的迟到或早到的应用行为。

独立看门狗就是一个 12 位的递减计数器,当计数器的值从某个值一直减到 0 的时候,系统就会产生一个复位信号,即 IWDG_RESET。如果在计数没减到 0 之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍能工作。

常规定时器 - 高级、通用、基本定时器(TIM1 ~ TIM8)

它们之间有一些区别:高级定时器具有捕获/比较通道和互补输出,通用定时器只有捕获/比较通道,基本定时器没有以上两者。

通用定时器

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

它们的功能特点

  • TIM2 ~ TIM5 位于低速的总线 APB1 上
  • 16 位向上、向下、向上/下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。
  • 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1 ~ 65536 之间的任意整数
  • 4 个独立通道(TIMx_CH1 ~ TIMx_CH4),可用作: 输入捕获输出比较PWM生成(边缘或中间对齐模式)单脉冲
  • 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
  • 若发生如下时间,则产生中断/DMA(6个独立的 IRQ/DMA 请求生成器):
        更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
        触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
        输入捕获
        输出比较
        支持针对定位的增量(正交)编码器和霍尔传感器电路
        触发输入作为外部时钟或按周期的电流管理

计数模式

它们共有三种计数模式:

  • 向上计数模式: 计数器从 0 计数到自动加载值(TIMx_ARR),然后重新从 0 开始计数并且产生一个计数器溢出事件。
  • 向下计数模式: 计数器从自动装入的值(TIMx_ARR0)开始向下计数到 0 ,然后从自动装入的值重新开始,并产生一个计数器向下溢出时间。
  • 中央对齐模式: 计数器从0计数到自动装入的值-1,产生一个计数器溢出时间,然后向下计数到1并产生一个计数器溢出时间;然后再从0重新计数。

SysTick 结构

图中表明系统节拍定时器有4个相关的寄存器,了解了这4个寄存器的内容,即可掌握系统节拍定时器的工作原理。

在 core_cm3.h 里定义了 SysTick 的4个寄存器,分别是控制与状态寄存器 SysTick_CTRL 、重装值寄存器 SysTick_LOAD 、当前计数值寄存器 SysTick_VAL 、校正值寄存器 SysTick_CALIB 。

1
2
3
4
5
6
7
typedef struct
{
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;

在stm32f10x.h中则定义了SysTick的4个寄存器里每个bit的地址和名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */

#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */

#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */

#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */

/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */

/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */

/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */

#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */

#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */

学路漫漫其修远兮,吾将上下而求索


此间车厢已使用  次 |   人乘坐过此趟开往世界尽头的列车