超乎你想象的Stm32中的TIM定时器


注:本文属博主学习时所作笔记,内容源大参考于野火的《零死角玩转STM32F103》以及部分网络资料,笔记内容仅作为自己参考,免去频繁查询参考手册的麻烦,如有错误,还请指出!

定时器分类

STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。

类别 定时器 分辨率 计数器类型 预分频系数 产生DMA 捕获/比较通道 互补输出
高级定时器 TIM1,TIM8 16位 向上/向下 1~65535 可以 4
通用定时器 TIM2<sub>TIM5 16位 向上/向下 165535 可以 4
基本定时器 TIM6,TIM7 16位 向上 1~65535 可以 0

基本定时器

  1. 时钟源 TIMxCLK由APB1预分频提供,库函数中 APB1 预分频系数为 2 ,定时器时钟TIMxCLK = 36 * 2 =72

  2. 计数器时钟 CK_CNT 经 PSC 得到,PSC是16位预分频器,可对 TIMxCLK 进行1~65536 之间任意一个数进行分频:CK_INT=TIMxCLK/(PSC + 1)

  3. 计数器 CNT 是一个16位的计数器,只能向上计数,最大值位65535,计数值到达自动重装载寄存器时,产生更新时间,清零重新计数

  4. 自动重装载寄存器 ARR 是一个16位计数器,存放最大计数值,到达此值,如果开启中断,则定时器产生中断

定时时间计算

定时器的定时时间等于计数器的中断周期乘以中断的次数。这里用定时 500ms 作为例子:

  • 设置PSC预分频器为 72 - 1 = 71 MHz,则定时器频率为 72M/(PSC + 1) = 1 MHz
  • 设置 ARR = 1000 - 1,0 ~ 999,计数1000次
  • 中断周期 T = 1000 * 1 / 1000000 = 1 ms,(1MHz 周期为 1 ns)

定时器初始化结构体

基本定时器只用到TIM_TimeBaseInitTypeDef结构体:

typedef struct {
    uint16_t TIM_Prescaler;         // 预分频器
    uint16_t TIM_CounterMode;         // 计数模式,向上或向下
    uint32_t TIM_Period;             // 定时器周期
    uint16_t TIM_ClockDivision;     // 外部时钟分频
    uint8_t TIM_RepetitionCounter;     // 重复计算器,高级寄存器专用
} TIM_TimeBaseInitTypeDef;

而且只用到两个成员TIM_PrescalerTIM_Period,也就是定时器分配器设置和定时器周期(自动重装载寄存器值)。

代码实例——实现 1s 定时

初始化基本定时器

/********************基本定时器 TIM 参数定义,只限 TIM6、 7************/

#define BASIC_TIM6         // 如果使用 TIM7,注释掉这个宏即可

#ifdef  BASIC_TIM6         // 使用基本定时器 TIM6
#define BASIC_TIM                         TIM6
#define BASIC_TIM_APBxClock_FUN         RCC_APB1PeriphClockCmd
#define BASIC_TIM_CLK                     RCC_APB1Periph_TIM6
#define BASIC_TIM_IRQ                     TIM6_IRQn
#define BASIC_TIM_IRQHandler             TIM6_IRQHandler

#else                     // 使用基本定时器 TIM7
#define BASIC_TIM                         TIM7                        // 定时器
#define BASIC_TIM_APBxClock_FUN         RCC_APB1PeriphClockCmd        // 时钟函数
#define BASIC_TIM_CLK                     RCC_APB1Periph_TIM7            // 时钟
#define BASIC_TIM_IRQ                     TIM7_IRQn                    // 中断源
#define BASIC_TIM_IRQHandler             TIM7_IRQHandler                // 中断服务函数

#endif
void BASIC_TIM_Config(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    // 开启定时器时钟,即内部时钟 CK_INT=72M
    BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);

    // 自动重装载寄存器周的值(计数值)
    TIM_TimeBaseStructure.TIM_Period=1000;

    // 累计 TIM_Period 个频率后产生一个更新或者中断
    // 时钟预分频数为 71,则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M
    TIM_TimeBaseStructure.TIM_Prescaler= 71;

    // 其余三个结构体变量,基本定时器没有,不用管

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

    // 清除计数器中断标志位
    TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);

    // 开启计数器中断
    TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);

    // 使能计数器
    TIM_Cmd(BASIC_TIM, ENABLE);

    // 暂时关闭定时器的时钟,等待使用
    BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, DISABLE);
 }  

把定时器设置自动重装载寄存器 ARR 的值为 1000,设置时钟预分频器为 71,则驱动计数器的时钟: CK_CNT = CK_INT / (71+1)=1M,则计数器计数一次的时间等于:1/CK_CNT=1us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间为: 1/CK_CNT*ARR = 1ms。

定时器中断优先级配置

// 中断优先级配置
void BASIC_TIM_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    // 设置中断组为 0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    // 设置中断来源为基本定时器
    NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQ ;
    // 设置主优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    // 设置抢占优先级为 3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
 }  

定时器中断服务程序

void BASIC_TIM_IRQHandler (void)
{
    if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ) {
        time++;
        TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);
    }
}

定时器中断一次的时间是 1ms,定义一个全局变量 time 表示中断次数。实现一个 1s 的定时,只需判断 time 是否等于 1000 即可, 1000 * 1ms = 1s。然后把 time 清 0,重新计数,在最后,需要将中断标志位清除掉。

主函数

int main(void)
{
    /* led 端口配置 */
    LED_GPIO_Config();

    /* 基本定时器 TIMx,x[6,7] 定时配置 */
    BASIC_TIM_Config();

    /* 配置基本定时器 TIMx,x[6,7]的中断优先级 */
    BASIC_TIM_NVIC_Config();

    /* 基本定时器 TIMx,x[6,7] 重新开时钟,开始计时 */
    BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);

    while (1) {
        if ( time == 1000 ) { 
            /* 1000 * 1 ms = 1s 时间到 */
            time = 0;
            /* LED1 取反 */
            LED1_TOGGLE;
        }
    }
 }

文章作者: Mahoo Huang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mahoo Huang !
评论
 上一篇
Express & MongoDB 实战 Express & MongoDB 实战
开发环境配置配置 Express安装 express & express 脚手架 npm install express -g npm i express-generator -g 通过查看版本号,检验是否安装成功: expres
2020-04-11
下一篇 
简单入门CSS预处理器Less和Sass 简单入门CSS预处理器Less和Sass
Sass和Less都属于CSS预处理器,CSS预处理器定义了一种新的语言,其基本的思想是,用一种特殊的语言,为CSS增加一些编程的特性,如变量、语句,函数、继承等概念。将CSS作为目标生成文件,然后开发者就只要使用这种语言进行CSS的编码开
2020-03-08
  目录