一、项目概述
1、功能描述
当检测靠近时,垃圾桶会自动打开盖子,并伴有滴水声。 2 秒后关盖当发生振动时,垃圾桶自动打开盖子,并伴有滴水声, 2 秒后关盖按下按钮时,垃圾桶会自动打开盖子,滴一声, 2 秒后关盖
2、硬件部分
SG90舵机、超声波模块、振动传感器、蜂鸣器
3、接线说明
舵机(PWM)信号线 —> P1.1(定时器0) 超声波HC-SR04 Trig —> P1.5 、Echo —> P1.6 (定时器1) 震动传感器 —> P3.(外部中断0) 蜂鸣器 —> P2.0
二、基础参考
【51单片机STC89C52控制定时器(中断)LED_大头1213
【51单片机STC89C52】IO口模拟PWM控制SG90舵机_大头1213
【51单片机STC89C52】HC-SR04超声模块测距_大头1213
三、部分代码
1、接线部分
sbit D5 = P3^7.//根据原理图(电路图)设备变量led1指向P3组IO口的第7口 sbit D6 = P3^6.//根据原理图(电路图),设备变量led2指向P3组IO口的第6口 sbit KEY1 = P2^1;//按键KEY1 sbit Trig = P1^5; sbit Echo = P1^6; sbit sg90_con = P1^1; sbit vibrate = P3^2; sbit beep = P2^0;
2.超声波测距
double get_distance() { double time; ///定时器数据清零,以便下次测距 TH1 = 0; TL1 = 0; //1. 让它发送波:给Trig端口至少10us的高电平 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 return (time * 0.017); }
3.舵机-定时器0中断服务函数
void Time0Handler() interrupt 1 { cnt ; //统计溢出次数 ///重新给初值 TL0 = 0x33; TH0 = 0xFE; //控制PWM波 if(cnt < angle){ sg90_con = 1; }else{ sg90_con = 0; } if(cnt == 40){ //当溢出40次时,经过了20ms cnt = 0; sg90_con = 1; } }
4.振动传感器-外部中断0
打开外部中断
void EX0_Init() { EX0 = 1.//打开外部中断 IT0 = 0;///低电平触发 }
中断服务函数
void Ex0_Handler() interrupt 0 { mark_vibrate = 1; }
5.开关盖函数
void openDustbin() { char n; angle = 3; //90度 1.5ms高电平 //舵机开盖 if(angle_bak != angle){ cnt = 0; beep = 0; Delay150ms(); Delay150ms(); beep = 1; Delay2000ms(); } angle_bak = angle; } void closeDustbin() { //关盖 angle = 1; //0度 angle_bak = angle; cnt = 0; Delay150ms(); }
四、整体代码
#include "reg52.h" #include "intrins.h" sbit D5 = P3^7.//根据原理图(电路图)设备变量led1指向P3组IO口的第7口 sbit D6 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口 sbit KEY1 = P2^1;//按键KEY1 sbit Trig = P1^5; sbit Echo = P1^6; sbit sg90_con = P1^1; sbit vibrate = P3^2; sbit beep = P2^0; char angle; char angle_bak; char cnt = 0; char mark_vibrate = 0; 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 Delay10us() //@11.0592MHz { unsigned char i; i = 2; while (--i); } void Timer0Init(void) //500微秒@11.0592MHz { //AUXR &= 0x7F; TMOD &= 0xF0; ///设置定时器模式16位 TMOD |= 0x01; //设置定时器模式 TL0 = 0x33; //设置定时初始值0.5ms TH0 = 0xFE; //设置定时初始值 TF0 = 0; //清除TF0标志 TR0 = 1; ///定时器0开始计时 ET0 = 1; ///打开定时器0中断 EA = 1; ///打开总中断EA } void Timer1Init() //设置定时器0工作模式1,初始值设置0开始数,不急着启动定时器 { TMOD &= 0x0F; //设置定时器模式 TMOD |= 0x10; TH1 = 0; TL1 = 0; } void startHC() { Trig = 0; Trig = 1; Delay10us(); Trig = 0; } double get_distance() { double time; ///定时器数据清零,以便下次测距 TH1 = 0; TL1 = 0; //1. 让它发送波:给Trig端口至少10us的高电平 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 return (time * 0.017); } void openStatusLight() { D5 = 0; D6 = 1; } void closeStatusLight() { D5 = 1; D6 = 0; } void initSG90_0() { angle = 1; ///初始角度为0度,0.5ms,溢出1就是0.5ms高电平 cnt = 0; sg90_con = 1;//一开始从高电平开始 } void openDustbin() { char n; angle = 3; //90 1.5ms高电平
//舵机开盖
if(angle_bak != angle){
cnt = 0;
beep = 0;
for(n = 0; n < 2; n++)
Delay150ms();
beep = 1;
Delay2000ms();
}
angle_bak = angle;
}
void closeDustbin()
{
//关盖
angle = 1; //0度
angle_bak = angle;
cnt = 0;
Delay150ms();
}
void EX0_Init()
{
EX0 = 1;//打开外部中断
IT0 = 0;//低电平触发
}
void main()
{
double dis;
Timer0Init();
Timer1Init();
EX0_Init();
initSG90_0();//舵机的初始位置
while(1){
dis = get_distance();//超声波测距
if(dis < 10 || KEY1 == 0 || mark_vibrate == 1){
//开盖,灯状态,D5亮
openStatusLight();
openDustbin();
mark_vibrate = 0;
}else{
//关盖,灯状态,D5灭
closeStatusLight();
closeDustbin();
}
}
}
void Time0Handler() interrupt 1
{
cnt++; //统计溢出的次数
//重新给初值
TL0 = 0x33;
TH0 = 0xFE;
//控制PWM波
if(cnt < angle){
sg90_con = 1;
}else{
sg90_con = 0;
}
if(cnt == 40){ //当溢出40次,经过了20ms
cnt = 0;
sg90_con = 1;
}
}
void Ex0_Handler() interrupt 0
{
mark_vibrate = 1;
}