基于51单片机的超声波测距仪设计方案


基于51单片机的超声波测距仪设计方案
一、 引言
超声波测距技术作为一种非接触式测量方法,因其高精度、高可靠性、对环境适应性强等优点,在工业自动化、机器人导航、物联网设备、智能家居以及安防领域有着广泛的应用前景。超声波测距仪通过发射超声波脉冲并接收其回波,利用声波在介质中传播的速度恒定性,通过测量超声波从发射到接收的总时间来精确计算出被测物体与传感器之间的距离。本设计方案将深入探讨基于经典的51系列单片机实现超声波测距仪的详细过程,涵盖其系统构成、硬件选型、软件设计以及可能遇到的问题与解决方案,旨在为读者提供一个全面且实用的设计指南,使其能够成功构建并优化自己的超声波测距系统。51单片机凭借其成熟的生态系统、丰富的资料、易学易用等特点,成为初学者和工程师进行嵌入式系统设计的理想选择,尤其适用于对成本和功耗有一定要求的中小型项目。本文将着重分析每个关键元器件的选择理由及其在整个系统中的功能,确保读者对设计的每一个环节都有清晰的认识。
二、 超声波测距原理
超声波测距的基本原理是利用超声波在空气中传播的时间与距离之间的关系。当超声波发射器发出超声波脉冲后,该脉冲在空气中传播,遇到障碍物后会被反射回来,并被超声波接收器接收。我们知道声波在介质中传播的速度是一个相对稳定的常数(在标准大气压和20℃时,声速约为343米/秒)。通过精确测量从超声波发射到接收到回波的总时间t,就可以利用简单的物理公式计算出距离D。由于超声波是从发射器发出,传播到障碍物后再反射回接收器,因此这个时间t实际上是超声波往返的总时间。所以,单程距离D的计算公式为:D=2v×t其中,v是超声波在当前介质(通常是空气)中的传播速度。需要注意的是,声速会受到环境温度、湿度、气压等因素的影响。在实际应用中,为了提高测距精度,通常需要对声速进行温度补偿。然而,对于大多数非高精度要求的应用场景,可以采用一个固定的经验值。51单片机在接收到回波信号后,会启动定时器计时,直至接收到回波停止,从而得到超声波的往返时间,再通过上述公式换算为距离。这一过程的精度高度依赖于单片机的定时器精度和对外界干扰的滤除能力。
三、 系统整体构成
基于51单片机的超声波测距仪主要由以下几个核心模块组成:主控模块、超声波收发模块、显示模块、电源模块和按键模块(可选)。每个模块协同工作,共同完成超声波的发射、接收、时间测量、距离计算以及最终的显示功能。主控模块作为整个系统的大脑,负责协调各个模块的工作,处理数据并进行逻辑控制。超声波收发模块是实现测距功能的关键,包括超声波发射电路和超声波接收电路。显示模块则用于直观地展示测量结果。电源模块为整个系统提供稳定的工作电压。按键模块(如果需要)可以用于模式切换、参数设置或校准等功能,增加了系统的交互性。这种模块化的设计思路使得系统的开发、调试和维护变得更加便捷高效,同时也为后续功能的扩展预留了空间。
四、 主要元器件选型及作用分析
本部分将详细介绍构建超声波测距仪所需的关键元器件,并深入分析其选择原因、功能及在系统中的作用。
4.1 主控芯片:STC89C52RC/AT89C52
选择理由: STC89C52RC和AT89C52是广泛应用于教学和工业控制领域的经典51系列单片机。它们具有成熟的架构、丰富的IO口资源、内置定时器/计数器、串口通信能力以及片内Flash存储器。STC系列的单片机相比传统的AT系列,通常具有更快的运行速度、更宽的工作电压范围、更低的功耗和更为便捷的ISP(在系统编程)功能,无需专用编程器即可下载程序,极大地简化了开发流程。对于超声波测距这种需要精确时间测量和实时数据处理的应用,51单片机的定时器/计数器资源完全能够满足需求,其性价比极高,资料丰富,便于学习和开发。
功能:
控制超声波模块: 通过控制超声波模块的Trigger(触发)引脚发射超声波,并通过Echo(回响)引脚接收回波信号。
时间测量: 利用其内部的定时器/计数器功能,精确测量超声波从发射到接收回波之间的时间间隔。例如,可以使用定时器T0或T1,设置为计数模式,通过捕捉Echo引脚的高电平持续时间来获取时间。
数据处理: 根据测量到的时间,结合声速计算出实际距离。
显示控制: 控制LCD1602或数码管显示模块,将计算出的距离值显示出来。
系统协调: 负责整个系统的工作流程调度,包括初始化、数据采集、计算、显示刷新等。
具体型号分析: STC89C52RC具有8KB的Flash程序存储器、512B的RAM、32个可编程I/O口、3个16位定时器/计数器、一个全双工UART串口以及看门狗定时器。这些资源对于超声波测距仪的设计绰绰有余。其工作频率可达35MHz,足以提供足够的指令执行速度来处理实时测距任务。
4.2 超声波测距模块:HC-SR04
选择理由: HC-SR04是一款集成度高、使用方便且性价比极高的超声波测距模块。它包含了超声波发射器和接收器,以及相应的控制电路,仅通过两个引脚(Trig和Echo)即可完成测距功能,极大地简化了外部电路设计。其测量范围通常在2cm至400cm之间,精度可达0.3cm,足以满足大多数通用测距需求。模块内部已经集成了超声波发射和接收的压电陶瓷片以及驱动电路和信号处理电路,用户无需关心超声波信号的具体产生和接收细节,只需关注Trig和Echo引脚的时序控制。
功能:
Trig(触发)引脚: 通过向该引脚输入一个10微秒(us)以上的高电平脉冲,模块会内部自动发射8个40KHz的超声波脉冲。
Echo(回响)引脚: 当超声波模块发射超声波后,Echo引脚会变为高电平。当接收到回波信号时,Echo引脚会变为低电平。因此,Echo引脚高电平的持续时间就代表了超声波从发射到接收的总时间。
工作原理概览: 51单片机首先给HC-SR04的Trig引脚一个短促的高电平脉冲,HC-SR04随即发射超声波。单片机同时启动定时器开始计时。超声波遇到障碍物反射回来后,HC-SR04的Echo引脚会从低电平变为高电平,并持续到接收到回波为止。单片机检测到Echo引脚变为高电平后,开始捕捉高电平的持续时间,当Echo引脚再次变为低电平时,停止计时。根据计时器的时间差,即可计算出距离。这种简单而高效的接口设计是选择HC-SR04的关键原因。
4.3 显示模块:LCD1602液晶显示屏
选择理由: LCD1602是一种经典的字符型液晶显示模块,可以显示两行,每行16个字符。它结构简单、价格便宜、接口友好,非常适合用于显示简单的数字和文字信息,如距离值、单位等。与数码管相比,LCD1602能够显示更多的信息,并且功耗较低,显示效果更清晰。其内部集成了LCD控制器,与单片机连接方便,通常通过并行或I2C(如果带有转换模块)接口进行通信。
功能: 接收来自51单片机的数据和控制命令,并将其转换为可视的字符或数字显示出来。在本设计中,它主要用于显示测量到的距离值,例如“Distance: XX.XX cm”。
接口说明: LCD1602通常有16个引脚,包括数据线(D0-D7)、控制线(RS、RW、EN)和电源线。RS(Register Select)用于选择命令寄存器或数据寄存器;RW(Read/Write)用于选择读写模式;EN(Enable)用于使能操作。通过对这些引脚的电平组合和时序控制,单片机可以向LCD1602发送命令(如清屏、设置光标位置)和显示数据。
4.4 电源模块:AMS1117-3.3/5.0V稳压模块
选择理由: 超声波测距仪需要稳定可靠的电源供应。51单片机通常工作在5V,而HC-SR04模块也推荐5V供电,但有些版本的LCD1602可能需要3.3V或5V。为了确保整个系统的稳定运行,通常会采用一个稳压模块将外部电源(如9V电池或12V适配器)转换为单片机和各模块所需的稳定电压。AMS1117系列稳压芯片是常见的低压差线性稳压器,具有输出电压稳定、纹波小、功耗低、成本低廉等优点。选择带有AMS1117芯片的模块可以方便地将较高输入电压转换为所需的5V或3.3V输出。
功能: 将外部输入的非稳压直流电源(例如直流9V或12V)转换为系统所需的稳定5V或3.3V直流电源,为单片机、超声波模块和显示模块提供可靠的工作电压,避免因电压波动引起的系统不稳定或误动作。
选择原因: 尽管可以直接使用三端稳压芯片7805,但AMS1117系列具有更低的压差,这意味着在输入电压与输出电压差较小的情况下也能保持稳定输出,且其封装和集成度更适合模块化设计。
4.5 其他辅助元器件
晶振: 通常为11.0592MHz或12MHz。
选择理由: 晶振是单片机的心脏,为单片机提供稳定的时钟信号。11.0592MHz是一个常用值,因为它能产生标准的波特率,方便串口通信(如果需要)。12MHz则是一个常用的整数频率,便于计算定时器和延时。
功能: 提供单片机系统时钟,决定了单片机指令执行速度和定时器/计数器的计时精度。
复位电路: 通常由一个10kΩ电阻和10μF电容组成。
选择理由: 复位电路是单片机正常启动的必要条件。RC复位电路是最简单、最常用的复位方式,在系统上电时为单片机提供一个短暂的低电平复位信号,确保单片机从已知状态开始运行。
功能: 在上电瞬间或按下复位按钮时,强制单片机回到初始状态,重新开始执行程序,防止因上电不稳定等因素导致程序运行异常。
滤波电容: 0.1μF陶瓷电容(并联在电源引脚附近)和10μF/100μF电解电容(并联在稳压输出端)。
选择理由: 电源滤波是确保系统稳定运行的关键。陶瓷电容用于滤除高频噪声,电解电容用于滤除低频噪声,提供稳定的直流电源。
功能: 降低电源纹波和噪声,保证各芯片工作电压的稳定性,防止干扰信号通过电源线进入芯片,提高系统抗干扰能力和工作稳定性。
五、 硬件电路设计
硬件电路设计是实现测距仪功能的物理基础,需要将上述选定的元器件按照正确的连接方式组合起来。
5.1 主控芯片最小系统
STC89C52RC/AT89C52单片机需要构建一个最小系统才能正常工作。这包括:
电源连接: VCC接5V,GND接地。
晶振电路: 将11.0592MHz或12MHz的晶振连接到单片机的XTAL1和XTAL2引脚,并分别并联两个22pF或33pF的瓷片电容到地。这两个电容是晶振的负载电容,用于提供稳定的谐振频率。
复位电路: 将单片机的RST引脚通过一个10kΩ电阻连接到VCC,同时并联一个10μF电解电容到GND。此外,可以并联一个按键开关,一端接RST,另一端接地,用于手动复位。
5.2 超声波模块连接
HC-SR04模块与51单片机的连接非常简单:
VCC: 连接到51单片机的5V电源。
GND: 连接到51单片机的GND。
Trig(触发): 连接到51单片机的一个普通I/O口,例如P1.0。用于单片机向HC-SR04发送触发脉冲。
Echo(回响): 连接到51单片机的另一个普通I/O口,例如P1.1。最好选择可以作为外部中断或定时器输入捕捉的引脚,但对于测量高电平持续时间,普通I/O口结合定时器查询也可行。
5.3 LCD1602显示模块连接
LCD1602通常采用4位或8位并行模式与单片机连接。为了节省I/O口资源,通常选择4位模式。
VCC和GND: 连接到51单片机的5V电源和GND。
VDD和VSS: VDD接5V,VSS接地。
VO: 对比度调节引脚,通常连接一个10kΩ的滑动变阻器,一端接VCC,另一端接地,中间滑动端接VO,用于调节显示对比度。
RS、RW、EN: 控制线,分别连接到51单片机的三个I/O口,例如P0.0、P0.1、P0.2。
RS (Register Select):P0.0
RW (Read/Write):P0.1 (通常接地,只进行写操作)
EN (Enable):P0.2
DB4-DB7: 数据线(高4位),连接到51单片机的另外四个I/O口,例如P0.4-P0.7。
A和K: 背光引脚,A(Anode)接VCC(通常串联一个限流电阻),K(Cathode)接地。
如果使用带I2C接口的LCD1602模块,连接会更简单,只需要SCL和SDA两根线连接到单片机的I2C接口引脚即可。
六、 软件程序设计
软件程序设计是实现超声波测距仪功能的灵魂,它负责控制硬件、处理数据并实现逻辑功能。程序主要包括初始化、超声波发射、时间测量、距离计算和显示等模块。
6.1 主程序结构
主程序通常包含初始化函数、无限循环以及必要的延时或任务调度。
#include <reg52.h> // 引入51单片机头文件
#include <intrins.h> // 包含_nop_()函数用于微秒级延时
sbit Trig = P1^0; // 定义Trig引脚
sbit Echo = P1^1; // 定义Echo引脚
// LCD1602接口定义
sbit LCD_RS = P0^0;
sbit LCD_RW = P0^1; // 实际应用中常直接接地,只进行写操作
sbit LCD_EN = P0^2;
#define LCD_DATA P0 // 将P0口定义为数据端口
unsigned int time_count; // 存储定时器计数值
float distance; // 存储计算出的距离
// 函数声明
void delay_us(unsigned int us);
void delay_ms(unsigned int ms);
void HCSR04_Init();
void HCSR04_Start();
unsigned int HCSR04_GetDistance();
void LCD_WriteCommand(unsigned char cmd);
void LCD_WriteData(unsigned char dat);
void LCD_Init();
void LCD_ShowChar(unsigned char row, unsigned char col, unsigned char dat);
void LCD_ShowString(unsigned char row, unsigned char col, unsigned char *str);
void LCD_ShowNum(unsigned char row, unsigned char col, float num, unsigned char len);
void main()
{
HCSR04_Init(); // 初始化超声波模块
LCD_Init(); // 初始化LCD1602
LCD_ShowString(0, 0, "Distance:"); // 第一行显示固定文本
while(1)
{
time_count = HCSR04_GetDistance(); // 获取超声波往返时间
// 根据时间计算距离
// 声速v = 343 m/s = 0.0343 cm/us
// 距离D = (v * t) / 2
// 如果定时器是1us计数一次,那么time_count就是us数
// 实际计算时,需要考虑单片机晶振和定时器分频。
// 例如:12MHz晶振,定时器工作在模式1,1us计数一次
(12/12 = 1个机器周期,1个机器周期1us)
// D = time_count * 0.0343 / 2;
// D = time_count * 0.01715; // 简化计算
// 考虑更精确的声速计算:在20℃空气中声速约为343.2m/s,即34320cm/s = 0.03432 cm/us
// distance = (float)time_count * 0.03432 / 2.0; // 往返时间除以2得到单程时间
// 更准确的计算方法是:12MHz晶振,一个机器周期为1us,如果定时器是1us加1,
那么time_count的单位就是us
// 距离 = (时间(us) * 0.034cm/us) / 2
distance = (float)time_count / 58.0; // 经验公式,将us转换为cm的便捷方法
(1/0.03432)*2 ≈ 58
// 或者 distance = (float)time_count * 0.01716;
if(distance > 400 || distance < 2) // 超出测量范围或无效值
{
LCD_ShowString(1, 0, "Out of Range "); // 清除旧显示,显示超范围
}
else
{
LCD_ShowNum(1, 0, distance, 4); // 在LCD第二行显示距离,保留2位小数
LCD_ShowString(1, 6, " cm "); // 显示单位
}
delay_ms(100); // 延时100ms,等待下一次测量,避免测量过于频繁
}
}
6.2 延时函数
延时函数是嵌入式编程中常用的基本功能,用于产生精确的时间延迟。
// 微秒级延时函数
void delay_us(unsigned int us)
{
while(us--)
{
_nop_(); // 执行一个空指令,一个机器周期,通常为1us(12MHz晶振)
}
}
// 毫秒级延时函数
void delay_ms(unsigned int ms)
{
unsigned int i, j;
for(i=ms; i>0; i--)
{
for(j=110; j>0; j--); // 经过校准的循环,使延时接近1ms (对于12MHz晶振)
}
}
6.3 HC-SR04模块操作函数
这是超声波测距的核心部分,负责触发超声波并测量回波时间。
// HC-SR04初始化 (在此示例中无需特殊初始化,主要是引脚配置)
void HCSR04_Init()
{
// 配置Trig和Echo引脚为输出/输入,对于51单片机,默认是准双向口,直接操作即可
// P1M0 = 0x00; P1M1 = 0x00; // 配置P1口为准双向口(默认)
}
// 启动超声波测距并获取时间
unsigned int HCSR04_GetDistance()
{
unsigned int timer_value = 0;
Trig = 0; // 清除Trig
Trig = 1; // 产生一个10us以上的高电平脉冲
delay_us(12); // 延时12us,确保脉冲宽度
Trig = 0; // 脉冲结束
// 等待Echo引脚变为高电平(接收到超声波发射)
while(!Echo);
// 启动定时器开始计时
// 这里使用定时器0,设置为模式1(16位定时器)
TMOD &= 0xF0; // 清除TMOD的低四位,不影响T1
TMOD |= 0x01; // 设置T0为模式1 (16位定时器/计数器)
TH0 = 0x00; // 定时器高8位清零
TL0 = 0x00; // 定时器低8位清零
TR0 = 1; // 启动定时器0
// 等待Echo引脚变为低电平(接收到回波)
while(Echo && !TF0); // Echo为高电平且定时器未溢出
TR0 = 0; // 停止定时器0
if(TF0) // 如果定时器溢出,说明超出了测量范围或没有收到回波
{
TF0 = 0; // 清除溢出标志
return 0xFFFF; // 返回一个无效值
}
else
{
timer_value = TH0 * 256 + TL0; // 读取定时器计数值
return timer_value;
}
}
关于定时器的说明:上述代码中,定时器T0被设置为模式1(16位定时器),最大计数值为65535。如果使用12MHz晶振,一个机器周期是1μs。那么定时器每计数1次就是1μs。
因此,timer_value
的单位就是μs。HC-SR04的有效测量范围是2cm-400cm,对应的往返时间大约是116μs到23200μs。65535μs对应的距离约为11.2米,远超HC-SR04的测量上限,所以定时器溢出的情况很少发生,除非长时间没有回波。TF0
是定时器溢出标志位,用于判断是否溢出。
6.4 LCD1602显示函数
这部分代码用于控制LCD1602显示测量结果。
// LCD1602发送命令
void LCD_WriteCommand(unsigned char cmd)
{
LCD_RS = 0; // RS=0,表示写命令
LCD_RW = 0; // RW=0,表示写操作
// 发送高4位
LCD_DATA = (cmd & 0xF0);
LCD_EN = 1; // EN高电平
delay_us(5); // 延时片刻
LCD_EN = 0; // EN低电平
delay_us(5); // 延时片刻
// 发送低4位
LCD_DATA = ((cmd << 4) & 0xF0); // 将低四位左移到高四位
LCD_EN = 1;
delay_us(5);
LCD_EN = 0;
delay_us(5);
delay_ms(2); // 命令执行延时
}
// LCD1602发送数据
void LCD_WriteData(unsigned char dat)
{
LCD_RS = 1; // RS=1,表示写数据
LCD_RW = 0; // RW=0,表示写操作
// 发送高4位
LCD_DATA = (dat & 0xF0);
LCD_EN = 1;
delay_us(5);
LCD_EN = 0;
delay_us(5);
// 发送低4位
LCD_DATA = ((dat << 4) & 0xF0);
LCD_EN = 1;
delay_us(5);
LCD_EN = 0;
delay_us(5);
delay_ms(1); // 数据写入延时
}
// LCD1602初始化
void LCD_Init()
{
delay_ms(15); // 上电延时
LCD_WriteCommand(0x30); // 功能设置:8位数据接口
delay_ms(5);
LCD_WriteCommand(0x30);
delay_us(100);
LCD_WriteCommand(0x30);
LCD_WriteCommand(0x20); // 功能设置:4位数据接口
LCD_WriteCommand(0x28); // 功能设置:4位数据,2行显示,5x7点阵
LCD_WriteCommand(0x0C); // 显示开,光标关,不闪烁
LCD_WriteCommand(0x06); // 地址自动加1,显示不移动
LCD_WriteCommand(0x01); // 清屏
delay_ms(2);
}
// 在指定位置显示字符
void LCD_ShowChar(unsigned char row, unsigned char col, unsigned char dat)
{
unsigned char address;
if(row == 0) // 第一行
{
address = 0x80 + col;
}
else // 第二行
{
address = 0xC0 + col;
}
LCD_WriteCommand(address); // 设置DDRAM地址
LCD_WriteData(dat); // 写入数据
}
// 在指定位置显示字符串
void LCD_ShowString(unsigned char row, unsigned char col, unsigned char *str)
{
unsigned char address;
if(row == 0) // 第一行
{
address = 0x80 + col;
}
else // 第二行
{
address = 0xC0 + col;
}
LCD_WriteCommand(address); // 设置DDRAM地址
while(*str != '