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,则舵机不重头计数,蜂鸣器不响