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

发布于:2025-06-25 ⋅ 阅读:(18) ⋅ 点赞:(0)

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

超声波测距技术作为非接触式测量的重要手段,在工业检测、智能家居、机器人避障等领域有着广泛应用。本文将详细介绍一款基于 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
显示模块 LCD1602 16×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-SR04 Trig→P1.0 超声波触发信号
Echo→P1.1 回波接收信号
LCD1602 RS→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();          // 初始化定时器0
    LCD1602_Init();         // 初始化LCD
    LCD1602_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);              //延时xms

void 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();          // 初始化定时器0
	LCD1602_Init();         // 初始化LCD
	LCD1602_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);         //延时15ms
	LCD1602_WriteCmd(0x38);
	delay_xms(5);          //延时5ms
	LCD1602_WriteCmd(0x38);
	delay_xms(5);          //延时5ms
	
	LCD1602_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 传感器的结合,实现了一个功能完整的超声波测距系统。从硬件电路设计到软件模块化编程,充分体现了嵌入式系统开发的全流程。项目的核心价值在于:

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

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


网站公告

今日签到

点亮在社区的每一天
去签到