STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例

MCU主控:

STM32L051C8T6

超声波模块:

RCWL-1601

STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例_第1张图片

STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例_第2张图片

STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例_第3张图片

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

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

输入捕获简介

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

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

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

STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例_第5张图片

2、STM32CubeMx 配置

1)、系统时钟配置

STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例_第6张图片

2)、定时器22配置

STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例_第7张图片

3)、串口1配置

STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例_第8张图片

3、代码说明:

tim.c文件

/* USER CODE BEGIN 0 */
#include "stdio.h"

uint8_t   text_flag = 0;
uint8_t   dis_fm = 0;
uint8_t   Channel2Edge = 0;
uint16_t  Channel2HighTime, Channel2RisingTime, Channel2FallingTime;

/* USER CODE END 0 */

.....

/* USER CODE END 1 */

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
  /*防止未使用参数(s)编译警告*/
	UNUSED(htim);

	if(htim->Instance == htim22.Instance)
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			if(Channel2Edge == 0)          //捕获上升沿
			{
				Channel2RisingTime = HAL_TIM_ReadCapturedValue(&htim22, TIM_CHANNEL_2);                         //获取上升沿时间点
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim22, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);        //切换捕获极性
				HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2);     //切换捕获极性后需重新启动

				Channel2Edge = 1;          	 //上升沿、下降沿捕获标志位
			}
			else if(Channel2Edge == 1)     //捕获下降沿
			{
				Channel2FallingTime = HAL_TIM_ReadCapturedValue(&htim22, TIM_CHANNEL_2);                       //获取下降沿时间点
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim22, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);        //切换捕获极性
				HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2);   	 //切换捕获极性后需重新启动

				Channel2HighTime = Channel2FallingTime < Channel2RisingTime ? Channel2FallingTime + 0xffff - Channel2RisingTime + 1 : Channel2FallingTime - Channel2RisingTime;
				//高电平持续时间 = 下降沿时间点 - 上升沿时间点
				dis_fm = Channel2HighTime * 17 / 100; //计算超声波测量距离
				printf("dis_fm = %dcm \r\n", dis_fm);
				//i++;//累加计数
				Channel2Edge = 0;		  			 //一次采集完毕,清零
			}
			HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
		}
	}
}


/* USER CODE END 1 */

usart.c文件

/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
....

/* USER CODE BEGIN 1 */
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
 
  return ch;
}
/* USER CODE END 1 */

main.c文件

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

void Delay_us(uint32_t t)//64M条件下的一微妙
{   
    int n  =  11;
    while(--t)
    {
        while(--n);
        n = 11;
    }
}

void gases_start_signal(void)
{  
  unsigned char i=0;

  HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
  //延时20us
  Delay_us(20);

  HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
/* USER CODE END 0 */

....

/* USER CODE BEGIN 2 */
	HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2);
/* USER CODE END 2 */
....

/* USER CODE BEGIN WHILE */
  while (1)
  {
		//ADC_GetValue();
		gases_start_signal();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

串口助手打印结果:

STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例_第9张图片

代码连接

你可能感兴趣的:(stm32单片机开发)