基于STM32_HAL库实现超声波测距

核心板               :STM32F103C8T6。

超声波测距模块 :HC-SR04超声波测距模块

实验目的            :利用超声波测距,将测量的距离打印在串口并输出。


HC-SR04超声波测距模块介绍

        接口定义:Vcc、 Trig(控制端——PA2)、 Echo(接收端——PA11)、 Gnd

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


 测距方法介绍:

        距离 = 超声波来回的时间/2 * 340,因此最重要的就是求时间。

        方法一:利用定时器计数功能在成功发送触发信号后,通过读取Echo信号引脚的高低电平变化的时间内计数器所计数的值,再乘以计一下数的所用的时间即可计算出该段变化电平所用的时间。

        方法二:利用定时器的输入捕获功能,在Echo电平升高时进入回调函数,在回调函数中将此时的计数值保存,并设置定时器为下降沿捕获;在Echo电平降低时进入回调函数,在回调函数中将此时的计数值保存,并设置定时器为下降沿捕获(为了下次测量准备);将两次保存的计数值进行相减并乘以计一下数所用的时间就可计算出该段电平变化所用的时间。


STM32CubeMX的配置:

        配置时钟,为最高的72MHZ

 

         串口的配置

 

         定时器的配置

        ( 为了不在重复配置,这里就直接配置成输入捕获模式,开启溢出中断与捕获中断,方法一只需要开启定时器即可。)

        (利用TIM1_CH4是因为Echo与TIM1_CH4共用引脚)

                        以上配置就可以得到我们记一次数需要 72MHZ/72 = 1us

        引脚的命名

 

                生成代码 


首先,重定向printf函数

        打开 usart.c,在 /* USER CODE BEGIN 0 */ 和 /* USER CODE END 0 */加入以下代码:


#include <stdio.h>
 
#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__ */

 

           在 /* USER CODE BEGIN 1 */ 和 /* USER CODE END 1 */ 之间加入以下代码:


/**
* @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;
}

        记得勾选

 以上就是最基础的配置,接下来我们进行方法一

        在tim.c中编写毫秒延时函数

/* USER CODE BEGIN 1 */

//使用TIM1来做us级延时函数,此函数为1us
void TIM1_Delay_us(uint16_t n_us)
{
	/* 使能定时器1计数 */
	__HAL_TIM_ENABLE(&htim1);
	
	__HAL_TIM_SetCounter(&htim1, 0);//htim1
	
	while(__HAL_TIM_GetCounter(&htim1) < ((1 * n_us)-1) );
	
    /* 失能定时器1计数 */
	__HAL_TIM_DISABLE(&htim1);
}


/* USER CODE END 1 */

        在main.c中编写超声波开始函数

void Start()
{
	HAL_GPIO_WritePin(Trig_GPIO_Port, Trig_Pin, GPIO_PIN_SET);//拉高
		
	TIM1_Delay_us(20);
		
	HAL_GPIO_WritePin(Trig_GPIO_Port, Trig_Pin, GPIO_PIN_RESET);//拉低
}

        在主函数外定义变量

int Cnt;//计数值
float Distance;//距离

        主函数

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_USART1_UART_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
	
	HAL_TIM_Base_Start(&htim1);//开启定时器
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

  while (1)
  {
		/* 定时器1,通道1,模式随便,主要用于计数,没有使用边沿捕获 */	
		Start();//开启超声波模块
		
		HAL_TIM_Base_Start(&htim1);//开启定时器

		//对超声波输入端口操作
		while( HAL_GPIO_ReadPin (Echo_GPIO_Port ,Echo_Pin) == GPIO_PIN_RESET);//等待输入电平拉高
		
		__HAL_TIM_SetCounter(&htim1,0);
		
		//对超声波输入端口操作
		while( HAL_GPIO_ReadPin (Echo_GPIO_Port ,Echo_Pin) == GPIO_PIN_SET);//等待输入电平变低
		
		Cnt = __HAL_TIM_GetCounter(&htim1);
		
		HAL_TIM_Base_Stop(&htim1);
		
		Distance = Cnt*340/2*0.000001*100 ;
		
		printf("Distance=%.1fcm\n",Distance);
		
		HAL_Delay(500);
		
    /* USER CODE END WHILE */

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

         实验结果


方法二

        在主函数外编写溢出中断与捕获中断的回调函数

int Edge;//0为捕获到上升沿,1为捕获到下降沿
int Cnt = 0;//完成了几次溢出
uint32_t  t1,t2,T;
float Distance;

/* 定时器溢出中断回调函数 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if((htim->Instance == htim1.Instance))
		Cnt++;
}

/* 定时器输入捕获中断回调函数 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if((htim->Instance == htim1.Instance) && (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4))
	{
		if(Edge == 0)//如果捕获到上升沿
		{
			t1 = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_4);
			
			//__HAL_TIM_SetCounter(&htim1,0);
			
			//设置为下降沿捕获
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim1,TIM_CHANNEL_4,TIM_INPUTCHANNELPOLARITY_FALLING);
			
			Cnt = 0;//计数器清零
			
			Edge = 1;//采集下降沿
		}
		else if(Edge == 1)
		{
			t2 = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_4);
			
			t2 += Cnt * 65535;
			
			T = t2 - t1;
			
			//设置为上升沿沿捕获
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim1,TIM_CHANNEL_4,TIM_INPUTCHANNELPOLARITY_RISING);
			
			Distance = T * 0.000001 * 170 * 100 ; 
			
			printf("Distance=%.1fcm\n",Distance);
			
			Edge = 0;//采集上升沿
		}
	}
}

        主函数中

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_USART1_UART_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
	
	HAL_TIM_Base_Start(&htim1);//开启定时器
	
	HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_4);//在中断模式下开启定时器输入捕获
	
	HAL_TIM_Base_Start_IT(&htim1);//开启溢出中断

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		Start();//开启超声波模块
		
		HAL_Delay(500);
		
    /* USER CODE END WHILE */

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

        实验结果:


以上仅供自己与大家学习积累,欢迎各位大佬批评与指正! 

  • 27
    点赞
  • 199
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值