超声波测量距离的原理
超声波指向性强,在介质中传播的距离较远,因而超声波经常用于距离的测量,如测距仪和物 位测量仪等都可以通过超声波来实现。利用超声波检测往往比较迅速、方便、计算简单、易于做到实时控制,并且在测量精度方面能达到工业实用的要求,因此在移 动机器人的研制上也得到了广泛的应用。
超声波测距原理是在超声波发射装置发出超声波,它的根据是接收器接到超声波时的时间差,与雷达测距原理相似。 超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。
(超声波在空气中的传播速度为340m/s,根据计时器记录的时间t(秒),就可以计算出发射点距障碍物的距离(s),即:s=340t/2)
HC-SR04介绍
HC-SR04是一款超声波发射接收模组,电子爱好者常用这款模组来做自己的试验。
本模块性能稳定,测度距离精确,模块高精度,盲区小。
主要技术参数:
使用电压:DC—5V
静态电流:小于2mA
电平输出:高5V
电平输出:底0V
感应角度:不大于15度
探测距离:2cm-450cm
高精度 :可达0.2cm
这张图片是HC-SR04超声波模组的原理图,对硬件原理感兴趣的朋友可以到网络上查找。
接线方式:VCC、trig(控制端)、echo(接收端)、GND
(1)采用IO口TRIG触发测距,给至少10us的高电平信号;
(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;
(3)有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;
本模块使用方法简单,一个控制口发一个10US以上的高电平,就可以在接收口等待高电平输出.一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,即可以达到你测量的值。
机器人避障
物体测距
液位检测
公共安防
停车场检测
STM32F103RCT6
STM32F103RCT6这款MCU功能很强大,下面是这个MCU的基本参数介绍:
系列:STM32F10X
内核:ARM-COTEX32
速度:72MHz
通讯接口:CAN,I2C,IrDA,LIN,SPI,UART/USART,USB
外围设备:DMA,电机控制PWM,PDR,POR,PVD,PWM,温度传感器,WDT
程序存储器容量:256KB
程序存储器类型:FLASH
RAM容量:48K
电压-电源(Vcc/Vdd):2 V ~ 3.6 V
振荡器:内部
工作温度:-40°C ~ 85°C
封装/外壳:64-LQFP
在这个项目中,我会用到STM32F103RCT6的UART,GPIO,Watch Dog, Timer.
STM32使用的是Keil MDK软件开发,关于这个软件大家一定很熟悉,所以我就不介绍这个软件的安装方法了。
STM32可以通过J-LINK或者ST-LINK等仿真工具进行在线仿真调试,下面这张图片是我使用的STM32开发板:
初始化时将trig和echo端口都置低,首先向给 trig发送至少10 us的高电平脉冲(模块自动向外发送8个40K的方波),然后等待,捕捉 echo 端输出上升沿,捕捉到上升沿的同时,打开定时器开始计时,再次等待捕捉echo的下降沿,当捕捉到下降沿,读出计时器的时间,这就是超声波在空气中运行的时间,按照S=(高电平时间*(340M/S))/2 就可以算出超声波到障碍物的距离。
根据这个思路,我们就可以写出简单的测试代码了。
我们可以看到串口返回的测量结果。
LCD模组选用的是STONE STVC050WT,这款显示模组使用起来非常方便,前面我们是通过串口来显示超声波测量的距离,而STONE的LCD模组也是通过UART来接收数据并显示到模组中的。这个过程只需要在MCU中做一个简单的协议封装就可以了。
STVC050WT-01是TFT显示器和触摸控制器。它包括处理器,控制程序,驱动程序,闪存,RS232/RS485/TTL端口,触摸屏、电源等,是一个功能强大的显示系统
操作系统简单,可由任意单片机控制。STVC050WT-01可用于执行所有基本功能,如文本显示、图像显示、曲线显示、触摸功能、视音频功能等。的用户界面可以更加丰富和多样。闪存可以存储你的数据,配置文件和图片等。
-内置Cortex CPU和驱动
-可用任何单片机来控制
-显示图片/文字/曲线
**
智能TFT-LCD模块通过命令与客户的MCU通信(十六进制代码),然后MCU将控制其连接的设备按照接收到的命令工作。
开发步骤
使用STONE的TFT-LCD模块只需3个步骤:
医疗美容设备
工程机械及车辆设备
电子仪器
工业控制系统
电力行业
民用电子设备
自动化设备
交通
目前STONE提供的TOOL软件最新版本是TOOL2019,打开这个软件新建项目,然后导入之前设计好的UI显示图片,再添加自己的按键、文本显示框等。关于这个软件的使用,STONE官网有非常完善的教程,感兴趣的朋友可以点击下面的网页链接:
https://www.stoneitech.com/support/download/video
LCD模组的UI图片设计
可以使用Photoshop软件或者其他图片设计软件来设置UI界面,我设计的界面如下:
点击箭头所指的按钮就可以生成配置文件,然后把配置文件下载到显示模组中就可以显示出我们设计的UI界面了。
这部分的内容和教程我就不详细介绍了,大家可以到STONE官网去下载到很详细的教程。
这个demo的功能比较简单,主要有以下两点:
1、显示超声波模组测试到的距离
2、通过显示屏的“+”和“-”按钮修改刷新时间
硬件连接的可靠性
硬件接线比较简单,可以参考下面这张图片的连接方式:
STM32单片机驱动HC-SR04的程序可以在网络上下载到,这里我也是使用了网友提供的demo例程去修改的。
单片机外设只使用到了两个GPIO引脚(trig、echo)和一个Timer。另外还需要一个UART与STONE显示屏通讯。
程序初始化时将trig和echo端口都配置成低电平输出,首先给 trig输出至少10 us的高电平脉冲(模块自动向外发送8个40K的方波),然后等待,捕捉 echo 端输出上升沿,捕捉到上升沿的同时,打开timer并且开始计时,再次等待捕捉echo的下降沿,当捕捉到下降沿,读出Timer的时间,这就是超声波在空气中运行的时间,按照S=(高电平时间*(340M/S))/2 就可以算出超声波到障碍物的距离。
void EXTI9_5_IRQHandler(void)
{
static u8 flag_Sta = 0;
if(EXTI_GetITStatus(EXTI_Line5) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line5);
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)==1)
{
TIM_SetCounter(TIM6,0);
flag_Sta=1;
TIM_Cmd(TIM6, ENABLE);
}
else
{
TIM_Cmd(TIM6, DISABLE);
if(flag_Sta)
{
Distance = TIM_GetCounter(TIM6);
Distance = Distance /29;
if(Distance > 300)
Distance = 300;
Done = 1;
}
flag_Sta=0;
}
}
}
这是一个GPIO外部中断的Handler,最终通过获取Distance这个变量的值,就可以得到超声波模块测试出来的距离。
Main.c
#include "usart1.h"
#include "Sonic.h"
#include "SysTick.h"
#define DISPLYER_ADDR 0x05
#define CHANGE_TIME_ADDR 0x10
u8 data_send[8]= {0xA5, 0x5A, 0x05, 0x82, 0x00, 0x00, 0x00,0x00};
extern u16 Distance;
extern u8 USART_RX_BUF[10];
extern u8 USART_RX_END;
extern u16 USART_RX_STA;
void UART1_Send_Array(u8 send_array[],unsigned char num)
{
u8 i=0;
while(i=time_set)
{
time=0;
data_send[5]=DISPLYER_ADDR;
data_send[6] = Distance >> 8;//hight
data_send[7] = Distance & 0x00ff;//low
UART1_Send_Array(data_send,8);
// printf("The Distance is: %d centimetre\r\n",Distance);
}
if(USART_RX_END)
{
// UART1_Send_Array(USART_RX_BUF,8);
switch (USART_RX_BUF[5])
{
case CHANGE_TIME_ADDR:
time_set=USART_RX_BUF[7]*10;
break;
default:
USART_RX_END=0;
USART_RX_STA=0;
break;
}
USART_RX_END=0;
USART_RX_STA=0;
}
}
}
/******************* (C) COPYRIGHT 2017 *****END OF FILE************/
Sonic.c
#include "Sonic.h"
/*******************************************************************************
* Sonic Init
*******************************************************************************/
u32 Distance = 0;
u8 Done;
u32 __IO time_1ms = 0;
void TIM6_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//NVIC_InitTypeDef NVIC_InitStructure;
/* TIM6 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 142; //144£¬500K
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM6, TIM_IT_Update, DISABLE);
TIM_Cmd(TIM6, DISABLE);
}
void Sonic_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //PC4 Trig
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; //PC5 Echo
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_WriteBit(GPIOC,GPIO_Pin_4,(BitAction)0); //trig
//EXTI_DeInit();
EXTI_ClearITPendingBit(EXTI_Line5);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
EXTI_InitStructure.EXTI_Line= EXTI_Line5;
EXTI_InitStructure.EXTI_Mode= EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Rising_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
Distance = 0;
Done = 1;
}
void Sonic_Trig(void)
{
u16 i = 0;
if((Done == 1)&&(time_1ms > 100))
{
time_1ms = 0;
GPIO_WriteBit(GPIOC,GPIO_Pin_4,(BitAction)1);
for(i=0;i<0xf0;i++);
GPIO_WriteBit(GPIOC,GPIO_Pin_4,(BitAction)0);
Done = 0;
}
}
void EXTI9_5_IRQHandler(void)
{
static u8 flag_Sta = 0;
if(EXTI_GetITStatus(EXTI_Line5) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line5);
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)==1)
{
TIM_SetCounter(TIM6,0);
flag_Sta=1;
TIM_Cmd(TIM6, ENABLE);
}
else
{
TIM_Cmd(TIM6, DISABLE);
if(flag_Sta)
{
Distance = TIM_GetCounter(TIM6);
Distance = Distance /29;
if(Distance > 300)
Distance = 300;
Done = 1;
}
flag_Sta=0;
}
}
}
/******************* (C) COPYRIGHT 2017 *END OF FILE************/
Uart
#include "usart1.h"
void USART1_Config(uint32_t uBaud)
{
USART1_Configuration(uBaud);
USART1_NVIC_Configuration();
}
void USART1_Configuration(uint32_t uBaud)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* config USART1 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* USART1 GPIO config */
/* Configure USART1 Tx (PA.09) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USART1 mode config */
USART_InitStructure.USART_BaudRate = uBaud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
}
void USART1_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
/* Enable the USARTy Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (unsigned char) ch);
while (!(USART1->SR & USART_FLAG_TXE));
//while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);
return (ch);
}
u16 USART_RX_STA=0;
u8 USART_RX_END=0;
u8 USART_RX_BUF[10];
void USART1_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);
//printf("%x",USART_ReceiveData(USART1));
// USART_SendData(USART1,Res);
if(USART_RX_END==0)
{
USART_RX_BUF[USART_RX_STA]=Res ;
USART_RX_STA++;
if(USART_RX_STA>=8)
{
USART_RX_END=1;
}
}
}
}
Sys_tick
void SysTick_Handler(void)
{
time_1ms++;
time_120ms++;
if(time_120ms>=80)
{
Sonic_Trig(); //50ms Trig Sonic
time_120ms=0;
}
TimingDelay_Decrement();
}
整体运行效果
在硬件连接没有错误的情况下,把代码下载进STM32开发板中,就可以在STONE显示屏中看到超声波模组测量到的距离了,另外可以通过显示模组上面的“+”和“-”按钮调整距离刷新的时间。
查看原文:https://www.stoneitech.com/news/sharing/ultrasonic-module-test-with-stone-lcd-module.html