找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9525|回复: 6
打印 上一主题 下一主题
收起左侧

stm32系列定时器输入捕获检测高、低脉冲时长的方法 附源程序

[复制链接]
跳转到指定楼层
楼主
ID:407977 发表于 2019-7-16 10:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
大家好,本人在校老菜鸡一个,最近抽空接手了一个项目,其中一个关键点在于“通过输入捕获检测任意引脚、任意顺序高低电平的持续时间”。
咱们直入主题,stm32的具有丰富的外设资源,小编选择用stm32f1系列单片机作为核心控制器,来完成这个项目。
方案有两种:
方案一:采用中断,例如外部引脚中断等,直接在检测到指定电平时,发生跳变进入中断函数,然后进行计时。
方案二:采用定时器输入捕获,在上升沿、下降沿时发生跳变,然后进行计时。
优缺点分析:方案一实行难度较小,但是需要引脚资源较多(一个检测高电平,一个检测低电平),时间精度稍微弱一点。
方案二拥有现成的历程,直接调用即可,通过定时器输入捕获模式,中断里进行计数。
看似使用方案二是最佳的选择,但是,如果这样的话,小编就不用写这篇博客了.
至于方案一、小弟也还没有尝试过,不清楚具体效果如何。

背景介绍(大牛不喜勿喷)
输入捕获模式:输入捕获模式可以用来测量脉冲宽度或者测量频率,Stm32定时器除了定时器6和定时器7,其他定时器都有输入捕获功能,简单来说,就是在边沿信号发生跳变的时候(上升沿、下降沿),将当前定时器的值存放到对应通道的捕获/比寄存器中,完成一次捕获,同时,可以再配置捕获到相应跳变时,是否触发中断/DMA等等。

一、测量高电平脉冲宽度:采用正点原子的代码思路。先将引脚设定为下拉输入,然后设置输入捕获为“上升沿触发”,将当前定时器中的时间存储起来,然后再中断里将触发方式设置为“下降沿触发”,再记录一下触发时间,二者相减,即可得出高电平持续时间。
二、测量低电平脉冲宽度:与测量高电平脉冲宽度正好相反,不过应该如何设置呢?小编找了很久,也没有答案,所以只能自己动手,丰衣足食咯。
先看检测高电平脉冲的代码:
//定时器2中断服务程序
void TIM2_IRQHandler(void)
{
  if((TIM2CH1_CAPTURE_STA&0X80)==0)// 这里采用了两个变量作为临时判断条件,这两个变量最初值都为0
{   
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//如果是发生了中断,那么向下执行
   
  {     
   if(TIM2CH1_CAPTURE_STA&0X40)//如果已经捕获到高电平那么就进一步执行程序。
   {
    if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//
    {
     TIM2CH1_CAPTURE_STA|=0X80;/
     TIM2CH1_CAPTURE_VAL=0XFFFF;
    }else TIM2CH1_CAPTURE_STA++;
   }  
  }
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//
  {
   if(TIM2CH1_CAPTURE_STA&0X40)  /   
   {      
    TIM2CH1_CAPTURE_STA|=0X80;  /
    TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
       TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); /
   }else          //
   {
    TIM2CH1_CAPTURE_STA=0;   
    TIM2CH1_CAPTURE_VAL=0;
     TIM_SetCounter(TIM2,0);
    TIM2CH1_CAPTURE_STA|=0X40;  //
       TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling);  //
   }      
  }                     
  }
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); /
}//////(小小吐槽一下,网站上传图片功能个人感觉有点鸡肋。这一段很重要,必须要认真去揣摩TIM2CH1_CAPTURE_STA的赋值关系。不要做拿来主义,这样只能是拔苗助长,得不偿失。)
通过两个变量的“与”、“赋值”等操作,对高电平进行不同的操作。在输入捕获通道中,设置为上升沿触发。过来一个上升沿,进入中断,检查是否标记位被赋值,如果没有,代表是是第一次检测到高电平,记录当前定时器的值,然后设置为下降沿........


测量低电平脉冲时长的代码:简述一下思路,就是同样定义两个变量,按照上述代码的格式,照猫画虎一次,几乎没有大的改变。
具体情况,请在代码文件中进行查看。
备注:有一个语句 TIM_SetCounter(TIM2,0);具体作用我在代码中也有标注,时间所限,就不再多说了,一切尽在代码中。有空再来补全相关内容。

单片机源程序如下:
  1. #include "sys.h"
  2. #include "usart.h"               
  3. #include "delay.h"        
  4. #include "led.h"   
  5. #include "stm32f10x.h"
  6. #include "usart1.1.h"
  7. #include "oled.h"
  8. #include "timer.h"
  9. //MPU6050

  10. //串口1发送1个字符
  11. //c:要发送的字符
  12. float x,y=0;
  13. u8 xy[20];//用于接收坐标?
  14. u8 len;        



  15.         u16 led0pwmval=1;

  16. int main(void)
  17. {

  18.         int i=0;
  19.                  u8 t;

  20.         u16 times=0;

  21.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  22.         delay_init();                    //延时函数初始化         
  23.         usart_init(19200);                 //串口初始化为9600
  24.   OLED_Init();
  25.         LED_Init();
  26.         TIM2_Cap_Init(0XFFFF,7199);                //以1Mhz的频率计数 0XFFFF----1111 1111 1111 1111(2进制)//10khz计数频率,每计数一下是1ms
  27.         TIM1_PWM_Init(9999,7199);//1MHZ频率输出。
  28.         TIM3_PWM_Init(9999,7199);//10kHZ技术频率。
  29.          while(1)
  30.         {
  31.     //OLED_show();
  32.                 //show1_all();这两个暂时取消
  33.                 //delay_ms(300);不清楚会造成什么样的后果
  34.                 TIM_SetCompare3(TIM3,led0pwmval);        
  35.           TIM_SetCompare4(TIM3,led0pwmval);

  36. //                TIM_SetCompare4(TIM1,led0pwmval);
  37.          
  38.                 if(USART_RX_STA&0x8000)//判断接收数组的最高位是否为一,本次接收是否完成
  39.                 {                                          
  40.                         len=USART_RX_STA&0x3fff;//取出u16中的低16 位,得到此次接收到的数据长度
  41.                         USART_RX_STA=0;//对数组清零,方便下一次接收
  42.       
  43.                 }
  44.                 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)==0)
  45.                 {
  46.                         delay_ms(1000);
  47.                         LED=0;
  48.                         printf("1");
  49.                 }
  50.                 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)==0)
  51.                 {
  52.                         delay_ms(1000);
  53.                         LED=1;
  54.                         printf("2");

  55.                 }
  56.                 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)==0)
  57.                 {
  58.                         delay_ms(1000);
  59.                         printf("3");
  60.           }
  61.                 convey();
  62.           }
  63.         }
复制代码

目前代码还存在很多问题,求大神指导如何修改:
交替检测高低电平.7z (215.35 KB, 下载次数: 149)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:291789 发表于 2020-3-27 09:50 | 只看该作者
楼主这个程序是用定时器2的两个输入捕获通道,一个配置成检测高电平脉冲,一个检测低电平脉冲。但是两个通道接到一路PWM信号输入点?
回复

使用道具 举报

板凳
ID:729100 发表于 2020-6-6 21:15 | 只看该作者
都是捕获高电平的
回复

使用道具 举报

地板
ID:303060 发表于 2020-8-14 20:15 | 只看该作者

误导别人
回复

使用道具 举报

5#
ID:303060 发表于 2020-8-14 20:15 | 只看该作者

他这个代码简直在搞笑吧
回复

使用道具 举报

6#
ID:603342 发表于 2022-1-7 17:05 | 只看该作者
太扯了,完全不对题
回复

使用道具 举报

7#
ID:292427 发表于 2023-8-6 11:49 | 只看该作者
这个程序能用吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表