【嵌入式】基于STC89C52RC的51单片机学习(五)——感应开关盖垃圾桶

1、项目概述

(1) 功能描述

        检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖

        发生震动时,垃圾桶自动开盖并伴随滴一声,2 秒后关盖
        按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖

(2)硬件说明  

        SG90舵机,超声波模块,震动传感器,蜂鸣器

(3)接线说明  

        舵机控制口 P1.1 ;超声波 Trig P1.5 ,Echo P1.6 ;蜂鸣器接 P2.0 ; 震动传感器接 P3.2 ( 外部中断0)

2、 编程实现

(1) 舵机和超声波代码整合

        舵机用定时器0,超声波用定时器1,实现物靠近后开盖,两秒后自动关盖

#include "reg52.h"
#include 

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;
    }
}


(2)添加按键方式控制垃圾桶 

    增加按键的引脚配置并修改主函数中对于开关垃圾桶的判断,这里按键直接通过轮询方式判断

sbit Sw1     = P2^1;

if(dis <10 || Sw1 == 0){

          openStatuesLight();//led5亮

          openDustbin();//开盖

	      mark_vibrate = 0;

}

(3) 添加震动控制垃圾桶 

  前面做电动车报警器中我们已经用到过震动传感器,这里我们就不再说明了

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();
    
}

到这里我们的项目就完成的差不多了,可以开始搭建硬件了 

 3、硬件搭建   

 用塑料胶袋简单粘了下,这些模块以后会用到,就不用热熔胶了。

【嵌入式】基于STC89C52RC的51单片机学习(五)——感应开关盖垃圾桶_第1张图片 【嵌入式】基于STC89C52RC的51单片机学习(五)——感应开关盖垃圾桶_第2张图片【嵌入式】基于STC89C52RC的51单片机学习(五)——感应开关盖垃圾桶_第3张图片  【嵌入式】基于STC89C52RC的51单片机学习(五)——感应开关盖垃圾桶_第4张图片

 4、存在的问题

搭建好了硬件然后我们将代码烧录进去后又发现马,当手持续放在感应开关前时,垃圾桶盖子会上下抖动,其实是舵机在抖动。原因是当我们将手放在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();

 这样我们的感应垃圾桶就没有问题啦!

你可能感兴趣的:(51单片机,学习,嵌入式硬件)