cubemx下的输入捕获进行超声波测距

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sensiki/article/details/70788817

主控板

  • NUCLEO-F411RE

NUCLEO-F411RE 是ST公司推出的一款针对STM32F4系列设计的Cortex-M4开发板,具有 mbed 功能,支持Arduino。同时还提供 ST Morpho 扩展排针,可连接微控制器的所有周边外设。
开发板基于STM32F411RET6设计,开发板还集成了ST-LINK/V2-1仿真下载器(但仅对外提供SWD接口),免除另外采购仿真器或下载器的麻烦。并且具备Arduino接口,可接入 Arduino 巨大生态系统的各种 Shield 扩展板,能够轻松快速增加特殊功能。

超声波模块

  • HC-SR04超声波模块

使用HC-SR04超声波模块,此模块性能稳定,测度距离精确,模块高精度,盲区小。主要的电气参数如下:

电气参数 HC-SR04超声波模块
工作电压 DC 5V
工作电流 15mA
工作频率 40Hz
最远射程 4m
最近射程 2cm
测量角度 15度
输入触发信号 10Us的TTL脉冲
输出回响信号 输出TTL电平信号,与射程成比例
规格尺寸 45*20*15mm

基本工作原理:
1、采用IO口TRIG触发测距,给至少10us的高电平信号;
2、模块自动发送8个40khz的方波,自动检测是否有信号返回;
3、有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;

本模块使用方法简单,一个控制口发一个10US以上的高电平,就可以在接收口等待高电平输出.一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,即可以得到你移动测量的值。超声波模块时序图如下:
这里写图片描述

输入捕获简介

输入捕获可以用来测量脉冲宽度或者测量频率。超声波用到的是测量脉宽,这里我以测量脉宽为例,用一个简图来说明输入捕获的原理,如下图:
这里写图片描述

如上图所示,就是输入捕获测量高电平脉宽的原理,假定定时器工作在向上计数模式,图中t1-t2时间,就是我们需要测量的高电平时间。测量方法如下:首先设置定时器通道x为上升沿捕获,这样,t1时刻就会捕捉到CNT值,然后立即清零CNT,并设置通道x为下降沿捕获,这样t2时刻又会发生捕获事件,得到此时的CNT值,记为CCRx2。这样,根据定时器的计数频率,我们就可以算出t1-t2的时间,从而得到高电平的脉宽。

在t1-t2之间,可能产生N次定时器溢出,这就要求我们对定时器溢出做处理,防止高电平太长,导致数据不准确。如上图所示,t1-t2之间CNT计数的的次数等于:N*ARR+CRRx2,有了这个计数次数,再乘以CNT的计数周期,即可得到t1-t2的时间长度,即高电平持续时间。

STM32CubeMX配置定时器输入捕获功能

使用STM32CubeMX配置输入捕获功能初始化代码步骤如下:

  1. 在Pinout->TIM2配置项中,配置Channel1的值为Input Capture direct mode,然后选中Internal Clock。操作过程如下图所示
    这里写图片描述
  2. 进入Configuration->TIM2配置页,在弹出的界面中点击Parameter Settings选项卡,Counter Settings配置栏下面的四个选项就是用来配置定时器的预分频系数,自动装载值,计数模式以及时钟分频因子。在界面的Input Capture Channel 1配置栏配置输入捕获通道1的捕获极性,分频系数、映射、滤波器等参数,操作方法如下图:
    这里写图片描述

  3. 进入Configuration->NVIC配置页,在弹出的界面中点击NVIC选项卡,配置Interrupt
    这里写图片描述

  4. 配置PA1口为输出口
    这里写图片描述

配置完上面步骤后,生成代码。在生成的代码中,并没有使能相应中断的代码,也没有改写中断处理回调函数,这都需要我们自己来编写

软件设计

tim.c文件新增的内容如下

/* USER CODE BEGIN 1 */
uint8_t   TIM2CH1_CAPTURE_STA=0;    //ÊäÈ벶»ñ״̬                          
uint32_t    TIM2CH1_CAPTURE_VAL;    //ÊäÈ벶»ñÖµ(TIM2/TIM5ÊÇ32λ)

//¶¨Ê±Æ÷¸üÐÂÖжϣ¨¼ÆÊýÒç³ö£©Öжϴ¦Àí»Øµ÷º¯Êý£¬ ¸Ãº¯ÊýÔÚHAL_TIM_IRQHandlerÖлᱻµ÷ÓÃ
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//¸üÐÂÖжϣ¨Òç³ö£©·¢ÉúʱִÐÐ
{

    if((TIM2CH1_CAPTURE_STA&0X80)==0)//»¹Î´³É¹¦²¶»ñ
    {
            if(TIM2CH1_CAPTURE_STA&0X40)//ÒѾ­²¶»ñµ½¸ßµçƽÁË
            {
                if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//¸ßµçƽ̫³¤ÁË
                {
                    TIM2CH1_CAPTURE_STA|=0X80;      //±ê¼Ç³É¹¦²¶»ñÁËÒ»´Î
                    TIM2CH1_CAPTURE_VAL=0XFFFFFFFF;
                }
                else TIM2CH1_CAPTURE_STA++;
            }    
    }       
}


//¶¨Ê±Æ÷ÊäÈ벶»ñÖжϴ¦Àí»Øµ÷º¯Êý£¬¸Ãº¯ÊýÔÚHAL_TIM_IRQHandlerÖлᱻµ÷ÓÃ
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//²¶»ñÖжϷ¢ÉúʱִÐÐ
{
    if((TIM2CH1_CAPTURE_STA&0X80)==0)//»¹Î´³É¹¦²¶»ñ
    {
        if(TIM2CH1_CAPTURE_STA&0X40)        //²¶»ñµ½Ò»¸öϽµÑØ      
            {               
                TIM2CH1_CAPTURE_STA|=0X80;      //±ê¼Ç³É¹¦²¶»ñµ½Ò»´ÎµÍµçƽÂö¿í
                TIM2CH1_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//»ñÈ¡µ±Ç°µÄ²¶»ñÖµ.

                long long temp=0;
                temp=TIM2CH1_CAPTURE_STA&0X3F; 
                temp*=0XFFFFFFFF;               //Òç³öʱ¼ä×ܺÍ
                temp+=TIM2CH1_CAPTURE_VAL;      //µÃµ½×ܵĸߵçƽʱ¼ä
                temp=temp*17/1000;
                printf("distence:%lld cm\r\n",temp);//´òÓ¡×ܵĸߵãƽʱ¼ä 
                __HAL_TIM_DISABLE(&htim2);        //¹Ø±Õ¶¨Ê±Æ÷2
            }
        else                                //»¹Î´¿ªÊ¼,µÚÒ»´Î²¶»ñÉÏÉýÑØ
            {
                TIM2CH1_CAPTURE_STA=0;          //Çå¿Õ
                TIM2CH1_CAPTURE_VAL=0;
                TIM2CH1_CAPTURE_STA|=0X40;      //±ê¼Ç²¶»ñµ½ÁËÉÏÉýÑØ
                __HAL_TIM_DISABLE(&htim2);        //¹Ø±Õ¶¨Ê±Æ÷2
                __HAL_TIM_SET_COUNTER(&htim2,0);
                TIM_RESET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1);   //Ò»¶¨ÒªÏÈÇå³ýÔ­À´µÄÉèÖã¡£¡
                TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);//¶¨Ê±Æ÷2ͨµÀ1ÉèÖÃΪÉÏϽµÑز }           
    }       

}
/* USER CODE END 1 */

定义了两个全局变量,用于辅助实现高电平捕获。其中TIM2CH1_CAPTURE_STA是用来记录捕获状态,各位描述如下:辅助实现高电平捕获。其中TIM2CH1_CAPTURE_STA是用来记录捕获状态,各位描述如下:
bit7:捕获完成标志
bit6:捕获到高电平的标志
bit5~0:捕获高电平后定时器溢出的次数
另一个变量TIM2CH1_CAPTURE_VAL,则用来记录捕获到下降沿的时候,TIM2_CNT的值。

main函数内容

int main(void)
{

  /* USER CODE BEGIN 1 */
    long long temp=0;
  /* USER CODE END 1 */

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

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM2_Init();

  /* USER CODE BEGIN 2 */

    HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);   //¿ªÆôTIM5µÄ²¶»ñͨµÀ1£¬²¢ÇÒ¿ªÆô²¶»ñÖжÏ
  __HAL_TIM_ENABLE_IT(&htim2,TIM_IT_UPDATE);   //ʹÄܸüÐÂÖжÏ
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
            HAL_Delay(1);
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
        if(TIM2CH1_CAPTURE_STA&0X80)        //³É¹¦²¶»ñµ½ÁËÒ»´ÎµÍµçƽ
        {
            HAL_Delay(1000);
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
            HAL_Delay(1);
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);

            __HAL_TIM_SET_COUNTER(&htim2,0);
            TIM_RESET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1);   //Ò»¶¨ÒªÏÈÇå³ýÔ­À´µÄÉèÖã¡£¡
            TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//¶¨Ê±Æ÷2ͨµÀ1ÉèÖÃΪÉÏÉýÑز¶»ñ
            __HAL_TIM_ENABLE(&htim2);//ʹÄܶ¨Ê±Æ÷5
            TIM2CH1_CAPTURE_STA=0; 
        }
  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

完整工程下载:http://download.csdn.net/detail/sensiki/9825937

猜你喜欢

转载自blog.csdn.net/sensiki/article/details/70788817