STM32单片机基于HAL库开发HC-SR04 超声波测距模块(终极版)
参考:
- 某宝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模式下测距就三步:
- 给Trig引脚一个大于10us的高电平
- 等待回响信号,单片机测量ECHO引脚的高电平时间
- 计算距离
我学习到的对于回响信号的高电平时间的测量,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
- 引用对应的头文件
/* USER CODE BEGIN Includes */
#include "hc-sr04.h"
#include "printf.h"
/* USER CODE END Includes */
- 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 */
}
- 重定义定时器的中断服务函数
/* 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 超声波测距模块(终极版)相关推荐
- STM32系列之HAL库开发
STM32系列文章目录 文章目录 STM32系列文章目录 前言 一.HAL库之串口收发 1.配置STM32CUBEID 2.使用串口中断收发 2.1 配置串口中断 2.2 HAL库中断处理逻辑 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液晶屏 ...
- 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液 ...
- 【STM32】基于HAL库的中断详细学习
目录 1.中断概述 1.1中断相关概念 1.2 STM32中断系统 2 .HAL库的中断处理 2.1 HAL 库的中断封装 2.2 外部中断处理流程 3.外部中断的HAL库定义 3.1. 外部中断的数 ...
- STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例
目录 概述 1.MCU主控: 2.超声波模块: 3.输入捕获简介 4.STM32CubeMx 配置 1).系统时钟配置 2).定时器22配置 3).串口1配置 5.代码说明: 1).tim.c文件 2 ...
- STM32机器人控制开发教程No.3 使用遥控控制电机/舵机(基于HAL库)
01 前言 本教程使用的机器人控制板拥有4个带编码器的电机接口,4个舵机接口,串口通信接口.SWD下载调试接口.航模遥控接口.USB5V输出接口以及方便与树莓派直接连接的40PIN接口等,板载资源丰富 ...
- STM32软件学习笔记(一)基于HAL库的STM32F429单片机串口打印程序
|版权声明:本文为博主原创文章,转载请注明出处.https://blog.csdn.net/NeverImagine_/article/details/95517664 目前ST官方有提供两种库文 ...
- STM32机器人控制开发教程No.1驱动电机(基于HAL库)
01 前言 本教程使用的机器人控制板拥有4个带编码器的电机接口,4个舵机接口,串口通信接口.SWD下载调试接口.航模遥控接口.USB5V输出接口以及方便与树莓派直接连接的40PIN接口等,板载资源丰富 ...
- STM32外挂FLASH模拟U盘(基于HAL库)
STM32外挂FLASH模拟U盘(基于HAL库) 1.背景 1.1这篇文章能给你带来什么 1.2根据你要解决的问题,精确快速跳转到相应位置 1.3我在做完这个后还有不明白的地方,希望能有大触解答困惑 ...
最新文章
- php http请求xml数据,php获取通过http协议post提交过来xml数据及解析xml
- bzoj 4942: [Noi2017]整数
- left edge algorithm.
- 操作系统基础:进程知识笔记(三)
- TensorFlow的各种应用,你晓得不?
- Codeforces Round #498 (Div. 3)
- 数据结构-排序基础代码
- ubuntu 11.10下载和编译Android源码
- SuperRuntimeLibrary.TextVoice 发布,支持文本到语音 文本到.wav
- (附源码)spring boot网上购物平台 毕业设计 141422
- Android视频的操作
- 游戏制作之路(48)地形纹理工具
- python实现矩阵乘法(不用numpy)
- php cms系统 知乎,php cms 知乎
- 流量渠道 转化率 买家行为 处罚扣分规则 如何不被抓单,被判虚假交易对店铺的影响
- 法国电子与计算机信息工程学校排名,法国工程学院的十大排名情况
- 关于OSM数据的使用与下载
- 两点GPS经纬度获取局部位置的理论
- 运维派 企业面试题1 监控MySQL主从同步是否异常
- 计算机语言属于人类意识的客观内容,《2008年考研政治800题精解》世界的物质性和人的实践活动(5)...
热门文章
- kingcms php 漏洞,kingcms任意php文件删除(可截断时升级为任意文件删除 )
- ubuntu的一些安装设置
- 弄它!!!理论加实验,小小ISIS分分钟拿下!!
- PLC需要有什么样的基础才能学?
- 知识图谱嵌入经典方法(Trans系列、KG2E)
- 大数据转型方案:首推数据湖!
- 用ultraiso安装linux系统教程,U盘安装Ubuntu 12.10 图文教程(ultraiso)
- Open vSwitch概述
- Vue 新手学习笔记:vue-element-admin 之按钮级权限管控
- 如何语言讲述雪铁龙c6,到底是一款怎样的车 浅谈雪铁龙C6体验感受