超声波测距系统

这篇具有很好参考价值的文章主要介绍了超声波测距系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

  具有测距、温度补充、实时时钟、记忆、阈值警报、串口数据发送等等功能,通过LCD1602显示,按键进行相关操作。

一、功能描述

  LCD1602显示共有五个界面,按键一用于切换显示界面。

一、界面一

  此界面测距为连续测距模式,LCD1602不间断刷新测量距离和温度,一旦测量距离小于设置的阈值,单片机将会发出警报。此界面按下按键4可进入与上位机连接状态,当上位机发送1至单片机后,mcu立刻将测量数据发送至上位机。

二、界面二

  此界面为阈值设置界面,按键二用于改变设置位(上限还是下限),设置位会闪烁显示,以此提示。按键三四用于加减。

三、界面三

  此界面测距为单次测距模式,按键二按下测量一次,按键三按下则将当前测量距离和测量时间(如23:59:45时测量距离为45cm)保存到EEPROM里面,最多可以记录十次,第十一次将会覆盖第一次数据。

四、界面四

  此界面测距为回放模式,按下按键二三切换回放序号,LCD1602会显示在界面三时记录的距离和测量时间。

五、初始界面

  上电后,LCD1602会显示DS1302的初始时间设置,此时需要通过按键二三四进行时间设置。设置完成后,按下按键一,系统进入界面一,开始工作。

二、编程实现

  核心代码main.c如下,项目工程见超声波测距系统
  各模块原理和代码见于单片机文章来源地址https://www.toymoban.com/news/detail-774576.html

#include "main.h"
typedef unsigned char u8;
//P2用于选择P0输出通道,P0输出数据
#define outputp0(y,x) P0=x,P2&=0x1f,P2=y,P2&=0x1f;
//按键值,按键值缓存值
u8 kbdnum=0,kbdtemp=0;
//显示页面值,距离阈值设置选择位,保存次数值,时间设置选择位,测量数据保存起始地址;
u8 show_page=0,distance_set_flag=0,save_times=1,set_time_flag=0,save_distance_addr=0x04;
//测量阈值上限,测量阈值下限,LCD闪烁位
int distance_h=350,distance_l=6,LCD_showflag=0;
//测量阈值上下限数组,十六进制,便于进行保存到EEPROM或从EEPROM读取的操作
u8 distance_limit[4]={0};
//测量温度
float temper=0;
//时间保存中间量
u8 time_s_temp=0;
//主函数延时函数,t ms
void main_Delay1ms(int t)	//@11.0592MHz
{
	unsigned char data i, j;
	while(t--)
	{
		_nop_();
		_nop_();
		_nop_();
		i = 11;
		j = 190;
		do
		{
			while (--j);
		} while (--i);
	}
}

/*
  *  @brief     按键值读取工作函数
  *  @param    
  *  @reval      
  *  @note:    
*/

void work_kbd()
{
	if(kbdnum)   //如果有按键按下
	{
		if(kbdnum==13)   //key1按下
		{
			show_page++;
			show_page%=4;   //切换显示界面
			
			if(show_page==0)    //如果为界面0,连续测距模式
			{
				TR0=0;
				temper=rd_temper();
				TR0=1;
				work_ultra();  //界面0

				LCD_ShowString(1,1,"Distance:   . CM");  //显示相应界面
				LCD_ShowString(2,1,"Temper:    .  C ");
			}
			else if(show_page==1)   //如果为界面1,测量阈值设置模式
			{
				outputp0(0xa0,0x00);    //关闭蜂鸣器,防止在界面0警报状态下进入界面1导致蜂鸣器一直响
				distance_set_flag=0;LCD_showflag=0;    //复位距离阈值设置位和LCD闪烁位
				LCD_ShowString(1,1,"High:   CM      ");  //显示相应界面
				LCD_ShowString(2,1,"Low:   CM       ");
			}
			else if(show_page==2)  //如果为界面2,逐次测量模式
			{			
				save_distance_addr=4;save_times=1;  //复位数据保存起始地址和保存次数
				LCD_ShowString(1,1,"Distance:   . CM");   //显示相应界面
				LCD_ShowString(2,1,"Time:  -  -     ");
			}
			else if(show_page==3)   //如果为界面3,回放模式
			{
				save_distance_addr=4;save_times=1;  //复位数据保存起始地址和保存次数
				LCD_ShowString(1,1,"Save_Dis:   . CM");  //显示相应界面
				LCD_ShowString(2,1,"Time:  -  -     ");
				TR0=0;
				at24c02_read_multi(read_time,save_distance_addr,3);
				distance=at24c02_read(save_distance_addr+3)*256+at24c02_read(save_distance_addr+4);
				TR0=1;   //将第一次保存数据读取出来
			}

		}
		else if(kbdnum==14)  //key2按下
		{
			if(show_page==1)   //如果是界面1,测量阈值设置模式
				distance_set_flag=!distance_set_flag;  //改变距离阈值设置位,用于切换选择设置上限或下限
			else if(show_page==2)  //如果是界面2,逐次测量模式
			{				
				TR0=0;
				temper=rd_temper();
				TR0=1;
				work_ultra();    //执行一次距离测量
			}	
			else if(show_page==3)  //如果是界面3,回放模式
			{
				if(save_distance_addr<=48)  //用于选取下一个数据保存地址
				{
					save_distance_addr+=5;
					save_times++;
				}
				else if(save_distance_addr>48)  //超出数据保存最大地址,则返回最小地址
				{
					save_distance_addr=4;
					save_times=1;
				}
				TR0=0;     //将保存数据读取出来
				at24c02_read_multi(read_time,save_distance_addr,3);
				distance=at24c02_read(save_distance_addr+3)*256+at24c02_read(save_distance_addr+4);	
				TR0=1;				
			}	
		}
		else if(kbdnum==15) //key3按下
		{
			if(show_page==1)  //如果是界面1,测量阈值设置模式
			{
				if(distance_set_flag==0)  //如果是设置距离上限
				{
					distance_h++;    //加一
					if(distance_h>350)   //防超过最大值
						distance_h--;
				}
				else if(distance_set_flag==1)  //如果是设置距离下限
				{
					distance_l++;     //加一
					if(distance_l>=distance_h)  //防超过距离上限
						distance_l--;
				}	
			}
			else if(show_page==2)  //如果是界面2,逐次测量模式,将测量数据进行保存
			{
				TR0=0;     
				time_s_temp=read_time[0];read_time[0]=read_time[2]; //用于DS1302读取时间顺序为秒分时,而人习惯为时分秒,因此将秒与时交换位置
				read_time[2]=time_s_temp;
				at24c02_write_multi_page(read_time,save_distance_addr,3); //保存测量时间
				save_distance_addr+=3;
				at24c02_write(save_distance_addr++,distance/256);  //保存测量距离
				at24c02_delay5ms();
				at24c02_write(save_distance_addr++,distance%256);	 //保存测量距离
				TR0=1;				
				if(save_distance_addr>=54)  //数据读取地址达到最大,返回最小地址
					save_distance_addr=4;
				save_times++;     //读取的数据对应的保存次序
				if(save_times>10)  //如果次序超过最大次数10,则返回第一次
					save_times=1;
			}	
			else if(show_page==3)  //如果是界面3,回放模式
			{
				if(save_distance_addr>=9)   
				{
					save_distance_addr-=5;  //读取上一次保存数据
					save_times--;
				}
				else if(save_distance_addr<9)  //如果读取数据地址达到最小地址,则返回最大地址
				{
					save_distance_addr=49;
					save_times=10;
				}
				TR0=0;    //将数据读取出来
				at24c02_read_multi(read_time,save_distance_addr,3);
				distance=at24c02_read(save_distance_addr+3)*256+at24c02_read(save_distance_addr+4);	
				TR0=1;				
			}
		}
		else if(kbdnum==16)  //key4按下
		{
			if(show_page==0)    //如果是界面0,连续测距模式
			{
				LCD_ShowString(1,1,"Please connect  ");   //等待与上位机连接
				LCD_ShowString(2,1,"  to computer!  ");
				while(receivebit==0);										  //一旦连接
				for(save_distance_addr=4;save_distance_addr<=53;save_distance_addr++)
				{
					sendbit(at24c02_read(save_distance_addr));  //将保存数据全部发送至上位机
				}
				LCD_ShowString(1,1,"Datas sent  OK! ");   //提示发送完成
				LCD_ShowString(2,1,"                ");	
				main_Delay1ms(3000);
				LCD_ShowString(1,1,"Distance:   . CM");   //回到连续测距显示
				LCD_ShowString(2,1,"Temper:    .  C ");	
				receivebit=0;	   //复位接收值
			}
			else if(show_page==1)    //如果是界面1,测量阈值设置模式
			{
				if(distance_set_flag==0)  //如果是设置距离上限
				{
					distance_h--;   //减一
					if(distance_h<=distance_l)   //防小于距离下限
						distance_h++;
				}
				else if(distance_set_flag==1)  //如果是设置距离下限
				{
					distance_l--;			//减一
					if(distance_l<6)   //防止小于最小值
						distance_l++;
				}				
			}
			else if(show_page==2)  //如果是界面2,逐次测距模式
			{
				show_page=0;  //切换回界面0,连续测距模式
				LCD_ShowString(1,1,"Distance:   . CM");   //显示相应界面
				LCD_ShowString(2,1,"Temper:    .  C ");				
			}		
		}
		if((kbdnum==15||kbdnum==16)&&show_page==1)  //如果在测量阈值设置模式改变了距离上限或下限的值,则将新值进行保存
		{
			distance_limit[0]=distance_h/256;  //将距离上下限转换为16进制
			distance_limit[1]=distance_h%256;
			distance_limit[2]=distance_l/256;
			distance_limit[3]=distance_l%256;
			TR0=0;
			at24c02_write_multi(distance_limit,0x00,4);  //一次写入多个数据
			TR0=1;
		}
	kbdnum=0;  //清零按键值
	}
}

/*
  *  @brief     界面0,连续测距模式
  *  @param    
  *  @reval      
  *  @note:    
*/

void page_0()
{	
		TR0=0;
		temper=rd_temper();  //测量温度
		TR0=1;
		if(tultra>=60)  //每60ms测量一次
		{
			work_ultra();  //测量距离
		}
		if(distance>=(distance_l*10)&&distance<=(distance_h*10))   //如果在测量范围之内
		{
			LCD_ShowString(1,1,"distance:");  //正常显示测量距离
			LCD_ShowNum(1,10,distance/10,3);
			LCD_ShowNum(1,14,distance%10,1);
			LCD_ShowChar(1,13,'.');
			LCD_ShowString(1,15,"CM");		
			
			outputp0(0xa0,0x00);  //蜂鸣器关
		}
		else if(distance<(distance_l*10)||distance>(distance_h*10))  //如果超出测量范围
		{
			LCD_ShowString(1,1,"Error!          ");  //测量距离显示“ERROR!”
			outputp0(0xa0,0x40);  //蜂鸣器开
		}
		LCD_ShowSignedNum(2,8,temper,3);
		LCD_ShowNum(2,13,(int)(temper*100)%100,2);	//显示温度
}

/*
  *  @brief     界面1,测量阈值设置模式
  *  @param    
  *  @reval      
  *  @note:    
*/

void page_1()
{
	if(LCD_showflag==0)   //如果LCD闪烁位为0,正常显示
	{
		LCD_ShowNum(1,6,distance_h,3);
		LCD_ShowNum(2,5,distance_l,3);
	}
	else if(LCD_showflag==1)  //如果LCD闪烁位为1,则清空相应数据显示位置
	{
		if(distance_set_flag==0)LCD_ShowString(1,6,"   ");
		else if(distance_set_flag==1)LCD_ShowString(2,5,"   ");
	}
}

/*
  *  @brief     界面2,逐次测距模式
  *  @param    
  *  @reval      
  *  @note:    
*/

void page_2()
{
	TR0=0;
	DS1302_read(DS1302_write_addr);  //读取时间
	TR0=1;
	
	LCD_ShowNum(1,10,distance/10,3);   //显示相应数据
	LCD_ShowNum(1,14,distance%10,1);
	LCD_ShowNum(2,6,read_time[2]/16*10+read_time[2]%16,2);
	LCD_ShowNum(2,9,read_time[1]/16*10+read_time[1]%16,2);
	LCD_ShowNum(2,12,read_time[0]/16*10+read_time[0]%16,2);
	LCD_ShowNum(2,15,save_times,2);
}

/*
  *  @brief     界面3,回放模式
  *  @param    
  *  @reval      
  *  @note:    
*/

void page_3()
{
	LCD_ShowNum(1,10,distance/10,3);  //显示相应数据
	LCD_ShowNum(1,14,distance%10,1);
	LCD_ShowNum(2,6,read_time[0]/16*10+read_time[0]%16,2);  //由于数据以16进制保存,因此需要转换为10进制
	LCD_ShowNum(2,9,read_time[1]/16*10+read_time[1]%16,2);
	LCD_ShowNum(2,12,read_time[2]/16*10+read_time[2]%16,2);
	LCD_ShowNum(2,15,save_times,2);	
}

/*
  *  @brief     界面显示
  *  @param    
  *  @reval      
  *  @note:    
*/

void page_show()
{
	switch(show_page)
	{
		case 0:page_0();break;
		case 1:page_1();break;
		case 2:page_2();break;
		case 3:page_3();break;
	}
}

/*
  *  @brief     上电时间初始化
  *  @param    
  *  @reval      
  *  @note:    
*/

void set_time()
{
	outputp0(0x80,0xff);  //关闭8位LED
	outputp0(0xa0,0x00);		//关闭蜂鸣器继电器等
	LCD_Init();	     //LCD1602初始化
	rd_temper();   //由于DS18B20上电默认+85°,为了防止温度有极小时间错误显示,因此上电后即让DS18B20测量一次温度
	main_Delay1ms(1000);  //系统上电后延时一秒,确保各单位准备好工作
	Timer0_Init();  //定时器0初始化
	LCD_ShowString(1,1,"Please set time!");  //设置时间提示
	LCD_ShowString(2,1,"Time:  -  -     ");

	while(kbdnum!=13)   //如果key1按下,则退出时间设置
	{	
		if(kbdnum==14)   //如果key2按下
		{
			set_time_flag++;set_time_flag%=3; //时间设置选择位
			kbdnum=0;		  //清零按键值
		}
		else if(kbdnum==15) //如果key3按下
		{
			DS1302_write_time[set_time_flag]++;  //相应数据加一
			if(DS1302_write_time[set_time_flag]==24&&set_time_flag==2) //防止秒分时超出各自上限
				DS1302_write_time[set_time_flag]=0;
			else if(DS1302_write_time[set_time_flag]==60)
				DS1302_write_time[set_time_flag]=0;
			kbdnum=0;		  //清零按键值
		}
		else if(kbdnum==16) //如果key4按下
		{
			if(DS1302_write_time[set_time_flag]>=1)
				DS1302_write_time[set_time_flag]--;    //相应数据减一
			else
				DS1302_write_time[set_time_flag]=59*(set_time_flag<2)+23*(set_time_flag==2); //防止秒分时小于各自下限
			kbdnum=0;		  //清零按键值
		}	
		if(LCD_showflag==0)   //如果LCD闪烁位为0,正常显示
		{
			LCD_ShowNum(2,6,DS1302_write_time[2],2);
			LCD_ShowNum(2,9,DS1302_write_time[1],2);
			LCD_ShowNum(2,12,DS1302_write_time[0],2);
		}
		else if(LCD_showflag==1)    //如果LCD闪烁位为1,则清空相应数据显示位置
		{
			switch(set_time_flag)
			{
				case 0:LCD_ShowString(2,12,"  ");break;
				case 1:LCD_ShowString(2,9,"  ");break;
				case 2:LCD_ShowString(2,6,"  ");break;	
			}	
		}
	}
	if(kbdnum==13)  //key1按下
	{
		TR0=0;	
		for(set_time_flag=0;set_time_flag<3;set_time_flag++) //将设置时间从10进制转换为16进制
			DS1302_write_time[set_time_flag]=DS1302_write_time[set_time_flag]/10*16+DS1302_write_time[set_time_flag]%10;
		DS1302_set(DS1302_write_addr,DS1302_write_time);  //设置DS1302时间
		TR0=1;
		kbdnum=0;	  //清零按键值
	}	
}

/*
  *  @brief     系统初始化
  *  @param    
  *  @reval      
  *  @note:    
*/

void init()
{
	Timer1_Init();  //定时器0初始化
	Uart1Init();    //串口1初始化
	LCD_ShowString(1,1,"distance:   CM  "); //上电默认界面0,显示相应界面
	LCD_ShowString(2,1,"Temper:    .  C ");
	//将保存的距离上下限读取并设置为距离阈值
	at24c02_read_multi(distance_limit,0x00,4);
	distance_h=distance_limit[0]*256+distance_limit[1];
	distance_l=distance_limit[2]*256+distance_limit[3];
	
	distance=distance_l*10+1;  //防止未开始测量即报警
}
void main()
{
	set_time();  //设置时间
	init();   //系统初始化
	receivebit=0;  //清零接收位
	while(1)
	{
		work_kbd();  //按键读取
		page_show();   //界面显示
	}
	
}

void Timer0_Isr(void) interrupt 1
{
	static u8 kbd_longflag=0;      //矩阵键盘长按标志位,1长按0短按
	static int kbd_short_t=0,kbd_t=0,kbd_long_t=0,tlcd=0;
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	
	kbd_short_t++;          //矩阵键盘按键短按时间计数
	if(kbd_short_t>=(500*kbd_longflag+25*(!kbd_longflag)))   //短按每25ms检测一次按键
	{
		if(!(colu1&colu2&colu3&colu4))     //长按检测,每25ms检测矩阵键盘按键是否仍在按下,如果是
		{
			kbd_t++;						//矩阵键盘按键按下时间计数(以25ms为单位)
			if(kbd_t>=80)       //如果持续按下2s
			{
				kbd_t=80;         //防止溢出
				kbd_longflag=1;           //切换为长按模式
			}
		}
		else if(colu1&colu2&colu3&colu4)		//长按检测,每25ms检测按键是否仍在按下,如果不是
		{
			kbd_t=0;							//清零按键按下时间计数
			kbd_longflag=0;								//切换为短按模式
		}
		
		kbd_short_t=0;             //清零短按时间计数
		if(kbd_longflag==0)         //如果是短按模式
		{
			kbdtemp=kbd_send(0);
			if(kbdtemp)   //按键以短按模式检测
				kbdnum=kbdtemp;
		}
	}
	
	kbd_long_t++;           //按键长按时间计数
	if(kbd_long_t>=500)     //长按时每500ms检测一次按键
	{
		kbd_long_t=0;						  //清零按键长按时间计数
		if(kbd_longflag==1)         //如果是长按模式
		{
			
			if(kbd_send(1))			  //按键以长按模式检测
				kbdnum=kbd_send(1);
		}
	}
	
	tultra++; //超声波工作时间间隔计数
	
	tlcd++;   //LCD闪烁位时间计数
	if(tlcd>=500)
	{
		tlcd=0;
		LCD_showflag=!LCD_showflag;  //实现LCD1602闪烁显示
	}
}

到了这里,关于超声波测距系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于c51单片机超声波测距仪

            整个系统由AT89C51,超声波电路,显示电路和报警电路,按键控制组成,系统复位后,首先对各模块进行初始化,初始化后根据超声波模块返回的回波进行数据计算,把数据显示到LMO16L液晶显示器上,并与设定的报警值相比较,小于报警值则蜂鸣器响起、指示灯亮

    2024年02月04日
    浏览(41)
  • 基于51单片机的超声波测距及温度显示

    (仿真+程序+PCB+原理图+设计报告) 功能介绍 具体功能: 1.超声波测距传感器HC-SR04、温度传感器DS18B20将检测的数据传给51单片机; 2.LCD1602实时显示测得的距离和温度; 3.按键可以设置距离的上下限; 4.距离超过设定范围,蜂鸣器+LED产生声光报警; ​演示视频: 基于5

    2024年04月24日
    浏览(40)
  • 【51单片机练习1——超声波测距+LCD12864显示】

    PS:这是人生中的第一篇博客,记录了我人生中的第一次实习工作。与其说是博客文章,这些更像是一个小白的流水账日记,可能会有很多错误和有待优化的地方,希望各位大佬可以多多提出。如有问题可以私信联系。 行文过程中,欲说尽心中无限事,感慨万千。不过各位“

    2024年02月04日
    浏览(44)
  • 【C语言】51单片机超声波测距(实作 非仿真)

    一、设计目标     使用51单片机和超声波测距模块实现超声波测距。 二、主要功能     超声波测距。 三、硬件部分     51单片机,超声波测距模块,导线,动态数码管,74HC245芯片,74HC138芯片。 图1                       图2   图3   图4     图1为超声波测距模块的

    2024年02月09日
    浏览(37)
  • 超声波测距模块HC-SR04详解(基于51单片机)

    本篇文章是个人整理的包含超声波测距模块HC-SR04的基本介绍与基本工作原理以及分别通过LCD1602、数码管和串口显示距离的实例讲解与代码的笔记,部分内容来自《HC-SR04超声波测距模块说明书》,代码使用模块化编辑,部分模块来自江科大自化协的51单片机教学视频。 希望大

    2023年04月16日
    浏览(40)
  • 基于单片机的超声波探伤仪

    摘要 超声波探伤仪是目前工业制造和现代化检测的重要途径之一,广泛的应用在质量检测和产品检测中,通过使用其产品能够有效地降低产品次品的风险。尽管随着电子技术的发展, 国内出现了一些数字化的超声检测仪器,但其数据处理及扩展能力有限,缺乏足够的灵活性

    2024年04月11日
    浏览(47)
  • 基于单片机的超声波探伤仪设计

    摘要 超声波探伤仪是目前工业制造和现代化检测的重要途径之一,广泛的应用在质量检测和产品检测中,通过使用其产品能够有效地降低产品次品的风险。尽管随着电子技术的发展, 国内出现了一些数字化的超声检测仪器,但其数据处理及扩展能力有限,缺乏足够的灵活性

    2024年02月08日
    浏览(39)
  • 51单片机使用HC-S104超声波模块

      HC-S104超声波模块是一种测量距离的传感器,可以用于51单片机的测距应用。下面是使用HC-S104超声波模块的步骤: 1.将HC-S104超声波模块的VCC引脚连接到51单片机的3.3V或5V电源,GND引脚连接到51单片机的GND,TRIG引脚连接到51单片机的一个可编程输出口,ECHO引脚连接到51单片机的

    2024年02月12日
    浏览(50)
  • 【毕业设计】基于超声波智能跟随小车 - 单片机 物联网 stm32 c51

    自动跟随小车系统由两部分组成:跟随小车和移动目标携带装置。 工作原理:跟随小车系统通过无线通信模块发送寻找信号,同时超声波接收器开始计时,如果移动目标接收到无线寻找信号,则立即发送超声波信号。这样小车的三角超声波接收器陆续收到超声波信号,CPU通过

    2023年04月08日
    浏览(54)
  • 基于51单片机驱动HC-SR04超声波模块(LCD1602显示)

    点击图片购买 HC- SR04+是一款宽电压工作的超声波测距模块。模块外形尺寸及软件与老版本 HC- SR04完全兼容;可以与老版本HC SR04无缝切换。低至3V的低工作电压, 使其与3.3V供电的MCU可以直接连接。 特点 探测角度: 15° 采用工业级MCU,工作温度:-20C~80C 探测距离:5V:2cm-- 450cm;3.3V: 2c

    2024年02月02日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包