STM32—超声波测距仪

准备工作:
材料:

- STM32最小系统板
- 超声波模块HC-SR04
- 面包板
- 0.96 OLED
- 导线
硬件连接




单片机 ---->OLED
PB14 ---->SCK
PB15 ---->SDA
V3.3 ---->VDD
GND ---->GND
单片机----->超声波模块
PBA0 -----> ECHO
PBA8 -----> TRIG
V5 -----> VCC
GND -----> GND
打包OLED代码为模块








在上篇文中,OLED接单片机的引脚是A0、A1,这次是B14、B15。把上次的代码修改一下,在HARDWARE文件夹下,新建文件夹OLED。在Keil中新建2个文件,取名为oled.c和oled.h,保存在刚才新建的OLED文件夹下。分别复制代码到oled.c和oled.h(定义和声明放.h别的放.c)。这样就把oled文件打包成了单独的文件模块,配置这两个文件到项目中。用同样的方法添加配置Timer模块(附件中有做好的文件)
建立超声波模块文件




用同样的方法,在HARDWARE文件夹下,新建文件夹HCSR04。在Keil中新建2个文件,取名为hcsr04.c和hcsr04.h,保存在刚才新建的HCST04文件夹下,并配置它。分别复制下面的代码到hcsr04.c和hcsr04.h。
hcsr04.h文件:
#ifndef __HCSR04_H
#define __HCSR04_H
#include "sys.h"
void HC_SR04_Init(void);
int16_t sonar_mm(void);
float sonar(void);
#endif
Hcsr04.c文件:
#include "sys.h"
#include "delay.h"
#include "hcsr04.h"
#define Echo GPIO_Pin_0 //HC-SR04模块的Echo脚接GPIOB6
#define Trig GPIO_Pin_8 //HC-SR04模块的Trig脚接GPIOB5
uint64_t time=0; //声明变量,用来计时
uint64_t time_end=0; //声明变量,存储回波信号时间
void HC_SR04_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //启用GPIOB的外设时钟
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置GPIO口为推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //设置GPIO口5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置GPIO口速度50Mhz
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化GPIOB
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置GPIO口为下拉输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //设置GPIO口6
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化GPIOB
GPIO_WriteBit(GPIOA,GPIO_Pin_8,0); //输出低电平
// delay_us(15); //延时15微秒
}
int16_t sonar_mm(void) //测距并返回单位为毫米的距离结果
{
uint32_t Distance,Distance_mm = 0;
GPIO_WriteBit(GPIOA,GPIO_Pin_8,1); //输出高电平
delay_us(15); //延时15微秒
GPIO_WriteBit(GPIOA,GPIO_Pin_8,0); //输出低电平
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0); //等待低电平结束
time=0; //计时清零
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1); //等待高电平结束
time_end=time; //记录结束时的时间
if(time_end/100<38) //判断是否小于38毫秒,大于38毫秒的就是超时,直接调到下面返回0
{
Distance=(time_end*346)/2; //计算距离,25°C空气中的音速为346m/s
Distance_mm=Distance/100; //因为上面的time_end的单位是10微秒,所以要得出单位为毫米的距离 //结果,还得除以100
}
return Distance_mm; //返回测距结果
}
float sonar(void) //测距并返回单位为米的距离结果
{
uint32_t Distance,Distance_mm = 0;
float Distance_m=0;
GPIO_WriteBit(GPIOA,GPIO_Pin_8,1); //输出高电平
delay_us(15);
GPIO_WriteBit(GPIOA,GPIO_Pin_8,0); //输出低电平
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0);
time=0;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1);
time_end=time;
if(time_end/100<38)
{
Distance=(time_end*346)/2;
Distance_mm=Distance/1000;
Distance_m=Distance_mm/1000;
}
return Distance_m;
}
void TIM3_IRQHandler(void) //更新中断函数,用来计时,每10微秒变量time加1
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //获取TIM3定时器的更新中断标志位
{
time++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除更新中断标志位
}
}
编辑主程序代码并测试

复制下面的代码到主程序文件main.c,编译并烧录到单片机中,如果操作都对的话,屏幕上就会显示距离的数值了,用手挡在HCSR04模块的前面并调整距离,并观看屏幕结果。
#include "sys.h"
#include "delay.h"
#include "timer.h"
#include "usart.h"
#include "oled.h"
#include "hcsr04.h"
int main(void)
{
Init_OLED(); //初始化OLED屏
Timer_Init(); //初始化定时器
HC_SR04_Init(); //初始化超声波测距模块
string_8x16(20,0,"Rangefinder");//Rangefinder
OLED_diplay();
delay_init();
while (1)
{
string_8x16(0,4,"DIST: ");
string_8x16_num(40,4,sonar_mm()/10);//sonar_mm()
OLED_diplay();
delay_ms(300); //延时300毫秒
}
}
测试视频见附件:











