stm32初学之定时器TIM的基本定时功能以及介绍 您所在的位置:网站首页 定时器什么原理 stm32初学之定时器TIM的基本定时功能以及介绍

stm32初学之定时器TIM的基本定时功能以及介绍

2023-07-04 19:19| 来源: 网络整理| 查看: 265

文章目录 前言一、定时器基本介绍以及定时器原理图1.定时器基本介绍2.定时器原理图3.定时器配置 二、定时器计算

前言

提示:以下是本篇文章正文内容,下面案例可供参考

一、定时器基本介绍以及定时器原理图 1.定时器基本介绍

定时器可以分为基本定时器、通用定时器和高级定时器。对于stm32f103系列来言,对于基本定时器平时只来用于计数,以及对于dma的请求,对于计数上基本定时器只能向上计数,对于通用定时器以及高级定时器可以向上向下计数,其他两种定时器可以完成的功能有很多,例如输入捕获、输出比较、pwm波的输出。 输入捕获:管脚开启功能,定时器在内部时钟的作用下在运行,此时管脚来了个中断,假如上升沿吧。在中断的作用下,定时器停止工作,此时可以读出定时器的数值,读出后再开启定时器,等待下次中断,再读取一次定时器数值,二次相减,就可求出二次中断的间隔时间。 输出比较:有一寄存器先存放你要定时的数,例如50.定时器在内部时钟下有0开始慢慢向上加,没加一次都会和那个寄存器比较,当等于那个寄存器值时 如50,此管脚就会跳变(输出一高电平或低电平)。 输入捕获和输出比较就相当于秒表和闹钟,都是定时器的基本功能。 输出pwm波,就是可以通过pwm波的占空比(高电平所占用时间/总时间:通电时间相对于总时间所占的比例)比如改变pwm的占空比可以改变led的亮暗。

2.定时器原理图

以通用定时器的原理图为例子: 通用定时器 通用定时器原理图可以分为四部分:时钟生成、时基、输入捕获、输出,在这五部分中,基础定时器只有个时钟生成部分。 一、时钟生成部分: 图中1部分:1、RCC寄存器中的APB1外设时钟使能寄存器,经过倍频之后输出时钟源,这是因为该寄存器的位0到位5分别表示的是定时器2到定时器7的使能位。(位于图上第一部分)

2、外部触发引脚TIMx_ETR的外部触发输入ETR,对应的引脚可以通过查数据手册得到。ETR经过分频得到ETRP,在经过滤波得到ETRF作为时钟信号。(位于图上第一部分)

3、内部触发输入(ITRx),来自其他的定时器的时钟,即将,经过后面的选择器,进入到触发控制器。(位于图上第一部分)

4、外部输入引脚Tix,这个主要来自于TIMx_CHx (四个通道)。(位于图上第四部分) 上图第二部分也属于时钟生成部分,即是时钟生成后经过触发器到其他定时器或者到dac和adc中去

二 时基部分: 这也是定时器的主要部分这部分主要是3这一部分,包括PSC预分频器、自动重装载寄存器和CNT计数器。首先由第一部分产生时钟源,进入PSC预分频器进行分频处理,得到新的时钟信号CK_CNT,使得CNT计数器加1或者减1,此时在自动重装载寄存器中有一个预先设定的装载值,当计数器的值达到装载值的时候,会产生溢出事件,然后触发中断。如何去计算时间后边会附上

第三部分为输入捕获: 上图中4,TIMx_CH1——TIMx_CH4 这四个通道,在芯片中都有对应的引脚,当脉冲从通道口进入时,经过输入滤波器(抗干扰的作用),然后经过边沿检测器检测到上升沿(下降沿),经过分频器,输入到公用部分中的捕获寄存器中,然后捕获寄存器记录此刻CNT计数器的值,当下一次下降沿(上升沿)过来时,也记录下CNT计数器的值,这样就可以计算出输入脉冲的宽度。

第四部分为输出比较(注意输入捕获和输出比较不可以同时进行) 上图中5,比如在比较寄存器中预先设定一个值,计数器从初始值到装载值之间计数时,当正好等于比较寄存器中的预设值时,控制TIMx_CH1——TIMx_CH4通道输出低电平或者高电平,这样随着计数器不断的计数,就可以获得一个脉冲,通过调整预设值,就可以调整脉冲宽度,调整初始值和装载值就可以调整周期就如同一个闹钟一样。

3.定时器配置

1、 编程要点 (1) 开定时器时钟 TIMx_CLK, (2) 初始化时基初始化结构体 ; (3) 使能 TIMx, update 中断; (4) 打开定时器; (5) 编写中断服务程序 通用定时器和高级定时器的定时编程要点跟基本定时器差不多,只是还要再选择下计数器的计数模式,是向上还是向下。因为基本定时器只能向上计数,且没有配置计数模式的寄存器,默认是向上。

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

2 #define BASIC_TIM6 // 如果使用 TIM7,注释掉这个宏即可 3 4 #ifdef BASIC_TIM6 // 使用基本定时器 TIM6 5 #define BASIC_TIM TIM6 6 #define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd 7 #define BASIC_TIM_CLK RCC_APB1Periph_TIM6 8 #define BASIC_TIM_IRQ TIM6_IRQn 9 #define BASIC_TIM_IRQHandler TIM6_IRQHandler 10 11 #else // 使用基本定时器 TIM7 12 #define BASIC_TIM TIM7 13 #define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd 14 #define BASIC_TIM_CLK RCC_APB1Periph_TIM7 15 #define BASIC_TIM_IRQ TIM7_IRQn 16 #define BASIC_TIM_IRQHandler TIM7_IRQHandler 17 18 #endif

基本定时器有 TIM6 和 TIM7,我们可以有选择的使用,为了提高代码的可移植性,我们把当需要修改定时器时需要修改的代码定义成宏,默认使用的是定时器 6,如果想修改成定时器 7,只需要把宏 BASIC_TIM6 注释掉即可。

基本定时器设定

void BASIC_TIM_Config(void) 2 { 3 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 4 5 // 开启定时器时钟,即内部时钟 CK_INT=72M 6 BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE); 7 8 // 自动重装载寄存器周的值(计数值) 9 TIM_TimeBaseStructure.TIM_Period=1000; 10 11 // 累计 TIM_Period 个频率后产生一个更新或者中断 12 // 时钟预分频数为 71,则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M 13 TIM_TimeBaseStructure.TIM_Prescaler= 71; 14 15 // 时钟分频因子 ,基本定时器没有,不用管 16 //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 17 18 // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置 19 //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; 20 21 // 重复计数器的值,基本定时器没有,不用管 22 //TIM_TimeBaseStructure.TIM_RepetitionCounter=0; 23 24 // 初始化定时器 25 TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure); 26 27 // 清除计数器中断标志位 28 TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update); 29 30 // 开启计数器中断 31 TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE); 32 33 // 使能计数器 34 TIM_Cmd(BASIC_TIM, ENABLE); 35 36 // 暂时关闭定时器的时钟,等待使用 37 BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, DISABLE) 38 }

我们把定时器设置自动重装载寄存器 ARR 的值为 1000,设置时钟预分频器为 71,则驱动计数器的时钟:CK_CNT = CK_INT / (71+1)=1M,则计数器计数一次的时间等于:1/CK_CNT=1us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间为:1/CK_CNT*ARR=1ms。 在初始化定时器的时候,我们定义了一个结构体:TIM_TimeBaseInitTypeDef,TIM_TimeBaseInitTypeDef 结构体里面有 5 个成员,TIM6 和 TIM7 的寄存器里面只有TIM_Prescaler 和 TIM_Period,另外三个成员基本定时器是没有的,所以使用 TIM6 和TIM7的时候只需初始化这两个成员即可, 另外三个成员是通用定时器和高级定时器才有,具体说明如下:

1 typedef struct { 2 TIM_Prescaler // 都有 3 TIM_CounterMode // TIMx,x[6,7]没有,其他都有 4 TIM_Period // 都有 5 TIM_ClockDivision // TIMx,x[6,7]没有,其他都有 6 TIM_RepetitionCounter // TIMx,x[1,8,15,16,17]才有 7 } TIM_TimeBaseInitTypeDef; 1 2 3 4 5 6

7

定时器中断优先级配置 1 // 中断优先级配置 2 void BASIC_TIM_NVIC_Config(void) 3 { 4 NVIC_InitTypeDef NVIC_InitStructure; 5 // 设置中断组为 0 6 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); 7 // 设置中断来源 8 NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQ ; 9 // 设置主优先级为 0 10 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 11 // 设置抢占优先级为 3 12 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 13 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 14 NVIC_Init(&NVIC_InitStructure); 15 } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

定时器中断服务程序

1 void BASIC_TIM_IRQHandler (void) 2 { 3 if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ) { 4 time++; 5 TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update); 6 } 7 }

定时器中断一次的时间是 1ms,我们定义一个全局变量 time,每当进一次中断的时候,让 time 来记录进入中断的次数。如果我们想实现一个 1s 的定时,我们只需要判断time 是否等于 1000 即可,1000 个 1ms 就是 1s。然后把 time 清 0,重新计数,以此循环往复。在中断服务程序的最后,要把相应的中断标志位清除掉,切记。

主函数

1 int main(void) 2 { 3 /* led 端口配置 */ 4 LED_GPIO_Config(); 5 6 /* 基本定时器 TIMx,x[6,7] 定时配置 */ 7 BASIC_TIM_Config(); 8 9 /* 配置基本定时器 TIMx,x[6,7]的中断优先级 */ 10 BASIC_TIM_NVIC_Config(); 11 12 /* 基本定时器 TIMx,x[6,7] 重新开时钟,开始计时 */ 13 BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE); 14 while(1) { }'; 二、定时器计算

在时基部分,定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,如:PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M。 定时器时钟经过 PSC 预分频器之后,即计数器时钟 CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)。

计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达 到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。 自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数 值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。 定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在 CK_CNT 的驱动 下,计一个数的时间则是 CK_CNT 的倒数,等于:1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于:(1/CK_CNT) * (ARR+1)。如果在中断服务程序里面设置一个变量 time,用来记录中断的次数,那么就可以计算出我们需要的定时时间等于:(1/CK_CNT) * (ARR+1) * time。Stm32定时器定时计算通过计数溢出计算,也就是说计数溢出就触发中断 计算公式: TimeOut = ((Prescaler + 1) * (Period + 1) ) / TimeClockFren; 解释下公式参数意义: TimeOut:定时器溢出时间(单位为us),多少触发(进入)一次TIM中断。 Prescaler:分频TIM时钟的预分频器值。 Period:计数重载值,TIM计数当超过这个值,则重新计数。 TimeClockFren:定时器的输入时钟频率(单位MHZ), 也就是当前使用的TIM所用的CLOK的时钟频率。如果不清楚,可通过相关参数得到。

eg:

TIM2_InitStruct.Instance = TIM2; TIM2_InitStruct.Init.Prescaler = 1999; TIM2_InitStruct.Init.Period = 999; ......

如上所示,上述代码在TimeClockFren为2.09Mhz的频率下,则定时器溢出的时间为 TimeOut = ((1999 + 1) * (999 + 1) ) / 2; TimeOut = 1000000us = 1s。 TIM_TimeBaseStructure.TIM_Period = arr; //自动装填定时器周期 超过即重新开始计数 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 使能 确定频率是t的话 (arr+1)*(psr+1)/t=时钟多长时间触发一次中断

什么是预计分频, 时钟频率是总频率/预分频数。 时钟频率是t 周期为1/t; Period为重载数 重载数*1/t=多少秒产生中断 重映射部分: 对TIM3而言: 1、当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB1 2、当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB1 3、当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9 重映射以后相对应的通道即将会改变,复用的将会被禁用。 同一个定时器不可以同时用中断以及pwm输出除非同种频率

附录: Static: 定义的变量在静态存储区 ,程序结束不会被释放。 TIM_ClearITPendingBit 清除的是一些中断标志位,TIM_ClearFlag 清除的是定时器的状态标志,比如定时器捕获状态位 定时器触发标志位.

附录,本文章仅是个人笔记,如有错误还请斧正,如有侵权必删。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有