基于单片机的HC-SR04超声波模块测距仪设计(数码管显示)

功能要求

(1)用单片机实现;
(2)用C语言编程;
(3)硬件电路板布局合理;
(4)用数码管显示器显示;
(5)距离测量范围是:10cm----100cm;
(6)误差小于8%;
(7)超过测距量程并报警;
(8)通过按键调节测距范围。

一、材料准备

工具:

  电烙铁、万用表、STC烧写器、5V电源、PC机、Keil uVision5、AltiumDesigner 13.3.4、stc-isp程序烧写软件(可到STC官方网站下载:http://www.stcmcu.com/index.htm)等。

可能涉及到的元器件:
  • 最小系统:STC89C52RC单片机x1、12MHz有源晶振x1、10uF电解电容x1、22pFx2、10KΩ排阻x1、10KΩx1、
  • 数码管显示电路:四位共阴数码管x1、74HC573x1、220Ω电阻x8
  • 报警电路:5V有源蜂鸣器x1、S8550三极管x1、1KΩx1
  • 测距电路:HC-SR04超声波模块x1
  • 键盘输入:轻触开关x3
  • 其他原件:100mil插针若干、LEDx1、自锁开关x1

二、硬件设计

1、单片机最小系统电路

  如图1所示,是单片机最小系统电路图。学过51单片机的人都知道单片机最小系统包括:晶振电路、复位电路、单片机芯片和电源,这里作大概讲解即可,想了解详细电路原理请另查资料。晶振电路是为单片机提供时钟源;复位电路是为了让单片机从头到尾重新执行一遍程序,为了方便调试笔者采用按键复位方式;单片机芯片采用国产的STC单片机,型号为STC89C52RC(注:可以选择其他型号,譬如STC89、STC90、STC12等等),代码是完全兼容的,不必过多地担心,只是单片机内部资源不同而已;电源电路很简单,采用普通5V供电即可,为了方便调试建议加一个总电源开关,开关类型根据个人喜欢随便选。
单片机最小系统电路图
                      图1 单片机最小系统电路图
  图1中的J2是程序下载接口,接法很简单,单片机的串口P3.0和P3.1口引出即可;RP1是P0口的上拉排阻。

2、数码管显示电路

  如图2所示
数码管显示电路图
                        图2 数码管显示电路图

3、按键电路

  如图3所示
按键电路图
                            图3 按键电路图

4、HC-SR04超声波模块电路

  如图4所示
在这里插入图片描述
                          图4 超声波测距电路图

5、报警电路

  如图5所示
报警电路图
                            图5 报警电路图

6、硬件测试

三、程序设计

1、搭建工程

  头文件common.h:

#ifndef __COMMON_H__
#define __COMMON_H__

//头文件包含
#include <reg52.h> 	//提供单片机寄存器地址
#include <intrins.h>	//提供_nop_()函数

#endif
2、数码管显示模块程序设计

程序如下:
头文件dig.h

#ifndef __DIG_H__
#define __DIG_H__

//头文件包含
#include "common.h"

//管脚定义
#define digDuan  P0  //数码管段控制端口,高电平有效
sbit digWei1 = P2^4;  //第1位数码管控制端口,低电平有效
sbit digWei2 = P2^5;  //第2位数码管控制端口,低电平有效
sbit digWei3 = P2^6;  //第3位数码管控制端口,低电平有效
sbit digWei4 = P2^7;  //第4位数码管控制端口,低电平有效

//函数声明
void dig_scan(unsigned int *dat); //数码管扫描

#endif

源文件dis.c

#include "dig.h"

/* 
 * 数码管扫描
 * *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;
}
3、超声波测距模块程序设计

程序如下:
头文件HC-SR04.h:

#ifndef __HC_SR04_H__
#define __HC_SR04_H__

#include "common.h"

//引脚定义
sbit Ttig = P1^3;  //触发信号控制端口
sbit Echo = P1^4;  //回响信号接收端口

//函数声明
void start_ranging(void);

#endif

源程序文件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;
}
4、按键模块程序设计

程序如下:
头文件key.c:

#ifndef __KEY_H__
#define __KEY_H__

//头文件包含
#include "common.h"

//管脚定义
sbit KEY1 = P1^0;   //设置键
sbit KEY2 = P1^1;   //加键
sbit KEY3 = P1^2;   //减键

//函数声明
unsigned char key_scan(void);  //按键扫描

#endif

源程序文件key.c:

#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
}
5、报警模块程序设计

程序如下:
头文件

在这里插入代码片

源程序文件

在这里插入代码片
6、定时器程序设计

程序如下:
头文件timer.h

#ifndef __TIMER_H__
#define __TIMER_H__

//头文件包含
#include "common.h"
#include "dig.h"

//函数声明
void InitTimer0(void); //定时器0初始化

#endif

源程序文件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);	//数码管显示温度
}
7、功能实现程序设计

程序如下:
头文件tack.h:

#ifndef __TASK_H__
#define __TASK_H__

#include "dig.h"	//添加数码管显示程序
#include "HC-SR04.h"
#include "timer.h"
#include "key.h"

//引脚定义
sbit BEEP = P3^7;	//蜂鸣器控制端口,低电平有效,无源蜂鸣器

//函数声明
void delayms(unsigned int ms);	//延时,单位:ms
void count(void);		//计算距离
void dis_distance(void);	//显示距离
void key_fuction(void);

#endif

源程序文件tack.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; //算出来是CM    
}
/*
* 显示距离
*/
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(100);
			++mode_flag;
			if(mode_flag >= 3)	//如果满3了,则退出
				break;  
		}
		if(key_scan() == 2)		//如果加键按下
		{
			BEEP = 0;		//按键提示音
			delayms(50);
			BEEP = 1;
			delayms(100);
			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(100);
			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];		//显示个位数
		}  
	}
}

编写完功能程序之后,在主函数main()中测试功能程序是否成功,内容如下:
源程序文件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;		//蜂鸣器鸣叫
		}
		else
		{
			BEEP = 1;		//关闭蜂鸣器
			dis_distance();		//显示距离
		}
		if(key_scan() == 1) 		//如果按下设置键,则进入设置报警功能
		{
			BEEP = 0;		//按键提示音
			delayms(50);
			BEEP = 1;
			delayms(100);
			key_fuction();		//进入设置报警功能
		}   
	}
}

四、小结

五、附录

附录1:整体电路原理图

整体原理图

附录2:元件清单

BOM表

附录3:资源分享
  • 42
    点赞
  • 330
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值