立即注册
查看: 5562|回复: 1

[转载] STM32单定时器四通道捕获功能实现

发表于 2016-5-16 15:30:01 | 显示全部楼层 |阅读模式 来自 广东省深圳市
输入捕获作为定时器的一个功能,在工业测速上有很大的应用。STM32的一些定时器具有四个外部通道,可利用一个定时器采集外部四路脉冲频率,节约硬件资源和软件代码
如需要测量一个或多个外部方波脉冲频率,频率低于单片机运行频率,可如下操作:(以TIM4为例)
初始化:(省略GPIO配置,将TIM4的四个通道引脚配置为上拉或浮空输入,省略定时器RCC配置,省略中断NVIC配置)

  • void TIM_Configuration(void)
  • {
  • TIM_ICInitTypeDef
  • TIM_ICInitStructure;
  • TIM_TimeBaseInitTypeDef
  • TIM_TimeBaseStructure; // TIM4 时基
  • TIM_DeInit(TIM4);
  •     TIM_TimeBaseStructure.TIM_Period =
  • 0xffff;
  • //自动重装值
  •     TIM_TimeBaseStructure.TIM_Prescaler =
  • 719;
  • //预分频值, 使TIMx_CLK=1MHz
  • TIM_TimeBaseStructure.TIM_ClockDivision =
  • TIM_CKD_DIV1;
  • //输入时钟不分频
  •     TIM_TimeBaseStructure.TIM_CounterMode =
  • TIM_CounterMode_Up;
  • //向上计数
  •     TIM_TimeBaseInit(TIM4,
  • &TIM_TimeBaseStructure);
  • //TIM4_TimeBase
  • //  TIM_ICInitStructure.TIM_ICMode =
  • TIM_ICMode_ICAP;
  • //输入捕捉方式
  •   TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//|
  • TIM_Channel_2;        //输入通道
  • TIM_ICInitStructure.TIM_ICPolarity =
  • TIM_ICPolarity_Rising;     //捕捉上升沿
  • TIM_ICInitStructure.TIM_ICSelection =
  • TIM_ICSelection_DirectTI;    //捕捉中断
  • TIM_ICInitStructure.TIM_ICPrescaler =
  • TIM_ICPSC_DIV1;       //捕捉不分频
  • TIM_ICInitStructure.TIM_ICFilter =
  • 0x0;          //捕捉输入不滤波
  •   TIM_ICInit(TIM4, &TIM_ICInitStructure);
  •   TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;//|
  • TIM_Channel_2;        //输入通道
  • TIM_ICInitStructure.TIM_ICPolarity =
  • TIM_ICPolarity_Rising;     //捕捉上升沿
  • TIM_ICInitStructure.TIM_ICSelection =
  • TIM_ICSelection_DirectTI;    //捕捉中断
  • TIM_ICInitStructure.TIM_ICPrescaler =
  • TIM_ICPSC_DIV1;       //捕捉不分频
  • TIM_ICInitStructure.TIM_ICFilter =
  • 0x0;          //捕捉输入不滤波
  •   TIM_ICInit(TIM4, &TIM_ICInitStructure);
  •   TIM_ICInitStructure.TIM_Channel = TIM_Channel_3 ;//|
  • TIM_Channel_2;        //输入通道
  • TIM_ICInitStructure.TIM_ICPolarity =
  • TIM_ICPolarity_Rising;     //捕捉上升沿
  • TIM_ICInitStructure.TIM_ICSelection =
  • TIM_ICSelection_DirectTI;    //捕捉中断
  • TIM_ICInitStructure.TIM_ICPrescaler =
  • TIM_ICPSC_DIV1;       //捕捉不分频
  • TIM_ICInitStructure.TIM_ICFilter =
  • 0x0;          //捕捉输入不滤波
  •   TIM_ICInit(TIM4, &TIM_ICInitStructure);
  •   TIM_ICInitStructure.TIM_Channel = TIM_Channel_4 ;//|
  • TIM_Channel_2;        //输入通道
  • TIM_ICInitStructure.TIM_ICPolarity =
  • TIM_ICPolarity_Rising;     //捕捉上升沿
  • TIM_ICInitStructure.TIM_ICSelection =
  • TIM_ICSelection_DirectTI;    //捕捉中断
  • TIM_ICInitStructure.TIM_ICPrescaler =
  • TIM_ICPSC_DIV1;       //捕捉不分频
  • TIM_ICInitStructure.TIM_ICFilter =
  • 0x0;          //捕捉输入不滤波
  •   TIM_ICInit(TIM4, &TIM_ICInitStructure);
  •   /* TIM enable counter */
  •   TIM_Cmd(TIM4, ENABLE);
  •   /* Enable the CC2 Interrupt Request */
  •   TIM_ITConfig(TIM4,
  • TIM_IT_CC1, ENABLE);
  •   TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
  • TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE);
  •   TIM_ITConfig(TIM4, TIM_IT_CC4,
  • ENABLE);
  • }


[color=rgb(51, 102, 153) !important]复制代码


其中:
TIM_TimeBaseStructure.TIM_Period = 0xffff;为自动重装值,与普通单片机一样
TIM_TimeBaseStructure.TIM_Prescaler = 719; 预分频值, 使TIMx_CLK=100KHz ,系统时钟运行于72M时720分频,定时器运行于100KHZ,即10us每分度
TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP; 此句选择定时器为输入捕获模式,但在我的库函数下未定义,所以注释掉,未影响程序执行
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;配置通道1
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;捕获中断
TIM_ICInitStructure.TIM_ICFilter = 0x0;不滤波
TIM_ICInit(TIM4, &TIM_ICInitStructure);将配置应用
以上每个通道都需要将整个配置再写一遍,使用与'|'是无效的。
TIM_Cmd(TIM4, ENABLE);使能定时器4
  TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);
  TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
  TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE);
  TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);打开四个通道的捕获中断
以上将TIM配置完成,下面是中断内代码:
  • void
  • TIM4_IRQHandler(void)
  • {
  • //频率缓冲区计数
  • static u16 this_time_CH1 = 0;
  • static u16
  • last_time_CH1 = 0;
  • static u8 capture_number_CH1 = 0;
  • vu16
  • tmp16_CH1;
  • static u16 this_time_CH2 = 0;
  • static u16 last_time_CH2 = 0;
  • static u8 capture_number_CH2 = 0;
  • vu16 tmp16_CH2;
  • static u16 this_time_CH3 = 0;
  • static u16 last_time_CH3 = 0;
  • static u8 capture_number_CH3 = 0;
  • vu16 tmp16_CH3;
  • static u16 this_time_CH4 = 0;
  • static u16 last_time_CH4 = 0;
  • static u8 capture_number_CH4 = 0;
  • vu16 tmp16_CH4;
  •   if(TIM_GetITStatus(TIM4, TIM_IT_CC1) == SET)
  •     {
  • TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);
  •         if(capture_number_CH1 == 0)
  •         {
  • capture_number_CH1 = 1;
  • last_time_CH1 = TIM_GetCapture1(TIM4);
  •         }
  •         else if(capture_number_CH1 == 1)
  •         {
  • capture_number_CH1 = 0;
  • this_time_CH1 = TIM_GetCapture1(TIM4);
  • if(this_time_CH1 > last_time_CH1)
  •             {
  • tmp16_CH1 = (this_time_CH1 - last_time_CH1);
  •             }
  •             else
  •             {
  • tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1);
  •             }
  •             //TIM2
  • counter clock = 1MHz
  • //
  • FreqBuf[cnt] = (1000000L * 100) /
  • tmp16;
  • //*100为扩大显示量程
  •    Freq_Value[0]=tmp16_CH1;
  •         }
  •   }
  •     if(TIM_GetITStatus(TIM4, TIM_IT_CC2) == SET)
  •     {
  • TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);
  •         if(capture_number_CH2 == 0)
  •         {
  • capture_number_CH2 = 1;
  • last_time_CH2 = TIM_GetCapture2(TIM4);
  •         }
  •         else if(capture_number_CH2 == 1)
  •         {
  • capture_number_CH2 = 0;
  • this_time_CH2 = TIM_GetCapture2(TIM4);
  • if(this_time_CH2 > last_time_CH2)
  •             {
  • tmp16_CH2 = (this_time_CH2 - last_time_CH2);
  •             }
  •             else
  •             {
  • tmp16_CH2 = ((0xFFFF - last_time_CH2) + this_time_CH2);
  •             }
  •             //TIM2
  • counter clock = 1MHz
  • //
  • FreqBuf[cnt] = (1000000L * 100) /
  • tmp16;
  • //*100为扩大显示量程
  •    Freq_Value[1]=tmp16_CH2;
  • }
  • }
  • if(TIM_GetITStatus(TIM4, TIM_IT_CC3) == SET)
  •     {
  • TIM_ClearITPendingBit(TIM4, TIM_IT_CC3);
  •         if(capture_number_CH3 == 0)
  •         {
  • capture_number_CH3 = 1;
  • last_time_CH3 = TIM_GetCapture3(TIM4);
  •         }
  •         else if(capture_number_CH3 == 1)
  •         {
  • capture_number_CH3 = 0;
  • this_time_CH3 = TIM_GetCapture3(TIM4);
  • if(this_time_CH3 > last_time_CH3)
  •             {
  • tmp16_CH3 = (this_time_CH3 - last_time_CH3);
  •             }
  •             else
  •             {
  • tmp16_CH3 = ((0xFFFF - last_time_CH3) + this_time_CH3);
  •             }
  •             //TIM2
  • counter clock = 1MHz
  • //
  • FreqBuf[cnt] = (1000000L * 100) /
  • tmp16;
  • //*100为扩大显示量程
  •    Freq_Value[2]=tmp16_CH3;
  •         }
  • }
  • if(TIM_GetITStatus(TIM4, TIM_IT_CC4) == SET)
  •     {
  • TIM_ClearITPendingBit(TIM4, TIM_IT_CC4);
  •         if(capture_number_CH4 == 0)
  •         {
  • capture_number_CH4 = 1;
  • last_time_CH4 = TIM_GetCapture4(TIM4);
  •         }
  •         else if(capture_number_CH4 == 1)
  •         {
  • capture_number_CH4 = 0;
  • this_time_CH4 = TIM_GetCapture4(TIM4);
  • if(this_time_CH4 > last_time_CH4)
  •             {
  • tmp16_CH4 = (this_time_CH4 - last_time_CH4);
  •             }
  •             else
  •             {
  • tmp16_CH4 = ((0xFFFF - last_time_CH4) + this_time_CH4);
  •             }
  •             //TIM2
  • counter clock = 1MHz
  • //
  • FreqBuf[cnt] = (1000000L * 100) /
  • tmp16;
  • //*100为扩大显示量程
  •    Freq_Value[3]=tmp16_CH4;
  •         }
  • }
  • //
  • GPIO_WriteBit(GPIOC, GPIO_Pin_13,
  • (BitAction)((1-GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13))));
  • }


[color=rgb(51, 102, 153) !important]复制代码


中断内四部分代码完全一样,只分析其中一段
输入捕获的原理是,定时器正常计数运行,当外部脉冲到来时,将定时器计数值存起来,当下次脉冲到来时,求出这两次计数值差值,即为这两段脉冲的周期。
例如,定时器计数到10,外部脉冲到来,使用last_time_CH1存储10,下次脉冲到来,此时定时器计数值运行到110,使用this_time_CH1存储110,之后做差,tmp16_CH1存储差值100,由于定时器运行于100KHZ,10us计数值增加一次,所以脉冲周期为100*10=1000us=1ms,即为1KHZ。
当然,定时器会溢出重装,此时需要将差值补偿运算,tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1);
可测量的范围取决于定时器运行的频率,如果外部频率慢到当定时器整个计数一周后也没有触发两次,会发生溢出,此时计数值已不准确。所以定时器时钟配置取决于外部脉冲频率,应配置得当使得脉冲频率范围不致溢出。
由于每次外部脉冲都会触发中断,尤其是四通道时,所以使用中断方式会略微占用CPU资源,使用DMA可以解决这一问题。
得到脉冲周期后,即可通过运算获得外部频率,进而测速。

  • 一牛网商城 一牛网直播
已绑定手机
已实名认证
发表于 2016-5-20 11:02:31 | 显示全部楼层 来自 福建省厦门市
谢谢分享
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

合作/建议

TEL: 19168984579

工作时间:
周一到周五 9:00-11:30 13:30-19:30
  • 扫一扫关注公众号
  • 扫一扫打开小程序
Copyright © 2013-2024 一牛网 版权所有 All Rights Reserved. 帮助中心|隐私声明|联系我们|手机版|粤ICP备13053961号|营业执照|EDI证
在本版发帖搜索
微信客服扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表