【STM32】通用定时器的输入捕获(实例:输入捕获)

发布者:快乐的成长最新更新时间:2019-01-04 来源: eefocus关键字:STM32  通用定时器  输入捕获 手机看文章 扫描二维码
随时随地手机看文章

通用定时器输入捕获概述


输入捕获的工作原理



在通用定时器框图中,主要涉及到最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、左下部分(输入捕获)这三个部分。这里主要讲解一下左下部分(输入捕获),其他两个部分可以参考文章:【STM32】通用定时器的基本原理(实例:定时器中断)。


输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6、TIM7,其他的定时器都有输入捕获的功能。下面以一个简单的脉冲输入为例,简单地讲述一下输入捕获用于测量脉冲宽度的工作原理:



先设置输入捕获为上升沿检测,记录发生上升沿时TIMx_CNT的值。然后配置捕获信号为下降沿捕获,当下降沿到来的时候发生捕获,并记录此时的TIMx_CNT的值。这样,前后两次TIMx_CNT的值之差就是高电平的脉宽。同时根据TIM的计数频率,我们就能知道高电平脉宽的准确时间。


输入捕获的通道概览


每一个捕获/比较通道都是围绕着一个捕获/比较寄存器(包含影子寄存器),包括捕获的输入部分(数字滤波、多路复用和预分频器),和输出部分(比较器和输出控制)。


捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。读写过程仅操作预装载寄存器。


在捕获模式下,捕获发生在影子寄存器上,然后再复制到预装载寄存器中。 


在比较模式下,预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较。



输入部分对相应的TIx输入信号采样,并产生一个滤波后的信号TIxF。然后,一个带极性选择的边缘检测器产生一个信号(TIxFPx),它可以作为从模式控制器的输入触发或者作为捕获控制。该信号通过预分频进入捕获寄存器(ICxPS)。


一句话总结工作过程:通过检测TIMx_CHx通道上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时,还可以配置捕获时是否触发中断/DMA等。


输入捕获的工作过程


将输入捕获的通道图进行分解,分解成四个部分,下面对这四个部分进行分析来了解输入捕获的工作过程:



设置输入捕获滤波器

输入捕获滤波器IC1F[3:0],这个用于设置采样频率和数字滤波器长度。其中:fCK_INT是定时器的输入频率,fDTS是根据TIMx_CR1的CKD[1:0]的设置来确定的。


这里滤波器的作用是什么意思呢?数字滤波器由一个事件计数器组成,它记录到N个事件后会产生一个输出的跳变。也就是说连续N次采样,如果都是高电平,则说明这是一个有效的触发,就会进入输入捕捉中断(如果设置了的话)。这样就可以滤除那些高电平脉宽低于8个采样周期的脉冲信号,从而达到滤波的作用。


设置输入捕捉极性

这里是设置捕捉事件是发生在上升沿还是下降沿。


设置输入捕获映射关系

由于我们只显示了一路通道的通道图,如果在几条通路的情况下:



在TIMx_CH1和TIMx_CH2两条通道的情况下,我们可以看出除了TIMx_CH1捕捉到的信号可以连接到IC1,TIMx_CH2捕捉到的信号可以连接到IC2之外,TIMx_CH1捕捉到的信号也可以连接到IC2,TIMx_CH2捕捉到的信号也可以连接到IC1。


一般情况下,我们设置成TIMx_CH1捕捉到的信号可以连接到IC1,TIMx_CH2捕捉到的信号可以连接到IC2。


设置输入捕获分频器

这里设置的是每N个事件触发一次捕捉。也就是说,我们可以设置成,每2次上升沿事件触发一次捕捉。



输入捕获相关配置寄存器

捕获/比较模式寄存器1(TIMx_CCMR1)



作用:在输入捕获模式下,确定数字滤波器、通道映射、预分频系数。


捕获/比较使能寄存器(TIMx_CCER)



作用:在输入捕获模式下,确定捕捉极性和捕捉使能。


捕获/比较寄存器1(TIMx_CCR1)


作用:在输入捕获模式下,确定上一次输入捕捉事件传输的计数值。



输入捕获相关配置库函数


1个输入初始化函数

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

作用:初始化捕获通道、滤波器、捕获极性、映射关系、分频系数等参数。


注意:由于输出初始化函数将所有的4个通道的函数分开各自定义了一个函数,而输入初始化函数并没有这么做。所以在输入初始化函数中,需要指定捕获通道。


1个参数获取函数

uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);

uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);

uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);

uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);

作用:在四个通道中选择一个,确定上一次输入捕捉事件传输的计数值。


1个参数设置函数

void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

作用:在四个通道中选择一个,设置通道极性。通常在初始化函数中已经设置了通道极性,此函数用于除初始化之外的修改。




输入捕获的一般步骤

实例要求:使用TIM5的通道1(PA0)来作为输入捕获,捕获PA0上高电平的脉宽(用WK_UP按键输入高电平),通过串口打印高电平脉冲时间。


初始化定时器和通道对应IO的时钟;

初始化IO口,模式为输入。调用函数:GPIO_Init();

初始化定时器ARR,PSC。调用函数:TIM_TimeBaseInit();

初始化输入捕获通道。调用函数:TIM_ICInit();

如果要开启捕获中断。调用函数:TIM_ITConfig();NVIC_Init();

使能定时器。调用函数:TIM_Cmd();

编写中断服务函数。调用函数:TIMx_IRQHandler()。

下面按照这个一般步骤来进行一个简单的输入捕获程序:


//定时器5通道1输入捕获配置

 

TIM_ICInitTypeDef  TIM5_ICInitStructure;

 

void TIM5_Cap_Init(u16 arr,u16 psc)

{  

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    NVIC_InitTypeDef NVIC_InitStructure;

 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能TIM5时钟

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA时钟


GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;  //PA0 清除之前设置  

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入  

GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉


//初始化定时器5 TIM5  

TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值 

TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器   

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式

TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

  

//初始化TIM5输入捕获参数

TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上

  TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获

  TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上

  TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 

  TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波

  TIM_ICInit(TIM5, &TIM5_ICInitStructure);


//中断分组初始化

NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;  //TIM3中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占优先级2级

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能

NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 


TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断


    TIM_Cmd(TIM5,ENABLE ); //使能定时器5

 

}

 

u8  TIM5CH1_CAPTURE_STA=0; //输入捕获状态    

u16 TIM5CH1_CAPTURE_VAL; //输入捕获值

 

//定时器5中断服务程序  

void TIM5_IRQHandler(void)

 

  if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获

{   

if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)

 

{     

if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了

{

if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了

{

TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次

TIM5CH1_CAPTURE_VAL=0XFFFF;

}else TIM5CH1_CAPTURE_STA++;

}  

}

if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件

{

if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿

{  

TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次高电平脉宽

TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);

    TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获

}else  //还未开始,第一次捕获上升沿

{

TIM5CH1_CAPTURE_STA=0; //清空

TIM5CH1_CAPTURE_VAL=0;

TIM_SetCounter(TIM5,0);

TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿

    TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获

}     

}              

  }

 

    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位

 

}

extern u8  TIM5CH1_CAPTURE_STA; //输入捕获状态    

extern u16 TIM5CH1_CAPTURE_VAL; //输入捕获值

 int main(void)

 {

  u32 temp=0; 

delay_init();     //延时函数初始化   

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级

uart_init(115200); //串口初始化为115200

 

  TIM5_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 

    while(1)

{

  delay_ms(10);

 

  if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿

{

temp=TIM5CH1_CAPTURE_STA&0X3F;

temp*=65536;//溢出时间总和

temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间

printf("HIGH:%d us\r\n",temp);//打印总的高点平时间

TIM5CH1_CAPTURE_STA=0;//开启下一次捕获

}

}

 }

代码逻辑

这里关于输入捕获的初始化部分比较简单,对照着一般步骤来就行了。但是在中断处理函数TIM5_IRQHandler()部分就有所难度了,为什么会比较复杂呢?


由于我们进行输入捕获,一旦捕捉到了上升沿,就设置计数器当前值为0,让它从0开始重新计数:


TIM_SetCounter(TIM5,0);

但是如果脉冲的长度过于宽了,也就是说,从0开始计数到自动重加载值一个循环结束了,脉冲还是没有结束。这个情况下,显而易见不能只记录一下最后的计数器当前值。


解决这个问题的办法:

设置一个变量TIM5CH1_CAPTURE_STA,bit5-0为捕捉高电平后定时器溢出的次数,bit6为捕捉到高电平标志,bit7为捕获完场标志。


同时设置两个中断(更新中断和捕获中断):


TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断

在中断处理函数中,先判断是否捕获成功,如果捕获成功了,说明是在脉冲低电平的阶段,什么都不需要做;如果捕获没有成功,说明是在脉冲高电平的阶段,就需要继续判断中断类型,然后再分别进行处理。在更新中断中,表示此时脉冲长度过长,TIM5CH1_CAPTURE_STA加1。在捕获中断中,判断捕捉到的是否为上升沿,如果是,计数器当前值清零,TIM5CH1_CAPTURE_STA清零,同时标记标志,设置极性下降沿捕捉;如果不是,标记捕获完成,保存当前计数器的值,设置极性上升沿捕获。


extern关键字

C语言中,extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此类变量和函数时在其他模块中寻找其定义。


注意:对于extern申明变量可以多次,但是定义只有一次。

关键字:STM32  通用定时器  输入捕获 引用地址:【STM32】通用定时器的输入捕获(实例:输入捕获)

上一篇:STM32——定时器TIME模块之输入捕获
下一篇:STM32之通用定时器输入捕获模式

推荐阅读最新更新时间:2024-03-16 16:21

stm32中断学习总结
经过了两天,终于差不多能看懂32的中断了,由于是用的库函数操作的,所以有些内部知识并没有求甚解,只是理解知道是这样的。但对于要做简单开发的我来说这些已经够了。 我学习喜欢从一个例程来看,下面的程序是我粘贴但是改编的,大部分都做了注释。 主要是感谢这位博主的文章:http://www.cnblogs.com/chineseboy/archive/2013/03/14/2956782.html 其实主要步骤就是: 1、将GPIO口配置成中断输入模式。 void Init_LED(void) { GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO结构体变量 RCC_APB2PeriphCl
[单片机]
STM32】Keil中Debug模式下全局变量的实时查看
在使用Keil开发环境编写stm32程序时我们经常会用到硬件在线仿真的功能,能在watch窗口中看到我们在程序中定义的全局变量。我们希望在程序实时运行中看到变量的变化情况,但有时不能实时查看,原因是软件的设置不对。 在Debug模式下,点击菜单栏下的View,在下面有一个Periodic Window update 点一下,选定一下就行了。
[单片机]
基于STM32的四旋翼飞行姿态串级控制的设计与实现
四旋翼飞行器与传统的单桨直升机相比,其飞行原理简单,结构紧凑,单位体积所提供的升力大,且可以扭矩自平衡而不需要反扭桨。四旋翼飞行器只通过改变螺旋桨的速度来实现各种动作,是一种六自由度的垂直起降机,非常适合在静态和准静态条件下飞行,近几年在军事和民用领域广泛应用。然而四旋翼飞行器是个具有4个输入量,6个输出量的欠驱动系统,控制器的设计要求高。 姿态解算是姿态参考系统的关键技术,算法的优劣直接决定了解算效率和系统的精度。目前姿态描述的主要方式有:欧拉角、方向余弦、四元素法。欧拉角物理意义明确,但存在“奇点”。方向余弦计算没有“奇点”,但三角函数运算量大,不适合实时运算。四元素法没有“奇点”,而且运算为一般代数运算,运算量小,方法简
[单片机]
基于<font color='red'>STM32</font>的四旋翼飞行姿态串级控制的设计与实现
基于STM32设计的自动刹车灯
一、项目介绍 随着科技的发展,人们对低碳环保的认知和需求不断提高。骑自行车既能够低碳环保,又能够锻炼身体,成为了很多人出行的首选。然而,由于自行车本身没有带指示灯,比如刹车指示灯等,所以自行车的安全性并不是很好,如果人们在骑自行车时紧急刹车,后车无法及时判断前方自行车的行为,容易造成交通事故。因此,设计一款自动刹车灯系统具有十分重要的意义。 本项目实现了通过安装ADXL345陀螺仪和四枚LED灯还有STM32F103C8T6主控芯片来实现自行车自动刹车灯的功能。当自行车上安装了该设备后,ADXL345通过IIC通信协议将X,Y,Z三轴的加速度实时值发送给SMT32F103C8T6主控芯片,并结合STM32高级定时器的PWM功能
[单片机]
基于<font color='red'>STM32</font>设计的自动刹车灯
stm32 串口发送数据第一字节丢失
使用stm32f10x调试串口通讯时,发现一个出错的现象,硬件复位重启之后,发送测试数据0x01 0x02 0x03 0x04..接收端收到的数据为:0x02 0x03 0x04,第一个数据丢失。 查阅stm32f10x参考手册,找到这样一句话: TC:发送完成 当包含有数据的一帧发送完成后,由硬件将该位置位。如果USART_CR1中的TCIE为1,则产生中断。由软件序列清除该位(先读USART_SR,然后写入USART_DR)。TC位也可以通过写入0来清除,只有在多缓存通讯中才推荐这种清除程序。 0:发送还未完成; 1:发送完成。 注意到这一句:由软件序列清除该位(先读USART_SR,然后写入USART_DR)。 也就
[单片机]
两片STM32使用HAL完成SPI全双工主从通信
SPI是一种非常简单易用的全双工主从式通信协议。 本文使用两片STM32F429,一个作为主机,一个作为从机完成SPI的全双工通信测试。 在STM32的HAL库中简化了SPI主机端的发送接收,但是HAL库没有提供一个简单的SPI从机代码接口,这样就需要自己拼接接口来完成全双工的通信。以下都以实现全双工通信为目的进行配置和编写: 一 主机端: 禁止使用SPI的硬件片选信号,因为这个信号是SPI使能了之后就一直为低,直到禁止了SPI之后才为高。可以使用某一个普通IO来充当片选信号。 这里选用一个较低的速率来通信,在HAL库的spi头文件中有说明各个模式下SPI的最大速度。 二 从机端:
[单片机]
两片<font color='red'>STM32</font>使用HAL完成SPI全双工主从通信
STM32学习笔记-ADC采集-串口2发送至上位机
串口2的配置(一根杜邦线不行纠结了半天) void USART2_Initialise( u32 bound ) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE); /* Enable the USART2 Pins Software Remapping */ RCC_APB2
[单片机]
<font color='red'>STM32</font>学习笔记-ADC采集-串口2发送至上位机
STM32串口通信设置(查询方式)
首先是配置UART的GPIO口 void UART1_GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; // Configure USART1_Tx as alternate push-pull GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_I
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved