1、项目概述
功能描述:
检测靠近时,垃圾桶自动开盖并伴随滴一声,2s后关盖。
发生震动时,垃圾桶自动开盖并伴随滴一声,2s后关盖。
按下按键时,垃圾桶自动开盖并伴随滴一声,2s后关盖。
硬件说明:
c52单片机、sg90舵机、超声波模块、震动传感器、蜂鸣器
接线说明:
舵机控制口 P1.1
超声波 Trig 接 P1.5口
Echo 接 P1.6口
蜂鸣器接 P2.0口
震动传感器接 P3.2口(外部中断INT0)
2、编程实现
开发步骤
1、舵机和超声波代码整合,
舵机用定时器0,
超声波用定时器1,
(手册中高 4 位管定时器 1 ,低 4 位管定时器 0。0x0F:F四个一,保持低四位不变,高四位全部为0;0x10:低四位不变,使高四位M0变为16位定时器)
实现物体靠近自动滴一声开盖,2s后关盖
2、查询法实现按键控制
3、查询法实现震动控制
4、使用外部中断0配合震动控制
3、优化
解决靠近超2s抽搐问题,
添加延时关盖
优化关盖震动控制开盖问题
#include"reg52.h"#include
//距离小于10cm,D5亮,D6灭,反之相反 sbit SW1 = P2^1; //按键开关接口 sbit D5 = P3^7; sbit D6 = P3^6; sbit Trig = P1^5; sbit Echo = P1^6; sbit sg90_con = P1^1; //舵机 sbit vibrate = P3^2; //振动传感器(外部中断) sbit beep = P2^0; //蜂鸣器(低电平响) //int换为char,节省空间 char jiaodu; char jiaodu_bak; char cnt = 0; char mark_vibrate = 0; //外部中断标志位 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 Delay150ms() //@11.0592MHz { unsigned char i, j, k; _nop_(); i = 2; j = 13; k = 237; do { do { while (--k); } while (--j); } while (--i); } void Delay10us() //@11.0592MHz { unsigned char i; i = 2; while (--i); } void startHC() { Trig = 0; Trig = 1; Delay10us(); Trig = 0; } //定时器0初始化 void Time0Init() { TMOD &= 0xF0; //设置定时器 0 模式 TMOD |= 0x01; TL0 = 0x33; //给初值,定一个0.5ms TH0 = 0xFE; ET0 = 1; //打开定时器0中断 EA = 1; //打开总中断EA TR0 = 1; //开始计时 TF0 = 0; } //定时器1初始化 void Time1Init() { TMOD &= 0x0F; //设置定时器 1 模式 TMOD |= 0x10; TH1 = 0; TL1 = 0; //设置定时器0工作模式1,初值设定为0开始数数,不着急启动定时器 } double get_distance() //封装函数距离 { double time;//时间 //定时器数据清零,方便下一次测距 TH1 = 0; TL1 = 0; startHC(); //给TRIG一个10us的高电平 while(Echo == 0); //ECHO由**低电平跳转到高电平**表示开始发送波 TR1 = 1; //波发送时启动定时器 while(Echo == 1); //ECHO由**高电平跳转到低电平**表示波返回 TR1 = 0; //波回来时关闭定时器 time = (TH1 * 256 + TL1)*1.085; //计算中间经过的时间,以 um 为单位 return (time * 0.017); //距离=(时间)*波的速度(340m/s)/ 2 ; 340m/s = 34cm/ms = 0.034cm/us } void openStatuslight() //封装函数,状态灯开D5亮,开盖 { D5 = 0; D6 = 1; } void closeStatuslight() //封装函数,状态灯关D5灭,关盖 { D5 = 1; D6 = 0; } void initSG90_0() //封装函数,舵机角度 { jiaodu = 1; //初始化角度,0°,0.5ms的高电平 cnt = 0; //角度变化,cnt从0计算 sg90_con = 1;//给高电平 } void openDustbin()//封装函数,舵机转动角度--打开垃圾桶 { char n; jiaodu = 4;//爆表4次,0.5*4=2ms高电平,转135度 if(jiaodu_bak != jiaodu){ cnt = 0; beep = 0; //蜂鸣器响 for(n = 0;n < 2;n++); Delay150ms(); beep = 1; Delay2000ms(); //每隔两秒转一次 } jiaodu_bak = jiaodu; } void closeDustbin()//封装函数,舵机转动角度--关闭垃圾桶 { jiaodu = 1; jiaodu_bak = jiaodu; cnt = 0; Delay150ms(); } void EX0_Init() //封装函数,外部中断 { EX0 = 1; //打开外部中断 (下降沿触发IT0/TCON.0 = 1 ;低电平触发IT0/TCON.0 = 0 ) IT0 = 0; //低电平触发 } void main() { double dis;//距离 Time0Init();//定时器0初始化 Time1Init();//定时器1初始化 EX0_Init(); initSG90_0();//舵机角度 while(1){ dis = get_distance();//超声波测距 if(dis < 10 || SW1 == 0 || mark_vibrate == 1){ //小于10cm,或者sw1按键被按下,或者震动产生 //振动产生有可能发生在延时期间,电频转变急促,不稳定,所以要使用外部中断(INIT0 ) openStatuslight(); //D5亮,开盖 openDustbin(); //打开垃圾桶 mark_vibrate = 0; //恢复 }else{ closeStatuslight(); //D5灭,关盖 closeDustbin(); //关闭垃圾桶 } } } //定时器0中断 void Time0Handler() interrupt 1 { cnt++; //统计爆表的次数 TL0 = 0x33; //重新给初值 TH0 = 0xFE; if(cnt < jiaodu){ //PWM波形控制 sg90_con = 1; }else{ sg90_con = 0; } if(cnt == 40){ //爆表40次,经过20ms cnt = 0; //重新计算cnt sg90_con = 1; } } //外部中断 void EX0_Handler() interrupt 0 { mark_vibrate = 1; }