赞
踩
检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
发生震动时,垃圾桶自动开盖并伴随滴一声,2 秒后关盖按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
SG90舵机,超声波模块,震动传感器,蜂鸣器
舵机控制口 P1.1 ;超声波 Trig 接 P1.5 ,Echo 接 P1.6 ;蜂鸣器接 P2.0 口 ; 震动传感器接 P3.2 口 ( 外部中断0)
2、 编程实现
(1) 舵机和超声波代码整合
舵机用定时器0,超声波用定时器1,实现物靠近后开盖,两秒后自动关盖
- #include "reg52.h"
- #include <intrins.h>
-
- sfr AUXR = 0x8e; /*声明AUXR寄存器的地址*/
-
- //距离小于10cm,led5里亮,led6灭,反之现象相反
- sbit led5 = P3^7;
- sbit led6 = P3^6;
-
- sbit Trig = P1^5;
- sbit Echo = P1^6;
- sbit sg_90 = P1^1;
-
- int angle = 1;
- int cnt = 0;
-
- 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 Delay2000ms() //@11.0592MHz
- {
- unsigned char i, j, k;
-
- _nop_();
- i = 15;
- j = 2;
- k = 235;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
-
-
- void Trig_HC_SR04()
- {
- Trig = 0;
- Trig = 1;
- Delay10us();
- Trig = 0;
- }
-
- void Time0Init(void) //0.5毫秒@11.0592MHz
- {
- AUXR &= 0x7F; //定时器时钟12T模式
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01;
- TL0 = 0x33; //设置定时初值
- TH0 = 0xFE; //设置定时初值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0 = 1; //打开定时器中断
- EA = 1;
- }
-
- void Time1Init()
- {
- AUXR &= 0x7F; //定时器时钟12T模式
- TMOD &= 0x0F; //设置定时器模式
- TMOD |= 0x10; //设置定时器模式
- TH1 = 0;
- TL1 = 0;
- }
-
-
- double get_distance()
- {
- double time;
-
- TH1 = 0;
- TL1 = 0;
- // 1.Trig,给Trig端口至少10us的高电平
- Delay200ms();
- Trig_HC_SR04();
-
- //2.Echo由低电平跳转到高电平,表示开始发送波
- while(Echo == 0);
- //波出去的那一下子开启定时器
- TR1 = 1;
- //3.Echo由高电平到低电平,表示波回来了
- while(Echo == 1);
- //波回来的那一下,开始关闭定时器
- TR1 = 0;
- //4.计算出中间经过多长时间
- time = ( TH1 * 256 + TL1 )* 1.085;
- //5.距离=速度*时间; 340m/s=34000cm/s=34cm/ms=0.034cm/us
- return (0.017*time);
- }
-
- void openStatuesLight()
- {
- led5 = 0;
- led6 = 1;
- }
-
- void closeStatusLight()
- {
- led5 = 1;
- led6 = 0;
- }
-
- void openDustbin()
- {
- angle = 3; //转90度
- cnt = 0;
- Delay2000ms();
- }
-
- void closeDustbin()
- {
- angle = 1 ;//转0度
- cnt = 0;
- Delay200ms();
- }
- void main()
- {
- double dis;
- led5 = 1;
- led6 = 1;
- Time1Init();
- Time0Init();
- while(1){
- dis = get_distance();
- if(dis <10){ //距离判断,小于10cm,开盖,led5亮
- openStatuesLight();//led5亮
- openDustbin();//开盖
-
- }
- else{ //距离超过10cm,关盖,led6亮
- closeStatusLight();
- closeDustbin();
- }
-
- }
- }
-
- //执行中断处理函数
- void Time0Handler() interrupt 1
- {
- cnt++;//统计爆表的次数
- TL0 = 0x33; //重新设置定时值
- TH0 = 0xFE;
- if( cnt < angle){
-
- sg_90 = 1;
- }
- else{
- sg_90 = 0;
- }
-
- if(cnt == 40){
- cnt = 0;//当100次表示1s,cnt重新从0开始计算下一次的一秒
- sg_90 = 1;
- }
- }
-
-
增加按键的引脚配置并修改主函数中对于开关垃圾桶的判断,这里按键直接通过轮询方式判断
- sbit Sw1 = P2^1;
-
- if(dis <10 || Sw1 == 0){
-
- openStatuesLight();//led5亮
-
- openDustbin();//开盖
-
- mark_vibrate = 0;
-
- }
前面做电动车报警器中我们已经用到过震动传感器,这里我们就不再说明了
- sbit Vibrate = P3^2;
-
- if(dis <10 || Sw1 == 0 || Vibrate == 0){//距离判断,小于10cm,开盖,led5亮
- openStatuesLight();//led5亮
- openDustbin();//开盖
- mark_vibrate = 0;
-
- }
<1> 查询方式添加震动传感器的弊端
需要注意的是,当我们把震动模块配置好后,烧入程序中执行发现,当震动发生时,垃圾桶开关盖反应很是迟钝。 原因是 我们在当条件成立或不成立时,调用了开关盖函数,实际上也就是控制舵机转动的函数,这个函数里面又调用了延迟函数,导致cpu在执行时延迟函数时,不能同时判断是否有其他影响因素,这里解决办法是通过设置外部中断来判断震动传感器。
那么为什么按键判断就不需要外部中断呢,这是因为按键的信号输入比较的稳定,cpu在执行延时函数后还能捕获到。但是振动传感器传来的信号是不稳定的,cpu不一定能捕获的到,所以我们采用中断方式
<2> 采用外部中断方式添加震动传感器
这里我们就可以设置一个标志位,专门用来判断是否产生了振动。程序开始时我们设置标识mark = 0;当有振动时,执行中断函数,将mark = 0改为mark = 1;一旦关盖后,又将 mark 设置为0。
- char angle = 1;
- char angle_bak = 1;
- char cnt = 0;
- char mark_vibrate = 0;
-
-
- //主函数内部修改条件判断
-
- if(dis <10 || Sw1 == 0 || mark_vibrate == 1){//距离判断,小于10cm,开盖,led5亮
- openStatuesLight();//led5亮
- openDustbin();//开盖
- mark_vibrate = 0;
- }
-
- //外部中断处理函数
- void Exit0_Handler() interrupt 0
- {
- mark_vibrate = 1;
- }
-
(4) 添加蜂鸣器
这里为了使得我们的功能更多我们可以再添加一个蜂鸣器,当垃圾桶打打开时响一会儿
- sbit Beep = P2^0;
-
- void openDustbin()
- {
- angle = 3; //转90度
- cnt = 0;
- Beep = 0;
- for(i=0;i<2;i++)
- Delay150ms();
- Beep = 1;
- Delay2000ms();
-
- }
到这里我们的项目就完成的差不多了,可以开始搭建硬件了
用塑料胶袋简单粘了下,这些模块以后会用到,就不用热熔胶了。
搭建好了硬件然后我们将代码烧录进去后又发现马,当手持续放在感应开关前时,垃圾桶盖子会上下抖动,其实是舵机在抖动。原因是当我们将手放在10cm的范围内时,垃圾桶不停的判断,开盖函数不断调用,里面的cnt也跟着清零,导致垃圾桶仿佛抽搐了一般,所以这里我们修改一下,增加一个变量,表示上一次判断时角度值 angle_bak,每次开盖时判断一下,要是不相等,再将cnt清零,将angle赋给angle_bak,同时改变angle。代码如下:
这里为了节省空间,我们将变量设置为char 型
( 因为 在C51的编译环境里,char就是一个范围小一些的int ,一般都用unsigned char 因为这种变量在C51中刚好满足最大为0XFF,就是255,可以方便通常的运算,单片机是八位系统 那么对于int 来说 ,是和char是一样的空间 都是1B 也就是8bits,以上来自网上的解释)
char angle = 1; char angle_bak = 1; char cnt = 0; char mark_vibrate = 0; void openDustbin() { char i; angle = 3; //转90度 if( angle_bak != angle){ cnt = 0; Beep = 0; for(i=0;i<2;i++) Delay150ms(); Beep = 1; Delay2000ms(); } angle_bak = angle; } void closeDustbin() { angle_bak = angle; angle = 1 ;//转0度 cnt = 0; Delay150ms();这样我们的感应垃圾桶就没有问题啦!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。