【STM32F103】HC-SR04超声波测距模块详解(附工程文件)

news2024/11/24 20:41:02

前言:

使用的硬件:STM32F103C8T6,HC-SR04,ST-Link(其他烧录器也可以),0.96寸OLED屏幕(非必须,仅供显示测距结果,可以使用串口助手代替),若干杜邦线。

涉及操作stm32的GPIO口,外部中断,定时器,本文中不会详细解释,仅提供代码思路。

HC-SR04:

HC-SR04超声波测距模块提供2cm~400cm的测距功能,精度达3mm。

以下图片截取自深圳市捷深科技有限公司的《HC-SR04超声波测距模块说明书》

 通过时序图我们可以知道,我们给HC-SR04发送长达10us的TTL脉冲,然后模块就会进行测距,测距的结果通过回响信号传达,回响的TTL电平信号时间即是超声波从HC-SR04模块发出,触碰到障碍物后返回到HC-SR04模块的时间总和。

TTL是逻辑电平标准,当电压达到2.4V~5V之间,那么为逻辑1(高电平),电压在0V~0.4V之间,那么为逻辑0(低电平)。所以我们可以直接通过GPIO口来输出以及输入时序所需的电平信号。

总所周知,声音的速度为340m/s,因此我们将回响电平的时间除340再除2之后得到的就是单位为米的测距结果。

编写思路:

结合说明书我们可以知道,我们仅需提供10us的高电平给Trig口即可。然后HC-SR04在测量完毕之后会将结果通过Echo回响回来。

所以我们只需要将Trig口拉高,等待10us(最好再延长一些,代码中用的是15us)后再拉低即可。

接着就只需要等待Echo将数据传输回来,通过时序图我们可以得知回响信号是拉高Echo口,再拉低,中间持续的时间就是测距的结果。

所以我们给Echo口配置一个中断事件,设置为上跳变下跳变都触发,另外再用一个变量记录Echo口到底是拉高还是拉低即可。

如果是拉高,那么我们需要记录下持续的时间,这时候我们需要用定时器计时,所以需要在一开始的时候就配置好定时器的初始化。唯一的问题就是该如何配置定时器的预分频器和自动重装器了。

根据说明书我们可以知道HC-SR04的精度为3mm,而测距的公式为 us/58-cm,稍加计算可知,如果我们需要测量3mm,那么得到的时间为17.4us,以此为一个刻度,那么定时器的频率应该为57471Hz。然而这样太麻烦了,而且也不好用,因此我们可以随意一些,我在代码中使用的是预分频器为72,自动重装器为100,那么得到的频率为72MHz/72/100=1000Hz,也就是一次定时器中断的时间为100us,而自动重装器里的每一个值就是1us,所以每次外部中断的下降沿触发之后只需要将定时器触发的次数*100再加上自动重装器里的值就可以得到回响信号的持续时间了,单位是us。

接线:

HC-SR04需要单独提供5V的供电,因此不能与stm32共用一个VCC(3.3V),而ST-Link有5V的供电接口,因此我将5V电压单独拉出来给HC-SR04供电,GND与stm32用同一个。

HC-SR04的Trig接GPIOA的6号口,Echo接GPIOA的7号口。

接线端口没有硬性要求,只需要修改对应代码即可。需要注意的是修改GPIO口的同时还需要修改为对应的中断通道。

OLED的SCK接GPIOB的8号口,SDA接GPIOB的9号口。

精度还是可以的。

完整代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"           //使用的是b站江科大的延时函数,可以自己用别的替代延时功能
#include "OLED.h"            //使用的是b站江科大的OLED驱动代码,用于展示测距结果,可以在相应的地方更换为串口通信展示到电脑的串口助手上

uint8_t flag=0;				//用于记录中断信号是上升沿还是下降沿
uint32_t number=0;			//记录定时器中断的次数
uint32_t times=0;			//记录回响信号的持续时间

int main(void){
    OLED_Init();
    OLED_ShowString(1,1,"Hello World!!!");
    
    //初始化GPIO口,Trig使用推挽输出,Echo使用浮空输入
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能GPIOA的外设时钟
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_PP;                             //选择推挽输出模式
    itd.GPIO_Pin=GPIO_Pin_6;                                    //选择GPIO_Pin_6
    itd.GPIO_Speed=GPIO_Speed_50MHz;                            //默认选择50MHz
    GPIO_Init(GPIOA,&itd);
    
    itd.GPIO_Mode=GPIO_Mode_IN_FLOATING;                        //选择浮空输入模式
    itd.GPIO_Pin=GPIO_Pin_7;                                    //选择GPIO_Pin_7
    GPIO_Init(GPIOA,&itd);
    
    //AFIO映射中断引脚
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);         //使能AFIO的外设时针
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);  //选择外部中断源和中断通道
    
    //EXTI中断配置
    EXTI_InitTypeDef itd1;
    itd1.EXTI_Line=EXTI_Line7;                                  //echo使用的端口7,因此选择7号中断线
    itd1.EXTI_LineCmd=ENABLE;
    itd1.EXTI_Mode=EXTI_Mode_Interrupt;
    itd1.EXTI_Trigger=EXTI_Trigger_Rising_Falling;              //上升沿和下降沿都触发中断
    EXTI_Init(&itd1);
    
    //NVIC分配外部中断的中断优先级
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);             //指定中断分组
    NVIC_InitTypeDef itd2;
    itd2.NVIC_IRQChannel=EXTI9_5_IRQn;                          //使用的端口7,因此选择这个参数
    itd2.NVIC_IRQChannelCmd=ENABLE;
    itd2.NVIC_IRQChannelPreemptionPriority=2;                   //抢占优先级
    itd2.NVIC_IRQChannelSubPriority=2;                          //响应优先级 
    NVIC_Init(&itd2);
    
    //配置定时器
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    TIM_TimeBaseInitTypeDef itd3;
    itd3.TIM_ClockDivision=TIM_CKD_DIV1;                        //使用时钟分频1
    itd3.TIM_CounterMode=TIM_CounterMode_Up;                    //向上计数
    //72MHz/72/100=1000,每秒定时器计数1000个,因此每个计数为100us
    itd3.TIM_Period=72-1;                                       //预分频系数
    itd3.TIM_Prescaler=100-1;                                   //自动重装器
    itd3.TIM_RepetitionCounter=0;                               //该参数仅给高级定时器使用
    TIM_TimeBaseInit(TIM2,&itd3);
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);                    //使能中断输出信号
    TIM_InternalClockConfig(TIM2);                              //选择内部时钟    
    
    //NVIC分配定时器的中断优先级
    NVIC_InitTypeDef itd4;
    itd4.NVIC_IRQChannel=TIM2_IRQn;                             //指定Tim2的中断通道
    itd4.NVIC_IRQChannelCmd=ENABLE;
    itd4.NVIC_IRQChannelPreemptionPriority=1;                   //抢占优先级
    itd4.NVIC_IRQChannelSubPriority=1;                          //响应优先级
    NVIC_Init(&itd4);
    
    uint32_t distance;
    while(1){
        distance=0;
        for(int i=0;i<10;++i){              //每次取10次测距数据,取平均值减少误差
            GPIO_SetBits(GPIOA,GPIO_Pin_6);
            Delay_us(15);                   //根据说明书,需要提供至少10us的高电平
            GPIO_ResetBits(GPIOA,GPIO_Pin_6);
            Delay_ms(65);                   //根据说明书,每个周期至少需要等待60ms
            distance+=(times/5.8);          //根据说明书提供的公式,获取单位为mm的距离
        }
        distance/=10;
        OLED_ShowNum(2,1,distance,4);
    }
}

//定时器中断函数
void TIM2_IRQHandler(void){
    if(SET==TIM_GetITStatus(TIM2,TIM_FLAG_Update)){
        number++;                                   //每次中断将次数++
        TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
    }
}

//外部中断函数
void EXTI9_5_IRQHandler(void){
    if(SET==EXTI_GetITStatus(EXTI_Line7)){
        if(flag==0){
            //上升沿即回响电平开始,打开计数器
            number=0;flag=1;
            TIM_SetCounter(TIM2,0);
            TIM_Cmd(TIM2,ENABLE);
            
        }else{
            //下降沿即回响电平结束,统计高电平持续时长
            TIM_Cmd(TIM2,DISABLE);
            flag=0;
            times=number*100+TIM_GetCounter(TIM2);  //得到回响的高电平持续的us
        }
        EXTI_ClearITPendingBit(EXTI_Line7);
    }
}

参考:

《HC-SR04超声波测距模块说明书》—— 深圳市捷深科技有限公司

 

b站江科大

STM32驱动HC-SR04超声波测距模块测距_哔哩哔哩_bilibili

 

完整的工程文件在这边:

链接:https://pan.baidu.com/s/1k4oXI_XNgQwquPyXXRIafQ 
提取码:yvz6

也可以关注下微信“折途想要长高高” 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1258464.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rabbitMQ对消息不可达处理-备份交换机/备份队列

生产者发送消息&#xff0c;在消息不可达指定队列时&#xff0c;可以借助扇出类型交换机&#xff08;之前写过消息回退的处理方案&#xff0c;扇出交换机处理的方案优先级高于消息回退&#xff09;处理不可达消息&#xff0c;然后放置一个备份队列&#xff0c;供消费者处理不可…

Pytorch中的gather的理解和用法

Pytorch中的gather的理解和用法 这个Gather的用法花费了点时间&#xff0c;我相信很多人一开始不太懂。 跟着我简单理解。 首先样例是&#xff1a; tensor([[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])然后index: [[2, 1, 0]]然后执行的代码&#xff1a; tensor_0.gather(0…

使用 SIEM 管理安全事件

每家公司都必须处理检测、管理和解决安全事件&#xff0c;未能制定事件响应计划可能会对任何组织产生重大的影响&#xff0c;无论是在财务损失还是声誉损害方面。本文探讨了事件响应的重要性、检测和管理事件的关键要素&#xff0c;以及帮助组织处理安全事件的最佳实践。 安全…

FLASK博客系列6——数据库之谜

我们上一篇已经实现了简易博客界面&#xff0c;你还记得我们的博客数据是自己手动写的吗&#xff1f;但实际应用中&#xff0c;我们是不可能这样做的。大部分程序都需要保存数据&#xff0c;所以不可避免要使用数据库。我们这里为了简单方便快捷&#xff0c;使用了超级经典的SQ…

如何使用内网穿透将Tomcat网页发布到公共互联网上【内网穿透】

文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 前言 Tomcat作为一个轻量级的服务器&#xff0c;不仅名字很有趣&#xff0…

Redis面试题:分布式锁相关问题

目录 面试官&#xff1a;Redis的内存用完了会发生什么&#xff1f; 面试官&#xff1a;Redis分布式锁如何实现 ? 面试官&#xff1a;好的&#xff0c;那你如何控制Redis实现分布式锁有效时长呢&#xff1f; 面试官&#xff1a;好的&#xff0c;redisson实现的分布式锁是可重…

现货黄金走势图下载与保存

MetaTrader 4 (MT4) 是一款在全球范围内广受欢迎的现货黄金交易软件&#xff0c;简单性和灵活性是其深受市场欢迎的原因。它的显示界面的主要部分由品种的走势图表组成&#xff0c;投资者可以在其中查看实时的行情走势。屏幕左上角是市场观察窗口&#xff0c;当中列出了平台所有…

群晖NAS:docker(Container Manager)、npm安装Verdaccio并常见命令集合

群晖NAS&#xff1a;docker&#xff08;Container Manager&#xff09;、npm安装Verdaccio并常见命令集合 自建 npm 资源库&#xff0c;使用Verdaccio。如果觉得麻烦&#xff0c;直接可以在外网注册 https://www.npmjs.com/ 网站。大同小异&#xff0c;自己搭建搭建方便局域网…

如何进行有效的移动应用测试?

1、识别关键功能: 对于移动应用测试&#xff0c;首先要了解应用的需求和功能规格&#xff0c;确定哪些功能是最关键的。 关键功能通常是用户最常用的功能&#xff0c;对应用的成功和用户体验至关重要。 2、设定测试目标和用例: 针对每个关键功能&#xff0c;设置具体的测试目…

基于springboot+maven的个人理财管理系统

基于springbootmaven的个人理财管理系统,演示地址:个人理财系统登录界面 用户名:admin,密码&#xff1a;123456 共分为用户信息管理(用户信息&#xff0c;银行卡&#xff0c;个人征信)&#xff0c;理财产品管理(零钱理财&#xff0c;工资理财&#xff0c;期限理财&#xff0c…

如何在本地安装部署WinSCP,并实现公网远程本地服务器

可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器 文章目录 可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器1. 简介2. 软件下载安装&#xff1a;3. SSH链接服务器4. WinSCP使用公网TCP地址链接本地服务器5. WinSCP使用固定公网TCP地址访问服务器 1. 简介 …

有效实施的五条教学策略

作为老师&#xff0c;是否曾为如何提高教学质量而苦恼&#xff1f;也为如何引导学生而思考&#xff1f;如果你正面临这些困扰&#xff0c;那么这篇文章将对你有帮助。为你介绍五条教学策略&#xff0c;帮你实施教学&#xff0c;提高效果。 明确教学目标 你是否知道你的教学目标…

3D数字孪生场景编辑器

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 数字孪生的强大功能来自于将真实世界的资产与真实世界的数据联系起来&#xff0c;因此您可以…

代码块01-Java

代码块01 一、介绍二、语法三、好处举例 四、使用细节五、练习题1题2 一、介绍 代码块又称为初始化块&#xff0c;属于类中的成员[即是类的一部分]&#xff0c;类似于方法&#xff0c;将逻辑语句封装在方法体中&#xff0c;通过包围起来。 但和方法不同&#xff0c;没有方法名…

ZKP15.1 Secure ZK Circuits via Formal Methods

ZKP学习笔记 ZK-Learning MOOC课程笔记 Lecture 15: Secure ZK Circuits via Formal Methods (Guest Lecturer: Yu Feng (UCSB & Veridise)) Motivation Bugs in blockchain software are extremely dangers and costly.Smart Contract Bugs, Blockchain Protocol Bugs,…

OSError: symbolic link privilege not held报错解决

本人情况介绍 本人在复现某个代码的时候&#xff0c;需要安装开源代码已经封装好的setup.py代码。具体安装的库具体如下。 fairseqpython3.6.0pytorch1.6.0File2ROUGE 在安装fairseq的时候遇见了如下问题。 Installing build dependencies … done Getting requirements to …

使用 Redis Zset 有序集合实现排行榜功能(SpringBoot环境)

目录 一、前言二、Redis Zset 的基本操作三、通过Redis 命令模拟排行榜功能3.1、排行榜生成3.2、排行榜查询 四、SpringBoot 使用 Redis Zset 有序集合实现排行榜功能 一、前言 排行榜功能是非常常见的需求&#xff0c;例如商品售卖排行榜单、游戏中的积分排行榜、配送员完单排…

原创文章生成器-批量原文高质量伪原创

在信息爆炸的时代&#xff0c;创作者们面临的挑战愈发严峻。写一篇原创文章&#xff0c;不仅需要脑洞大开&#xff0c;还得担心自己的文字是否能够迎合读者口味。原创文章生成器只需输入标题或关键词&#xff0c;即可轻松生成原创文章。而与此同时&#xff0c;147SEO改写软件也…

FLASK博客系列8——我也有后台管理

上次我们学习了如何往数据库里插入数据&#xff0c;显示我们自己的文章。 有些朋友可能会问&#xff0c;django有后台管理&#xff0c;插入不用这么麻烦&#xff0c;那flask有类似的吗&#xff1f;当然有&#xff0c;而且还挺多的。今天我们就用一个最常用的包来完成 flask-adm…

数据库系统原理与实践 笔记 #10

文章目录 数据库系统原理与实践 笔记 #10存储管理与索引(续)数据字典存储系统元数据的关系表示 数据缓冲区存储访问缓冲区管理器缓冲区替换策略 顺序索引基本概念索引技术评价指标顺序索引稠密索引稀疏索引索引多级索引辅助索引主索引与辅助索引多码索引 B树索引B树索引文件B树…