• 最详细STM32,cubeMX 超声波测距


    这篇文章将详细介绍 STM32使用 cubeMX驱动超声波测距 。


    前言

    • 实验材料:STM32F103C8T6开发板, HC-SR04 超声波模块。
    • 所需软件:keil5 , cubeMX ,AiThinker Serial Tool 串口助手。
    • 实验目的:了解 STM32使用 cubeMX驱动超声波 。
    • 实验:超声波测距。

    一、超声波模块

    HC-SR04 超声波测距模块可提供 2cm-400cm 的非接触式距离感测功能。有4 个引脚:VCC, GND, Trig(信号触发引脚),Echo(接收返回信号)。

    当超声波发出一个信号时,信号碰到物体或阻碍后会立即返回。只要得到 信号往返传输的时间就可以测出距离。
    在这里插入图片描述

    参数列表:
    工作电压 VCC5 V
    最远射程 : 4m
    最近射程 :2cm
    信号传输速度 :340m/s

    测距原理

    下图是 超声波时序图。

    1. 首先让超声波的 trig 引脚发送触发信号:一个 10 us 的 TTL 高电平。

    2. 然后模块内部会自动循环发出 8 个 40 KHZ 的脉冲。

    3. 接着 超声波的 echo 引脚会接收到回返信号。

    4. 最后只需要计算出这段回返信号的高电平时间 再带入公式 S = 340(m/s) * T(s) / 2 即可算出距离.这里是往返时间,要除 2。(因为 高电平的时间就是信号往返传输的时间)
      在这里插入图片描述

    二、cubeMX 配置

    对于基础的配置可以看我之前的文章。

    1. 由于 要发送一个 10us 的高电平,这个时间用定时器进行配置,所以这里我使用 定时器 2 进行延时。(尽量不要使用 HAL_Delay 函数,多次使用会导致程序卡顿)

    这里选择内部时钟源,并配置相关参数。这里配置的参数是 1us 延时。
    在这里插入图片描述

    1. 我们还需要 一个定时器去 计算回返信号的高电平时间。使用定时器3。配置的定时时间依然是 1us。

    如果对 定时器的定时时长有不了解的可以参考我之前的文章:最详细STM32,cubeMX 定时器

    在这里插入图片描述

    1. 需要将测出的距离使用串口助手打印出来,所以这里需要使用一个 串口 USART2.(使用 异步传输)

    如果对 串口的配置有不了解的可以参考我之前的文章:最详细STM32,cubeMX串口发送,接收数据

    在这里插入图片描述

    1. 对于检测 是否接收到 回返信号 ,可以使用外部中断。

    超声波需要两个引脚分别用来 发送触发信号 ,接收回返信号。所以,这里我使用 PB3 用来 发送触发信号,设置为输出引脚。使用 PB6 接收信号,并将其设置为 外部中断模式。

    如果对 外部中断的配置有不了解的可以参考我之前的文章:STM32不使用 cubeMX实现外部中断

    在这里插入图片描述

    • 并将 PB6 设置为 双边沿触发中断。
      在这里插入图片描述

    • 并将外部中断使能。
      在这里插入图片描述

    三、实验程序

    sr04.h:

    #ifndef _SR04_H_
    #define _SR04_H_
    
    #include 
    #include "main.h"
    
    #define		Trigger_ON 		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_SET)
    #define		Trigger_OFF 	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_RESET)
    
    
    void Delay_us(uint16_t us);						// 使用定时器2编写的延时函数
    void Trigger_signal(void);						// 发送 10us 的触发信号
    
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    sr04.c:

    #include "sr04.h"
    
    int distance_cm = 0;
    
    
    extern TIM_HandleTypeDef htim2;
    extern TIM_HandleTypeDef htim3;
    
    
    /* 延时函数(单位 us) */
    void Delay_us(uint16_t us)
    {
    	uint16_t time = 0xffff - us - 5;
    	__HAL_TIM_SET_COUNTER(&htim2,time);								// 设置 定时器2 的值
    	HAL_TIM_Base_Start(&htim2);										// 开启定时器2
    
    	while(time < 0xffff-5)
    	{
    		time = __HAL_TIM_GET_COUNTER(&htim2);						// 获取定时器2 值
    	}
    
    	HAL_TIM_Base_Stop(&htim2);										// 停止 定时器2
    }
    
    
    /* 发送 10us 的触发信号 */
    void Trigger_signal(void)
    {
    	Trigger_ON;							// 发送高电平
    	Delay_us(10);						// 延时 10 us
    	Trigger_OFF;						// 发送低电平
    }
    
    
    /* 外部中断回调函数 */
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {	
    	 static uint32_t time_us = 0;
    	
    	if(GPIO_Pin == GPIO_PIN_6)
    	{
    		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6))
    		{
    			HAL_TIM_Base_Start(&htim3);									// 开启定时器3(开始计时)
    			__HAL_TIM_SetCounter(&htim3,0);								// 清空定时器3
    		}
    		else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6) == 0)
    		{
    			HAL_TIM_Base_Stop(&htim3);									//关闭定时器3(停止计时)
    			time_us = __HAL_TIM_GetCounter(&htim3);							// 获取高电平时间
    			printf("time_us : %d\r\n", time_us);
    			distance_cm = time_us * 340/2*0.000001*100;
    			printf("distance_cm is %d cm\r\n", distance_cm);
    			
    			time_us = 0;
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    对于串口发送数据,可以使用重定义函数,简化代码:

    int fputc(int ch,FILE* f)
    {
    	while(HAL_UART_Transmit(&huart2,(uint8_t*)&ch,sizeof(ch),1000) != HAL_OK);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    测试程序:
    在 while 循环中持续发送触发信号。

      int count = 0;
    
      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
    		
    		/* 每 50 ms 发送一次触发信号 */
    		if(HAL_GetTick() - count > 50)
    		{
    			count = HAL_GetTick();
    			Trigger_signal();
    		}		
    		
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    HAL_GetTick() 函数 用来获取当前的时间。可以看到这个函数返回 uwTick 变量,在 HAL_IncTick() 中一直增加。uwTick 变量是从STM32 开机就开始计时。 1 uwTick 就是 1ms.
    在这里插入图片描述


    总结

    下一篇文章为大家介绍 STM32 驱动蓝牙的实现。

  • 相关阅读:
    自动驾驶行业源代码防泄漏解决方案
    Softing连接解决方案——将FANUC数控机床数据集成到西门子工业边缘
    IDEA导入Eclipse项目的方法步骤(图文教程)
    数据中台稳定性的“四高” | StartDT Tech Lab 18
    JAVA大学生社团活动管理系统计算机毕业设计Mybatis+系统+数据库+调试部署
    分层测试(三):接口测试
    未来5年,只有这种产品团队才能开启上帝视角【玩转IPD】
    【云原生之k8s】Kubeadm搭建K8S
    MongoDB系列之适用场景和不适用场景
    数据库上云实践:使用Ora2pg进行数据库迁移
  • 原文地址:https://blog.csdn.net/wuyiyu_/article/details/133998314