历史上的今天
返回首页

历史上的今天

今天是:2025年03月13日(星期四)

正在发生

2019年03月13日 | 【STM32】通用定时器的输入捕获(实例:输入捕获)

2019-03-13 来源:eefocus

STM32F1xx官方资料:


《STM32中文参考手册V10》-第14章  通用定时器


通用定时器输入捕获概述

输入捕获的工作原理



在通用定时器框图中,主要涉及到最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、左下部分(输入捕获)这三个部分。这里主要讲解一下左下部分(输入捕获),其他两个部分可以参考文章:【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申明变量可以多次,但是定义只有一次。

推荐阅读

史海拾趣

ALLEN BRADLEY公司的发展小趣事

ALLEN BRADLEY 公司是一家享有盛誉的电子行业企业,其发展历程有许多引人注目的里程碑。以下是关于 ALLEN BRADLEY 公司发展的五个相关故事:

  1. 公司成立和早期发展: ALLEN BRADLEY 公司于1903年由Lynde Bradley和Dr. Stanton Allen 在美国威斯康星州的密尔沃基市成立。最初,公司主要从事制造电气开关、继电器和其他电气控制设备。他们的产品质量和可靠性使其迅速成为当时工业领域的领先供应商之一。

  2. 工业自动化的先驱: 在20世纪上半叶,ALLEN BRADLEY 公司成为工业自动化领域的先驱之一。他们开发了许多创新的产品和技术,如PLC(可编程逻辑控制器),这项技术彻底改变了工厂和生产线的运作方式。PLC的普及使得生产自动化水平大幅提高,为工业生产效率的提升做出了重要贡献。

  3. 公司的扩张与国际化: 随着业务的不断壮大,ALLEN BRADLEY 公司开始向全球扩张。他们在世界各地建立了销售和服务网络,为客户提供更加全面的支持。逐步建立的全球业务网络使得 ALLEN BRADLEY 成为了全球工业自动化领域的领先品牌之一。

  4. 汇丰电气(Rockwell Automation)的收购: 1990年,汇丰电气公司(Rockwell International)收购了 ALLEN BRADLEY 公司。这一收购加强了两家公司在工业自动化领域的实力,并进一步巩固了其在全球市场上的地位。汇丰电气公司将 ALLEN BRADLEY 公司的产品整合到其工业自动化解决方案中,为客户提供更加全面的解决方案和服务。

  5. 持续创新与发展: ALLEN BRADLEY 公司一直致力于持续创新和技术发展。他们不断推出新产品,引领着工业自动化技术的发展方向。通过不断地投资研发和技术创新,ALLEN BRADLEY 公司在工业自动化领域保持着领先地位,并为客户提供更加先进、高效的解决方案。

以上是 ALLEN BRADLEY 公司发展的五个相关故事,这些故事展示了该公司在电子行业中的重要地位和不断发展壮大的历程。

台湾凌通(Generalplus)公司的发展小趣事
检查控制电路中的其他元件(如继电器、晶体管等)是否工作正常,有无损坏或接触不良的情况。
Antiference公司的发展小趣事

Antiference公司最初以生产电磁屏蔽材料起家,但随着电子设备的普及和电磁干扰问题的日益严重,公司意识到单纯的材料生产已无法满足市场需求。于是,Antiference投入巨资研发新型电磁干扰抑制技术,成功开发出了一款能够显著降低电磁干扰的芯片。这款芯片迅速在市场上获得了广泛认可,Antiference也因此成为了电磁干扰抑制领域的领军企业。

HTSEMI( Jin Yu Semiconductor )公司的发展小趣事

为了进一步提升技术实力,金宇半导体积极与国内外知名高校和科研机构建立合作关系。2010年,公司与某顶尖大学联合成立了“先进半导体技术研究中心”,共同开展前沿技术的研发。通过产学研的紧密合作,金宇半导体在先进制程工艺、芯片封装测试等领域取得了重大突破,成功推出了多款具有自主知识产权的高端芯片产品,进一步巩固了其在行业内的领先地位。

智浦欣(Chipstar)公司的发展小趣事

为了进一步提升公司的技术实力和品牌影响力,智浦欣公司积极寻求与国际知名企业的合作机会。经过多次沟通和洽谈,公司成功与一家国际知名半导体企业达成了战略合作协议。双方将在技术研发、产品推广和市场开拓等方面展开深度合作。通过这一合作,智浦欣公司不仅获得了宝贵的技术支持和市场资源,还进一步提升了其品牌形象和市场份额。

Acopian Power Supplies公司的发展小趣事

随着技术的不断进步和市场需求的日益增长,智浦欣公司意识到,只有不断创新和突破,才能在激烈的市场竞争中立于不败之地。于是,公司加大了对研发团队的投入,引进了一批国内外顶尖的模拟器件和混合信号设计人才。经过数月的努力,团队成功研发出了一款具有高性价比的WLED驱动器产品,该产品以其卓越的性能和稳定的质量赢得了客户的广泛好评。随后,公司又相继推出了多款具有竞争力的新产品,进一步巩固了其在消费类电子市场的地位。

问答坊 | AI 解惑

如何定制Windows XP Embedded (一)

Windows XP Embedded是基于 Win32 编程模型,由于采用常见的开发工具,如 Visual Studio .NET,使用商品化 PC 硬件,与桌面应用程序无缝集成,因此可以缩短上市时间。有很多的同胞们已经开始对Windows XP Embedded产生兴趣,在这里我简要说说如何定 ...…

查看全部问答>

WiMAX技术综述

人类的科学总是不断进步的,技术总是为应运而生的。WiMAX 作为一项新兴技术,能够在比Wi-Fi更广阔的地域范围内提供“最后一公里”宽带连接性,由此支持企业客户享受T1 类服务以及居民用户拥有相当于线缆/DSL 的访问能力。凭借其在任意地点的1~6 英 ...…

查看全部问答>

硬件测试技术

对硬件设计人员和测试人员提高设计测试水平有益。59页的内容包括: 硬件测试概述 硬件测试前准备 硬件测试的种类与操作 硬件测试的级别 可靠性测试 测试问题解决 测试效果评估 硬件测试参考的通信技术标准 测试规范制定 测试人员的培养…

查看全部问答>

wavecom传输语音文件的问题

我想要做一个自动语音回复系统,比如用户拨打wavecom的号码,接通后wavecom自动把之前录好的语音文件打开,这样用户就可以听到事先录好的语音了,这个程序应该怎么设计呢?…

查看全部问答>

请教高手:单片机中断处理的问题

我在单片机中编程如下,SendKey_Protocl();是一个费时的操作,超过30ms,小于600ms,我得不到想要的结果,请问:--在中断处理服务程序中,如果费时的函数调用没有处理完是否在后台处理?还是被舍弃?。。。请问高手应该怎么处理? //TIMER0 ini ...…

查看全部问答>

2009年全国大学生电子设计竞赛试题之一

2009年全国大学生电子设计竞赛试题                                   参赛注意事项 (1)2009年9月2日8:00竞赛正式开始。本 ...…

查看全部问答>

汇编语言中的#define #include #ifdef 等问题

小弟在学习汇编语言中遇到一下情况(ARM构架 AT&T语法) 出现#include  #ifdef  #endif #define等类似于C语言中的相关关键字从程序本身分析其作用应该相似, 如: #include #include 又如: #ifdef CONFIG_USE_IRQ /* ...…

查看全部问答>

25岁生日!!!散分,也和大家討論下25岁後的生活安排.

         在下現在研二. 今年下半年就要找工作了,26岁生日的時候就應該在單位呆著了(如果找到了的話).              目前在我們實驗室的公司里打雜. 主要弄c/c++編程(PC ...…

查看全部问答>

汽车多媒体娱乐系统解决方案

辰汉电子是一家专业从事嵌入式底层开发平台研发的高科技公司,我们致力于为消费类电子、多媒体、嵌入式系统、汽车电子、工业控制等行业提供创新的嵌入式产品方案。 从辰汉电子成立之初,就一直关注汽车多媒体影音娱乐系统(infortament)的发展 ...…

查看全部问答>

获得的设备描述符的idVendor, idProduct,bcdDevice的值老是变化的

这个是ddk vista 6000版本的一个toast例子中的,我只是改写filter.c中的这段想获得设备描述符。 每次读到的都不一样。怎么会这样啊。ddk下的。其他地方都没有改,就在FilterDispatchPnp中添加一段代码来获得设备描述符。但是问题如标题。每次运 ...…

查看全部问答>