超声波模块简介
超声波测距原理
超声波具有较强的方向性,在介质中的传播距离较远。因此,超声波常用于距离测量,如距离测量仪器和物体高度测量仪器,这些都可以通过超声波实现。超声波检测通常更快、更方便、计算简单、易于实现实时控制,且在测量精度方面能满足工业实际需求,因此在移动机器人领域得到了广泛应用。
超声波测距的原理是超声波发射器发出超声波,基于接收器接收超声波的时间差进行测量,与雷达测距原理相似。超声波发射器向特定方向发送超声波,同时开始计时,超声波在空气中传播,遇到障碍物后立即反射回发射器,超声波接收器接收到反射波后立即停止计时。
(超声波在空气中的传播速度为340m/s。根据计时器记录的时间t(秒),可计算出发射点到障碍物的距离s,即s=340t/2)。
HC-SR04简介
HC-SR04是一款电子爱好者常用于自行实验的超声波发射器和接收器模块。
该模块具有性能稳定、测量距离准确、精度高、盲区小的特点。
主要技术参数:
- 工作电压:DC– -5V
- 静态电流:小于2mA
- 电平输出:高电平5V
- 电平输出:低电平0V
- 感应角度:不超过15度
- 检测范围:2cm-450cm
- 高精度:最高可达0.2cm
HC-SR04模块原理图
此图为HC-SR04超声波模块的原理图。若对硬件原理感兴趣,可自行查阅相关资料。
T
接线:VCC、TRIG(控制端)、ECHO(接收端)、GND 基本工作原理:
- IO 端口 TRIG 用于触发测距并输出至少 10us 的高电平信号;
- 模块自动发送 8 个 40kHz 的方波以自动检测是否存在信号返回;
- 信号返回后,通过 IO 端口 ECHO 输出高电平。高电平持续时间即为超声波从发射到返回所需的时间。测试距离 = (高电平时间 × 声速 (340m/s)) / 2;
该模块使用方法简单,发送端输出高电平超过10us,接收端即可输出高电平。为实现定时计时,可在发送端平时输入低电平时开启定时器,定时器值可用于计算时间距离。通过不断循环测试,即可获得测量值。
应用场景
- 机器人避障
- 物体距离测量
- 液体液位检测
- 公共安全
- 停车场巡检
使用MCU测试HC-SR04
STM32F103RCT6
STM32F103RCT6是一款性能强大的MCU,以下是该MCU的基本参数:
- 系列:STM32F10X
- 内核:ARM – CORTEX32
- 速度:72 MHz
- 通信接口: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、看门狗和定时器。
以下是本项目的代码开发记录。
STM32 使用 Keil MDK 软件进行开发,关于此软件您应已熟悉,因此不再介绍该软件的安装方法。
STM32 可通过 j-link 或 st-link 等仿真工具进行在线仿真和调试。下图是我使用的 STM32 开发板:
通过串口助手显示测试结果
Trig 和 Echo 端口配置为低电平输出,输出超过 10 微秒的 Trig 引脚高电平脉冲(模块自动发送八个 40 kHz 方波),然后等待,捕获输出 Echo 的上升沿,同时捕获上升沿,启动定时器开始计时, 再次等待捕获回波的下降沿,在捕获下降沿时读取定时器时间,这就是超声波在空气中的传播时间,根据公式 S = (高电平时间 * (340 m/s)) / 2 可计算超声波到障碍物的距离。
基于此,我们可以编写简单的测试代码。
我们可以查看串口返回的测量结果。
通过串口助手显示测试结果
Trig 和 Echo 端口配置为低电平输出,输出超过 10 微秒的 Trig 引脚高电平脉冲(模块自动发送八个 40 kHz 方波),然后等待,捕获输出 Echo 的上升沿,同时捕获上升沿,启动定时器开始计时, 再次等待捕获回波的下降沿,在捕获下降沿时读取定时器时间,这就是超声波在空气中的传播时间,根据公式 S = (高电平时间 * (340 m/s)) / 2 可计算超声波到障碍物的距离。
基于此,我们可以编写简单的测试代码。
我们可以查看串口返回的测量结果。
STONE串口屏的工作原理
智能串口屏通过命令(十六进制代码)与客户的MCU通信,MCU根据接收的命令控制连接的设备工作。
3步开发STONE串口屏
使用STONE的TFT-串口屏只需3步:
- 设计一套美观的人机交互界面。
- 通过RS232、RS485或TTL直接连接至客户的MCU。即插即用。
- 编写简单程序,通过MCU命令控制TFT-串口屏。(十六进制代码)
TFT 串口屏串行命令帧由5个数据块组成,所有串行命令或数据均以十六进制格式表示。数据传输
采用MSB方式。例如,对于0x1234,首先发送0x12,然后发送0x34。
STONE串口屏的9个常见应用场景
常见应用场景已在STONE的官方网站上详细描述。
STONE显示屏广泛应用于各类工业领域
- 医疗美容设备
- 建筑机械及车辆设备
- 电子仪器
- 工业控制系统
- 电力行业
- 民用电子设备
- 自动化设备
- 交通行业
关于STONE TOOL软件的使用
目前,STONE提供的最新版本STONE TOOL软件为TOOL2019。打开软件创建新项目,然后导入之前设计的UI显示图片,并添加自定义按钮、文本显示框等。STONE官方网站提供了该软件使用的详细教程。感兴趣的朋友可点击以下链接:
STONE 串口屏的UI图形设计
您可以使用Photoshop或其他图像设计软件设置UI界面。我设计的界面如下:
使用TOOL2019软件生成STONE 串口屏配置文件
点击箭头所示按钮生成配置文件,然后将配置文件下载到显示模块中,即可显示我们设计的UI界面。
这部分内容和教程我不再详细展开,您可以前往STONE官网下载非常详细的教程。
STM32 LCD项目实现过程(使用UART TTL)
该演示功能相对简单,主要包括以下两点:
显示超声波模块测量的距离
通过显示屏上的“+”和“-”按钮更改刷新时间
STONE LCD项目硬件连接的可靠性
硬件接线非常简单,可参考以下连接示意图:
STM32微控制器驱动STONE串口屏程序
STM32微控制器驱动HC-SR04的程序可从网络下载,此处也使用用户提供的示例程序进行修改。
外设资源使用
MCU外设仅使用两个GPIO引脚(trig、echo)和一个定时器。此外,需通过UART与STONE显示器进行通信。
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;
}
}
}
Trig 和 echo 端口配置为低电平输出。首先向 Trig 输出至少 10 微秒的高电平脉冲(模块会自动发送八个 40 kHz 方波),然后等待,捕获输出 echo 的上升沿,同时捕获上升沿,开启定时器并开始计时,再次等待捕获 echo 的下降沿,在捕获下降沿时读取定时器时间, 这是超声波在空气中的传播时间,根据S = (高电平时间 * (340 m/s)) / 2可计算超声波到障碍物的距离。
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<num)< span=""></num)<>
{
USART_SendData(USART1,send_array[i]);
while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);
i++;
}
}
/*
* Function£ºmain
*/
int main(void)
{
u8 time=0,time_set=100;
SysTick_Init();
USART1_Config(115200); /* USART1 INIT*/
TIM6_Init(); //TIM6 Init
Sonic_Init(); //Sonic_Init
// printf("STM32F103VET6_Sonic Test!\r\n");
// printf("2017-04-14 9:00\r\n\r\n");
while(1)
{
Delay_ms(10);
time++;
if(time>=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();
}
超声波模块与STONE 串口屏效果测试
在硬件连接无误的情况下,将代码下载至STM32开发板,超声波模块测得的距离可在STONE串口屏上查看。此外,可通过电机显示模块上方的“+”和“-”按钮调整距离刷新时间。