51单片机-感应开关盖垃圾桶

1、项目需求

检测靠近时,垃圾桶自动开盖并伴随滴一声,2s后关盖

发生震动时,垃圾桶自动开盖并伴随滴一声,2s后关盖

按下按键时,垃圾桶自动开盖并伴随滴一声,2s后关盖

2、硬件

sg90舵机,超声波模块,震动传感器,蜂鸣器

3、接线说明

舵机接P1.1,超声波Trig接P1.5,Echo接P1.6,蜂鸣器接P2.0,震动传感器接P3.2(外部中断0)

4、开发步骤

①舵机与超声波代码整合

舵机用定时器0,超声波用定时器1,实现物体靠近时自动开盖,2s后关盖

#include "reg52.h"

//------------------------------------------------------------接口
sbit D5       = P3^7;  //灯
sbit D6       = P3^6;
sbit Trig     = P1^5;  //超声波模块
sbit Echo     = P1^6;
sbit sg90_con = P1^1;  //舵机


//------------------------------------------------------------全局变量
int cnt = 0;           //定义全局变量,记录爆表次数
int jd;                //舵机角度

//------------------------------------------------------------延时函数
//延时2s函数
void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	//_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
//延时100毫秒
void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}

//延时10us函数
void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

//------------------------------------------------------------定时器0与定时器1初始化
//定时器0初始化
void Time0Init()
{
	//配置定时器0工作模式
	TMOD &= 0xF0;	
	TMOD |= 0x01;
	//给初值,定一个10ms
	TL0 = 0x33;
	TH0 = 0xFE;
	//开始计时
	TR0 = 1;
	//初始化TF,准备记录爆表
	TF0 = 0;
	
	//打开定时器0中断
	ET0 = 1;
	//打开总中断
	EA = 1;
}
//定时器1初始化
void Time1Init()
{
	//设置定时器1工作模式
	TMOD &= 0x0F;	
	TMOD |= 0x10;
	TH1 = 0;
	TL1 = 0;
}

//------------------------------------------------------------定时器0中断
//定时器0中断
void Time0Handler() interrupt 1 //中断函数
{
	cnt++;
	//重新给初值
	TL0 = 0x33;
	TH0 = 0xFE;
	if(cnt < jd)
	{
		sg90_con = 1;
	}
	else
	{
		sg90_con = 0;
	}
	if(cnt == 40)//爆表40次经过了20ms
	{
		cnt = 0;
		sg90_con = 1;
	}
	
}

//------------------------------------------------------------超声波测距模块
//开始测距标志有一个不小于10us的电平变化
void startHC()
{
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}
//测距函数封装
double get_distance()
{
	double time;
	
	//定时器数据清零,以便于下次测距
	TH1 = 0;
	TL1 = 0;
	   
	//1、TRIG,给其至少10us的高电平
	startHC();
	//2、由低电平跳转到高电平,表示开始发送波,波发出一刹那开始启动定时器
	while(Echo == 0);
	TR1 = 1;
	//3、由高电平跳转到低电平,表示收到波,停止定时器
	while(Echo == 1);
	TR1 = 0;
	//4、计算中间经过多长时间 
	time = (TH1*256+TL1)*1.085;//us为单位
	//5、距离=速度*时间/2
	return (time*0.017);
	
}
//测距开灯函数封装
void openLight()
{
	D5 = 0;
	D6 = 1;
}
//测距关灯函数封装
void closeLight()
{
	D5 = 1;
	D6 = 0;
}

//------------------------------------------------------------舵机模块
//舵机初始化
void initSG90_0()
{
	jd = 1;
	cnt = 0;
	sg90_con = 1;
}
//测距开盖函数封装
void openLid()
{
	jd = 3;//90°,1.5ms高电平
	cnt = 0;
	Delay2000ms();
}
//测距关盖函数封装
void closeLid()
{
	jd = 1;//0°
	cnt = 0;
	Delay100ms();
}
//------------------------------------------------------------主函数
void main()
{
	double dis;
	
	//初始化定时器
	Time0Init();
	Time1Init();
	//初始化舵机
	initSG90_0();
	while(1){
		dis = get_distance();
		if(dis<10)//小于10cm
		{
			//开盖D5亮
			openLight(); 
			//舵机开盖
			openLid();
		}
		else
		{
			//关盖D5灭
			closeLight();
			//舵机关盖
			closeLid();
		}		
	}
} 

②查询方式添加按键控制

#include "reg52.h"

//------------------------------------------------------------接口
sbit D5       = P3^7;  //灯
sbit D6       = P3^6;
sbit Trig     = P1^5;  //超声波模块
sbit Echo     = P1^6;
sbit sg90_con = P1^1;  //舵机
sbit sw1      = P2^1;  //按键一


//------------------------------------------------------------全局变量
int cnt = 0;           //定义全局变量,记录爆表次数
int jd;                //舵机角度

//------------------------------------------------------------延时函数
//延时2s函数
void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	//_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
//延时100毫秒
void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}

//延时10us函数
void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

//------------------------------------------------------------定时器0与定时器1初始化
//定时器0初始化
void Time0Init()
{
	//配置定时器0工作模式
	TMOD &= 0xF0;	
	TMOD |= 0x01;
	//给初值,定一个10ms
	TL0 = 0x33;
	TH0 = 0xFE;
	//开始计时
	TR0 = 1;
	//初始化TF,准备记录爆表
	TF0 = 0;
	
	//打开定时器0中断
	ET0 = 1;
	//打开总中断
	EA = 1;
}
//定时器1初始化
void Time1Init()
{
	//设置定时器1工作模式
	TMOD &= 0x0F;	
	TMOD |= 0x10;
	TH1 = 0;
	TL1 = 0;
}

//------------------------------------------------------------定时器0中断
//定时器0中断
void Time0Handler() interrupt 1 //中断函数
{
	cnt++;
	//重新给初值
	TL0 = 0x33;
	TH0 = 0xFE;
	if(cnt < jd)
	{
		sg90_con = 1;
	}
	else
	{
		sg90_con = 0;
	}
	if(cnt == 40)//爆表40次经过了20ms
	{
		cnt = 0;
		sg90_con = 1;
	}
	
}

//------------------------------------------------------------超声波测距模块
//开始测距标志有一个不小于10us的电平变化
void startHC()
{
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}
//测距函数封装
double get_distance()
{
	double time;
	
	//定时器数据清零,以便于下次测距
	TH1 = 0;
	TL1 = 0;
	   
	//1、TRIG,给其至少10us的高电平
	startHC();
	//2、由低电平跳转到高电平,表示开始发送波,波发出一刹那开始启动定时器
	while(Echo == 0);
	TR1 = 1;
	//3、由高电平跳转到低电平,表示收到波,停止定时器
	while(Echo == 1);
	TR1 = 0;
	//4、计算中间经过多长时间 
	time = (TH1*256+TL1)*1.085;//us为单位
	//5、距离=速度*时间/2
	return (time*0.017);
	
}
//测距开灯函数封装
void openLight()
{
	D5 = 0;
	D6 = 1;
}
//测距关灯函数封装
void closeLight()
{
	D5 = 1;
	D6 = 0;
}

//------------------------------------------------------------舵机模块
//舵机初始化
void initSG90_0()
{
	jd = 1;
	cnt = 0;
	sg90_con = 1;
}
//测距开盖函数封装
void openLid()
{
	jd = 3;//90°,1.5ms高电平
	cnt = 0;
	Delay2000ms();
}
//测距关盖函数封装
void closeLid()
{
	jd = 1;//0°
	cnt = 0;
	Delay100ms();
}
//------------------------------------------------------------主函数
void main()
{
	double dis;
	
	//初始化定时器
	Time0Init();
	Time1Init();
	//初始化舵机
	initSG90_0();
	while(1){
		dis = get_distance();
		if(dis<10 || sw1 == 0)//小于10cm或者按键sw1被按下
		{
			//开盖D5亮
			openLight(); 
			//舵机开盖
			openLid();
		}
		else
		{
			//关盖D5灭
			closeLight();
			//舵机关盖
			closeLid();
		}		
	}
} 

③查询方式添加震动控制

查询方式不可行,震动传感器不稳,得靠硬件的外部中断来实现

④使用外部中断0配合震动控制

#include "reg52.h"

//------------------------------------------------------------接口
sbit D5       = P3^7;  //灯
sbit D6       = P3^6;
sbit Trig     = P1^5;  //超声波模块
sbit Echo     = P1^6;
sbit sg90_con = P1^1;  //舵机
sbit sw1      = P2^1;  //按键一
sbit vibrate  = P3^2;


//------------------------------------------------------------全局变量
int cnt = 0;           //定义全局变量,记录爆表次数
int jd;                //舵机角度
int mark_vibrate = 0; //震动标志位

//------------------------------------------------------------延时函数
//延时2s函数
void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	//_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
//延时100毫秒
void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}

//延时10us函数
void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

//------------------------------------------------------------定时器0与定时器1初始化
//定时器0初始化
void Time0Init()
{
	//配置定时器0工作模式
	TMOD &= 0xF0;	
	TMOD |= 0x01;
	//给初值,定一个10ms
	TL0 = 0x33;
	TH0 = 0xFE;
	//开始计时
	TR0 = 1;
	//初始化TF,准备记录爆表
	TF0 = 0;
	
	//打开定时器0中断
	ET0 = 1;
	//打开总中断
	EA = 1;
}
//定时器1初始化
void Time1Init()
{
	//设置定时器1工作模式
	TMOD &= 0x0F;	
	TMOD |= 0x10;
	TH1 = 0;
	TL1 = 0;
}

//------------------------------------------------------------定时器0中断函数
//定时器0中断
void Time0Handler() interrupt 1 //中断函数
{
	cnt++;
	//重新给初值
	TL0 = 0x33;
	TH0 = 0xFE;
	if(cnt < jd)
	{
		sg90_con = 1;
	}
	else
	{
		sg90_con = 0;
	}
	if(cnt == 40)//爆表40次经过了20ms
	{
		cnt = 0;
		sg90_con = 1;
	}
	
}

//------------------------------------------------------------外部中断初始化
void EX0_Init()
{
//打开外部中断
	EX0 = 1;
	IT0 = 0;//低电平触发 
}
//------------------------------------------------------------外部中断函数
void EX0_Handler() interrupt 0
{
	 mark_vibrate = 1;
}
//------------------------------------------------------------超声波测距模块
//开始测距标志有一个不小于10us的电平变化
void startHC()
{
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}
//测距函数封装
double get_distance()
{
	double time;
	
	//定时器数据清零,以便于下次测距
	TH1 = 0;
	TL1 = 0;
	   
	//1、TRIG,给其至少10us的高电平
	startHC();
	//2、由低电平跳转到高电平,表示开始发送波,波发出一刹那开始启动定时器
	while(Echo == 0);
	TR1 = 1;
	//3、由高电平跳转到低电平,表示收到波,停止定时器
	while(Echo == 1);
	TR1 = 0;
	//4、计算中间经过多长时间 
	time = (TH1*256+TL1)*1.085;//us为单位
	//5、距离=速度*时间/2
	return (time*0.017);
	
}
//测距开灯函数封装
void openLight()
{
	D5 = 0;
	D6 = 1;
}
//测距关灯函数封装
void closeLight()
{
	D5 = 1;
	D6 = 0;
}

//------------------------------------------------------------舵机模块
//舵机初始化
void initSG90_0()
{
	jd = 1;
	cnt = 0;
	sg90_con = 1;
}
//测距开盖函数封装
void openLid()
{
	jd = 3;//90°,1.5ms高电平
	cnt = 0;
	Delay2000ms();
}
//测距关盖函数封装
void closeLid()
{
	jd = 1;//0°
	cnt = 0;
	Delay100ms();
}
//------------------------------------------------------------主函数
void main()
{
	double dis;
	
	//初始化定时器
	Time0Init();
	Time1Init();
	//初始化外部中断
	EX0_Init();
	
	//初始化舵机
	initSG90_0();
	
	while(1){
		dis = get_distance();
		if(dis<10 || sw1 == 0 || mark_vibrate == 1)//小于10cm或者按键sw1被按下或者震动
		{
			//开盖D5亮
			openLight(); 
			//舵机开盖
			openLid();
			mark_vibrate = 0;
		}
		else
		{
			//关盖D5灭
			closeLight();
			//舵机关盖
			closeLid();
		}		
	}
} 

⑤加蜂鸣器

#include "reg52.h"

//------------------------------------------------------------接口
sbit D5       = P3^7;  //灯
sbit D6       = P3^6;
sbit Trig     = P1^5;  //超声波模块
sbit Echo     = P1^6;
sbit sg90_con = P1^1;  //舵机
sbit sw1      = P2^1;  //按键一
sbit vibrate  = P3^2;	 //震动传感器
sbit bee      = P2^0;  //蜂鸣器


//------------------------------------------------------------全局变量
char cnt = 0;           //定义全局变量,记录爆表次数
char jd;                //舵机角度
char mark_vibrate = 0; //震动标志位
char mark_jd;

//------------------------------------------------------------延时函数
//延时2s函数
void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	//_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
//延时100毫秒
void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}

//延时10us函数
void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

//------------------------------------------------------------定时器0与定时器1初始化
//定时器0初始化
void Time0Init()
{
	//配置定时器0工作模式
	TMOD &= 0xF0;	
	TMOD |= 0x01;
	//给初值,定一个10ms
	TL0 = 0x33;
	TH0 = 0xFE;
	//开始计时
	TR0 = 1;
	//初始化TF,准备记录爆表
	TF0 = 0;
	
	//打开定时器0中断
	ET0 = 1;
	//打开总中断
	EA = 1;
}
//定时器1初始化
void Time1Init()
{
	//设置定时器1工作模式
	TMOD &= 0x0F;	
	TMOD |= 0x10;
	TH1 = 0;
	TL1 = 0;
}

//------------------------------------------------------------定时器0中断函数
//定时器0中断
void Time0Handler() interrupt 1 //中断函数
{
	cnt++;
	//重新给初值
	TL0 = 0x33;
	TH0 = 0xFE;
	if(cnt < jd)
	{
		sg90_con = 1;
	}
	else
	{
		sg90_con = 0;
	}
	if(cnt == 40)//爆表40次经过了20ms
	{
		cnt = 0;
		sg90_con = 1;
	}
	
}

//------------------------------------------------------------外部中断初始化
void EX0_Init()
{
//打开外部中断
	EX0 = 1;
	IT0 = 0;//低电平触发 
}
//------------------------------------------------------------外部中断函数
void EX0_Handler() interrupt 0
{
	 mark_vibrate = 1;
}
//------------------------------------------------------------超声波测距模块
//开始测距标志有一个不小于10us的电平变化
void startHC()
{
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}
//测距函数封装
double get_distance()
{
	double time;
	
	//定时器数据清零,以便于下次测距
	TH1 = 0;
	TL1 = 0;
	   
	//1、TRIG,给其至少10us的高电平
	startHC();
	//2、由低电平跳转到高电平,表示开始发送波,波发出一刹那开始启动定时器
	while(Echo == 0);
	TR1 = 1;
	//3、由高电平跳转到低电平,表示收到波,停止定时器
	while(Echo == 1);
	TR1 = 0;
	//4、计算中间经过多长时间 
	time = (TH1*256+TL1)*1.085;//us为单位
	//5、距离=速度*时间/2
	return (time*0.017);
	
}
//测距开灯函数封装
void openLight()
{
	D5 = 0;
	D6 = 1;
}
//测距关灯函数封装
void closeLight()
{
	D5 = 1;
	D6 = 0;
}

//------------------------------------------------------------舵机模块
//舵机初始化
void initSG90_0()
{
	jd = 1;
	cnt = 0;
	sg90_con = 1;
}
//测距开盖函数封装
void openLid()
{
	char i;
	jd = 3;//90°,1.5ms高电平
	if(mark_jd != jd)
	{
		cnt = 0;
		bee = 0;
		for(i=0;i<=2;i++)
		{
			Delay100ms();
		}
		bee = 1;
		Delay2000ms();
	}
	mark_jd = jd;
	
}
//测距关盖函数封装
void closeLid()
{
	jd = 1;//0°
	mark_jd = jd;
	cnt = 0;
	Delay100ms();
}

//------------------------------------------------------------主函数
void main()
{
	double dis;
	
	//初始化定时器
	Time0Init();
	Time1Init();
	//初始化外部中断
	EX0_Init();
	
	//初始化舵机
	initSG90_0();
	
	while(1){
		dis = get_distance();
		if(dis<10 || sw1 == 0 || mark_vibrate == 1)//小于10cm或者按键sw1被按下或者震动
		{
			//开盖D5亮
			openLight(); 
			//舵机开盖
			openLid();
			mark_vibrate = 0;
		}
		else
		{
			//关盖D5灭
			closeLight();
			//舵机关盖
			closeLid();
		}		
	}
} 

问题:如果手一直放在超声波传感器上,舵机会抽抽,是因为它一直在做一个jd从0到3的过程

处理:加一个mark_jd标志位,记录当前jd的数据,如果jd是3,则舵机不重头计数,蜂鸣器不响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值