本篇重点记录的是STM32F1的通用定时器。STM32F103ZE有8个定时器,其中2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5),2个基本定时器(TIM6、TIM7)。下表是对这8个定时器的详细描述。

| 定时器名称 | 描述 |

| -------- | -------------------------------------------- |

| TIM1 | APB1总线上的高级定时器 |

| TIM8 | APB1总线上的高级定时器 |

| TIM2 | 位于低速的APB1总线上的通用定时器(向下计数模式) |

| TIM3 | 位于低速的APB1总线上的通用定时器(向上计数模式) |

| TIM4 | 位于低速的APB1总线上的通用定时器(向上/向下模式) |

| TIM5 | 位于低速的APB1总线上的通用定时器(中央对齐模式-向下) |

| TIM6 | 位于高速的APB2总线上的基本定时器 |

| TIM7 | 位于高速的APB2总线上的基本定时器 |

上表中可看出STM32F103ZE定时器都是16位的,捕获/比较通道有4个,计数模式包括3种(向上计数、向下计数、中央对齐(向上/向下)计数)。在此对计数模式做一个解释:

1. 向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。

2. 向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。

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

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

通用计时器是一种在STM32微控制器中广泛使用的定时器,它具有预分频器和RCC时钟控制器预分频器功能,使得脉冲长度和波形周期可以在几个微秒到几个毫秒之间进行调整。STM32的每个通用定时器都是完全独立的,没有互相共享的任何资源。

通用计时器的框图如下:

从图中我们可以看到通用计时器由时钟、时基单元、输入电路、输出电路构成。下面我们将分别对这四部分进行介绍。

1. 通用计数器时钟的选择

上图总结为计数器的时钟有8种选择:

- 内部RCC提供的时钟:TIMxCLK(CK_INT)

- 内部触发器输入口1~4(ITR1、ITR2、ITR3、ITR4),用一个定时器作为另一定时器的分频

- 外部捕捉比较引脚,引脚1(TI1FP1或TI1F_ED)、引脚2(TI2FP2)

- 外部引脚:ETR(使能/禁止位、可编程设定极性、4位外部触发过滤器、外部触发分频器[分频器关闭、二分频、四分频、八分频])

计数器时钟可以由下列时钟源提供(该内容意思同上):内部时钟(CK_INT)、外部时钟模式1:外部输入脚(TIx)、外部时钟模式2:外部触发输入(ETR)、内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。

2. 时基单元

从上图中我们可以看到定时器的构成:

- 计数寄存器(TIMx_CNT):该寄存器计数模式为3种,向上计数、向下计数和对齐计数

- 预分频器寄存器(TIMx_PSC):可将时钟频率按1到65536之间的任意值进行分频,可在运行时改变其设置值

- 自动装载寄存器(TIMx_ARR):用于设置定时器的自动装载值,以确定下一个中断发生的时间点。

以下是重构后的内容:

TIMx_CR1寄存器控制定时器的运行模式和中断功能。如果ARPE位为0,ARR寄存器的内容将直接写入影子寄存器;如果ARPE为1,ARR寄存器的内容将再每次的更新事件UEV发生时,传送到影子寄存器。如果TIMx_CR1中的UDIS位为0,当计数器产生溢出条件时,产生更新事件。

控制寄存器1(TIMx_CR1)用于配置定时器的运行模式和中断功能。

DMA中断使能寄存器(TIMx_DIER)用于启用或禁用定时器的DMA中断。

定时器中断实现步骤如下:

1. 使能定时器时钟。

2. 初始化定时器,配置ARR(自动装载寄存器)和PSC(预分频寄存器),即配置自动装载寄存器TIMx_ARR和预分频寄存器值TIMx_PSC。

3. ARR和PSC的确定方法:我们知道计数器ARR溢出后会产生更新中断,我们以中心对齐模式的时序图来说明。上图中CK_INT前面已说过,其频率由APB1来决定,若使用默认时钟SystemInit初始化的话,CK_INT=72MHz。CK_CNT的确定方法可以参考下图。

示例程序:通过定时器中断配置,实现每500ms中断一次,通过定时中断实现LED灯闪烁。

```c

// 使能定时器时钟

RCC_APB1PeriphClockCmd();

// 初始化定时器,配置ARR和PSC

TIM_TimeBaseInit(TIM_TypeDef* TIMx, IM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

// 通过定时器中断配置,实现每500ms中断一次,通过定时中断实现LED灯闪烁

while (1) {

// 主循环

}

```

根据提供的内容,我们可以重构如下:

CK_INT = APB1 或 APB1 * 2

Fck_psc = CK_INT

T = 1 / CK_CNT

Tout(溢出时间) = (ARR + 1) * T

其中,CK_INT 是时钟输入信号,Fck_psc 是时钟频率,T 是时钟周期时间,Tout(溢出时间) 是计数器溢出产生的中断时间。

为了满足需求,我们需要将中断时间设置为500ms。首先,我们需要计算出相应的 Fck_psc 和 ARR 值。已知 Fck_psc = CK_INT = 72MHz,我们可以使用以下公式计算 ARR:

Tout(溢出时间) = (ARR + 1) * T

500ms = (ARR + 1) * (PSC[15:0] + 1) / 72000

解这个方程,我们可以得到 ARR = 4999。然后,我们需要将 ARR 和 PSC 配置到寄存器中。最后,我们可以根据计算出的 Fck_psc 值来设置时钟频率。

. 开启定时器中断并配置NVIC。

```c

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

{

// 配置定时器中断

}

void NVIC_Init()

{

// 初始化NVIC

}

```

4. 使能定时器。

```c

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

{

// 使能或禁用定时器

}

```

5. 编写中断服务函数。

```c

void TIMx_IRQHandler()

{

// 处理定时器中断事件

}

```

7. 程序编写:STM32通用定时器在此篇仅记录了定时器基本的概念和时基单元的功能编程。由于篇幅的限制,通用定时器的输入和输出功能将在下篇介绍。