本文主要是为了下测距做的,本实验主要包括:(HC-SR04)和(SHARP GP2Y0A21YK0F)。两个模块的测距原理和编程实验方法不同,测距效果也大不相同。有兴趣的读者可以看看这篇文章。文章末尾有实验。
STM32F103C8T6;OLED;超声模块:HC-SR04及红外测距模块:SHARP GP2Y0A21YK0F
VCC --> VCC
GND --> GND
Trig --> PA5
Echo --> PA0
VCC --> VCC
GND --> GND
Vo(数据) --> PA1
超声波是振动频率机械波。它具有频率高、波长短、绕射现象小、方向性好等特点适用于大学生、工程师、技术人员和电子爱好者。
,性能远超老版HC-SRO4、US-015测距精度高于旧版HC-SRO4和US-在015的情况下,测距范围更远,,远超一般超声波测距模块。CS-100A超声波测距SOC芯片,高性能,工业级,宽电压,低价格,只有普通超声波测距模块的一半,性能远远超过普通超声波测距模块。US-均采用025相同,。
CS100A
DC 3V-5.5V
5.3mA
-40℃-85℃
GPI0
小于15度
2cm~600cm
0.1cm 1%
1、采用测量距离个测量距离us的高电平;
自动发送模块,自动检测是否有信号返回;
3.信号返回,通过、高电平就是,测试距离=();
该模块有一个接口:。为2.54mm如图所示:从左到右依次编号,它们的定义如下∶
接VCC电源(直流3V-5.5V)。
连接外部电路,输入一个管脚模块测距可触发高电平。
连接外部电路,当测距结束时,管脚将输出高电平超声波往返。
连接外部电路的地面。
上面的时序图表明你只需要提供模块内部触发信号。
输出回波信号。
回响信号的与所测的成。距离可以通过发射信号到收到的回响信号的时间间隔来计算。
us/58-厘米或者uS/148-英寸;或:
1.该模块不应带电连接。如果要带电连接,请先让模块连接GND先连接,否则会影响模块的正常工作。
2.测距时,被测物体的面积不小于0.平面应尽可能平整,否则会影响测量结果。
/span>是测距传感器单元的集成组合构成(位置敏感探测器),IRED((红外发光二极管)和信号处理电路的各种物体的反射率,对和受到影响的距离检测由于采用,这个装置输出对应于该电压检测距离,所以这种传感器还可以来作为
4.5~5.5V DC
典型30mA
-10~60℃
-40~70℃
10~80cm
①Vo:模拟电压输出
②GND:地
③VCC:电源正
从上图就可以明显看出,该模块的不成单调关系,故一般该传感器的有效值在。
篇幅有限,如果这方面不熟悉的朋友可以去看看本人的另一篇文章,十分相近,希望对您有所帮助。【强烈推荐】基于stm32的OLED各种显示实现(含动态图)_混分巨兽龙某某的博客-CSDN博客https://blog.csdn.net/black_sneak/article/details/125418537?spm=1001.2014.3001.5501
四、CubexMX配置
晶振(精度更高)——HSE;
();
设置定时器,为上升沿捕获并连接到超声波模块的,记得(涉及到捕获中断+定时器溢出中断)。
ADC的时钟频率,否则会影响精度(8~12Mhz)
五、代码
5.1 超声波
其实,超声波HC-SR04的驱动就是。同时,由于超声波测距模块是基于的物理性质,去进行距离测量,故此其精度受到。
温度,传播介质及其物理属性等
本次实验就不进行超声波模块的精度补偿了,后面有空可以给大家出一个相关的文章。
#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_ */
#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-1
Hcsr04Info.period = htim->Init.Period; // 65535
Hcsr04Info.instance = htim->Instance; // TIM2
Hcsr04Info.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 >= 500)
{
Hcsr04Info.distance = 500; //元器件资料说是600cm最高距离,这里保守一点
}
return Hcsr04Info.distance;
}
由于利用中断去读取定时测算的脉冲距离,所以这里需要重写
/* 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 */
其实,红外测距模块就是,通过电压结合手册中电压与距离的得到计算的距离。
#ifndef __SHARP2Y0A21_H
#define __SHARP2Y0A21_H
#include "main.h"
#define Adc1IN1Distance_READ_TIMES 10 //定义红外传感器读取次数,以便取平均值
void DistanceSensor_Init(void); //初始化红外传感器
float DistanceSensor_Get_Val(void); //读取红外传感器的值
#endif
#include "sharp.h"
#include "adc.h"
#include "main.h"
#include "stdio.h"
//初始化ADC,不用修改
//这里我们仅以规则通道为例
//初始化传感器,需要修改端口和引脚号,这里是c出口,c1引脚,ADC1的IN1
void DistanceSensor_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
__HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA时钟
//先初始化ADC1通道11 IO口
GPIO_InitStructure.Pin = GPIO_PIN_1;//PA1
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;//模拟输入
GPIO_InitStructure.Pull = GPIO_NOPULL ;//不带上下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
MX_ADC1_Init();//初始化ADC1
}
//PA1=IN1
float DistanceSensor_Get_Val(void)
{
uint32_t temp_val=0;
float distemp=0.0;
uint8_t t;
for(t=0;t<Adc1IN1Distance_READ_TIMES;t++)
{
temp_val+=HAL_ADC_GetValue(&hadc1); //读取ADC值,通道1
HAL_Delay(5);
}
temp_val/=Adc1IN1Distance_READ_TIMES;//得到平均值,这个是平均的ADC,
distemp=temp_val*3.3/4095;
//电压对应距离
distemp=(-13.2*distemp*distemp*distemp)+72.84*distemp*distemp-140*distemp+107.12;
return distemp;
}
5.3 OLED显示代码
OLED模块作为常用的数据输出显示模块,应该是必须要掌握的。如果有朋友不是很熟悉,可以去参考本人上面提到的那篇文章,十分详尽!!!
本实验的目的是需要对比一下与的效果怎么样。其精度最高越好,这里就需要考虑到
//z_len为整数显示位数,f_len为小数显示位数,size2为字体大小
void OLED_Showdecimal(u8 x,u8 y,float num,u8 z_len,u8 f_len,u8 size2)
{
u8 t,temp;
u8 enshow;
int z_temp,f_temp;
z_temp=(int)num;
//整数部分
for(t=0;t<z_len;t++)
{
temp=(z_temp/oled_pow(10,z_len-t-1))%10;
if(enshow==0 && t<(z_len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
continue;
}
else
enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
}
//小数点
OLED_ShowChar(x+(size2/2)*(z_len),y,'.',size2);
f_temp=(int)((num-z_temp)*(oled_pow(10,f_len)));
//小数部分
for(t=0;t<f_len;t++)
{
temp=(f_temp/oled_pow(10,f_len-t-1))%10;
OLED_ShowChar(x+(size2/2)*(t+z_len)+5,y,temp+'0',size2);
}
}
5.4 main函数
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_I2C2_Init();
MX_ADC1_Init();
MX_TIM2_Init();
MX_TIM1_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
OLED_CLS();
Hcsr04Init(&htim2, TIM_CHANNEL_1); // 通道选择
Hcsr04Start(); // 启动超声波
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//显示实验对比
OLED_ShowCN_STR(30,0,0,4);
//红外测距显示
HAL_ADC_Start(&hadc1);
adcx=HAL_ADC_GetValue(&hadc1);
distance=DistanceSensor_Get_Val();
OLED_ShowCN_STR(0,2,4,5);
OLED_Showdecimal(80,2,distance,3,2,16);
//超声波测距显示
Hcsr04Start();
OLED_ShowCN_STR(0,4,9,5);
OLED_Showdecimal(80,4,Hcsr04Read(),3,2,16);
//显示单位
OLED_ShowCN_STR(30,6,14,5);
}
/* USER CODE END 3 */
}
六、实验效果
测距模块对比实验
经过本人由于拍摄不方便,但是效果还是很明显的。经过笔者反复标定测试发现,测距的效果从,,等都略优于。而且,超声波模块比红外测距模块便宜很多,emmm,不是很理解其意义所作。当然,超声波模块在很多情况下是需要的。
代码开源
https://pan.baidu.com/s/1ouwFLF8ru9DROIFSZnEITg dktp