当前位置:   article > 正文

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

stc89c52rc项目

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,实现物靠近后开盖,两秒后自动关盖

  1. #include "reg52.h"
  2. #include <intrins.h>
  3. sfr AUXR = 0x8e; /*声明AUXR寄存器的地址*/
  4. //距离小于10cm,led5里亮,led6灭,反之现象相反
  5. sbit led5 = P3^7;
  6. sbit led6 = P3^6;
  7. sbit Trig = P1^5;
  8. sbit Echo = P1^6;
  9. sbit sg_90 = P1^1;
  10. int angle = 1;
  11. int cnt = 0;
  12. void Delay10us() //@11.0592MHz
  13. {
  14. unsigned char i;
  15. i = 2;
  16. while (--i);
  17. }
  18. void Delay200ms() //@11.0592MHz
  19. {
  20. unsigned char i, j, k;
  21. _nop_();
  22. i = 2;
  23. j = 103;
  24. k = 147;
  25. do
  26. {
  27. do
  28. {
  29. while (--k);
  30. } while (--j);
  31. } while (--i);
  32. }
  33. void Delay2000ms() //@11.0592MHz
  34. {
  35. unsigned char i, j, k;
  36. _nop_();
  37. i = 15;
  38. j = 2;
  39. k = 235;
  40. do
  41. {
  42. do
  43. {
  44. while (--k);
  45. } while (--j);
  46. } while (--i);
  47. }
  48. void Trig_HC_SR04()
  49. {
  50. Trig = 0;
  51. Trig = 1;
  52. Delay10us();
  53. Trig = 0;
  54. }
  55. void Time0Init(void) //0.5毫秒@11.0592MHz
  56. {
  57. AUXR &= 0x7F; //定时器时钟12T模式
  58. TMOD &= 0xF0; //设置定时器模式
  59. TMOD |= 0x01;
  60. TL0 = 0x33; //设置定时初值
  61. TH0 = 0xFE; //设置定时初值
  62. TF0 = 0; //清除TF0标志
  63. TR0 = 1; //定时器0开始计时
  64. ET0 = 1; //打开定时器中断
  65. EA = 1;
  66. }
  67. void Time1Init()
  68. {
  69. AUXR &= 0x7F; //定时器时钟12T模式
  70. TMOD &= 0x0F; //设置定时器模式
  71. TMOD |= 0x10; //设置定时器模式
  72. TH1 = 0;
  73. TL1 = 0;
  74. }
  75. double get_distance()
  76. {
  77. double time;
  78. TH1 = 0;
  79. TL1 = 0;
  80. // 1.Trig,给Trig端口至少10us的高电平
  81. Delay200ms();
  82. Trig_HC_SR04();
  83. //2.Echo由低电平跳转到高电平,表示开始发送波
  84. while(Echo == 0);
  85. //波出去的那一下子开启定时器
  86. TR1 = 1;
  87. //3.Echo由高电平到低电平,表示波回来了
  88. while(Echo == 1);
  89. //波回来的那一下,开始关闭定时器
  90. TR1 = 0;
  91. //4.计算出中间经过多长时间
  92. time = ( TH1 * 256 + TL1 )* 1.085;
  93. //5.距离=速度*时间; 340m/s=34000cm/s=34cm/ms=0.034cm/us
  94. return (0.017*time);
  95. }
  96. void openStatuesLight()
  97. {
  98. led5 = 0;
  99. led6 = 1;
  100. }
  101. void closeStatusLight()
  102. {
  103. led5 = 1;
  104. led6 = 0;
  105. }
  106. void openDustbin()
  107. {
  108. angle = 3; //转90度
  109. cnt = 0;
  110. Delay2000ms();
  111. }
  112. void closeDustbin()
  113. {
  114. angle = 1 ;//转0度
  115. cnt = 0;
  116. Delay200ms();
  117. }
  118. void main()
  119. {
  120. double dis;
  121. led5 = 1;
  122. led6 = 1;
  123. Time1Init();
  124. Time0Init();
  125. while(1){
  126. dis = get_distance();
  127. if(dis <10){ //距离判断,小于10cm,开盖,led5亮
  128. openStatuesLight();//led5亮
  129. openDustbin();//开盖
  130. }
  131. else{ //距离超过10cm,关盖,led6亮
  132. closeStatusLight();
  133. closeDustbin();
  134. }
  135. }
  136. }
  137. //执行中断处理函数
  138. void Time0Handler() interrupt 1
  139. {
  140. cnt++;//统计爆表的次数
  141. TL0 = 0x33; //重新设置定时值
  142. TH0 = 0xFE;
  143. if( cnt < angle){
  144. sg_90 = 1;
  145. }
  146. else{
  147. sg_90 = 0;
  148. }
  149. if(cnt == 40){
  150. cnt = 0;//当100次表示1s,cnt重新从0开始计算下一次的一秒
  151. sg_90 = 1;
  152. }
  153. }

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

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

  1. sbit Sw1 = P2^1;
  2. if(dis <10 || Sw1 == 0){
  3. openStatuesLight();//led5亮
  4. openDustbin();//开盖
  5. mark_vibrate = 0;
  6. }

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

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

  1. sbit Vibrate = P3^2;
  2. if(dis <10 || Sw1 == 0 || Vibrate == 0){//距离判断,小于10cm,开盖,led5亮
  3. openStatuesLight();//led5亮
  4. openDustbin();//开盖
  5. mark_vibrate = 0;
  6. }
<1>    查询方式添加震动传感器的弊端

    需要注意的是,当我们把震动模块配置好后,烧入程序中执行发现,当震动发生时,垃圾桶开关盖反应很是迟钝。 原因是 我们在当条件成立或不成立时,调用了开关盖函数,实际上也就是控制舵机转动的函数,这个函数里面又调用了延迟函数,导致cpu在执行时延迟函数时,不能同时判断是否有其他影响因素,这里解决办法是通过设置外部中断来判断震动传感器。  

        那么为什么按键判断就不需要外部中断呢,这是因为按键的信号输入比较的稳定,cpu在执行延时函数后还能捕获到。但是振动传感器传来的信号是不稳定的,cpu不一定能捕获的到,所以我们采用中断方式

<2> 采用外部中断方式添加震动传感器

这里我们就可以设置一个标志位,专门用来判断是否产生了振动。程序开始时我们设置标识mark = 0;当有振动时,执行中断函数,将mark = 0改为mark = 1;一旦关盖后,又将 mark 设置为0。

  1. char angle = 1;
  2. char angle_bak = 1;
  3. char cnt = 0;
  4. char mark_vibrate = 0;
  5. //主函数内部修改条件判断
  6. if(dis <10 || Sw1 == 0 || mark_vibrate == 1){//距离判断,小于10cm,开盖,led5亮
  7. openStatuesLight();//led5亮
  8. openDustbin();//开盖
  9. mark_vibrate = 0;
  10. }
  11. //外部中断处理函数
  12. void Exit0_Handler() interrupt 0
  13. {
  14. mark_vibrate = 1;
  15. }

(4) 添加蜂鸣器       

这里为了使得我们的功能更多我们可以再添加一个蜂鸣器,当垃圾桶打打开时响一会儿

  1. sbit Beep = P2^0;
  2. void openDustbin()
  3. {
  4. angle = 3; //转90度
  5. cnt = 0;
  6. Beep = 0;
  7. for(i=0;i<2;i++)
  8. Delay150ms();
  9. Beep = 1;
  10. Delay2000ms();
  11. }

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

 3、硬件搭建   

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

   

 4、存在的问题

搭建好了硬件然后我们将代码烧录进去后又发现马,当手持续放在感应开关前时,垃圾桶盖子会上下抖动,其实是舵机在抖动。原因是当我们将手放在10cm的范围内时,垃圾桶不停的判断,开盖函数不断调用,里面的cnt也跟着清零,导致垃圾桶仿佛抽搐了一般,所以这里我们修改一下,增加一个变量,表示上一次判断时角度值 angle_bak,每次开盖时判断一下,要是不相等,再将cnt清零,将angle赋给angle_bak,同时改变angle。代码如下:

这里为了节省空间,我们将变量设置为char 型

( 因为 在C51的编译环境里,char就是一个范围小一些的int ,一般都用unsigned char 因为这种变量在C51中刚好满足最大为0XFF,就是255,可以方便通常的运算,单片机是八位系统 那么对于int 来说 ,是和char是一样的空间 都是1B 也就是8bits,以上来自网上的解释)

  1. char angle = 1;
  2. char angle_bak = 1;
  3. char cnt = 0;
  4. char mark_vibrate = 0;
  5. void openDustbin()
  6. {
  7. char i;
  8. angle = 3; //转90度
  9. if( angle_bak != angle){
  10. cnt = 0;
  11. Beep = 0;
  12. for(i=0;i<2;i++)
  13. Delay150ms();
  14. Beep = 1;
  15. Delay2000ms();
  16. }
  17. angle_bak = angle;
  18. }
  19. void closeDustbin()
  20. {
  21. angle_bak = angle;
  22. angle = 1 ;//转0度
  23. cnt = 0;
  24. Delay150ms();

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/531318
推荐阅读
相关标签
  

闽ICP备14008679号