
接下来我们进入学会了HC---SR04 还有舵机那么现在我们将他们融合在一起,用超声波来引导舵机的转动
我们这个最后的成果是做一个智能垃圾桶
成品是这样的,是不是可有意思了

成品视频
- 现在我们将舵机的代码和超声波测距模块的代码整合到一起,实现目的超声波来引导舵机的转动




这边基本上就是整合代码了, 这边最主要的就是要把定时器1和定时器0都拿出来用,分别用于舵机的pwm波的计算,还有超声波Echo高电平持续的时,所以我们要在初始化两个定时器,都是一个用法,还有的就是为了main函数里面不会那么多代码,看上去整洁,和需要找问题的时候封装函数。这边openDusbin 和closeDusbin都是封装的函数,还有一个就是超声波定时器里面运行控制位TR要先设置为1,先不能启动,到Echo到高电平时候再开始启动。
加上按键触发舵机
这个就简单了直接加上去就好了
不浪费空间直接把这个地方的代码展示出来

就这样OK了
接着加上了震动传感器
直接上代码
#include "reg52.h"
#include <intrins.h> // ??nop()??
sbit D5 = P3^7; // ??(??<10cm??)
sbit D6 = P3^6; // ??(??=10cm??)
sbit Trig = P1^5; // ???????
sbit Echo = P1^6; // ???????
sbit SG90 = P1^1;
sbit sw1 = P2^1;
sbit vibrate = P3^2;
int count=0;
int jiaodu;
unsigned char i; //¶¨ÒåÑ>>·±äÁ¿
char mark_vibrate = 0;
void Delay300ms(void) //@11.0592MHz
{
unsigned char data i, j, k;
nop();
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay10us(void) //@11.0592MHz
{
unsigned char data i;
i = 2;
while (--i);
}
void Delay50ms() //@11.0592MHz
{
unsigned char i, j;
i = 90;
j = 163;
do
{
while (--j);
} while (--i);
}
void Delay100ms() //@11.0592MHz
{
unsigned char i, j;
i = 183;
j = 105;
do
{
while (--j);
} while (--i);
}
void Time1_Init()
{
TMOD &= 0x0F;
TMOD |= 0x10;
TH1 = 0; //³õʼ>>¯¼ÆÊý¼Ä´æÆ÷
TL1 = 0;
TR1 = 0; //³õʼ²>>Æô¶¯¶¨Ê±Æ÷
}
void Timer0_Init()
{
TMOD &= 0xF0;
TMOD |= 0x01;
TL0 = 0x33;
TH0 = 0xFE;
TF0 = 0;
TR0 = 1;
ET0 = 1;
EA=1;
}
void Delay10ms(void) //@11.0592MHz
{
unsigned char data i, j;
i = 18;
j = 235;
do
{
while (--j);
} while (--i);
}
// ´¥·¢³¬Éù²¨²â¾à
void Trigger_HC_SR04()
{
Trig = 0;
Delay10us();
Trig = 1; // ????10µs????????
Delay10us();
Trig = 0;
}
void checkBefore()
{
// Éϵç×Ô¼ì
for(i=0; i<3; i++) {
D5 = 0;
D6 = 1; // >>ƵÆÁÁ
Delay100ms();
D5 = 1;
D6 = 0; //À¶µÆÁÁ
Delay100ms();
}
}
void openDusbin()
{
D5 = 0; D6 = 1;
jiaodu = 3;//90¶È 1.5msµÄ¸ßµçƽ
count=0;
Delay300ms();//¸ø¶æ>>úµÄʱ¼ä£¬Íê³É¶¯×÷ºó±£³Ö¶¯×÷2s
}
void closeDusbin()
{
D5 = 1; D6 = 0;
jiaodu=1;//0¶È
count=0;
Delay100ms();
}
void sg90Init()
{
jiaodu =1;//³õʼ>>¯½Ç¶È0¶È 0.5msµÄ¸ßµçƽ 1¾ÍÊǶ¨Ê±Æ÷Òç³ö1´Î
count = 0;//count³õʼֵ
SG90 = 1;//Ò>>¿ªÊ¼¸ßµçƽ¿ªÊ¼
Delay10ms();//ΪÁ˵ÚÒ>>´ÎÍêÕûµÄ²¨ÐÎ>>³ö
}
void Ex0_Init()
{
//´ò¿ªÍⲿÖжÏ
EX0 =1;
//µÍµçƽ´¥·¢
IT0 =0;
}
void main()
{
unsigned int Time; //
unsigned int Distance; //
unsigned int timeout; //³¬Ê±¼ÆÊýÆ÷
//³õʼ>>¯¶¨Ê±Æ÷
Time1_Init();
Timer0_Init();
Ex0_Init();
checkBefore();
sg90Init();
//D5 = 1;
//D6 = 0;
//Delay100ms(); // ???????
while(1)
{
// ¼ì²âEchoµÄ³õʼµçƽ(³õʼÊÇµÍµçÆ½) ×÷Ϊ³õʼÌõ¼þÎÒÃÇÒª½øÐмì²âÒ>>Ï£¬ÓпÉÄܵÄÊÂÇé
if(Echo == 1) {
D5 = 0; D6 = 0; //Ë<<µÆÁÁ£¬±¨¾¯
Delay100ms();
continue;//Èç¹ûÕæµÄÊÇ¸ßµçÆ½ÄÇÎÒÃǾÍÌø¹ý±¾´Î²âÁ¿
}
//´¥·¢²â¾à
Trigger_HC_SR04();
// µÈ´ýEcho±ä¸ß(Ìí¼Ó³¬Ê±£ºÔ¼10ms)
timeout = 10000;
while(Echo == 0 && --timeout);
if(timeout == 0) {
D5 = 0; D6 = 0; // Èç¹û³¬Ê±Ë<<µÆÁÁ(±¨¾¯)
Delay50ms();//±£³Ö±¨¾¯×´Ì¬50ms
continue;
}
// Æô¶¯¶¨Ê±Æ÷
TH1 = 0;
TL1 = 0;
TR1 = 1;
timeout = 65535;
while(Echo == 1 && --timeout);
TR1 = 0;
if(timeout != 0) {
Time = (TH1 * 256 + TL1) * 1.085;
Distance = Time * 17 / 1000;
if(Distance < 10 || sw1 == 0 || mark_vibrate == 1) {
openDusbin();
mark_vibrate=0;
} else {
closeDusbin();
}
}else{
D5 = 1; D6 = 1;
}
Delay300ms();
}
}
void Timer0_Isr() interrupt 1
{
count++;
//ÖØÐ¸ø³õÖµ
TL0 = 0x33;
TH0 = 0xFE;
//¿ØÖÆPWM²¨
if(count<jiaodu){//jiaodu¾ÍÊÇcount´Ó0¿ªÊ¼¸ßµçƽռÁ˶àÉÙµÄÕ¼¿Õ±È
SG90 = 1;
}else{
SG90 = 0;
}
//Ò>>¸öÖÜÆÚ½áÊøÉèÖÃÏÂÒ>>ÖÜÆÚµÄµçÆ½×´Ì¬ºÍcountµÄ´ÎÊý
if(count==40){
SG90=1;
count = 0;
}
}
void Ex0_Handler() interrupt 0
{
mark_vibrate = 1;
}
主要区别就是我们本来有两种理想的方法可以加入震动传感器的,第一种就是使用查询法,但是我们发现了一种现象,怎么好像代码一点问题都没有但是,确不起效果呢???
真相只有一个!!

因为Vibrate被感受振动的时候的低电平没有按键的稳定和持久,所以用查询法是比较不好的,就是比较信号弱,那么按键为什么可以呢??因为跟按键比的话人按按键的时间肯定更长的,对于电路来说已经非常足够了,但是对于传感器他这个是一闪而过的,自然不行,比较弱不好
if(jd_bak !=jd){
count = 0;
D5=1;
D6=0;
Delay1000ms();
这个是我们的关盖子的时候延时有1000ms 我们这个低电平信号的时间都超不过这个时间 ,所以就捕获不到了,所以我们不能用查询法,那么我们既然知道了传感器信号触发时间在这个延时里面,那么我们就可以用中断来解决这个问题
这里我们使用外部中断(新知识点)


因为我们定时器0已经开了EA总中断了,所以这边就没有设置EA


这边我们了解一下外部中断0 EX0就是中断允许位,而且我们震动传感器感受振动的时候会传低电平,所以我们直接用IT0 ,这个是触发条件,和之前不一样,之前的溢出中断,还需要配置定时器模式,时间TH0 TL0 之类的,这个不用,这个只需要这样写
初始化外部中断

外部中断函数

好的继续解决问题 ,那么我们用查询法,没有用,那么我们用外部中断,触发条件是低电平触发,那么我们可以设置一个状态位,这样会比较的稳定

这个引脚也是有固定的,根据手册来的

说明有些引脚是专门有自己的特殊作用的
接着说
因为我们震动传感器只要震动,那就会触发中断,那么走中断函数

让mark_vibrate为1,满足我们的条件

这样就可以用震动的效果来开盖子,也就是操作舵机了,但是别忘了,要将mark_vibrate重置为0,方便下一次的使用;
最后加上蜂鸣器

最后加上我们的蜂鸣器,那我们肯定要将可以用的设备都用上
这个也是很简单,加上两行代码,主要知道他是低电平触发就好了

beep就是蜂鸣器,延时个50ms ,刚刚好,因为长时间真的很吵。
好了结束了
最后优化一下代码,我们发现如果收一直放在超声波前面,他就会一直抽抽抽的,因为我们的代码逻辑是超声波检测后开盖,然后闭盖,但是我们手只要一直放在这,他就会一直执行开盖闭盖,就是舵机还没到0度的时候又要到90度了,那么我们该怎么解决呢
在全局变量处添加状态标志:
int jd_bak=0;

这样子搞就好了,这个是常用的小技巧就等于是设置记录上一次的角度,如果是jdbak和jiaodu是一样的话就说明角度没有变化,那就不执行if里面的语句,if里面的语句就是正常我们开盖各个工作的状态,也就是证明超声波还是检测的到手,人还在丢垃圾,就不会执行closeDusbin关盖子的代码,只有移开之后,超声波检测不到了之后才会去走else的代码,然后开盖和闭盖之后,都要把自己的一个状态给jd_bak,因为对于下一步来讲,现在这一步已经是上一次的角度了,能懂吗......思路就是这样