输入捕获学习


《用CubeMX学习STM32》

注释 点击上面蓝字进入完整专栏,这个系列所有文章都会整合到这个专栏

5、STM32定时器输入捕获

前言: STM32定时器输入捕获简介

STM32的输入捕获可以用于捕获脉宽, 测量时间 . 例如超声波测距模块就是需要用输入捕获功能, 通过测量输入脉冲的高电平脉宽 , 从而计算出测量物体的距离 ;
定时器PWM工作模式上篇博客讲过了, 上篇是输出PWM, 本篇是要输入, 即外面的信号送给单片机的引脚, 然后单片机测量出脉宽 ;

注: 下面根据正点原子的标准库函数教程分析, 并用CubeMX完成配置以及HAL库函数编程


如图所示 : 以测量高电平脉宽为例, 我们先设置定时器通道为上升沿捕获, 到1的时候触发定时器计数, 然后立刻设置为下降沿捕获, 到2的时候就捕获到下降沿, 再记录输入捕获寄存器的值, 两个时间差就是高电平时长tH;
需要注意的是, 在tH这段高电平时间内, 是由很多个向上计数的脉冲来计数的。在这里面计数可能溢出N多次; 下面是原子的库函数指南pdf里面讲解的图

  在tH这段高电平里面, 可能有多个向上计数的脉冲, 而那个三角向上计数脉冲也可能溢出多次。就是利用这N多个向上计数的脉冲来计算tH的值的。  ARR的值是我们自己设定的,所以可以知道溢出一次是多长时间, 每溢出一次, 都给溢出次数加一。 溢出次数以及检测高低电平的数据记录在自己设定的一个变量里面
  N*ARR + CCRx2即为CNT计数次数, 从而就可以算出计数时间, 算出高电平时长
  N: 溢出次数  ARR: 溢出一次的时间   在一个tH内,溢出的次数不一定正好是整数, 所以用记录下CCRx2的值, 用以补充, 这样tH的值就更精确了

这是一个八位的变量,可以将其看做8位寄存器,不同的位储存不同的数据


5.1 操作简介

   通过信号发生器给单片机对应引脚输入一个给定频率和占空比的矩形波信号, 单片机通过输入捕获测量出高电平时长; 通过串口发送至PC端的串口调试助手查看测量的脉宽是否准确


5.2 STM32CubeMX配置初始化+IAR编程

Step1 : Cube配置

  • USART1串口1配置(按照串口那一篇配置串口即可–>串口通信 )


注: 详细解释转至串口通信

  • 时钟树配置


Step2 : Keil/IAR编程

  • (1)重定向printf函数(重定向之后我们才可以使用printf函数将调试信息打印到串口调试助手) 下面是串口通信那一篇博客写的话,直接搬到这里:
    在学习C语言的时候, 大家肯定都用过printf这个函数, printf可以将指定字符打印到电脑的显示器上;
    但是, 单片机要使用这个就要把他打印的方向改一下, 不是打印在电脑的命令行中, 而是打印到串口里面,传输到串口调试助手. 因此我们需要重定向printf函数;
    重定向后我们要将调试信息打印到USART1中, 需要对printf所依赖的打印函数fputc()重定向 .

    在usart.c里面添加重定向代码

    以后这段代码直接抄就好了, copy下来用

    /* USER CODE BEGIN 0 */
    #include "stdio.h"#ifdef __GNUC__#define PUTCHAR_PROTOTYPE int _io_putchar(int ch)
    #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    #endif /* __GNUC__*/// 重定向C语言中的printf函数
    PUTCHAR_PROTOTYPE
    {HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);return ch;
    }/* USER CODE END 0 */
    
  • (2) 查看一下定时器相关代码学习

  • 打开之后跟正点原子的标准库函数写的代码对比一下, 又利于自己理解CubeMX配置的机理, 以后会更得心应手, 慢慢的自己就可以一直标准库函数用HAL库写了。

    这张图左边是CubeMX配置后自动生成的代码, 蓝色框框里面就是对应的CubeMX里面的配置; 右侧是原子的标准库例程代码, 可以对比一下, 增强理解

    tips:CSDN只能上传不超过5M的图片, 所以这个图片经过了压缩 , 放大看可以看清晰一点。

  • (3) 编写中断部分函数

    • 因为要在中断中捕获上升沿和下降沿, 所以主要代码写在中断服务函数里面

      下图是计数中断

      TIM5CH1_CAPTURE_STA虽然是我们定义的一个变量,但可以把它看做是一个8位的寄存器

    • 下图是捕获中断

      在HAL_TIM_PeriodElapsedCallback()回调函数中用以处理计数次数和时间;   在HAL_TIM_IC_CaptureCallback()回调函数负责处理捕获到的上升沿和下降沿,
      并随着捕获到上升沿而更改为下降沿捕获,   随着捕获到下降沿而更改定时器为上升沿捕获.

    下面是完整代码:

    /* USER CODE BEGIN 1 */
    /*  bit7 捕获完成标识 bit6 捕获到高电平标识   bit5~0 捕获高电平后定时器溢出的次数 */
    uint8_t     TIM5CH1_CAPTURE_STA = 0;   // 输入捕获状态
    uint32_t    TIM5CH1_CAPTURE_VAL;        // 输入捕获值(TIM2/TIM5是32位的定时器所以这里定义为uint32_t)
    // 中断服务函数里面会自动调用这个回调函数  这个是定时器更新中断中处理的函数
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {if (htim->Instance == TIM5)   // 判断是定时器5发生中断{if ((TIM5CH1_CAPTURE_STA & 0x80) == 0) // 还未成功捕获{if (TIM5CH1_CAPTURE_STA & 0x40)          // 捕获到高电平{if ( (TIM5CH1_CAPTURE_STA & 0x3f) == 0x3f )      // 如果高电平太长  做溢出处理{TIM5CH1_CAPTURE_STA |= 0x80;             // 标记成功捕获了一次TIM5CH1_CAPTURE_VAL = 0xffffffff;}else{TIM5CH1_CAPTURE_STA++;        // 若没有溢出, 就只让TIM5CH1_CAPTURE_STA自加就ok}}}}
    }// 定时器输入捕获中断处理回调函数,该函数在 HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) 中会被调用
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {if ( (TIM5CH1_CAPTURE_STA & 0x80) == 0 ) // 还未成功捕获{if (TIM5CH1_CAPTURE_STA & 0x40)           // 捕获到一个下降沿{TIM5CH1_CAPTURE_STA |= 0x80;       // 标记成功捕获到一次高电平脉宽TIM5CH1_CAPTURE_VAL = HAL_TIM_ReadCapturedValue(&htim5, TIM_CHANNEL_1);   // 获取当前的捕获值. 即CCRx2TIM_RESET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1);                        // 清除原来的设置TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);    // 配置TIM5通道1上升沿捕获}else{TIM5CH1_CAPTURE_STA = 0;    // 清空自定义的状态寄存器TIM5CH1_CAPTURE_VAL = 0; // 清空捕获值TIM5CH1_CAPTURE_STA |= 0x40;// 标记捕获到了上升沿__HAL_TIM_DISABLE(&htim5); //关闭定时器5__HAL_TIM_SET_COUNTER(&htim5,0);TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);   //一定要先清除原来的设置!!TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器5通道1设置为下降沿捕获__HAL_TIM_ENABLE(&htim5);//使能定时器5}}
    }/* USER CODE END 1 */
    

    tips:每句话都有注释, 不要一看到密密麻麻代码就不看了, 看一下并不是很难理解。 也不要因为看到全是大写字母的函数或者变量而犯怵, 静下心来用两分钟看一看很容易看懂

    • 还有一个问题:就是这里为什么用HAL_TIM_PeriodElapsedCallback而不是其他的callback呢? 原因在IRQ_Handler函数里面。
  • (4) 主函数程序(main.c)

    • 首先使能定时器中断、同时定义一个变量备用:

      /* USER CODE BEGIN 2 */
      HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_1); // 开启输入捕获中断
      __HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE);  //使能更新中断
      long long temp = 0;        // 定义一个变量用以存储捕获到的时间 long long型是为了防止数据溢出
      /* USER CODE END 2 */
      
    • 在while(1)循环测量数据并打印

      while (1)
      {/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_Delay(10);// 信号发生器输入信号 串口打印高电平时长  msif (TIM5CH1_CAPTURE_STA & 0x80)   // 如果捕获完成{temp = TIM5CH1_CAPTURE_STA & 0x3f;temp *= 0xffffffff;                // Total Overflow Time(总的溢出时间)temp += TIM5CH1_CAPTURE_VAL;    // Get Total High Level Time(获取总的高电平时长)printf("HIGH: %lld ms\r\n", temp/1000); // Print Total High Level Time(打印总的高电平时长)TIM5CH1_CAPTURE_STA = 0;             // Clear Capture State , Open The Next Capture(清除捕获状态,打开下一次捕获)}
      }
      /* USER CODE END 3 */
      
  • (5) 至此程序就完成了.


    2020年4月10日2020年4月10日20:53:30
    == 补充说明:==
      输入捕获这一节 有个学弟反应有点问题,如果用检测按键输入,按下时间太久了就会显示4194ms ; 类比到我这里的操作就是,信号发生器产生的波形频率很低的时候,就达到了测量上限,高电平最多4194ms;

  这是因为原子的例程有一个时间上限 在于0x3f那个地方,0x3F就限制了时间的上限;下面这个是他给我的截图;
  后面返校之后我会修改代码,完善这个地方

在这里非常感谢这位学弟提出问题,也希望他能在比赛中拿到很好的排名。@冷冷~na


在主函数里面, TIM5CH1_CAPTURE_STA & 0x80的意思是判断有没有捕获到高电平 用TIM5CH1_CAPTURE_STA和0x80相与, 从而判断TIM5CH1_CAPTURE_STA的6位是否为1, 进而判断出是否捕获到高电平; 下面的一些涉及到相与的操作也都类似, 把一个变量看做一个寄存器, 把0x80、 0xffffffff等转换为二进制就好判断了, 在演草纸上画一下就很清楚

  • (6) 编译下载

上述代码都是之前经过测试的,但是当前由于疫情,没有条件展现结果, 如果有人用了这些代码并测试,有什么问题的话可以下面评论告知,感激不尽。效果展示会在后期补上


待到春暖花开时,愿人间皆安,山河无恙。樱花会如期而至

Author : 李光辉
date : Sun Feb 16 22:50:25 CST 2020
blog ID: Kevin_8_Lee
blog site : https://blog.csdn.net/Kevin_8_Lee

第五节:STM32输入捕获(用CubeMX学习STM32)相关推荐

  1. STM32输入捕获模式设置并用DMA接收数据

    参考: STM32的PWM输入模式设置并用DMA接收数据 Input capture mode The input stage samples the corresponding TIx input ...

  2. Python编程基础:第五节 用户输入User Input

    第五节 用户输入User Input 前言 实践 前言 为了方便于程序与用户进行交互,我们通常需要获取用户的键盘输入,这里我们就需要用到input()函数.需要注意的是,函数的返回结果均为字符串,如果 ...

  3. stm32 输入捕获 测量脉宽

    选用通用定时器TIM5的CH1. PA0接一个按键,默认接GND,当按键按下时,IO口被拉高,此时,可利用定时器的输入捕获功能,测量按键按下的这段高电平的时间. 宏定义方便程序升级.移植,举个例子: ...

  4. STM32 输入捕获 测量频率 PWM占空比

    看了网上关于STM32输入捕获的资料,有几篇介绍的很不错,但是内容上还有一点问题,稍加修改,大家可以参考一下. 重要概念理解(对于理解输入捕获功能很重要,特别看了数据手册CCR1\CCR2\CCR3\ ...

  5. STM32输入捕获实验

    STM32 输入捕获工作过程(通道1为例) 通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TI ...

  6. STM32输入捕获测试频率和正负脉宽

    @STM32输入捕获测试频率和正负脉宽 本博客相关程序调用转载正点原子 正点原子@ALIENTEK 广州市星翼电子科技有限公司 这次做的主要是测试频率,但系,也趁此机会捕获了高低脉宽的时间,题目所说的 ...

  7. stm32 输入捕获学习(二)

    (本文参考STM32  开发指南 V1.3   -- ALIENTEK 战舰 STM32 开发板库函数教程 ) 1. 实验设计 我们用 TIM5 的通道 1(PA0)来做输入捕获,捕获 PA0 上高电 ...

  8. stm32 输入捕获学习(一)

    输入捕获模式可以用来测量脉冲宽度或者测量频率.STM32 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能.STM32 的输入捕获,简单地说就是通过检测 TIMx_CHx 上的边沿信 ...

  9. STM32 输入捕获功能

    目录 01.STM32捕获功能 02.输入捕获过程 03.代码配置 本文将介绍通过STM32的定时器输入捕获,如果对定时器不太熟悉的同学可以看下之前的文章<STM32基础定时器详解>,关于 ...

  10. STM32 输入捕获测量脉冲周期/频率

    STM32捕获模式连续测量脉冲周期/频率,使用类似中断的方式,使用STM32内部的硬件滤波器,脉冲周期量程很大(固定时间脉冲计数的方式,量程有限). 硬件: STM32F103R8T6  TIM2  ...

最新文章

  1. homeassistant树莓派cpu_集成ESP8266的WiFi RGB灯泡接入Home Assistant
  2. boost::remove_edge用法的测试程序
  3. 轻量级的日期时间控件Pikaday
  4. 类库探源——System.ValueType
  5. 霍纳法树形流图中处理机p个数_2009系统结构试卷答案
  6. mediawiki自动生成sitemap
  7. Rulo扫地机器人app_米家扫拖机器人1T测评|米家扫拖机器人1T的3D避障实际效果如何?...
  8. 下午进行就业前的一次培训
  9. 解决Spring Boot启动项目Tomcat不能访问80端口的问题
  10. TCP/UDP-路由交换原理6-【HCNA笔记】
  11. 【微信小程序开发】 踩坑 抽奖幸运大转盘 完美实战
  12. SM951 NVMe 版本安装Win7 的正确方法
  13. simulink仿真实例_推荐几本关于制冷仿真的书籍(制冷仿真必备)
  14. mapgis k9将wp、wl、wt转shp属性字段名乱码
  15. 机房的防火墙有何作用
  16. 3-8 B: 分离LZY的字符串
  17. 许小年:企业家精神的衰落与重振
  18. 数商云智慧医疗管理系统解决方案:医药电商系统实现智能化改造
  19. 微信小程序 如何上传音视频到百度云Bos cloud BCE
  20. 2013年计算机模拟考2套题操作题,2013年考研模拟题二:计算机

热门文章

  1. JavaScript的apply和call方法及其区别
  2. hpasmcli查看HP服务器内存状态
  3. Extmail企业邮箱构建指南
  4. nyist oj 19 擅长排列的小明(dfs搜索+STL)
  5. 《编写有效用例》阅读笔记05
  6. struts2 中的 addActionError 、addFieldError、addActionMessage方法的区别添加错误信息
  7. 小议jQuery插件开发
  8. 二层交换机的安全方案与实施
  9. JS 回车提交,兼容IE、火狐、Opera、Chrome、Safari
  10. 用XAML做网页!!—广告展示区