STC89C51基础及项目第6天:感应开关盖垃圾桶

1. 感应开关盖垃圾桶需求设计(196.41)

项目概述

  • 功能描述
    • 检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
    • 发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
    • 按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
  • 硬件说明
    • SG90舵机,超声波模块,震动传感器,蜂鸣器
  • 接线说明
    • 舵机控制口 P1.1;
    • 超声波 Trig接 P1.5 ,Echo接 P1.6 ;
    • 蜂鸣器接 P2.0 口;
    • 震动传感器接 P3.2口(外部中断0)

2. 垃圾桶01_修改超声波为定时器一控制(197.42)

开发步骤:

  1. 舵机和超声波代码整合
    • 舵机用定时器0
    • 超声波用定时器1
    • 实现物体靠近后,自动开盖,2秒后关盖
  2. 查询的方式添加按键控制
  3. 查询的方式添加震动控制
  4. 使用外部中断0配合震动控制
  • 代码(13./垃圾桶01代码/11. 舵机控制)(舵机的代码不变)(舵机接P1.1口)
#include "reg52.h"
#include 

sbit sg90_con=P1^1;
int cnt=0;
int degree;

void Timer0Init()
{
	//1.配置定时器0工作模式为16位计时
	TMOD=0x01;
	//2.给初值,定一个10ms出来
	TH0=0xFE;
	TL0=0x33;
	//3.打开定时器0中断
	ET0=1;	
	//4.打开EA总中断
	EA=1;
	//5.开始计时
	TR0=1;//定时器0开始计时
	//TF0=0;//软件清零
}

void Delay300ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	i = 3;
	j = 26;
	k = 223;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void main()
{
	Delay300ms();//让硬件稳定一下
	Timer0Init();//初始化定时器
	
	degree=1; //初始角度是0度,0.5ms,定时器溢出1次就是0.5,高电平
	cnt=0;
	
	sg90_con=1;//一开始就从高电平开始
	
	//每隔两秒切换一次角度
	while(1)//若棒子0度没找准,校准:可将while内的注释掉,角度不做切换,去烧写即可校准
	{	
		degree=3;//切到90度位 1.5ms高电平
		cnt=0;//保持同步
		Delay2000ms();
		degree=1;//切到0度位  0.5ms高电平
		cnt=0;
		Delay2000ms();
	}
}

void Timer0Helper() interrupt 1//中断处理函数,记得加中断号//属于后台任务
{//CPU响应中断时,硬件清零TF0
	cnt++;//统计爆表的次数
	//重新给初值
	TH0=0xFE;
	TL0=0x33;
	
	//控制PWM波
	if(cnt<degree)
	{
		sg90_con=1;
	}else
	{
		sg90_con=0;
	}
	if(cnt==40)//爆表40次,经过了20ms
	{
		cnt=0;//重新让cnt从0开始,计算下一次的10nms
		sg90_con=1;
	}
}
  • 代码(13./垃圾桶01代码/12. 超声波测距)(修改超声波代码,定时器0改为定时器1)
#include "reg52.h"
#include 

sbit D5 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit D6 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
sbit trig = P1^5;
sbit echo = P1^6;

void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}
void Delay200ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 2;
	j = 103;
	k = 147;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Timer1Init()
{
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TH1 = 0;
	TL1 = 0;//设置定时器0工作模式1,初始值设定0开始数数,不着急启动定时器
}
/*十进制2左移1位,变成20。相当于乘以10
二禁止1左移1位,变成10(2)。相当于乘以2,左移8位,乘以2的8次方=256;*/

void startHC()
{
	trig=0;
	trig=1;
	Delay10us();
	trig=0;
}

void main()
{
	double time;
	double dis;
	
	Timer1Init();
	
	while(1)
	{
		//1.Trig ,给Trig端口至少10us的高电平
		Delay200ms();//老一批超声波模块带晶振,所以不用加延时
		startHC();
		//2.Echo信号由低电平跳转到高电平,表示开始发送波
		while(echo==0);//条件不满足时,就会由低电平调到高电平
		//波发出去的那一刻,开始启动定时器;
		TR1=1;
		//3.Echo信号由高电平跳转回低电平,表示波回来了
		while(echo==1);
		//波返回来的拿一刻,开始停止定时器;
		TR1=0;
		//4.计算出中间经过多少时间。
		time=(TH1*256 + TL1)*1.085;//us为单位
		//5.距离 = 速度 (340m/s)* 时间/2	340m/s=34000cm/1000ms=34cm/ms=34cm/1000us=0.034cm/us
		dis=time * 0.017;
		if(dis<10)//距离小于10cm,D5亮D6灭,否则相反现象
		{
			D5=0;
			D6=1;
		}
		else
		{
			D5=1;
			D6=0;
		}
		//定时器数据清零,以便下一次测距
		TH1 = 0;
		TL1 = 0;
	}
}

3. 垃圾桶02_封装超声波测距代码(198.43)

  • 代码(13./垃圾桶02代码_超声波封装)(简化main主函数:封装测距函数、封装对应状态灯亮灭的函数)
#include "reg52.h"
#include 

sbit D5 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit D6 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
sbit trig = P1^5;
sbit echo = P1^6;

void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}
void Delay200ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 2;
	j = 103;
	k = 147;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Timer1Init()
{
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TH1 = 0;
	TL1 = 0;//设置定时器0工作模式1,初始值设定0开始数数,不着急启动定时器
}
/*十进制2左移1位,变成20。相当于乘以10
二禁止1左移1位,变成10(2)。相当于乘以2,左移8位,乘以2的8次方=256;*/

void startHC()
{
	trig=0;
	trig=1;
	Delay10us();
	trig=0;
}

double getDistance()
{
		double time;
		//定时器数据清零,以便下一次测距
		TH1 = 0;
		TL1 = 0;
		//1.Trig ,给Trig端口至少10us的高电平
		Delay200ms();//老一批超声波模块带晶振,所以不用加延时
		startHC();
		//2.Echo信号由低电平跳转到高电平,表示开始发送波
		while(echo==0);//条件不满足时,就会由低电平调到高电平
		//波发出去的那一刻,开始启动定时器;
		TR1=1;
		//3.Echo信号由高电平跳转回低电平,表示波回来了
		while(echo==1);
		//波返回来的拿一刻,开始停止定时器;
		TR1=0;
		//4.计算出中间经过多少时间。
		time=(TH1*256 + TL1)*1.085;//us为单位
		//5.距离 = 速度 (340m/s)* 时间/2	340m/s=34000cm/1000ms=34cm/ms=34cm/1000us=0.034cm/us
		return (time * 0.017);
}

void open_lightStatus()
{
	D5=0;
	D6=1;
}
void close_lightStatus()
{
	D5=1;
	D6=0;
}
void main()
{
	
	double dis;
	
	Timer1Init();
	
	while(1)
	{
		dis=getDistance();
		if(dis<10)//距离小于10cm,D5亮D6灭,否则相反现象
		{
			open_lightStatus();
		}
		else
		{
			close_lightStatus();
		}
		
	}
}

4. 垃圾桶03_实现距离感应开关盖(199.44)

  • 代码(13./垃圾桶03代码_测距开关盖)(超声波接P1.5、P1.6口)
#include "reg52.h"
#include 

sbit D5       = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit D6       = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
sbit trig     = P1^5;
sbit echo     = P1^6;
sbit sg90_con = P1^1;

int cnt = 0;
int degree;

void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}
void Delay200ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 2;
	j = 103;
	k = 147;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void Delay150ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 2;
	j = 13;
	k = 237;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Timer0Init()
{
	//1.配置定时器0工作模式为16位计时
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	//2.给初值,定一个10ms出来
	TH0=0xFE;
	TL0=0x33;
	//3.打开定时器0中断
	ET0=1;	
	//4.打开EA总中断
	EA=1;
	//5.开始计时
	TR0=1;//定时器0开始计时
	//TF0=0;//软件清零
}

void Timer1Init()
{
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TH1 = 0;
	TL1 = 0;//设置定时器0工作模式1,初始值设定0开始数数,不着急启动定时器
}

void startHC()
{
	trig=0;
	trig=1;
	Delay10us();
	trig=0;
}

double getDistance()
{
		double time;
		//定时器数据清零,以便下一次测距
		TH1 = 0;
		TL1 = 0;
		//1.Trig ,给Trig端口至少10us的高电平
		Delay200ms();//老一批超声波模块带晶振,所以不用加延时
		startHC();
		//2.Echo信号由低电平跳转到高电平,表示开始发送波
		while(echo==0);//条件不满足时,就会由低电平调到高电平
		//波发出去的那一刻,开始启动定时器;
		TR1=1;
		//3.Echo信号由高电平跳转回低电平,表示波回来了
		while(echo==1);
		//波返回来的拿一刻,开始停止定时器;
		TR1=0;
		//4.计算出中间经过多少时间。
		time=(TH1*256 + TL1)*1.085;//us为单位
		//5.距离 = 速度 (340m/s)* 时间/2	340m/s=34000cm/1000ms=34cm/ms=34cm/1000us=0.034cm/us
		return (time * 0.017);
}

void open_lightStatus()
{
	D5=0;
	D6=1;
}
void close_lightStatus()
{
	D5=1;
	D6=0;
}

void initSG90_0()
{
	degree=1; //初始角度是0度,0.5ms,定时器溢出1次就是0.5,高电平
	cnt=0;
	sg90_con=1;//一开始就从高电平开始
}

void openDustbin()
{
	//舵机开盖
	degree=3;//切到90度位 1.5ms高电平
	cnt=0;//保持同步
	Delay2000ms();
}
void closeDustbin()
{
	//舵机关盖
	degree=1;//切到0度位  0.5ms高电平
	cnt=0;
	Delay150ms();//会有一点点延时,可删
}

void main()
{
	
	double dis;
	
	Timer0Init();
	Timer1Init();
	initSG90_0();
	
	while(1)
	{
		//超声波测距
		dis=getDistance();
		if(dis<10)//距离小于10cm,D5亮D6灭,否则相反现象
		{	//开盖,灯状态为D5亮D6灭
			open_lightStatus();
			openDustbin();
		}
		else
		{	//关盖,灯状态位D5灭D6亮
			close_lightStatus();
			closeDustbin();
		}
	}
}

void Timer0Helper() interrupt 1//中断处理函数,记得加中断号//属于后台任务
{//CPU响应中断时,硬件清零TF0
	cnt++;//统计爆表的次数
	//重新给初值
	TH0=0xFE;
	TL0=0x33;
	
	//控制PWM波
	if(cnt<degree)
	{
		sg90_con=1;
	}else
	{
		sg90_con=0;
	}
	if(cnt==40)//爆表40次,经过了20ms
	{
		cnt=0;//重新让cnt从0开始,计算下一次的10nms
		sg90_con=1;
	}
}

5. 垃圾桶04_添加按键开盖功能(200.45)

  • 思路
    if(dis<10 || sw1==0)//距离小于10cm,或者sw1按键被按下
  • 代码(13./垃圾桶04代码_测距开关盖添加按键开盖功能)

6. 垃圾桶05_添加震动开盖功能_使用外部中断优化(201.46)

  • 思路(振动器接P3.2口)
    • 配置外部中断0的触发方式为低电平触发
    • 当外部引脚的电平由高变为低时,触发外部中断0
    • 即 发生震动时(低电平触发),标记1
  • 代码(13./垃圾桶05代码_测距开关盖添加按键开盖震动开盖)

7. 垃圾桶06_添加开盖滴滴声_项目完结(202.47)

  • 蜂鸣器接P2.0口
  • 代码(13./垃圾桶06代码_添加开盖滴滴声_项目完结)

8. 垃圾桶成品展示(203.48)

9. 垃圾桶的抽抽BUG解决(204.49)

  • 思路
    • 做一个back让back判断是否为一直触发开盖状态
  • 如何让他一直开盖后还延时
    • 做一个if语句:如果是一直触发开盖状态,延时2s
  • 代码(13./垃圾桶07代码_添加开盖滴滴声_项目完结_解BUG)
void openDustbin()
{
	char n;
	//舵机开盖
	degree=3;//切到90度位 1.5ms高电平
	
	if(degree_back != degree){//做一个back让back判断是否为一直触发开盖状态
		cnt=0;//保持同步
		beep=0;
		for(n=0;n<2;n++){//循环体只包含一条语句,可以省略大括号{}	
			Delay150ms();  //但多条语句时,要用大括号
		} 
		beep=1;
		Delay2000ms();
	}
	if(degree_back = degree){//如果是一直触发开盖状态,延时2s
		Delay2000ms();
	}
	degree_back = degree;//做back
}
void closeDustbin()
{
	//舵机关盖
	degree=1;//切到0度位  0.5ms高电平
	degree_back = degree;//做back
	cnt=0;
	Delay150ms();//会有一点点延时,可删
}

你可能感兴趣的:(单片机,嵌入式硬件)