STM32定时器输入捕获功能应用——超声波模块

发布者:Yudie最新更新时间:2025-08-22 来源: cnblogs关键字:STM32  定时器  输入捕获  超声波模块 手机看文章 扫描二维码
随时随地手机看文章

一、工作原理

输入捕获是STM32单片机定时器的一项重要的功能,应用很广泛,常用于测量脉冲宽度,周期等。

超声波模块测距的原理是:单片机给超声波模块(我用到的超声波模块型号是HC-SR04,下面简称HC-SR04)发送一个大于10us的高电平,触发HC-SR04发出8个40kHz的方波,并自动检测是否有信号返回,如果有信号返回,就会通过Echo对单片机输出一个高电平,高电平的持续时间就是超声波从发射到返回的时间。

换而言之,单片机的工作就是给HC-SR04的Trig端发送一个一个大于10us的高电平,触发HC-SR04工作,然后利用输入捕获功能计算出HC-SR04的Echo端输入的高电平持续时间就可以测出超声波发出到返回的时间,声音在空气中的传播速度是340m/s,因此利用公式:测试距离=(高电平时间 * 声速)/2,就可以算出超声波模块与前方的物体之间的距离是多少。原理图如下:

 

用一个简图来说明输入捕获测量高电平延续时间的实现原理:

 

 

二、利用CubeMX生成驱动代码

HC-SR04上有4个引脚:VCC(5V)、GND、Trig(控制端)、Echo(接收端),所以需要配置一个GPIO作为控制HC-SR04的引脚,Echo这个引脚在配置定时器的时候就会自动配置好,不需要单独配置。另外还需要配置一个串口作为打印口方便调试。

1、时钟源配置:

 

 

 2、定时器

 

 

 

 

 3、控制引脚的配置

 4、开启串口

 

配置完成后生成代码。


三、修改代码


1、写一个us级别的延时:


/********************************************

*函数名称:void delay_us(__IO uint32_t delay)

*函数形参:__IO uint32_t delay--延时时间

*函数返回值:无

*函数功能:微秒级别延时

*********************************************/

void delay_us(__IO uint32_t delay)

{

    int last, curr, val;

    int temp;

 

    while (delay != 0)

    {

        temp = delay > 900 ? 900 : delay;

        last = SysTick->VAL;

        curr = last - CPU_FREQUENCY_MHZ * temp;

        if (curr >= 0)

        {

            do

            {

                val = SysTick->VAL;

            }

            while ((val < last) && (val >= curr));

        }

        else

        {

            curr += CPU_FREQUENCY_MHZ * 1000;

            do

            {

                val = SysTick->VAL;

            }

            while ((val <= last) || (val > curr));

        }

        delay -= temp;

    }

}

 

2、重定向


/********************************************

*函数名称:int fputc(int ch, FILE* stream)

*函数功能:重定向

*********************************************/

int fputc(int ch, FILE* stream)

{

     

   HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);

    return ch;

}


3、触发信号


/********************************************

*函数名称:void Trigger_Signal(__IO uint32_t us)

*函数形参:__IO uint32_t us--触发信号保持时间

*函数返回值:无

*函数功能:触发信号

*********************************************/

void Trigger_Signal(__IO uint32_t us)

{

    HAL_GPIO_WritePin(Trigger_GPIO_Port,Trigger_Pin,GPIO_PIN_SET);

    delay_us(us);

    HAL_GPIO_WritePin(Trigger_GPIO_Port,Trigger_Pin,GPIO_PIN_RESET);

    printf('发送触发信号rn');

}


4、 输入捕获中断回调函数:


/********************************************

*函数名称:void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

*函数形参:TIM_HandleTypeDef *htim--定时器句柄

*函数返回值:无

*函数功能:捕获到高电平后,计数器清零,配置为低电平捕获,

    当捕获到低电平时,读出CCR的值
*备注:TIM2_CH2_CAPTURE_STA这个是uint8_t数据类型的全局变量,
   它的每一位数据可以自定义为某些状态,在这里,第7位为1表示捕获完成,为0表示未完成,
   第6位为1表示捕获到上升沿,为0表示未捕获到高电平,0~5bit保留;
   TIM2_CH2_ELAPSED_CNT也是一个全局变量,表示从捕获到高电平起,计数器溢出的次数,
   TIM2_CH2_CAPTURE_VAL也是一个全局变量,当捕获到下降沿后把CCR2的值读取到这个变量里
*

*********************************************/

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

{

    if((TIM2_CH2_CAPTURE_STA&0x80) != 0x80)//还未完成捕获

    {

        if((TIM2_CH2_CAPTURE_STA&0x40) == 0)  //此前尚未捕获到上升沿,那么这次捕获到的就是上升沿

        {

            TIM2_CH2_CAPTURE_VAL = 0;    //清零,防止干扰

            TIM2_CH2_ELAPSED_CNT = 0;    //清零,捕获到上升沿后重新计算周期溢出次数

            TIM2_CH2_CAPTURE_STA |= 0x40;  //捕获到一个上升沿  

            __HAL_TIM_DISABLE(&htim2);    //停止TIM2

            __HAL_TIM_SET_COUNTER(&htim2,0);  //把TIM2的计数器清零

            TIM_RESET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_2);  //清除原来的设置

            TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING);  //将TIM2的通道2输入捕获设置为下降沿捕获

            __HAL_TIM_ENABLE(&htim2);  //使能TIM2

             

        }

        else

        {

            TIM2_CH2_CAPTURE_STA |= 0x80;  //捕获到一个下降沿,代表捕获完成

            TIM2_CH2_CAPTURE_VAL = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2);  //把此时CCR2的值读到变量TIM2_CH2_CAPTURE_VAL

            TIM_RESET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_2);  //清除原来的设置

            TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING);  //设置为上升沿捕获

        }

    }

}


5、计数周期溢出中断回调函数:


/********************************************

*函数名称:void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

*函数形参:TIM_HandleTypeDef *htim--定时器句柄

*函数返回值:无

*函数功能:定时器溢出次数计算

*********************************************/

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

    TIM2_CH2_ELAPSED_CNT++;    //每次溢出,该变量增加1

}


6、计算高电平的持续时间:


/********************************************

*函数名称:uint32_t CalculatePulseWide(void)

*函数形参:无

*函数返回值:无

*函数功能:计算出高电平的宽度

*********************************************/

uint32_t CalculatePulseWide(void)

{

    uint32_t PulseWide = 0;

    if((TIM2_CH2_CAPTURE_STA&0x80) == 0x80)

    {

        PulseWide = 0xffff*TIM2_CH2_ELAPSED_CNT+TIM2_CH2_CAPTURE_VAL;

        TIM2_CH2_CAPTURE_STA = 0;   //计算完将该变量清零,其实即使不清零应该也没关系,每次捕获到上升沿也会清零

        TIM2_CH2_ELAPSED_CNT = 0;   //计算完将该变量清零,其实即使不清零应该也没关系,每次捕获到上升沿也会清零

     }
     return PulseWide;
}

7、计算距离:


/********************************************

*函数名称:void GetDistance(void)

*函数形参:无

*函数返回值:无

*函数功能:获取距离

*********************************************/

void GetDistance(void)

{

    float temp = 0;

    float distance = 0;

    Trigger_Signal(20);  //发送触发信号,因为要大于10us,这里就设置为20us

    while(!temp)      //等待计算出高电平的时间,如果temp为0,说明还未计算出来,继续等待

    {

        temp = CalculatePulseWide();       

    }

    printf('temp:%frn',temp);  

    distance = (float)(temp*0.034)/2;  //计算出距离

    printf('distant:%.2f CMrn',distance);

 

    HAL_Delay(100);    //手册中说明两次测量的时间间距最好大于60ms,避免引起干扰,这里取100ms

 

}


8、主函数 


int main(void)

{

  /* USER CODE BEGIN 1 */

 

  /* USER CODE END 1 */

 

  /* MCU Configuration--------------------------------------------------------*/

 

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

  HAL_Init();

 

  /* USER CODE BEGIN Init */

 

  /* USER CODE END Init */

 

  /* Configure the system clock */

  SystemClock_Config();

 

  /* USER CODE BEGIN SysInit */

 

  /* USER CODE END SysInit */

 

  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  MX_TIM2_Init();

  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

    printf('********** HC-RS04 *********rn');

    HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);  //开启输入捕获中断

  /* USER CODE END 2 */

 

  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */

        GetDistance();  //计算出距离

    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}

  

完成代码修改后,烧录到单片机上,进行了测量,发现测得的距离跟实际距离之间的误差不大,当实际距离等于1米的时候,误差大概在1~5cm左右波动。


关键字:STM32  定时器  输入捕获  超声波模块 引用地址:STM32定时器输入捕获功能应用——超声波模块

上一篇:linux shell数据重定向(输入重定向与输出重定向)详细分析
下一篇:STM32定时器应用——PWM

推荐阅读最新更新时间:2026-03-22 11:17

STM32定时器输入捕获功能应用——超声波模块
一、工作原理 输入捕获是STM32单片机定时器的一项重要的功能,应用很广泛,常用于测量脉冲宽度,周期等。 超声波模块测距的原理是:单片机给超声波模块(我用到的超声波模块型号是HC-SR04,下面简称HC-SR04)发送一个大于10us的高电平,触发HC-SR04发出8个40kHz的方波,并自动检测是否有信号返回,如果有信号返回,就会通过Echo对单片机输出一个高电平,高电平的持续时间就是超声波从发射到返回的时间。 换而言之,单片机的工作就是给HC-SR04的Trig端发送一个一个大于10us的高电平,触发HC-SR04工作,然后利用输入捕获功能计算出HC-SR04的Echo端输入的高电平持续时间就可以测出超声波发出到返回的时间,声
[单片机]
<font color='red'>STM32</font><font color='red'>定时器</font><font color='red'>输入</font><font color='red'>捕获</font>功能应用——<font color='red'>超声波</font><font color='red'>模块</font>
STM32通用定时器输入捕获(实例:输入捕获
通用定时器输入捕获概述 输入捕获的工作原理 在通用定时器框图中,主要涉及到最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、左下部分(输入捕获)这三个部分。这里主要讲解一下左下部分(输入捕获),其他两个部分可以参考文章:【STM32】通用定时器的基本原理(实例:定时器中断)。 输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6、TIM7,其他的定时器都有输入捕获的功能。下面以一个简单的脉冲输入为例,简单地讲述一下输入捕获用于测量脉冲宽度的工作原理: 先设置输入捕获为上升沿检测,记录发生上升沿时TIMx_CNT的值。然后配置捕获信号为下降沿捕获,当下降沿到来的时候
[单片机]
<font color='red'>STM32</font>通用<font color='red'>定时器</font>的<font color='red'>输入</font><font color='red'>捕获</font>(实例:<font color='red'>输入</font><font color='red'>捕获</font>)
stm32 定时器5输入捕获
timer.h #ifndef _TIM5SANP_H #define _TIM5SANP_H #include sys.h void TIM14_PWM_Init(u32 arr,u32 psc); void TIM5_CH1_Cap_Init(u32 arr,u16 psc); #endif timer.c #include timer.h TIM_ICInitTypeDef TIM5_ICInitStructre; void TIM5_CH1_Cap_Init(u32 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeD
[单片机]
STM32定时器5的输入捕获实验
此处使用的普中开发板,实验内容定时器5输入捕获通道1的高电平时长。 软件实现方法: 定时器5主要使用了两个功能: ①时基单元;②输入捕获; 从下文可知,通过定时器5捕获到相应的极性(eg:上升沿或高电平and so on)后,保存计数器的当前值到捕获/比较寄存器(TIMx_CCRx)中。而后,通过第二次捕获成功后,通过差值就可以求出该极性的周期或保持时间。此实验室捕获高电平的时间,通过先捕获上升沿再捕获下降沿,即可求出一个高电平的时长。 数据手册描述如下: 在输入捕获模式下,当检测到ICx信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存 器(TIMx_CCRx)中。当发生捕获事件时,相应的CCxIF
[单片机]
<font color='red'>STM32</font><font color='red'>定时器</font>5的<font color='red'>输入</font><font color='red'>捕获</font>实验
STM32——定时器TIME模块输入捕获
STM32的定时器模块有很强大的功能,除了普通的定时功能之外还可以进行输入捕获和输出比较(PWM),PWM已在别的文章中介绍过,现在介绍一下输入捕获。 在这里先说本人在测试时想到的两个疑问: 疑问1:STM32的同一个定时器是否能同时进行输入捕获和输出比较(PWM)? 疑问2:假设疑问1的答案是可以,那输入捕获的范围是不是受限制? 功能实现: 1、既然是输入捕获,肯定需要相关引脚对信号进行检测,所以需要查找开发手册和数据手册来确定是哪几个引脚,要用哪几个引脚,然后给予合适的配置(图1)。 2、要进行输入捕获实验,首先需要配置某个定时器的时基功能,这样我们才能根据这个时基计算我们的捕获信息;其次就是要配置输
[单片机]
<font color='red'>STM32</font>——<font color='red'>定时器</font>TIME<font color='red'>模块</font>之<font color='red'>输入</font><font color='red'>捕获</font>
STM32之通用定时器输入捕获模式
#include stm32f10x.h /* RCC时钟配置 */ void RCC_config() { ErrorStatus HSEStartUpStatus; /* RCC寄存器设置为默认配置 */ RCC_DeInit(); /* 打开外部高速时钟 */ RCC_HSEConfig(RCC_HSE_ON); /* 等待外部高速时钟稳定 */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { /* 设置HCLK = SYSCLK */ RCC_HCLKConfig(RCC_SYSCLK_
[单片机]
STM32 通用定时器作为输入捕获 学习笔记
STM32 通用定时器作为输入捕获 通用定时器作为输入捕获的使用。我们将用TIM5的通道1(PA0)来做输入捕获,捕获PA0上高电平的脉宽(用 WK_UP 按键输入高电平),通过串口打印高电平脉宽时间。 输入捕获简介: 输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。 STM32 的输入捕获,简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候, 将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA
[单片机]
STM32学习笔记之定时器输入捕获实验
实验目的: 在串口调试助手上打印出按键按下的时间 实验步骤: 实验程序: /*******************************timer.c********************************/ #include sys.h #include stm32f4xx.h extern u8 TIM5CHA1_CAPTURE_STA; extern u16 TIM5CHA1_CAPTURE_VAL; /* 本示例的作用就是, 当按键按下时,每次输入捕获的时间差, 然后从串口调试助手中打印出其时间差; */ /*
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved