这个智能垃圾桶由51单片机,SG90舵机,超声波传感器,蜂鸣器,振动传感器组成。当人靠近距离小于10厘米或者按下单片机的key1键或者振动传感器震动,灯盖就会打开,蜂鸣器响600ms,盖子打开2600ms,然后盖子自动关闭。
我们选择了Timer0定时器及其中断用在输出pwm波来控制舵机的角度。用Timer1来计算超声波测距的来回时间,用INT0触发外部中断来为震动传感器低电平触发中断服务,这样就不会有那么大的延迟效果。下面是代码:
#include"reg52.h"
#include<intrins.h>
sbit D5=P3^7;
sbit D6=P3^6;
sbit Trig=P2^2;
sbit Echo=P2^3;
sbit sg90_con=P3^4;
sbit KEY1=P2^1;
sbit vibrate=P3^2;
sbit beep=P2^5;
int cnt=0;
int jd;
double dis;
int mark_vib=0;//自设标志位
int jd_back ;
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void Delay300ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
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 startHC()//开始条件,给Trig一个10us的高电平,让传感器启动
{
Trig=0;
Trig=1;
Delay10us();
Trig=0;
}
void Timer0Init() //500微秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式为16位
TMOD |= 0x01; //设置定时初值
TL0 = 0x33; //设置定时初值
TH0 = 0xFE;
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
void Timer1Init() //
{
TMOD &= 0x0F; //设置定时器模式为16位
TMOD |= 0x10;
TL1 = 0x00; //设置低八位定时初值
TH1 = 0x00; //设置高八位定时初值
}
double get_distance()
{
double time;
startHC();
while(Echo==0);//Echo由低电平变为高电平时,结束循环,硬件开发送波
TR1 = 1;//开启计数器计数模式
while(Echo==1);//Echo由高电平变为低电平时,结束循环,表明硬件接受到返回波
TR1 = 0;//关闭计数器计数模式
time=(TH1 * 256 + TL1)*1.085;//计算次数,乘以一次的时间1.085us,得到来回的总时间
return (0.017 * time);//速度是340m/s=0.034cm/us
}
void OpenStatusLight()//D5打开,D6关闭
{
D5=0;
D6=1;
}
void CloseStatusLight()//D6打开,D5关闭
{
D5=1;
D6=0;
}
void intiSG90_0()//初始化舵机为0度
{
sg90_con=1;
jd=1;
cnt=0;
}
void openDusbin()//舵机旋转90度,顶开垃圾盖。
{
jd=3;
if(jd_back!=jd)//添加jd_back!=jd是为了防止舵机抽搐,因为如果手长时间不开超声波传感器
{ //openDusbin()会被不断地调用,这样就会cnt的值就会不断变化,电平周期会遭到破坏
cnt=0;
beep=0;//蜂鸣器报警600ms
Delay300ms();
Delay300ms();
beep=1;//关闭蜂鸣器
Delay2000ms();//开盖延迟2000ms,方便扔垃圾
}
jd_back=jd;
}
void closeDusdin()//舵机为0度,关闭垃圾盖
{
jd=1;
jd_back=jd;
cnt=0;
Delay300ms();
}
void EX0_Init()//INT0外部中断,为震动传感器低电平触发中断服务,这样就不会有那么大的延迟效果
{
EX0=1;
IT0=0;//选择低电平触发
}
void main()
{
double dis;
Timer0Init();
Timer1Init();
EX0_Init();
intiSG90_0();
while(1)
{
Delay300ms();//让硬件稳定
Timer1Init();//每次都初始化低八位与高八位的值
dis=get_distance();
if(dis<10.00||KEY1==0||mark_vib==1)//距离小于10,或者按下按键一或者振动传感器震动D5灯亮,D6灯灭
{
OpenStatusLight();
openDusbin();
mark_vib=0;
}
else
{
CloseStatusLight();
closeDusdin();
}
}
}
void Time0Handler() interrupt 1
{
cnt++;
TL0 = 0x33; //设置定时初值
TH0 = 0xFE;
if(cnt<jd)//控制占空比
{sg90_con=1;}//sg90_con高电位
else
{sg90_con=0;}
if(cnt==40)//20ms的周期到了,cnt要置0
{
cnt=0;
sg90_con=1;
}
}
void EX0_Handler() interrupt 0
{
mark_vib=1;
}