参考:

  • 某宝HC-SR04 超声波测距模块商品详情页
  • STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例
  • STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)
  • cubemx下的输入捕获进行超声波测距
  • 【STM32】HAL库 STM32CubeMX教程八—定时器输入捕获
  • 基于stm32的多功能时钟4——超声波测距
  • 基于STM32的超声波传感器测距
  • STM32 Ultrasonic Sensor HC-SR04 Library With Timer Input Capture(这篇文章写的很好,我参考了他好多)

1.关于HC-SR04 超声波测距模块

某宝上的HC-SR04 超声波测距模块有很多种,大概分的话:

  • 一类是只能工作在5V电压下的,仅支持GPIO模式的模块(好多都是这种)
  • 还有一种是我最近买到的一款,支持宽电压(5V、3.3V),支持GPIO、UART、IIC三种模式接口,如下图

模块的背面有用来模式选择的电阻(0603),如下图

2.使用GPIO模式测量

2.1 先看原理


简单来说GPIO模式下测距就三步:

  1. 给Trig引脚一个大于10us的高电平
  2. 等待回响信号,单片机测量ECHO引脚的高电平时间
  3. 计算距离

我学习到的对于回响信号的高电平时间的测量,STM32单片机使用定时器的方式有两种:

  • 出现上升沿,开启定时器从0开始计数,然后while (HAL_GPIO_ReadPin(hc_sr04_device->echo_port, hc_sr04_device->echo_pin) == GPIO_PIN_SET);等待回响信号的下降沿,停止计数,根据定时器的计数值来计算距离。
  • 使用定时器的输入捕获功能,在捕获到上升沿或下降沿时的中断函数中记录下定时器的计数值,并计算距离。
    一开始我使用的方法1,可以用,但是由于用了while 等待回响信号的高电平结束,会造成阻塞,有时候不太好用。
    然后又学到可以用输入捕获来做高电平时间的测量,这里我仅记录下方法2

2.2 使用STM32CubeMX初始化代码

2.2.1 时钟配置

这里我用的是STM32F103C8T6的核心板,时钟配置如下图,我用了8MHz的HSE,HCLK调到了最大值72MHz

2.2.2 设置输入捕获的定时器

设置定时器TIM2每1us向上计数一次,通道4为上升沿捕获并连接到超声波模块的ECHO引脚,记得开启定时器中断(涉及到捕获中断+定时器溢出中断)。

2.2.3 触发引脚

PB10接到了HC-SR04的TIRG触发引脚,默认输出低电平

2.2.4 串口配置

还要开启一个串口,以便通过串口查看测距结果

2.3 编写代码(有时间改个好移植版本的)

hc-sr04.h

/** @Author       : yzy* @Date         : 2021-05-31 17:03:27* @LastEditors  : yzy* @LastEditTime : 2021-05-31 19:02:54* @Description  : * @FilePath     : \F103_Test\BSP_HARDWARE\hc-sr04.h*/
#ifndef HCSR04_H_
#define HCSR04_H_#include "main.h"
#include "delay.h"typedef struct
{uint8_t  edge_state;uint16_t tim_overflow_counter;uint32_t prescaler;uint32_t period;uint32_t t1;  //  上升沿时间uint32_t t2;   //  下降沿时间uint32_t high_level_us;    //  高电平持续时间float    distance;TIM_TypeDef* instance;uint32_t ic_tim_ch;HAL_TIM_ActiveChannel active_channel;
}Hcsr04InfoTypeDef;extern Hcsr04InfoTypeDef Hcsr04Info;/*** @description: 超声波模块的输入捕获定时器通道初始化* @param {TIM_HandleTypeDef} *htim* @param {uint32_t} Channel* @return {*}*/
void Hcsr04Init(TIM_HandleTypeDef *htim, uint32_t Channel);/*** @description: HC-SR04触发* @param {*}* @return {*}*/
void Hcsr04Start();/*** @description: 定时器计数溢出中断处理函数* @param {*}    main.c中重定义void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)* @return {*}*/
void Hcsr04TimOverflowIsr(TIM_HandleTypeDef *htim);/*** @description: 输入捕获计算高电平时间->距离* @param {*}    main.c中重定义void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)* @return {*}*/
void Hcsr04TimIcIsr(TIM_HandleTypeDef* htim);/*** @description: 读取距离 * @param {*}* @return {*}*/
float Hcsr04Read();#endif /* HCSR04_H_ */

hc-sr04.c

/** @Author       : yzy* @Date         : 2021-05-31 17:03:23* @LastEditors  : yzy* @LastEditTime : 2021-06-21 22:16:28* @Description  : * @FilePath     : \CSDN_HC-SR04_GPIO\BSP_HARDWARE\HC-SR04\hc-sr04.c*/
#include "hc-sr04.h"Hcsr04InfoTypeDef Hcsr04Info;/*** @description: 超声波模块的输入捕获定时器通道初始化* @param {TIM_HandleTypeDef} *htim* @param {uint32_t} Channel* @return {*}*/
void Hcsr04Init(TIM_HandleTypeDef *htim, uint32_t Channel)
{/*--------[ Configure The HCSR04 IC Timer Channel ] */// MX_TIM2_Init();  // cubemx中配置Hcsr04Info.prescaler = htim->Init.Prescaler; //  72-1Hcsr04Info.period = htim->Init.Period;       //  65535Hcsr04Info.instance = htim->Instance;        //  TIM2Hcsr04Info.ic_tim_ch = Channel;if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_1){Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_1;             //  TIM_CHANNEL_4}else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_2){Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_2;             //  TIM_CHANNEL_4}else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_3){Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_3;             //  TIM_CHANNEL_4}else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_4){Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_4;             //  TIM_CHANNEL_4}else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_4){Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_4;             //  TIM_CHANNEL_4}/*--------[ Start The ICU Channel ]-------*/HAL_TIM_Base_Start_IT(htim);HAL_TIM_IC_Start_IT(htim, Channel);
}/*** @description: HC-SR04触发* @param {*}* @return {*}*/
void Hcsr04Start()
{HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);DelayUs(10);  //  10us以上HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}/*** @description: 定时器计数溢出中断处理函数* @param {*}    main.c中重定义void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)* @return {*}*/
void Hcsr04TimOverflowIsr(TIM_HandleTypeDef *htim)
{if(htim->Instance == Hcsr04Info.instance) //  TIM2{Hcsr04Info.tim_overflow_counter++;}
}/*** @description: 输入捕获计算高电平时间->距离* @param {*}    main.c中重定义void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)* @return {*}*/
void Hcsr04TimIcIsr(TIM_HandleTypeDef* htim)
{if((htim->Instance == Hcsr04Info.instance) && (htim->Channel == Hcsr04Info.active_channel)){if(Hcsr04Info.edge_state == 0)      //  捕获上升沿{// 得到上升沿开始时间T1,并更改输入捕获为下降沿Hcsr04Info.t1 = HAL_TIM_ReadCapturedValue(htim, Hcsr04Info.ic_tim_ch);__HAL_TIM_SET_CAPTUREPOLARITY(htim, Hcsr04Info.ic_tim_ch, TIM_INPUTCHANNELPOLARITY_FALLING);Hcsr04Info.tim_overflow_counter = 0;  //  定时器溢出计数器清零Hcsr04Info.edge_state = 1;        //  上升沿、下降沿捕获标志位}else if(Hcsr04Info.edge_state == 1) //  捕获下降沿{// 捕获下降沿时间T2,并计算高电平时间Hcsr04Info.t2 = HAL_TIM_ReadCapturedValue(htim, Hcsr04Info.ic_tim_ch);Hcsr04Info.t2 += Hcsr04Info.tim_overflow_counter * Hcsr04Info.period; //  需要考虑定时器溢出中断Hcsr04Info.high_level_us = Hcsr04Info.t2 - Hcsr04Info.t1; //  高电平持续时间 = 下降沿时间点 - 上升沿时间点// 计算距离Hcsr04Info.distance = (Hcsr04Info.high_level_us / 1000000.0) * 340.0 / 2.0 * 100.0;// 重新开启上升沿捕获Hcsr04Info.edge_state = 0;  //  一次采集完毕,清零__HAL_TIM_SET_CAPTUREPOLARITY(htim, Hcsr04Info.ic_tim_ch, TIM_INPUTCHANNELPOLARITY_RISING);}}
}/*** @description: 读取距离 * @param {*}* @return {*}*/
float Hcsr04Read()
{// 测距结果限幅if(Hcsr04Info.distance >= 450){Hcsr04Info.distance = 450;}return Hcsr04Info.distance;
}

main.c

  1. 引用对应的头文件
/* USER CODE BEGIN Includes */
#include "hc-sr04.h"
#include "printf.h"
/* USER CODE END Includes */
  1. 200ms测距一次
/*** @brief  The application entry point.* @retval int*/
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 */DelayInit(72);Hcsr04Init(&htim2, TIM_CHANNEL_4);  //  超声波模块初始化Hcsr04Start();  //  开启超声波模块测距printf("hc-sr04 start!\r\n");/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){// 打印测距结果printf("distance:%.1f cm\r\n", Hcsr04Read());Hcsr04Start();DelayMs(200); //  测距周期200ms/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
  1. 重定义定时器的中断服务函数
/* USER CODE BEGIN 4 */
/*** @description: 定时器输出捕获中断* @param {TIM_HandleTypeDef} *htim* @return {*}*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{Hcsr04TimIcIsr(htim);
}/*** @description: 定时器溢出中断* @param {*}* @return {*}*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{Hcsr04TimOverflowIsr(htim);
}
/* USER CODE END 4 */

2.4 串口打印结果

3.使用UART模式测量

4.使用IIC模式测量

STM32单片机基于HAL库开发HC-SR04 超声波测距模块(终极版)相关推荐

  1. STM32系列之HAL库开发

    STM32系列文章目录 文章目录 STM32系列文章目录 前言 一.HAL库之串口收发 1.配置STM32CUBEID 2.使用串口中断收发 2.1 配置串口中断 2.2 HAL库中断处理逻辑 3 测 ...

  2. STM32(基于HAL库)驱动0.96寸OLED屏幕(六脚)

    STM32驱动0.96寸OLED屏幕(六脚) 1 序言 2 如何利用STM32单片机驱动12864液晶屏 2.1*基本配置* 2.2 *0.96寸OLED端口含义* 2.3 *0.96寸OLED液晶屏 ...

  3. STM32(基于HAL库)驱动0.96寸OLED屏幕(四脚且中英文皆可显示)

    STM32驱动0.96寸OLED屏幕(四脚) 1 注意事项 2 如何利用STM32单片机驱动12864液晶屏 2.1*基本配置* 2.2 *0.96寸OLED端口含义* 2.3 *0.96寸OLED液 ...

  4. 【STM32】基于HAL库的中断详细学习

    目录 1.中断概述 1.1中断相关概念 1.2 STM32中断系统 2 .HAL库的中断处理 2.1 HAL 库的中断封装 2.2 外部中断处理流程 3.外部中断的HAL库定义 3.1. 外部中断的数 ...

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

    目录 概述 1.MCU主控: 2.超声波模块: 3.输入捕获简介 4.STM32CubeMx 配置 1).系统时钟配置 2).定时器22配置 3).串口1配置 5.代码说明: 1).tim.c文件 2 ...

  6. STM32机器人控制开发教程No.3 使用遥控控制电机/舵机(基于HAL库)

    01 前言 本教程使用的机器人控制板拥有4个带编码器的电机接口,4个舵机接口,串口通信接口.SWD下载调试接口.航模遥控接口.USB5V输出接口以及方便与树莓派直接连接的40PIN接口等,板载资源丰富 ...

  7. STM32软件学习笔记(一)基于HAL库的STM32F429单片机串口打印程序

    |版权声明:本文为博主原创文章,转载请注明出处.https://blog.csdn.net/NeverImagine_/article/details/95517664   目前ST官方有提供两种库文 ...

  8. STM32机器人控制开发教程No.1驱动电机(基于HAL库)

    01 前言 本教程使用的机器人控制板拥有4个带编码器的电机接口,4个舵机接口,串口通信接口.SWD下载调试接口.航模遥控接口.USB5V输出接口以及方便与树莓派直接连接的40PIN接口等,板载资源丰富 ...

  9. STM32外挂FLASH模拟U盘(基于HAL库)

    STM32外挂FLASH模拟U盘(基于HAL库) 1.背景 1.1这篇文章能给你带来什么 1.2根据你要解决的问题,精确快速跳转到相应位置 1.3我在做完这个后还有不明白的地方,希望能有大触解答困惑 ...

最新文章

  1. php http请求xml数据,php获取通过http协议post提交过来xml数据及解析xml
  2. bzoj 4942: [Noi2017]整数
  3. left edge algorithm.
  4. 操作系统基础:进程知识笔记(三)
  5. TensorFlow的各种应用,你晓得不?
  6. Codeforces Round #498 (Div. 3)
  7. 数据结构-排序基础代码
  8. ubuntu 11.10下载和编译Android源码
  9. SuperRuntimeLibrary.TextVoice 发布,支持文本到语音 文本到.wav
  10. (附源码)spring boot网上购物平台 毕业设计 141422
  11. Android视频的操作
  12. 游戏制作之路(48)地形纹理工具
  13. python实现矩阵乘法(不用numpy)
  14. php cms系统 知乎,php cms 知乎
  15. 流量渠道 转化率 买家行为 处罚扣分规则 如何不被抓单,被判虚假交易对店铺的影响
  16. 法国电子与计算机信息工程学校排名,法国工程学院的十大排名情况
  17. 关于OSM数据的使用与下载
  18. 两点GPS经纬度获取局部位置的理论
  19. 运维派 企业面试题1 监控MySQL主从同步是否异常
  20. 计算机语言属于人类意识的客观内容,《2008年考研政治800题精解》世界的物质性和人的实践活动(5)...

热门文章

  1. kingcms php 漏洞,kingcms任意php文件删除(可截断时升级为任意文件删除 )
  2. ubuntu的一些安装设置
  3. 弄它!!!理论加实验,小小ISIS分分钟拿下!!
  4. PLC需要有什么样的基础才能学?
  5. 知识图谱嵌入经典方法(Trans系列、KG2E)
  6. 大数据转型方案:首推数据湖!
  7. 用ultraiso安装linux系统教程,U盘安装Ubuntu 12.10 图文教程(ultraiso)
  8. Open vSwitch概述
  9. Vue 新手学习笔记:vue-element-admin 之按钮级权限管控
  10. 如何语言讲述雪铁龙c6,到底是一款怎样的车 浅谈雪铁龙C6体验感受