定时器分频系数-1理解

在 STM32 定时器的配置中,TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/1000000 - 1; 这里减去 1 是由定时器预分频器的工作原理决定的。下面为你详细解释:

定时器预分频器的工作原理

定时器的预分频器(Prescaler)用于对输入时钟信号进行分频,从而降低定时器计数器的计数频率。预分频器的值(TIM_Prescaler)是一个无符号整数,它决定了输入时钟信号要经过多少次计数才会使定时器计数器加 1。

在 STM32 中,预分频器的工作方式是:当定时器的预分频器寄存器(TIMx_PSC)中的值为 N 时,输入时钟信号要经过 N + 1 个时钟周期,定时器计数器才会加 1。也就是说,实际的分频系数是 TIM_Prescaler + 1

代码解释

假设 SystemCoreClock 是系统的核心时钟频率,例如在 STM32F103 系列中,系统时钟频率可以达到 72MHz。现在我们想要将定时器的计数频率设置为 1MHz,那么就需要对系统时钟进行分频。

分频系数 = 系统时钟频率 / 目标计数频率,即 SystemCoreClock / 1000000

但由于预分频器的实际分频系数是 TIM_Prescaler + 1,所以为了得到我们期望的分频系数,需要将计算得到的理论分频系数减 1 后再赋值给 TIM_Prescaler

例如,如果系统时钟频率 SystemCoreClock 为 72MHz,我们希望定时器的计数频率为 1MHz,那么理论分频系数为 72000000 / 1000000 = 72。但由于预分频器的实际分频系数是 TIM_Prescaler + 1,所以需要将 TIM_Prescaler 设置为 72 - 1 = 71,这样实际的分频系数就是 71 + 1 = 72,从而将定时器的计数频率降低到 1MHz。

示例代码

#include "stm32f10x.h"

void TIM_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    // 使能定时器时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    // 配置定时器时基结构体
    TIM_TimeBaseStructure.TIM_Period = 1000 - 1;  // 定时器周期
    TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/1000000 - 1;  // 预分频器
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;  // 时钟分频
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  // 计数模式

    // 初始化定时器时基
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    // 使能定时器
    TIM_Cmd(TIM2, ENABLE);
}

在这个示例中,通过将 TIM_Prescaler 设置为 SystemCoreClock/1000000 - 1,将定时器的计数频率设置为 1MHz,然后将 TIM_Period 设置为 1000 - 1,可以实现 1ms 的定时周期。

综上所述,在设置定时器预分频器的值时减去 1 是为了补偿预分频器实际分频系数为 TIM_Prescaler + 1 的特性,从而得到我们期望的分频效果。

实际的分频系数为什么是 TIM_Prescaler + 1。

在 STM32 定时器中,实际的分频系数是 TIM_Prescaler + 1,这主要是由硬件设计和计数逻辑决定的,下面从计数逻辑原理和硬件设计意图两方面来详细解释:

计数逻辑原理

定时器的预分频器本质上是一个计数器,它会对输入的时钟信号进行计数。当预分频器寄存器(TIMx_PSC)被设置为一个值 TIM_Prescaler 时,预分频器会从 0 开始计数,一直计到 TIM_Prescaler 这个值。

  • 假设 TIM_Prescaler 设置为 0,预分频器从 0 开始计数,计到 0 时,实际上已经经过了 1 个时钟周期,此时定时器计数器加 1,也就是实际的分频系数为 1(即 0 + 1)。
  • 若 TIM_Prescaler 设置为 1,预分频器从 0 开始计数,依次经过 0、1 这两个值,总共经过了 2 个时钟周期,定时器计数器才加 1,实际的分频系数为 2(即 1 + 1)。
  • 一般地,当预分频器寄存器的值为 TIM_Prescaler 时,预分频器会从 0 计数到 TIM_Prescaler,总共经历 TIM_Prescaler + 1 个时钟周期,定时器计数器才会加 1,所以实际的分频系数就是 TIM_Prescaler + 1

硬件设计意图

从硬件设计的角度来看,将实际分频系数设计为 TIM_Prescaler + 1 有以下好处:

实现最小分频系数为 1

如果直接将 TIM_Prescaler 作为分频系数,那么当 TIM_Prescaler 设置为 0 时,就无法实现分频(因为分频系数不能为 0)。而采用 TIM_Prescaler + 1 的方式,当 TIM_Prescaler 设置为 0 时,实际分频系数为 1,这样可以方便地实现最小分频系数为 1 的情况,使得定时器可以直接使用输入时钟信号进行计数。

简化计数逻辑

采用 TIM_Prescaler + 1 的计数方式,预分频器可以从 0 开始计数,这样在硬件实现上可以简化计数器的逻辑。计数器只需要简单地从 0 开始递增,当计数值等于 TIM_Prescaler 时,就触发定时器计数器加 1 的操作,无需额外的逻辑来处理分频系数为 1 的特殊情况。

示例说明

假设系统时钟频率为 8MHz,我们希望将定时器的计数频率设置为 4MHz,即需要对系统时钟进行 2 分频。根据实际分频系数为 TIM_Prescaler + 1 的规则,我们应该将 TIM_Prescaler 设置为 1,因为 1 + 1 = 2,这样预分频器会在经过 2 个系统时钟周期后,让定时器计数器加 1,从而实现 2 分频的效果,将定时器的计数频率降低到 4MHz。

综上所述,实际的分频系数为 TIM_Prescaler + 1 是由定时器的计数逻辑和硬件设计决定的,这种设计方式既方便了实现最小分频系数为 1 的情况,又简化了硬件计数逻辑。

TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 定时器周期 为什么要减1

在 STM32 定时器配置中,TIM_TimeBaseStructure.TIM_Period = 1000 - 1; 这里减去 1 同样是由定时器计数器的工作机制决定的。下面为你详细解释其中的原理。

定时器计数器的工作机制

定时器的计数器会在每个时钟周期进行计数操作,计数方向可以是向上计数(从 0 开始递增)、向下计数(从预设值开始递减)或中央对齐计数等,常见的是向上计数模式。

定时器的自动重载寄存器(TIMx_ARR)用于存储一个预设值,也就是 TIM_Period 所对应的值。当计数器的值达到自动重载寄存器中的值时,会产生更新事件(如计数器溢出),并且计数器会根据配置重新归零或者重新加载初始值继续计数。

在 STM32 定时器中,计数器是从 0 开始计数的。例如,当 TIM_Period 设置为 0 时,计数器从 0 开始计数,计到 0 时就达到了预设值,此时就会产生更新事件,实际上只经历了 1 个计数周期。

代码解释

当我们想要设置定时器的周期为 1000 个计数周期时,由于计数器是从 0 开始计数的,所以当计数器的值从 0 递增到 999 时,刚好经历了 1000 个计数周期(分别是 0、1、2、...、999 这 1000 个值),此时就达到了我们期望的 1000 个计数周期,因此需要将 TIM_Period 设置为 1000 - 1 = 999

示例理解

假设定时器的计数频率为 1kHz(即每 1ms 计数器加 1),我们希望定时器每 1s 产生一次更新事件。由于 1s 包含 1000 个 1ms,也就是需要 1000 个计数周期,此时就应该将 TIM_Period 设置为 1000 - 1 = 999。当计数器从 0 开始计数,依次经过 0、1、2、...、999 这 1000 个值后,刚好过去了 1s 的时间,就会产生更新事件。

代码示例

#include "stm32f10x.h"

void TIM_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    // 使能定时器时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    // 配置定时器时基结构体
    TIM_TimeBaseStructure.TIM_Period = 1000 - 1;  // 定时器周期,1000个计数周期
    TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/1000000 - 1;  // 预分频器,使计数频率为1MHz
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;  // 时钟分频
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  // 向上计数模式

    // 初始化定时器时基
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    // 使能定时器
    TIM_Cmd(TIM2, ENABLE);
}

在上述代码中,TIM_Period 设置为 1000 - 1,结合预分频器的设置,定时器每 1000 个计数周期(也就是 1ms)就会产生一次更新事件。

综上所述,在设置定时器周期时减去 1 是为了补偿计数器从 0 开始计数的特性,从而得到我们期望的计数周期数和定时时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值