完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
STM32—定时器知多少
定时器的分类 定时器的分类: 定时器的类型可以查看STM32F1XX中文参考手册的第14,15,16章节,里面对定时器的知识有详细的介绍。 STM32F1系列的开发板一共有8个定时器,按照功能的不同可以分为: 高级定时器(TIM1、TIM8) 通用定时器(TIM2、TIM3、TIM4、TIM5) 基本定时器(TIM6、TIM7) 看门狗定时器 SysTick定时器 他们之间的区别情况见下表: 定时器的工作原理 1 高级定时器简介 TIM1 和 TIM8 简介 高级控制定时器(TIM1 和 TIM8)包含一个 16 位自动重载计数器,该计数器由可编程预分频器驱动。 此类定时器可用于各种用途,包括测量输入信号的脉冲宽度(输入捕获),或者生成输出波形(输出比较、PWM 和带死区插入的互补 PWM)。 使用定时器预分频器和 RCC 时钟控制器预分频器,可将脉冲宽度和波形周期从几微秒调制到几毫秒。 高级控制定时器(TIM1 和 TIM8)和通用 (TIMx) 定时器彼此完全独立,不共享任何资源。 14.2 TIM1 和 TIM8 主要特性 TIM1 和 TIM8 定时器具有以下特性: ● 16 位递增、递减、递增/递减自动重载计数器。 ● 16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数介于 1 到 65536 之间。 ● 多达 4 个独立通道,可用于: — 输入捕获 — 输出比较 — PWM 生成(边沿和中心对齐模式) — 单脉冲模式输出 ● 带可编程死区的互补输出。 ● 使用外部信号控制定时器且可实现多个定时器互连的同步电路。 ● 重复计数器,用于仅在给定数目的计数器周期后更新定时器寄存器。 ● 用于将定时器的输出信号置于复位状态或已知状态的断路输入。 ● 发生如下事件时生成中断/DMA 请求: — 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发) — 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数) — 输入捕获 — 输出比较 — 断路输入 ● 支持定位用增量(正交)编码器和霍尔传感器电路。 ● 外部时钟触发输入或逐周期电流管理。 STM32F103中有TIM1,TIM8两个高级定时器,每一定时器都有 一个16位向上、向下、向上/下自动装载计数器 一个16位预分频器和四个独立从输入输出通道 每一个通道都可用于输入捕获、输出比较、PWM和单脉冲模式(除了基本定时器,高级定时器和通用定时器都能产生PWM) 单片机中没有时间的概念,因此定时器本质是一个以单位时间为准的计数器,计数值可以从0开始累加,也可以从一个设定值(ARR)的值递减,每隔一个固定的时间(由psc和时钟周期控制)计数器的值+1或-1,加到或减到头时会产生一个溢出信号,此时计数器的计数值清零或补充成初值,重新开始计数。 高级定时器框图 1 时钟源 由四个时钟来源,分别是 内部时钟源 CK_INT 外部时钟模式 1:外部输入引脚 TIx(x=1,2,3,4) 外部时钟模式 2:外部触发输入 ETR 内部触发输入(ITRx) 我们一般只用内部时钟源CK_INT,对于高级定时器,其时钟是由APB2总线时钟决定的 其他类型的定时器同理可以参考参考手册的RCC部分的时钟框图。 2 控制器 用来控制和发送命令的相关的寄存器有 CR1(control register 1 )控制寄存器1 CR2(control register 2 )控制寄存器2 SMCR(slave mode control register)从模式控制寄存器 CCER(capture/compare enable register)捕获比较寄存器 3 时基单元Time-base unit 时基单元的组成: (1)1-16位的预分频器 PSC 对控制计数器的时钟进行分频,分配系数可以为1~65536。 (2)16位的计数器CNT 每经过一个计数器时钟周期这里变化1(+1或-1)。 (3)4-16位的自动重装载寄存器ARR 向上计数时,但计数器的值CNT从0计数到ARR的值的时候,会产生溢出中断(也叫更新中断,update interrupt),然后会清零重新计数向下计数时,当计数器的值CNT从ARR的值计数到0的时候会产生溢出中断,然后会重新填充ARR的值。 (4)8位的重复计数器RCR(高级定时器独有的,基本和基础定时器都没有) 向上计数时,我们把REO的值设置成10,如果有设置当计数器溢出的时候,那么此时不会产生中断,而是RCR的值+1,当加到10的时候才产生中断,向下 计数原理类似,只不过是从10减到0。 4 输入捕获 输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常用的有测量输入信号的脉宽和测量 PWM 输入信号的频率和占空比这两种。 输入捕获的大概原理: 输入引脚检测到电平跳变时(上升沿或下降沿),把计数器CNT的值锁存到捕获寄存器CCRx中,把前后两次捕获到的 CCR x寄存器中的值相减,就可以算出脉宽或者频率。 (1)输入通道引脚 需要测量的信号从TIMx_CH1~4进入 (2)输入滤波器和边沿检测器 信号受到干扰时,滤波器可以对输入信号进行滤波,即进行重新采样。 滤波器的配置由 CR1 寄存器的位 CKD[1:0]和 CCMR1/2 的位 ICxF[3:0]控制。 边沿检测器用来设置信号在捕获的时候是什么边沿有效,可以是上升沿,下降沿,或者是双边沿,由 CCER 寄存器的位 CCxP 和 CCxNP 决定。 (3)捕获通道 捕获通道就是图中的 IC1/2/3/4,每个捕获/比较通道都有相对应的捕获寄存器 CCR1/2/3/4,当发生捕获的时候,计数器 CNT 的值就会被锁存到捕获寄存器中。 (4)预分频器 ICx 的输出信号会经过一个预分频器,用于决定发生多少个事件时进行一次捕获。具体的由寄存器 CCMRx 的位 ICxPSC 配置。 如果希望捕获信号的每一个边沿,则不分频。 (5)捕获寄存器 经过预分频器的信号 ICxPS 是最终被捕获的信号。 当发生捕获时(第一次),计数器CNT 的值会被锁存到捕获寄存器 CCR 中,还会产生 CCxI 中断,相应的中断位 CCxIF(在SR 寄存器中)会被置位,通过软件或者读取 CCR 中的值可以将 CCxIF 清 0。 如果发生第二次捕获(即重复捕获: CCR 寄存器中已捕获到计数器值且 CCxIF 标志已置 1),则捕获溢出标志位 CCxOF(在 SR 寄存器中)会被置位, CCxOF 只能通过软件清零。 5.输出比较 通过定时器的外部引脚对外输出控制信号。 有八种模式,主要使用的是其PWM1和PWM2模式。 具体使用哪种模式由寄存器 CCMRx 的位 OCxM[2:0]配置。 (1)比较寄存器 比较寄存器与捕获寄存器是同一个寄存器。 计数器 CNT 的值跟比较寄存器 CCR 的值相等的时候,输出参考信号 OCxREF 的信号的极性就会改变( OCxREF=1(高电平)称之为有效电平, OCxREF=0(低电平)称之为无效电平)。会产生比较中断 CCxI,相应的标志位 CCxIF(SR 寄存器中(状态寄存器,里面有各种状态或中断标记))会置位。 (2)死区发生器 在生成的参考波形 OCxREF 的基础上,可以插入死区时间,用于生成两路互补的输出信号 OCx 和 OCxN(OCxN的波形与OCx的相反)。 死区时间的大小具体由 BDTR 寄存器的位 DTG[7:0]配置。 这里的T_ DTS是由内部时钟T_CK_INT经过分频得到的,由CR1寄存器上的CKD[9:8]位控制的。 (3)输出控制 (4)输出引脚 输出比较的输出信号最终是通过定时器的外部 IO 来输出的,分别为 CH1/2/3/4,其中 前面三个通道还有互补的输出通道 CH1/2/3N。 2 STM32的通用定时器 通用定时器功能特点描述 STM32的通用定时器是由一个可编程预分频器(PSC)驱动的16位自动重装载计数器(CNT)构成,可用于测量输入脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。 STM32的通用TIMx(TIM2、TIM3、TIM4 和 TIM5)定时器功能特点包括: 位于低速的APB1总线上(注意:高级定时器是在高速的APB2总线上); 16位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT); 16位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值; 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为: 输入捕获 输出比较 PWM生成(边缘或中间对齐模式) 单脉冲模式输出 可使用外部信号**(TIMx_ETR)控制定时器**和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。 如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器): 1 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) 2 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) 3 输入捕获 4 输出比较 5 支持针对定位的增量(正交)编码器和霍尔传感器电路 6 触发输入作为外部时钟或者按周期的电流管理 STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。 STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。 计数器模式 通用定时器可以向上计数、向下计数、向上向下双向计数模式。 向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。 向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。 中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。 简单地理解三种计数模式,可以通过下面的图形: 通用定时器工作流程 对于这个定时器框图,分成四部分来讲:最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、左下部分(输入捕获)、右下部分(PWM输出)。 计数时钟的选择 计数器时钟可由下列时钟源提供: 内部时钟(TIMx_CLK) 外部时钟模式1:外部捕捉比较引脚(TIx) 外部时钟模式2:外部引脚输入(TIMx_ETR) 内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。 内部时钟源 从图中可以看出:由AHB时钟经过APB1预分频系数转至APB1时钟,再通过某个规定转至TIMxCLK时钟(即内部时钟CK_INT、CK_PSC)。最终经过PSC预分频系数转至CK_CNT。 那么APB1时钟怎么转至TIMxCLK时钟呢?除非APB1的分频系数是1,否则通用定时器的时钟等于APB1时钟的2倍。 例如:默认调用SystemInit函数情况下:SYSCLK=72M、AHB时钟=72M、APB1时钟=36M,所以APB1的分频系数=AHB/APB1时钟=2。所以,通用定时器时钟CK_INT=2*36M=72M。最终经过PSC预分频系数转至CK_CNT。 由于高级定时器与通用定时器的时钟不同,上面重点介绍时钟源,对于时基单元,计数模式,定时器相关的寄存器,以及控制寄存器都大体相同,大家可以参考高级定时器的寄存器介绍。 通用定时器超时时间 超出(溢出)时间计算: Tout=(ARR+1)(PSC+1)/TIMxCLK 其中:Tout的单位为us,TIMxCLK的单位为MHz。 这里需要注意的是:PSC预分频系数需要加1,同时自动重加载值也需要加1。 为什么自动重加载值需要加1,因为从ARR到0之间的数字是ARR+1个; 为什么预分频系数需要加1,因为为了避免预分频系数不设置的时候取0的情况,使之从1开始。 这里需要和之前的预分频进行区分:由于通用定时器的预分频系数为1~65535之间的任意数值,为了从1开始,所以当预分频系数寄存器为0的时候,代表的预分频系数为1。而之前的那些预分频系数都是固定的几个值,比如1、4、8、16、32、64等等,而且可能0x000代表1,0x001代表4,0x010代表8等等。也就是说,一边是随意的定义(要从1开始),另一边是宏定义了某些值(只有特定的一些值)。 比如,想要设置超出时间为500ms,并配置中断,TIMxCLK按照系统默认初始化来(即72MHz),PSC取7199,由此可以计算出ARR为4999。 也就是说,在内部时钟TIMxCLK为72MHz,预分频系数为7199的时候,从4999递减至0的事件是500ms。 以上就是通用定时器的基本原理介绍,如有疑问可以参考STM32F4中文参考手册。 3 STM32基本定时器 基本定时器定时器(TIM6 和 TIM7)不仅可用作通用定时器以生成时基,还可以专门用于驱动数模转换器 (DAC)。实际上,此类定时器内部连接到 DAC 并能够通过其触发输出驱动 DAC。 这些定时器彼此完全独立,不共享任何资源。 TIM6 和 TIM7 的主要特性 基本定时器(TIM6 和 TIM7)的特性包括: ● 16 位自动重载递增计数器。 ● 16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数介于 1 和 65536 之间。 ● 用于触发 DAC 的同步电路。 ● 发生如下更新事件时会生成中断/DMA 请求:计数器上溢。。 以上就是对定时器工作原理的基本介绍,如果还有疑问可以查询STM32F4XX中文参考手册,里面有详细的介绍和讲解。 定时器的应用 定时器的应用的应用场景有很多种,如下所示: 1 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) 2 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) 3 输入捕获 4 输出比较 5 支持针对定位的增量(正 交)编码器和霍尔传感器电路 6 触发输入作为外部时钟或者按周期的电流管理 下面我重点给大家展示以下三个实验 1 定时器中断实验 2 PWM输出实验 3 输入捕获实验 定时器中断实验: 接下来我们以通用定时器 TIM3 为实例,来说明要经过哪些步骤,才能达到这个要求,并产生中断。 1 )TIM3 时钟使能。 这里我们通过 APB1ENR 的第 1 位来设置 TIM3 的时钟,因为 Stm32_Clock_Init 函数里面把APB1的分频设置为2了,所以我们的TIM3时钟就是APB1时钟的2倍,等于系统时钟(72M)。 2 )设置 TIM3_ARR 和 和 TIM3_PSC 的值。 通过这两个寄存器,我们来设置自动重装的值,以及分频系数。这两个参数加上时钟频率就决定了定时器的溢出时间。 3 )设置 TIM3_DIER 允许更 新中断。 因为我们要使用 TIM3 的更新中断,所以设置 DIER 的 UIE 位为 1,使能更新中断。 4 )允许 TIM3 工作。 光配置好定时器还不行,没有开启定时器,照样不能用。我们在配置完后要开启定时器,通过 TIM3_CR1 的 CEN 位来设置。 5 )TIM3 中断分组设置。 在定时器配置完了之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,以使能TIM3 中断。 6 )编写中断服务函数。 在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处理完中断之后应该向 TIM3_SR 的最低位写 0,来清除该中断标志。 定时器中断实现步骤: 1 使能定时器时钟。 RCC_APB1PeriphClockCmd(); ② 初始化定时器,配置ARR,PSC。 TIM_TimeBaseInit(); ③ 开启定时器中断,配置NVIC。 NVIC_Init(); ④ 使能定时器。 TIM_Cmd(); ⑥ 编写中断服务函数。 TIMx_IRQHandler(); void TIME3_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseStructure.TIM_Period=arr;//设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler=psc;//设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断 NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;//TIM3中断 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//IRQ通道被使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; //先占优先级2级 NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//从优先级0级 NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM3,ENABLE); } void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否 { LED1=!LED1; TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志 } } PWM输出实验 本节要实现通过 TIM3_CH1 输出PWM 来控制 DS0 的亮度。下面我们介绍配置步骤: 1) )启 开启 TIM1 时钟,配置 PB5 为复用输出。要使用 TIM1,我们必须先开启 TIM1 的时钟(通过 APB2ENR 设置),这点相信大家看了这么多代码,应该明白了。这里我们还要配置 PB5 为复用输出,这是因为 TIM3_CH1 通道将使用 PB5 的复用功能作为输出。 2 ))设置 TIM3 的 的 ARR 和 和 PSC 。 在开启了 TIM3的时钟之后,我们要设置 ARR 和 PSC 两个寄存器的值来控制输出 PWM 的周期。当 PWM 周期太慢(低于 50Hz)的时候,我们就会明显感觉到闪烁了。因此,PWM 周期在这里不宜设置的太小。 3) )置设置 TIM3_CH1 的 的 PWM 模式 及通道方向。 接下来,我们要设置 TIM3_CH1 为 PWM 模式(默认是冻结的),因为我们的 DS0 是低电平亮,而我们希望当 CCR1 的值小的时候,DS0 就暗,CCR1 值大的时候,DS0 就亮,所以我们要通过配置 TIM1_CCMR1 的相关位来控制 TIM3_CH1 的模式。另外,我们要配置 CH1 为输出,所以要设置 CC1S[1:0]为 00(寄存器默认就是 0,所以这里可以省略)。 4) )能 使能 TIM3 的 的 CH1 输出,使能 TIM3。 接下来,我们需要开启 TIM3 的通道 1 的输出以及 TIM3的时钟。前者通过 TIM3_CCER来设置,是单个通道的开关,而后者则通过 TIM3_CR1 来设置,是整个 TIM13的总开关。只有设置了这两个寄存器,这样我们才可能在 TIM1 的通道 1 上看到 PWM 波输出。 5) ) 设置 MOE 输出,使能 PWM 输出。 。 普通定时器在完成以上设置了之后,就可以输出 PWM 了,但是高级定时器,我们还需要使能刹车和死区寄存器(TIM1_BDTR)的 MOE 位,以使能整个 OCx(即 PWM)输出。 6) )改 修改 TIM3_CCR1 来控制占空比。 最后,在经过以上设置之后,PWM 其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改 TIM3_CCR1 则可以控制 CH1 的输出占空比。继而控制 DS0 的亮度。 通过以上 6 个步骤,我们就可以控制 TIM3 的 CH1 输出 PWM 波了。 简化上面的过程就是: 1 使能定时器14和相关IO口时钟。 使能定时器14时钟:RCC_APB1PeriphClockCmd(); 使能GPIOF时钟:RCC_AHB1PeriphClockCmd (); 2 初始化IO口为复用功能输出。函数:GPIO_Init(); 3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能 GPIOF9复用映射到定时器14 GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); 4 初始化定时器:ARR,PSC等:TIM_TimeBaseInit(); 5 初始化输出比较参数:TIM_OC1Init(); 6 使能预装载寄存器: TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); 7 使能自动重装载的预装载寄存器允许位TIM_ARRPreloadConfig(TIM14,ENABLE); 8 使能定时器。 9 不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare1(); void TIME3_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure;//结构体声明 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2-》PB5 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); TIM_TimeBaseStructure.TIM_ClockDivision=0; TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period=arr; TIM_TimeBaseStructure.TIM_Prescaler=psc; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;//PWM模式1或者模式2 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//比较输出极性 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能 OR失能 // TIM_OCInitStructure.TIM_Pulse=100;//比较值,写CCRx TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器 TIM_Cmd(TIM3, ENABLE); //使能TIM3 } int main(void) { delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); uart_init(115200); LED_Init(); //初始化与LED连接的硬件接口 BEEP_Init(); TIME3_Init(4999,7199); TIME3_PWM_Init(899,0); KEY_Init(); LCD_Init(); while(1) { delay_ms(10); if(dir) led0pwmval++; else led0pwmval--; if(led0pwmval》500) dir=0; if(led0pwmval==0) dir=1; TIM_SetCompare2(TIM3,led0pwmval); } } 输入捕获实验 下面我们介绍输入捕获的配置步骤: 1 ))开启 TIM2 时钟,配置 PA0 为下拉输入。 要使用 TIM2,我们必须先开启 TIM2 的时钟(通过 APB1ENR 设置)。这里我们还要配置 PA0为下拉输入,因为我们要捕获 TIM2_CH1 上面的高电平脉宽,而 TIM2_CH1 是连接在 PA0 上 面的。 2 ))设置 TIM2 的 的 ARR 和 和 PSC 。 在开启了 TIM2 的时钟之后,我们要设置 ARR 和 PSC 两个寄存器的值来设置输入捕获的自动重装载值和计数频率。 3 ))设置 TIM2 的 的 CCMR1 TIM2_CCMR1 寄存器控制着输入捕获 1 和 2 的模式,包括映射关系,滤波和分频等。这里我们需要设置通道 1 为输入模式,且 IC1 映射到 TI1(通道 1)上面,并且不使用滤波(提高响应速度)器。 4) ) 设置 TIM2 的 的 CCER ,开启输入捕获,并设置为上升沿捕获。 TIM2_CCER 寄存器是定时器的开关,并且可以设置输入捕获的边沿。只有 TIM2_CCER寄存器使能了输入捕获,我们的外部信号,才能被 TIM2 捕获到,否则一切白搭。同时要设置好捕获边沿,才能得到正确的结果。 5) ) 设 置 TIM2 的 的 DIER ,使能捕获和更新中断,并编写中断服务函数 因为我们要捕获的是高电平信号的脉宽,所以,第一次捕获是上升沿,第二次捕获时下降沿,必须在捕获上升沿之后,设置捕获边沿为下降沿,同时,如果脉宽比较长,那么定时器就会溢出,对溢出必须做处理,否则结果就不准了。这两件事,我们都在中断里面做,所以必须开启捕获中断和更新中断。 设置了中断必须编写中断函数,否则可能导致死机。我们需要在中断函数里面完成数据处理和捕获设置等关键操作,从而实现高电平脉宽统计。 6 )设置 TIM2 的 的 CR1 ,使能定时器 最后,必须打开定时器的计数器开关,通过设置 TIM2_CR1 的最低位为 1,启动 TIM2 的计数器,开始输入捕获。 通过以上 6 步设置,定时器 2 的通道 1 就可以开始输入捕获了,同时因为还用到了串口输出结果,所以还需要配置一下串口。 输入捕获的一般配置步骤: ① 初始化定时器和通道对应IO的时钟。 ② 初始化IO口,模式为复用:GPIO_Init(); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; ③设置引脚复用映射: GPIO_PinAFConfig(); ④初始化定时器ARR,PSC TIM_TimeBaseInit(); ⑤初始化输入捕获通道 TIM_ICInit(); ⑥如果要开启捕获中断, TIM_ITConfig(); NVIC_Init(); ⑦使能定时器:TIM_Cmd(); ⑧编写中断服务函数:TIMx_IRQHandler(); 代码如下: void TIME2_CAP_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM2_ICInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能TIM5时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //设置为浮空输入 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period=arr; TIM_TimeBaseStructure.TIM_Prescaler=psc; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM2_ICInitStructure.TIM_Channel=TIM_Channel_2; TIM2_ICInitStructure.TIM_ICFilter=0x03; TIM2_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising; TIM2_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; TIM2_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI; TIM_ICInit(TIM2,&TIM2_ICInitStructure); TIM_Cmd(TIM2,ENABLE ); } int main(void) { delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); uart_init(115200); LED_Init(); //初始化与LED连接的硬件接口 BEEP_Init(); TIME3_Init(4999,7199); TIME3_PWM_Init(899,0); TIME2_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 KEY_Init(); while(1) { delay_ms(10); TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1); if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0); if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { temp=TIM5CH1_CAPTURE_STA&0X3F; temp*=65536;//溢出时间总和 temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间 printf(“HIGH:%d usrn”,temp);//打印总的高点平时间 TIM5CH1_CAPTURE_STA=0;//开启下一次捕获 } 总结 以上就是我对定时器的理解,定时器的内容很多,很杂,很复杂,需要大家自己对一些寄存器进行深入的理解,最重要的是自己要上手写代码,复制粘贴是学习STM32的大忌,希望大家可以通过自己的刻苦努力,来实现自己能力的提升。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1786 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1622 浏览 1 评论
1089 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
730 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1680 浏览 2 评论
1943浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
740浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
577浏览 3评论
600浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
562浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 00:32 , Processed in 0.623522 second(s), Total 48, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号