目录

前言

定时器分类

一、STM32 基本定时器

1.1、基本定时器功能框图讲解

1.2、时钟源

1.3、计数器时钟

1.4、计数器

1.5、自动重装载寄存器

1.6、定时时间的计算

二、STM32 通用定时器

2.1、通用定时器简介

2.2、TIMx主要功能

2.3、STM32 的通用寄存器

三、实现程序的步骤

3.1、基本定时器实现程序步骤

3.2、基本定时器实验现象

3.3、通用定时器实现程序步骤

3.4、通用定时器实验现象


前言

定时器分类

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

基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。

通用定时器 TIM2、3、4、5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。

高级定时器 TIM1、8 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。

一、STM32 基本定时器

1.1、基本定时器功能框图讲解

基本定时器的核心是时基,不仅基本定时器有,通用定时器和高级定时器也有。

可编程通用定时器的主要部分是一个16位计数器和与其相关的自动装载寄存器。这个计数器可以向上计数、向下计数或者向上向下双向计数。此计数器时钟由预分频器分频得到。 计数器、自动装载寄存器和预分频器寄存器可以由软件读写,在计数器运行时仍可以读写。

时基单元包含:

● 计数器寄存器(TIMx_CNT)

● 预分频器寄存器 (TIMx_PSC)

● 自动装载寄存器 (TIMx_ARR) 

1.2、时钟源

定时器时钟 TIMxCLK即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果 APB1 预分频 系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M, 所以定时器时钟 TIMxCLK=36*2=72M。

        1.3、计数器时钟

定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数。PSC 是一个 16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。具体计算方式 为:CK_CNT=TIMxCLK/(PSC+1)。

1.4、计数器

        计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。

1.5、自动重装载寄存器

 自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。

1.6、定时时间的计算

        定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在 CK_CNT 的驱动下,计一 个数的时间则是 CK_CLK 的倒数,等于:1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于: 1/(CK_CLK * ARR)。如果在中断服务程序里面设置一个变量 time,用来记录中断的次数,那么就可以计算出我们需要的定时时间等于:1/CK_CLK* (ARR+1)*time。

二、STM32 通用定时器

2.1、通用定时器简介

STM32F1的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器 (CNT)构成。

STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。

STM32 的每个通用定时器都是完全独立的, 没有互相共享的任何资源。

2.2、TIMx主要功能

通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:

● 16位向上、向下、向上/向下自动装载计数器

自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到 这个值的时候,如果使能了中断的话,定时器就产生溢出中断。

● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意 数值

● 4个独立通道:

─ 输入捕获

─ 输出比较

─ PWM生成(边缘或中间对齐模式)

─ 单脉冲模式输出

● 使用外部信号控制定时器和定时器互连的同步电路

● 如下事件发生时产生中断/DMA:

─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)

─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

─ 输入捕获

─ 输出比较

● 支持针对定位的增量(正交)编码器和霍尔传感器电路

● 触发输入作为外部时钟或者按周期的电流管理

2.3、STM32 的通用寄存器

控制寄存器 1(TIMx_CR1)

TIMx_CR1 的最低位,也就是计数器使能位,该位必须置 1,才能让定时器开始计数。

从第 4 位 DIR 可以看出默认的计数方式是向上计数,同时也可以向下计数。

第 5,6 位是设置计数对齐方式的。

第 8 和第 9 位可以看出,可以设置定时器的时钟分频因子为 1,2,4。

DMA/中断使能寄存器 (TIMx_DIER),该寄存器是一个 16 位的寄存器。

  它的第 0 位,该位是更新中断允许位,用到的是定时器的更新中断,所以该位要设置为 1,来允许由于更新事件所产生的中断。

预分频寄存器(TIMx_PSC),该寄存器用设置对时钟进行分频,然后提供给计数器,作为计数器的时钟。

通过 TIMx_SMCR 寄存器的相关位来设置时钟:1.内部时钟(CK_INT)2.外部时钟模式 1:外部输入脚(TIx)3.外部时钟模式 2:外部触发输入(ETR)4.内部触发输入(ITRx):使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟)。

这里的 CK_INT 时钟是从 APB1 倍频的来的,除非 APB1 的时钟分频数设置为 1,否则通用定时器 TIMx 的时钟是 APB1 时钟的 2 倍,当 APB1 的时钟不分频的时候,通用定时器 TIMx 的时钟就等于 APB1 的时钟。这里还要注意的就是高级定时器的时钟不是来自 APB1,而是来自 APB2 的。

TIMx_CNT 寄存器,该寄存器是定时器的计数器,该寄存器存储了当前定时器的计数值。 

 自动重装载寄存器(TIMx_ARR)在物理上实际对应着 2 个寄存器。 一个是程序员可以直接操作的,另外一个是影子寄存器。

        真正起作用的是影子寄存器。根据 TIMx_CR1 寄存器中 APRE 位的设置:APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2 者是连通的;而 APRE=1 时,在每一次更新事件(UEV)时,才把预装在寄存器的内容传送到影子寄存器。

状态寄存器(TIMx_SR)用来标记当前与定时器相关的各种事件/中断是否发生。

三、实现程序的步骤

使用定时器产生中断,然后在中断服务函数里面翻转 DS1 上的电平,来指示定时器中断的产生。

3.1、基本定时器实现程序步骤

(1) TIM_Prescaler:定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定 TIMx_PSC 寄存器的值。可设置范围为 0 至 65535,实现 1 至 65536 分频。

(2) TIM_CounterMode:定时器计数方式,可是在为向上计数、向下计数以及三种中心对齐模式。 基本定时器只能是向上计数,即 TIMx_CNT 只能从 0 开始递增,并且无需初始化。

(3) TIM_Period:定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄 存器。可设置范围为 0 至 65535。

(4) TIM_ClockDivision:时钟分频,设置定时器时钟 CK_INT 频率与数字滤波器采样时钟频率分 频比,基本定时器没有此功能,不用设置。

(5) TIM_RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出 PWM 的个数。这里不用设置。

LED.h代码如下所示:

#ifndef __LED_H
#define __LED_H#include "stm32f10x.h"/* 定义LED连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的LED引脚 */
// R-红色
#define LED1_GPIO_PORT      GPIOB                         /* GPIO端口 */
#define LED1_GPIO_CLK       RCC_APB2Periph_GPIOB        /* GPIO端口时钟 */
#define LED1_GPIO_PIN       GPIO_Pin_5                  /* 连接到SCL时钟线的GPIO */#define ON  0
#define OFF 1/* 使用标准的固件库控制IO*/
#define LED1(a) if (a)  \GPIO_SetBits(LED1_GPIO_PORT,LED1_GPIO_PIN);\else       \GPIO_ResetBits(LED1_GPIO_PORT,LED1_GPIO_PIN)/* 直接操作寄存器的方法控制IO */
#define digitalHi(p,i)       {p->BSRR=i;}    //输出为高电平
#define digitalLo(p,i)       {p->BRR=i;}     //输出低电平
#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态/* 定义控制IO的宏 */
#define LED1_TOGGLE      digitalToggle(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_OFF           digitalHi(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_ON            digitalLo(LED1_GPIO_PORT,LED1_GPIO_PIN)void LED_GPIO_Config(void);#endif /* __LED_H */

LED.c程序如下所示:

#include "bsp_led.h"   void LED_GPIO_Config(void)
{       /*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启LED相关的GPIO外设时钟*/RCC_APB2PeriphClockCmd( LED1_GPIO_CLK , ENABLE);/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN; /*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置引脚速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIO*/GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure); /* 关闭所有led灯 */GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);}

TIMEBASE.h程序如下所示:

#ifndef __BSP_TIMEBASE_H
#define __BSP_TIMEBASE_H#include "stm32f10x.h"#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_Period            (1000-1)
#define            BASIC_TIM_Prescaler         71
#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_Period            1000-1
#define            BASIC_TIM_Prescaler         71
#define            BASIC_TIM_IRQ               TIM7_IRQn
#define            BASIC_TIM_IRQHandler        TIM7_IRQHandler#endifvoid BASIC_TIM_Init(void);#endif    /* __BSP_TIMEBASE_H */

TIMEBASE.c程序如下所示:

// 基本定时器TIMx,x[6,7]定时初始化函数
#include "bsp_TiMbase.h" // 中断优先级配置
static void BASIC_TIM_NVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);     // 设置中断来源NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQ ;  // 设置主优先级为 0NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   // 设置抢占优先级为3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}/** 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有* TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,* 另外三个成员是通用定时器和高级定时器才有.*-----------------------------------------------------------------------------*typedef struct*{ TIM_Prescaler            都有*  TIM_CounterMode              TIMx,x[6,7]没有,其他都有*  TIM_Period               都有*  TIM_ClockDivision        TIMx,x[6,7]没有,其他都有*  TIM_RepetitionCounter    TIMx,x[1,8,15,16,17]才有*}TIM_TimeBaseInitTypeDef; *-----------------------------------------------------------------------------*/static void BASIC_TIM_Mode_Config(void)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;// 开启定时器时钟,即内部时钟CK_INT=72MBASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period;   // 时钟预分频数为TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM_Prescaler;// 时钟分频因子 ,基本定时器没有,不用管//TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置//TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,基本定时器没有,不用管//TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 初始化定时器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);
}void BASIC_TIM_Init(void)
{BASIC_TIM_NVIC_Config();BASIC_TIM_Mode_Config();
}

main.c程序如下所示:


// 基本定时器TIMx,x[6,7]定时应用
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_TiMbase.h"volatile uint32_t time = 0; // ms 计时变量 int main(void)
{/* led 端口配置 */ LED_GPIO_Config();BASIC_TIM_Init();while(1){if ( time == 1000 ) /* 1000 * 1 ms = 1s 时间到 */{time = 0;/* LED1 取反 */      LED1_TOGGLE; }        }
}

3.2、基本定时器实验现象

正点原子精英开发板LED0红灯每隔一秒闪烁一次;

3.3、通用定时器实现程序步骤

time.h程序如下所示:

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"void TIM3_Int_Init(u16 arr,u16 psc);#endif

time.c程序如下所示:

#include "timer.h"
#include "led.h"   //通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能//定时器TIM3初始化TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值   TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断//中断优先级NVIC设置NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器TIM_Cmd(TIM3, ENABLE);  //使能TIMx
}
//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否{TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 LED1=!LED1;}
}

main.c程序如下所示

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"int main(void){     delay_init();            //延时函数初始化    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级uart_init(115200);     //串口初始化为115200LED_Init();               //LED端口初始化TIM3_Int_Init(4999,7199);//10Khz的计数频率,计数到5000为500ms  while(1){LED0=!LED0;delay_ms(200);         }     }   

3.4、通用定时器实验现象

正点原子精英开发板LED0红灯闪烁的比LED1绿灯快;

学习记录:TIM—基本定时器相关推荐

  1. 学习记录:TIM—电容按键检测

    目录 前言 一.电容按键原理 1.1.无手指触摸电容按键 1.2.有手指触摸电容按键 1.3.Vc 电压与充电时间关系 二.程序设计 2.1.设计思路 2.2.检测电容按键按下的具体过程 2.3.工程 ...

  2. 蓝桥杯STM32G431学习记录9——基本定时器CubeMX配置及使用

    定时器模块 定时器总体概述 定时器计数方式 复用引脚分配图(可通过此图查阅各个IO口的复用功能并进行配置) 基本定时器 基本定时器TIM6/7内部结构图 基本定时器CubeMX配置 basic_tim ...

  3. 面向应用学习stm32(6)-TIM基本定时器-计数计时

    前导:本文的目的与,意在于面向应用的学习单片机,故不会涉及太多的原理知识,例如寄存器之类的. 主要目的在于面向应用的学习单片机,学会单片机的基础用法,开发板采取野火的指南者f103. 作者大二小白,写 ...

  4. **51 32 学习记录**

    51 32 学习记录 STM32的时钟选择 (103) APB2总线时钟:最大72MHz,挂载了高级定时器 APB1总线时钟:最大36MHZ,挂在了通用定时器 定时器的时钟选择: 1.内部时钟, 2. ...

  5. 架构与设计 之一 C 嵌入式设计模式(Design Patterns for Embedded Systems in C)的学习记录

    唉   时至今日,已经不知道在嵌入式的道路上到底挣扎了多少个岁月,总感觉要"病入膏肓"了.此间总是不时出现一些疑惑:人家搞 Java.搞 C# 的动不动就是什么架构 / 框架的,搞 ...

  6. python大神的成长之路_Python大神成长之路: 第三次学习记录 集合 函数 装饰 re...

    学习记录day03 字符串可以直接切片,But字符串不可修改 字符串修改:生成了一个新的字符串 LIst修改,在原基础上修改(原内存上) 集合是一个无序的,不重复的数据组合,它的主要作用如下: 去重, ...

  7. react基础学习记录一

    react 学习记录 自己学习,记录便于后面回顾 基础知识点的记忆: state与props state是组件自己的数据,而props是父组件通过属性赋值方式将其传送给组件:这样达到了,父子组件数据的 ...

  8. JavaScript-WebAPIs学习记录

    JavaScript-WebAPIs学习记录 浏览器交互效果 console.dir(); // 更好地查看里面的属性和方法 javascript:void(0); 或者 javascript:; 可 ...

  9. 第31章 TIM—基本定时器—零死角玩转STM32-F429系列

    第31章     TIM-基本定时器 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...

  10. 前端逻辑练习题+学习记录 不定期更新

    编程题 1.返回数组中最大的数字(reduce函数) largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1 ...

最新文章

  1. 0x13.基础数据结构 — 链表与邻接表
  2. 在C#用HttpWebRequest中发送GET/HTTP/HTTPS请求
  3. soap php 分开类,PHP SoapClient类型映射的行为有所不同
  4. http 二进制_浅谈HTTP协议
  5. mysql数据异常增长_mysql表到一定数据量后会异常的增长
  6. 将之前写完的猜数字游戏改为通过javabean_42个宝宝益智游戏良心整理!让宝宝快人一步更聪明...
  7. 水文勘测工比赛计算机基本应用,第四届全国水文勘测工大赛内业操作试题A卷.doc...
  8. NodeManager 启动一会儿挂掉
  9. linux分区挂载点在哪个文件,挂载的信息是存放在哪个文件中?
  10. java 基础 —— 文件操作(File)
  11. 41. 使用内容发布网络(2)
  12. 大数据笔记_Hadoop基础知识
  13. adb提示已停止工作问题的解决方案
  14. 甲方爸爸素材给得少,怎么做出高大上的设计?
  15. Html监听Fbx文件加载,一些three.js的基础——加载FBX模型
  16. 项目经理的工具箱---走出软件作坊:三五个人十来条枪 如何成为开发正规军(三)
  17. HTML、CSS要点精华
  18. Techo TVP物联网开发者峰会青润的总结
  19. 小米、字节跳动、滴滴、英特尔、耐克、捷豹路虎等公司高管变动
  20. 测试环境docker-swarm安装部署

热门文章

  1. IntelliJ IDEA快捷键大全 + 动图演示
  2. 如何在win7下装win8以及我的win8之旅
  3. PyTorch报错:RuntimeError: CUDA error: device-side assert triggered at /pytorch/aten/src/THC/generic
  4. java版真女神转生系列_《真女神转生》适合新手融合的仲魔表
  5. 从Google Drive用命令行下载大文件
  6. 采用空白文件目录结构管理磁盘空间,实现磁盘空间的分配和回收
  7. 苹果审核的这些坑,我踩过现在写出来让你避坑
  8. 关于日志埋点的一些絮絮叨叨
  9. 把握刷脸支付行业致富的商机
  10. java图案_用java实现 图片组成心形图案