基于51单片机的按键控制超声波测距及显示(带提示音)的实现

       开头先自我介绍一下,本人是长春理工大学的一名本科生,技术上还是一个小白,主要学过还是单片机已经硬件这些东西,但都是稀松平常,鉴于本人专业是光电,所以以后想走的主要方向还是激光,现在在努力学习激光,这篇博文是我的第一篇博文,也是大一上学期的时候做过的一个类似于考核作品之类的东西,于是发出来,证明自己还是做了点事情,希望大家能包容我这个小(cai)白(ji),我会多多吸取各位大牛的经验,接纳意见。

下面是正文:

1.方案设计:

1.1器件的选择

hc-sr04超声波模块具有探测距离精度高、性能稳定、盲区小的特点,这能使测距更加精确和改进更加合理。

该系统的单片机采用宏晶公司的STC90C516RD+单片机,是原来STC89系列的升级版本,具有更强的抗干扰,抗静电能力,复位效果更好,功耗低,速度快。

蜂鸣器采用无源蜂鸣器,相比有源蜂鸣器虽然难度变大,必须用2K~5K的方波去驱动它,但声音频率可控,且价格更加低廉。

Lcd1602工业字符型液晶能够同时显示16x0232个字符,与其他液晶显示器相比,显示字母和数字比较方便,控制简单,成本较低。

按键采用独立按键。

如图:


1.2模块改进

   超声波模块的处理:由于这次题目要求测到7米,所以普通的超声波测距模块肯定达不到,所以要么通过硬件改进,要么通过软件改进。这里介绍硬件改进方法:

实物图:



原理图:


上图标志电阻R3,可以调节最大探测距离。R3电阻为392,探测距离最大4.5M 左右,探测角度小于15 度;R3 电阻为472,探测距离最大 7M左右,探测角度小于30度;出厂默认392,即最大探测距离4.5M左右。R3 电阻大,接收部分增益高,检测距离大,但检测角度会相应变大,容易检测到前方旁边的物体。所以精度又2mm降低到1cm。

可以通过在洞洞板上焊接排座和排针来固定超声波模块:同时更方便的连接引脚和更换超声波模块。


2.电路原理图,硬件连接图

lcd1602的RW、RS、E脚和D0~D7引脚通过手动焊接与单片机P0~P7引脚相连.如图:


蜂鸣器:


按键:通过软件延时消抖


硬件连接图:


说明:将hc-sr04 TRIG脚连接 P2.3,ECHO脚连接P2.4,VCC、GND分别连接单片机的VCC、GND。

P1连接8个独立按键,启动测距。

P0连接 D0~D7脚,E脚连接P2.7,RW = P2^5,RS脚连接P2.6(事先已焊接好内部电路,不需要外部连接)。

蜂鸣器接P2.1。

3.算法部分

通过检测按键是否为按下,按下,则启动检测,再检测按键是否松开。同时蜂鸣器响提示开始检测,给TRIG脚至少 10us 的高电平信号,模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回, 有信号返回,通过ECHO脚输出一高电平,高电平持续的时间就是超声波从发射到返回的时间。只需通过定时器记下ECHO脚高电平时间t,再通过公式s=(t*v)/2,就可算出距离s,

再通过lcd1602进行显示。

4.程序

#include<reg52.h>
#include<intrins.h>
#define	uchar unsigned char	
#define	uint  unsigned int
#define key P1//定义按键为P1
#define LCD1602_DATAPINS P0	//定义D0~D7
sbit LCD1602_E = P2^7;	//位定义E、RW、RS
sbit LCD1602_RW = P2^5;
sbit LCD1602_RS = P2^6;
sbit trig = P2^3; //定义超声波发,收
sbit echo = P2^4; 
sbit BF = P0^7;	//定义读忙
sbit beep=P2^1;//蜂鸣器
void check();//声明检测函数
void Delay1ms(uint c);//延时误差 0us
void LcdWriteCom(uchar com);//写指令函数	
void LcdWriteData(uchar dat);//写数据函数	
void LcdInit();//1602初始化函数			
void count();//计算距离
uchar busytest();//读忙函数	
uint scank();//扫描键盘
uint time,keyvalue,S;  //定义全局变量时间,键值,距离
void main()
{
	uchar x[]="0123456789cm";//
	TMOD=0x01;//设置工作方式
	EA=1; //开总中断
	ET0=1;	//开定时器允许中断
	TH0=0;//赋初值
	TL0=0;
	while(1)
	{
		int a=100;
		keyvalue=scank();  //扫描键盘
		if(keyvalue!=0)
		{
			while(a--)//蜂鸣器响一下
				{beep=1;
				Delay1ms(1);
				beep=0;
				Delay1ms(1);
				}
			check();	   //超声波测距
			count();  //计算距离
			LcdInit(); //1602初始化函数
			LcdWriteData(x[S/100]);//显示百位
			LcdWriteData(x[S%100/10]); //十位
			LcdWriteData(x[S%100%10]);	//个位
			LcdWriteData(x[10]);
			LcdWriteData(x[11]); //单位
			Delay1ms(100) ;
		
			while(1) //保持显示
			{
				keyvalue=scank();  //扫描键盘
				if(keyvalue!=0)
				break;
			}		
		}
	} 
}

/**************************************************************************************/

void check() //检测函数
{
	trig=1;
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	trig=0;
}
uint scank()
{ 
   uint i=0;
   keyvalue=0;
   if(key!=0xff)//检测按键是否按下
   {
   	  Delay1ms(5);//消抖
	 
   }
   if(key!=0xff)//再次检测按键是否按下
   {
       keyvalue=key;
	   while((key!=0xff)&&(i<50) )//检测按键是否送开
	   {
	   	  i++;
	   }
	   Delay1ms(5);//消抖
	}
   return keyvalue;//返回键值
}
void count() //计算函数
{
  while(!echo);//当ECHO脚为1,开始记时
  TR0=1;
  while(echo);//当ECHO脚为0,关闭计时
  TR0=0;
  time=TH0*256+TL0;
  TH0=0;
  TL0=0;
  S=(time*1.7)/100;	//单位厘米
} 
void LcdWriteCom(uchar com)	  //写入命令
{
	while(busytest()==1);
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择输入命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
    Delay1ms(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
    Delay1ms(5);	  //保持时间
	LCD1602_E = 0;
}
void LcdWriteData(uchar dat)			//写入数据
{
   	while(busytest()==1);
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	Delay1ms(1);

	LCD1602_E = 1;   //写入时序
	Delay1ms(5);   //保持时间
	LCD1602_E = 0;
}
void LcdInit()						  //LCD初始化子程序
{
 	LcdWriteCom(0x38);  //功能设定[8位数据],[双行显示],[5*8点阵显示模式]
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
void Delay1ms(uint c)   //误差 0us
{
    uchar a,b;
	for (; c>0; c--)
	{
		 for (b=199;b>0;b--)
		 {
		  	for(a=1;a>0;a--);
		 }      
	}
    	
}
uchar busytest(void)//读忙,1为忙,0为不忙
{
    bit result;//位定义,一字节
	LCD1602_E = 1;	
	LCD1602_RS = 0;	
	LCD1602_RW = 1;	
    Delay1ms(1);
	result=BF; //确定是否处于忙碌状态
	LCD1602_E=0;
	return result;


}
前提是你得添加51单片机的库reg52.h,我使用的是keil编译环境。

5.遇到的问题

通过改变电阻的方法来扩大增益,增大测量距离,将原来的测量范围由4.5增大到7米,但角度会增大到30度,会检测到前方旁边的物体。导致了稳定性降低,测距会出现大误差数据,并且精度降低。

6.结论

本文阐述了超声波模块的改进方法和各种模块连接的方法,采用了按键、lcd1602、蜂鸣器等模块,改变电阻解决了超声波模块测量距离短的问题,基于51单片机的按键控制超声波测距及显示(带提示音)具有测量范围大,稳定性较高的特点,能够较好的完成测距工作。

  • 52
    点赞
  • 301
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值