当前位置: 首页 > news >正文

基于 LCD1602 的超声波测距仪设计与实现:从原理到应用

具体材料可在主页资源里下载

超声波测距技术作为非接触式测量的重要手段,在工业检测、智能家居、机器人避障等领域有着广泛应用。本文将详细介绍一款基于 STC89C51 单片机与 LCD1602 显示屏的超声波测距系统,从硬件架构到软件实现,完整呈现一个兼具实用性与学习价值的嵌入式系统项目。

项目背景与功能概述

在工业自动化和智能设备领域,精准的距离测量是许多系统的核心需求。传统的接触式测量方法存在磨损、效率低等问题,而超声波测距凭借非接触、响应快、成本低的优势成为理想选择。本项目设计的测距仪具备以下核心功能:

  • 实时测距:利用 HC-SR04 模块实现 2cm-400cm 范围的距离测量,精度控制在 1cm 以内
  • 信息显示:通过 LCD1602 实时显示测量距离,支持自定义报警阈值显示
  • 智能报警:当距离小于设定阈值(默认 5cm)时触发声光报警
  • 人机交互:通过按键实现报警阈值的灵活调整(1cm-50cm)

系统设计架构与工作原理

模块化设计思想

整个系统采用模块化架构,将复杂功能分解为独立可维护的单元,主要包括:

  • 主控模块:STC89C51RD + 单片机作为核心控制器
  • 测距模块:HC-SR04 超声波传感器实现距离测量
  • 显示模块:LCD1602 液晶显示屏呈现测量结果
  • 报警模块:蜂鸣器与红绿 LED 实现声光提示
  • 输入模块:独立按键支持阈值调整

超声波测距原理

HC-SR04 的工作基于超声波的传播特性,其核心公式为:
距离(cm) = 回波时间(μs) × 0.034 / 2

  • 单片机向 Trig 引脚发送 10μs 高电平触发超声波发射
  • 传感器自动发射 8 个 40kHz 超声波脉冲并等待回波
  • Echo 引脚高电平持续时间即为声波往返时间
  • 利用定时器测量时间差,结合声速计算实际距离

硬件电路设计与实现

核心硬件选型

模块型号功能描述
主控芯片STC89C51RD+8 位单片机,8KB Flash,512B RAM
测距模块HC-SR04超声波传感器,测量范围 2-400cm
显示模块LCD160216×2 字符液晶,支持 ASCII 字符显示
报警模块有源蜂鸣器 + LED声音报警与状态指示
按键模块独立按键阈值加减与确认功能

关键电路设计

主控模块电路

STC89C51RD + 的最小系统包括:

  • 12MHz 晶振电路提供时钟信号
  • 上电复位与手动复位结合的复位电路
  • P0 口作为数据总线连接 LCD1602
  • P1/P2/P3 口用于外设控制
超声波模块接口

HC-SR04 与单片机的连接:

  • Trig 引脚 → P1.0(触发信号输出)
  • Echo 引脚 → P1.1(回波信号输入)
  • 采用上拉电阻提高抗干扰能力
LCD1602 驱动电路

LCD1602 的控制接口:

  • RS → P2.6(寄存器选择)
  • RW → P2.5(读写控制)
  • E → P2.7(使能信号)
  • D0-D7 → P0 口(8 位数据传输)

硬件连接方案

模块单片机引脚功能说明
HC-SR04Trig→P1.0超声波触发信号
Echo→P1.1回波接收信号
LCD1602RS→P2.6寄存器选择
RW→P2.5读写控制
EN→P2.7使能端
D0-D7→P0数据端口
蜂鸣器P2.1报警声音输出
绿灯P2.0安全距离指示
红灯P2.2危险距离指示
加键P3.0阈值 + 1cm
减键P3.1阈值 - 1cm
确认键P3.2恢复显示

软件设计与核心代码

软件开发环境

  • 集成开发环境:Keil C51
  • 下载工具:STC-ISP
  • 编程语言:C 语言

关键功能实现

主程序流程

主程序作为系统的控制核心,负责各模块的协调工作:

void main(void)
{Timer0_Init();          // 初始化定时器0LCD1602_Init();         // 初始化LCDLCD1602_DisString(0,5,"LCD1602");   // 显示欢迎信息GreenLED = 0;    // 初始化绿灯亮Buzzer = 1;      // 蜂鸣器关闭RedLED = 1;      // 红灯关闭while(1)         // 主循环{    Key_Scan();           // 扫描按键Start_HCSR04();     // 触发超声波测距LCD1602_DisDistance();   // 显示距离结果delay_xms(100);       // 延时100ms}
}
超声波测距实现

距离测量的核心在于精确计时:

void Start_HCSR04(void) 
{Trig=1;     // 发送10us高电平触发信号delay_xus(20);Trig=0;while(!Echo);     // 等待回波信号变高TR0=1;            // 启动定时器计数while(Echo);      // 等待回波信号变低TR0=0;            // 停止定时器
}float Count(void)
{uint time = TH0 * 256 + TL0;   // 计算总定时时间TH0 = TL0 = 0;          // 定时器清零return time*0.017f;    // 距离=时间/58(声速340m/s换算)
}
LCD1602 显示控制

实现字符与数字的精准显示:

void LCD1602_DisData(uchar hang,uchar lie,float dat)
{uchar int_part = (uchar)dat;          // 整数部分uchar dec_part = (uchar)((dat - int_part) * 10); // 小数部分LCD1602_DisChar(hang,lie,int_part / 10 + '0');LCD1602_DisChar(hang,lie+1,int_part % 10 + '0');LCD1602_DisChar(hang,lie+2,'.');LCD1602_DisChar(hang,lie+3,dec_part + '0');
}
按键处理与报警功能

实现人机交互与安全提示:

void Key_Scan(void)
{if(Key_Plus == 0)    // 加键处理{   ultrasound_enabled = 0;  //暂停超声波delay_xms(10); // 消抖if(Key_Plus == 0 && key_flag == 0){key_flag = 1;   if(threshold_cm < 50) threshold_cm++;    // 显示新阈值LCD1602_DisString(0,2,"TH:");LCD1602_DisData(0,5,threshold_cm);LCD1602_DisString(0,9,"cm ");}}// 减键与确认键处理逻辑类似...
}void Alarm_5Times() {uchar i;for (i = 0; i < 5; i++) {Buzzer = 0;  // 蜂鸣器响RedLED = 0;  // 红灯亮delay_xms(200);Buzzer = 1;  // 蜂鸣器停RedLED = 1;  // 红灯灭delay_xms(200);}
}

总代码

#include<reg52.h>
#include<intrins.h> //包含_nop_()函数#define uint unsigned int   // 类型重定义
#define uchar unsigned char
#define LCD1602_Port P0	     // LCD数据端口/* 硬件引脚定义 */sbit GreenLED = P2^0;      // 绿灯(正常状态指示)
sbit Buzzer = P2^1;        // 蜂鸣器(报警用)
sbit RedLED = P2^2;        // 红灯(报警指示)
sbit LCD1602_RS=P2^6;      // LCD寄存器选择
sbit LCD1602_RW=P2^5;      // LCD读写控制
sbit LCD1602_EN=P2^7;      // LCD使能端
sbit Key_Plus = P3^0;      // 阈值增加按键
sbit Key_Minus = P3^1;     // 阈值减少按键
sbit Key_OK=P3^2;          // 确认/返回按键//超声波模块HC-SR04引脚定义
sbit Trig=P1^0;
sbit Echo=P1^1;/* 全局变量 */
bit flag;
bit key_flag = 0;      // 按键防抖标志
uint key_delay = 0;    // 按键延时计数器
unsigned int threshold_cm = 5;  // 默认阈值5cm
bit ultrasound_enabled = 1;  // 全局启用标志/* 函数声明 */
void delay_xus(uint t);              //延时xus
void delay_xms(uint t);              //延时xmsvoid Timer0_Init();                  //定时器0初始化void LCD1602_BusyCheck(void);        //LCD1602判忙函数void LCD1602_WriteCmd(uchar cmd);     //LCD1602写指令
void LCD1602_WriteData(uchar dat);    //LCD1602写数据void LCD1602_Init(void);              //LCD1602初始化void LCD1602_DisChar(uchar hang,uchar lie,uchar ch);       //显示字符
void LCD1602_DisString(uchar hang,uchar lie,uchar *str);   //显示字符串
void LCD1602_DisData(uchar hang,uchar lie,float dat);       //显示数据void Start_HCSR04(void);                 //启动超声波模块
float Count(void);                       //计算距离值void LCD1602_DisDistance(void);          //把距离显示在LCD1602上
void Alarm_5Times();                     //蜂鸣器报警
void Key_Scan();                         // 按键扫描/* 主函数 */
void main(void)
{     uint s;Timer0_Init();          // 初始化定时器0LCD1602_Init();         // 初始化LCDLCD1602_DisString(0,5,"LCD1602");   // 显示欢迎信息GreenLED = 0;    // 初始化绿灯亮Buzzer = 1;      // 蜂鸣器关闭RedLED = 1;      // 红灯关闭while(1)         // 主循环{	Key_Scan();           // 扫描按键Start_HCSR04();     // 触发超声波测距LCD1602_DisDistance();   // 显示距离结果delay_xms(100);       // 延时100ms(控制测量频率)}
}/* 微秒级延时(基于_nop_指令)*/
void delay_xus(uint t) // 微秒级延时(基于_nop_指令)
{uint i;for(i=t;i>0;i--)_nop_();
}/* 毫秒级延时(软件循环)*/
void delay_xms(uint t) 
{uint i,j;for(i=t;i>0;i--)for(j=123;j>0;j--);
}/* 定时器0初始化(模式1,16位定时器)*/
void Timer0_Init(void) 
{TMOD=0x01;    // 设置定时器模式TH0=0;        // 初值清零TL0=0;EA=1;         // 开启总中断ET0=1;        // 允许定时器0中断
}/* 定时器0中断服务函数 */
void Timer0() interrupt 1  
{flag=1;        // 设置溢出标志
}/* 启动超声波测距 */
void Start_HCSR04(void) 
{Trig=1;     // 发送10us高电平触发信号delay_xus(20);Trig=0;while(!Echo);     // 等待回波信号变高TR0=1;            // 启动定时器计数while(Echo);      // 等待回波信号变低TR0=0;            // 停止定时器
}/* LCD忙检测(检查BF标志位)*/
void LCD1602_BusyCheck()  
{uchar LCD1602_Temp;LCD1602_Port=0xff;LCD1602_RS=0;LCD1602_RW=1;while(1){ LCD1602_EN=1;        // 使能LCD1602_Temp=LCD1602_Port;     // 读取状态LCD1602_EN=0;if((LCD1602_Temp & 0x80)==0)break;   // 检查忙标志}
}/* LCD写指令 */
void LCD1602_WriteCmd(uchar cmd)  // 写指令到LCD1602
{LCD1602_BusyCheck();      // 等待LCD空闲LCD1602_EN=0;LCD1602_RS=0;      // 命令模式LCD1602_RW=0;      // 写模式LCD1602_Port=cmd;  // 发送命令delay_xms(1); LCD1602_EN=1;    // 使能脉冲delay_xms(1);LCD1602_EN=0;
}/* LCD写数据 */
void LCD1602_WriteData(uchar dat)  // 写数据到LCD1602
{ LCD1602_BusyCheck();LCD1602_EN=0;LCD1602_RS=1;   // 数据模式LCD1602_RW=0;LCD1602_Port=dat;delay_xms(1);LCD1602_EN=1;delay_xms(1);LCD1602_EN=0;
}/* LCD初始化序列 */
void LCD1602_Init()  
{delay_xms(15);         //延时15msLCD1602_WriteCmd(0x38);delay_xms(5);          //延时5msLCD1602_WriteCmd(0x38);delay_xms(5);          //延时5msLCD1602_WriteCmd(0x38);LCD1602_WriteCmd(0x08);   //显示关闭LCD1602_WriteCmd(0x01);   //显示清屏LCD1602_WriteCmd(0x06);   //显示光标移动设置,光标右移LCD1602_WriteCmd(0x0C);   //显示开及光标设置,光标关,闪烁关
}/* 在指定位置显示字符 */
void LCD1602_DisChar(uchar hang,uchar lie,uchar ch)//在指定位置显示字符hang:0-1,lie:0-15  
{if(hang==0){ LCD1602_WriteCmd(0x80+lie);}if(hang==1){ LCD1602_WriteCmd(0xC0+lie);}LCD1602_WriteData(ch);	
}/* 显示数字(1个小数点)*/
void LCD1602_DisData(uchar hang,uchar lie,float dat)
{uchar int_part = (uchar)dat;          // 整数部分uchar dec_part = (uchar)((dat - int_part) * 10); // 小数部分(1位)LCD1602_DisChar(hang,lie,int_part / 10 + '0');LCD1602_DisChar(hang,lie+1,int_part % 10 + '0');LCD1602_DisChar(hang,lie+2,'.');LCD1602_DisChar(hang,lie+3,dec_part + '0');
}/* 显示字符串 */
void LCD1602_DisString(uchar hang,uchar lie,uchar *str)
{uchar a;if(hang==0)a=0x80;         // 第一行起始地址if(hang==1)a=0xC0;         // 第二行起始地址a=a+lie;     // 计算实际地址LCD1602_WriteCmd(a);while(*str!='\0')   // 遍历字符串{LCD1602_WriteData(*str);str++;}
}/* 计算距离值(单位:cm)*/
float Count(void)
{uint time = TH0 * 256 + TL0;   // 计算总定时时间TH0 = TL0 = 0;          // 定时器清零return time*0.017f;    // 距离=时间/58(声速340m/s换算)
}/* 显示距离结果(带错误检测)*/
void LCD1602_DisDistance(void)  // 显示距离结果(带错误检测)
{     float s;if(!ultrasound_enabled) return;s=Count();   // 获取距离值if(s<threshold_cm||s>50||flag==1)    // 距离过近/过远/超时{flag=0;LCD1602_DisString(1,5," error  ");GreenLED =1;     // 绿灯灭Alarm_5Times();    // 触发报警}else    {LCD1602_DisData(1,5,s);   // 显示距离LCD1602_DisString(1,9,"cm");GreenLED = 0;      // 绿灯亮Buzzer = 1;        // 关闭蜂鸣器RedLED = 1;        // 关闭红灯}
}/* 蜂鸣器报警(响5次)*/
void Alarm_5Times() {uchar i;for (i = 0; i < 5; i++) {Buzzer = 0;  // 蜂鸣器响RedLED = 0;  // 红灯亮delay_xms(200);Buzzer = 1;  // 蜂鸣器停RedLED = 1;  // 红灯灭delay_xms(200);}
}/* 按键扫描函数 */
void Key_Scan(void)
{if(Key_Plus == 0)    // 加键处理{   ultrasound_enabled = 0;  //暂停超声波delay_xms(10); // 消抖if(Key_Plus == 0 && key_flag == 0){key_flag = 1;   // 防抖标志if(threshold_cm < 50) threshold_cm++;    // 增加阈值// 显示新阈值LCD1602_DisString(0,2,"TH:");LCD1602_DisData(0,5,threshold_cm);LCD1602_DisString(0,9,"cm ");}}else if(Key_Minus == 0)   // 减键处理(逻辑同上){    ultrasound_enabled = 0;  //暂停超声波delay_xms(10); // 消抖if(Key_Minus == 0 && key_flag == 0){key_flag = 1;if(threshold_cm > 1) threshold_cm--;// 显示新阈值LCD1602_DisString(0,2,"TH:");LCD1602_DisData(0,5,threshold_cm);LCD1602_DisString(0,9,"cm ");}}else if(Key_OK == 0)         // 确认键处理{       LCD1602_DisString(0,2,"   LCD1602");   // 恢复初始显示ultrasound_enabled = 1;    //继续显示距离}else{key_flag = 0;     // 按键释放}}

效果展示

实物连接图

系统调试与测试分析

硬件调试挑战

在硬件调试过程中遇到的主要问题:

  1. 超声波模块无响应:发现电源连接错误,重新确认供电电路
  2. LCD 显示乱码:检查引脚定义错误,对比标准电路重新配置
  3. 报警功能异常:函数调用位置错误导致报警持续,调整逻辑顺序

软件调试优化

软件调试中的关键优化点:

  • 阈值显示问题:添加确认键实现显示模式切换
  • 测量中断问题:引入ultrasound_enabled标志控制测距状态
  • 精度优化:将数据类型改为浮点型,确保小数点后一位显示

测试结果分析

经过全面测试,系统性能如下:

  • 测量范围:2cm-400cm(符合 HC-SR04 规格)
  • 测量精度:全量程误差≤1cm(如图 13、14 所示)
  • 响应时间:单次测量约 100ms
  • 阈值调整:1cm-50cm 连续可调,实时生效
  • 稳定性:持续运行 8 小时无异常

应用场景与扩展方向

实际应用场景

该超声波测距仪可应用于:

  • 工业自动化:物料高度检测、生产线定位
  • 智能家居:自动门感应、垃圾桶开盖控制
  • 机器人技术:避障系统、地形感知
  • 安防领域:入侵检测、距离警戒

功能扩展方向

未来可优化的方向:

  1. 精度提升:加入温度补偿算法(声速受温度影响)
  2. 显示增强:升级为 OLED 显示屏或彩色 LCD
  3. 通信接口:增加蓝牙 / WiFi 模块实现数据远程传输
  4. 多传感器融合:结合红外、视觉传感器提升测量可靠性

总结与技术价值

本项目通过 STC89C51 单片机与 HC-SR04 传感器的结合,实现了一个功能完整的超声波测距系统。从硬件电路设计到软件模块化编程,充分体现了嵌入式系统开发的全流程。项目的核心价值在于:

  • 技术学习:涵盖单片机编程、传感器接口、显示控制等核心技术
  • 工程实践:掌握从需求分析到系统调试的完整开发流程
  • 应用价值:提供了可直接应用于多种场景的测距解决方案

超声波测距作为智能设备的 "眼睛",其技术原理和实现方法具有广泛的借鉴意义。通过本项目的实践,不仅加深了对嵌入式系统的理解,也为更复杂的智能设备开发奠定了基础。

http://www.lryc.cn/news/574859.html

相关文章:

  • uniapp项目之小兔鲜儿小程序商城(六) 地址模块:地址管理页的实现,地址表单页的实现
  • Metasploit常用命令详解
  • 2023年全国青少年信息素养大赛Python 复赛真题——玩石头游戏
  • 2025.6.16-实习
  • 搭建智能问答系统,有哪些解决方案,比如使用Dify,LangChain4j+RAG等
  • JVM(11)——详解CMS垃圾回收器
  • 猿人学js逆向比赛第一届第十二题
  • CDN+OSS边缘加速实践:动态压缩+智能路由降低30%视频流量成本(含带宽峰值监控与告警配置)
  • RSS解析并转换为JSON的API集成指南
  • SQL Server从入门到项目实践(超值版)读书笔记 18
  • [学习] C语言编程中线程安全的实现方法(示例)
  • 【Datawhale组队学习202506】YOLO-Master task04 YOLO典型网络模块
  • Python训练营-Day40-训练和测试的规范写法
  • 【Python-Day 29】万物皆对象:详解 Python 类的定义、实例化与 `__init__` 方法
  • 【Linux网络与网络编程】15.DNS与ICMP协议
  • 性能测试-jmeter实战4
  • 集成学习基础:Bagging 原理与应用
  • PyEcharts教程(009):PyEcharts绘制水球图
  • 60天python训练营打卡day41
  • Linux系统---Nginx配置nginx状态统计
  • 鸿蒙 Stack 组件深度解析:层叠布局的核心应用与实战技巧
  • AI时代工具:AIGC导航——AI工具集合
  • 接口自动化测试之pytest 运行方式及前置后置封装
  • 爬取小红书相关数据导入到excel
  • 项目需求评审报告参考模板
  • 图的拓扑排序管理 Go 服务启动时的组件初始化顺序
  • 飞往大厂梦之算法提升-day08
  • sqlserver怎样动态执行存储过程,并且返回报错
  • Java实现简易即时通讯系统
  • day41 打卡