51单片机超声波测距和报警+Proteus仿真

系统描述

基于51单片机超声波测距和报警,采用HC-SR04测距,数码管显示测量距离。按键设置报警上下限,超限报警。
源码下载地址:51单片机超声波测距和报警+Proteus仿真

硬件设计

仿真图1:
51单片机超声波测距和报警+Proteus仿真_第1张图片

仿真图2:
51单片机超声波测距和报警+Proteus仿真_第2张图片

程序设计

main.c

#include "task.h"

extern unsigned int S;	//声明距离缓存变量,在文件"task.c"中定义
extern unsigned int dis_buf[4];	//声明显示缓存数组,在文件"task.c"中定义
extern unsigned int code duan_ma[16];
extern unsigned int S_H, S_L;	//S_H:报警上限值,默认400cm,S_L:报警下限值,默认10cm



/* 主函数 */
void main(void)
{
	digDuan = 0x40;		//显示"----"
	digWei1 = 0;
	digWei2 = 0;
	digWei3 = 0;
	digWei4 = 0;
	delayms(1000);		//延时大约1s 
	InitTimer0();		//定时器0初始化

	while(1)
	{
		count();					//计算距离
		if(S>=S_H || S<=S_L)		//如果超出设定的范围,则显示"---"
		{
			dis_buf[3] = 0x00;
			dis_buf[2] = 0x40; 		//显示"---"
			dis_buf[1] = 0x40;
			dis_buf[0] = 0x40;	
			BEEP = 0;			//蜂鸣器鸣叫
			delayms(1000);
		}
		else
		{
			BEEP = 1;			//关闭蜂鸣器
			dis_distance();		//显示距离
		}

		if(key_scan() == 1)		//如果按下设置键,则进入设置报警功能
		{
			BEEP = 0;			//按键提示音
			delayms(50);
			BEEP = 1;
			delayms(100);
		 	key_fuction();		//进入设置报警功能
		}			
	}
}

HC-SR04.C

#include "HC-SR04.h"

/* 启动超声波程序 */
void start_ranging(void)
{
	Ttig = 1;			//启动一次模块
	_nop_();			//延时一段时间,至少10us以上 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_();
	_nop_(); 
	_nop_(); 
	_nop_(); 
	_nop_();
	Ttig = 0;
}

dig.c

#include "dig.h"


///* 数码管延时函数,单位:ms */
//static void dig_delayms(unsigned int ms)
//{
//	unsigned char a,b,c;
//	while(--ms)
//	{
//	    for(c=1;c>0;c--)
//	        for(b=142;b>0;b--)
//	            for(a=2;a>0;a--);
//	}
//}
/* 
 * 数码管扫描
 * *dat:以数组的方式传值,使用的时候直接填入数组名即可
 */  
void dig_scan(unsigned int *dat)
{
	static unsigned char i = 0;	//循环变量

	/* 数码管扫描处理 */
	digDuan = 0x00;		//消隐
	digWei1 = 1;			
	digWei2 = 1; 			
	digWei3 = 1;
	digWei4 = 1;
	switch(i)
	{
		case 0: 
		{
			digWei1 = 0;			//选通第1位数码管
			digDuan = dat[0];		//显示第1位数码管的内容
			break;
		}
		case 1:
		{
			digWei2 = 0;			//选通第2位数码管
			digDuan = dat[1];		//显示第2位数码管的内容
			break;
		}
		case 2:
		{
			digWei3 = 0;				//选通第3位数码管
			digDuan = dat[2] + 0x80;	//显示第3位数码管的内容,顺便也显示小数点
			break;
		}
		case 3:
		{
			digWei4 = 0;			//选通第4位数码管
		 	digDuan = dat[3];		//显示第4位数码管的内容
			break;	
		}
		default: break;
	}
	++i;		//数码管位选变量循环
	if(i >= 4)
		i = 0;				
}

key.h

#include "key.h"

/* 按键延时函数,单位:ms */
static void key_delayms(unsigned int ms)
{
	unsigned char a,b,c;
	while(--ms)
	{
	    for(c=1;c>0;c--)
	        for(b=142;b>0;b--)
	            for(a=2;a>0;a--);
	}
}
/* 按键扫描 */
unsigned char key_scan(void)
{
	if(KEY1 == 0)			//如果按键1按下
	{
		key_delayms(10);	//延时10ms,去除按键抖动
		if(KEY1 == 0)		//再判断一次按键按下
		{
			return 1; 		//输出键值1
		}	
	}
	if(KEY2 == 0)		//如果按键2按下
	{
		key_delayms(10);	//延时10ms,去除按键抖动
		if(KEY2 == 0)		//再判断一次按键按下
		{
			return 2; 		//输出键值2
		}
	}
	if(KEY3 == 0)		//如果按键3按下
	{
		key_delayms(10);	//延时10ms,去除按键抖动
		if(KEY3 == 0)		//再判断一次按键按下
		{
			return 3; 		//输出键值3
		}
	}

	return 0;				//如果没有按键按下,则输出0
}

task.c

#include "task.h"

//全局变量定义
//段码表,适用于共阴数码管
unsigned int code duan_ma[16] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,		//0~9
								 0x77,0x7c,0x39,0x5e,0x79,0x71};	//A~F
unsigned int dis_buf[4];			//显示缓存

unsigned int S = 0;					//距离缓存变量
unsigned long time = 0;				//时间缓存变量 
unsigned int S_H = 400, S_L = 10;	//S_H:报警上限值,默认400cm,S_L:报警下限值,默认10cm



/* 延时,单位:ms */
void delayms(unsigned int ms)
{
	unsigned char a,b,c;

	while(--ms)
	{
	    for(c=1;c>0;c--)
	        for(b=142;b>0;b--)
	            for(a=2;a>0;a--);	
	}
}



/* 计算测距 */
void count(void)
{
	start_ranging();	//启动一次超声波
	while(!Echo);		//等待超声波模块输出IO拉高 
	TR0 = 1;			//开启定时器计时
	while(Echo);		//等待超声波模块输出IO拉低
	TR0 = 0; 			//关闭定时器计时
	
	/* 计算距离 */
	time = TH0 * 256 + TL0;	//得到的时间,专业写法应该是这样:time = TH0 << 8 | TL0
	TH0 = 0;				//定时计数器清零	
	TL0 = 0;
	
	S = (time * 1.7) / 100; //算出来是M				
}
/* 显示距离 */
void dis_distance(void)
{
	dis_buf[3] = 0x00;
	dis_buf[2] = duan_ma[S / 100 %10]; 	//取出百位数,并在数码管的第3位显示,从右往左数
	dis_buf[1] = duan_ma[S / 10 %10];	//取出十位数,并在数码管的第2位显示,从右往左数
	dis_buf[0] = duan_ma[S % 10]; 		//取出个位数,并在数码管的第1位显示,从右往左数	
}
/* 设置报警功能 */
void key_fuction(void)
{
	unsigned char mode_flag = 1;	//模式切换标记位,1:设置上限值,2:设置下限值,3:退出

	while(1)
	{
		if(key_scan() == 1)	
		{
			BEEP = 0;			//按键提示音
			delayms(50);
			BEEP = 1;
			delayms(1000);
			++mode_flag;
			if(mode_flag >= 3)	//如果满3了,则退出
				break;		
		}
		if(key_scan() == 2)		//如果加键按下
		{
			BEEP = 0;			//按键提示音
			delayms(50);
			BEEP = 1;
			delayms(1000);
			if(mode_flag == 1)	//设置上限值
			{
				++S_H;
				if(S_H > 400)
					S_H = 2;	
			}
			if(mode_flag == 2)	//设置下限值
			{
				++S_L;
				if(S_L > 400)
					S_L = 2;	
			}
		}
		if(key_scan() == 3)		//如果减键按下
		{
			BEEP = 0;			//按键提示音
			delayms(50);
			BEEP = 1;
			delayms(1000);
			if(mode_flag == 1)	//设置上限值
			{
				--S_H;
				if(S_H < 2)
					S_H = 400;	
			}
			if(mode_flag == 2)	//设置下限值
			{
				--S_L;
				if(S_L < 2)
					S_L = 400;	
			}
		}

		/* 报警设置显示 */
		if(mode_flag == 1) 	//显示设置上限值内容
		{
			dis_buf[3] = 0x76;						//4位数码管显示字母 H
			dis_buf[2] = duan_ma[S_H / 100 % 10]; 	//显示百位数
			dis_buf[1] = duan_ma[S_H / 10 % 10];	//显示十位数
			dis_buf[0] = duan_ma[S_H % 10];			//显示个位数
		}
		if(mode_flag == 2)	 	//显示设置下限值内容
		{
			dis_buf[3] = 0x38;	//4位数码管显示字母 L
			dis_buf[2] = duan_ma[S_L / 100 % 10]; 	//显示百位数
			dis_buf[1] = duan_ma[S_L / 10 % 10];	//显示十位数
			dis_buf[0] = duan_ma[S_L % 10];			//显示个位数
		}		
	}
}









timer.c

#include "timer.h"

extern unsigned int dis_buf[4];

/* 定时器0初始化,定时1ms */
void InitTimer0(void)
{
    TMOD = 0x11;	//配置定时器0为工作方式1,定时器1位工作方式1
	TH0 = 0;
    TL0 = 0;
	TH1 = 0x0EC;	//定时5ms
    TL1 = 0x78;
	EA = 1;			//打开总中断
	ET1 = 1;		//打开定时器0中断
	TR1 = 1;		//打开定时器1
    TR0 = 0;		//打开定时器0
}
/* 定时器0中断服务函数,5ms进一次本中断,用于数码管扫描 */
void Timer1Interrupt(void) interrupt 3
{
	TH1 = 0x0EC;		//定时5ms,重新赋值
    TL1 = 0x78;

	dig_scan(dis_buf);	//数码管显示温度
}





你可能感兴趣的:(单片机,c语言)