这个51单片机做的智能垃圾桶具备以下功能:
自动感应开盖:通过红外传感器(来人检测)感应人体,触发箱盖开关电路自动打开箱盖。
箱满检测:另一路红外传感器(箱满检测)识别桶内垃圾是否装满,满时会触发提示。
语音提示:支持 3 种语音播报:
提示垃圾分类
提示垃圾桶已满
提示正在消毒
消毒功能:通过消毒泵电路,可对桶内进行消毒操作。
参数设置:借助按键电路(设置 / 增加 / 减小),可调整系统参数。
显示功能:通过 LCD 显示电路,展示时间、状态等信息(搭配时钟电路提供时间基准)。
上位机交互:支持与模拟上位机通信,可传输数据或接收控制指令。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:- //宏定义
- #define uint unsigned int
- #define uchar unsigned char
- //程序头函数
- #include <reg52.h>
- #include <string.H>
- #include <intrins.h>
- #include "Data.h"
- #include "DS1302.h"
- //显示函数
- #include <display.h>
- bit flag1s = 0; //1s定时标志
- unsigned char T0RH = 0; //T0重载值的高字节
- unsigned char T0RL = 0; //T0重载值的低字节
- void ConfigTimer0(unsigned int ms);
- //按键
- sbit Key1=P3^5; //设置键
- sbit Key2=P3^6; //加按键
- sbit Key3=P3^7; //减按键
- sbit beng=P2^3; //消毒泵
- sbit yuyin_1=P3^2; //请垃圾分类
- sbit yuyin_2=P3^3; //垃圾桶已满
- sbit yuyin_3=P3^4; //垃圾桶正在消毒
- sbit HW1=P2^6; //红外1
- sbit HW2=P2^7; //红外2 垃圾箱满标志
- uchar set; //设置状态
- uchar kaigai_yanshi;
- bit full=0; //箱满标志
- bit flag1=0; //
- bit flag2=0; // //开关门标志
- bit flag3=0; //
- bit flag4=0; //
- bit flag5=0; // 正反转
- /*******************************定义全局变量********************************/
- //电机部分
- unsigned char code Z_BeatCode[8] = { 0x1, 0x3, 0x2, 0x6, 0x4, 0xc, 0x8, 0x9}; //正向步进电机节拍对应的IO控制代码
- unsigned char code F_BeatCode[8] = { 0x9, 0x8, 0xc, 0x4, 0x6, 0x2, 0x3, 0x1}; //反向步进电机节拍对应的IO控制代码
- unsigned long beats = 0; //电机转动节拍总数
- void StartMotor(unsigned long angle);
- //函数声明
- void Key();
- //毫秒延时**************************
- void delay_nms(unsigned int k)
- {
- unsigned int i,j;
- for(i=0;i<k;i++)
- {
- for(j=0;j<121;j++)
- {;}}
- }
- void Key() //按键函数
- {
- if(Key1==0) //设置键按下时
- {
- while(Key1==0); //检测按键是否释放
- set++; //设置状态标志加
- }
- if(set==1) //设置时
- {
- write_com(0x38);//屏幕初始化
- write_com(0x80+1);//选中的位置
- write_com(0x0f);//打开显示 无光标 光标闪烁
- write_com(0x06);//当读或写一个字符是指针后一一位
- }
- else if(set==2) //设置时
- {
- write_com(0x38);//屏幕初始化
- write_com(0x80+4);//选中的位置
- write_com(0x0f);//打开显示 无光标 光标闪烁
- write_com(0x06);//当读或写一个字符是指针后一一位
- }
- else if(set==3) //设置时
- {
- write_com(0x38);//屏幕初始化
- write_com(0x80+7);//选中的位置
- write_com(0x0f);//打开显示 无光标 光标闪烁
- write_com(0x06);//当读或写一个字符是指针后一一位
- }
- else if(set==4) //设置时
- {
- write_com(0x38);//屏幕初始化
- write_com(0x80+0x40+1);//选中的位置
- write_com(0x0f);//打开显示 无光标 光标闪烁
- write_com(0x06);//当读或写一个字符是指针后一一位
- }
- else if(set==5) //设置时
- {
- write_com(0x38);//屏幕初始化
- write_com(0x80+0x40+4);//选中的位置
- write_com(0x0f);//打开显示 无光标 光标闪烁
- write_com(0x06);//当读或写一个字符是指针后一一位
- }
- else if(set==6) //设置时
- {
- write_com(0x38);//屏幕初始化
- write_com(0x80+0x40+7);//选中的位置
- write_com(0x0f);//打开显示 无光标 光标闪烁
- write_com(0x06);//当读或写一个字符是指针后一一位
- }
- else if(set>=7) //再按一下设置键时,退出设置
- {
- set=0; //设置状态清零
- Ds1302_Write_Time(); //保存时间
- Init1602(); //初始化显示
- write_com(0x38);//屏幕初始化
- write_com(0x0c);//打开显示 无光标 无光标闪烁
- }
- if(Key2==0&&set!=0) //当在设置状态时,按下加键时
- {
- while(Key2==0); //按键释放 ++
- //年
- if(set==1)
- {
- time_buf1[1]++;
- if(time_buf1[1]>=100)
- time_buf1[1]=0;
- ...........
- ............
- }
- }
- /* 步进电机启动函数,angle-需转过的角度 */
- void StartMotor(unsigned long angle)
- {
- //在计算前关闭中断,完成后再打开,以避免中断打断计算过程而造成错误
- // EA = 0;
- beats = (angle * 4076) / 360; //实测为4076拍转动一圈
- // EA = 1;
- }
- /* 配置并启动T0,ms-T0定时时间 */
- void ConfigTimer0(unsigned int ms)
- {
- unsigned long tmp; //临时变量
-
- TMOD=0x21;//定时器1操作模式2:8位自动重载定时器
- TH1=0xfd;//装入初值,波特率9600
- TL1=0xfd;
-
- TR1=1;//打开定时器
- SM0=0;//设置串行通讯工作模式,(10为一部发送,波特率可变,由定时器1的溢出率控制)
- SM1=1;//(同上)在此模式下,定时器溢出一次就发送一个位的数据
- REN=1;//串行接收允许位(要先设置sm0sm1再开串行允许)
- ES=1;//开串行口中断
- tmp = 11059200 / 12; //定时器计数频率
- tmp = (tmp * ms) / 1000; //计算所需的计数值
- tmp = 65536 - tmp; //计算定时器重载值
- tmp = tmp + 12; //补偿中断响应延时造成的误差
- T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
- T0RL = (unsigned char)tmp;
- TH0 = T0RH; //加载T0重载值
- TL0 = T0RL;
- ET0 = 1; //使能T0中断
- TR0 = 1; //启动T0
- }
- /* T0中断服务函数,执行2ms定时 */
- void InterruptTimer0() interrupt 1
- {
- static unsigned int tmr1000ms = 0;
- static unsigned int tmr50ms = 0;
- unsigned char tmp; //临时变量
- static unsigned char index = 0; //节拍输出索引
- TH0 = T0RH; //重新加载重载值
- TL0 = T0RL;
- tmr1000ms++;
- if (tmr1000ms >= 500) //定时1s
- {
- tmr1000ms = 0;
- flag1s = 1;
- }
- // StartMotor(180); //半圈
- //电机部分
- if (beats != 0) //节拍数不为0则产生一个驱动节拍
- {
-
- tmp = P1; //用tmp把P1口当前值暂存
- tmp = tmp & 0xF0; //用&操作清零低4位
- if(flag5==1)
- {
- tmp = tmp | Z_BeatCode[index]; //用|操作把节拍代码写到低4位
- }
- else
- {
- tmp = tmp | F_BeatCode[index]; //用|操作把节拍代码写到低4位
- }
- P1 = tmp; //把低4位的节拍代码和高4位的原值送回P1
- index++; //节拍输出索引递增
- index = index & 0x07; //用&操作实现到8归零
- beats--; //总节拍数-1
- }
- else //节拍数为0则关闭电机所有的相
- {
- // P1 = P1 | 0x0F;
- P1 = P1 & 0xF0;
- if(flag5==1) //反转 并停止时
- {
- tmr50ms++;
- if(tmr50ms>=500)
- {
- tmr50ms=0;
- flag1=0; //箱盖关闭标志
- }
- }
- }
- }
- /*串行通讯中断,收发完成将进入该中断*/
- void Serial_interrupt() interrupt 4
- {
- unsigned char temp_rec_data_uart0;
- temp_rec_data_uart0 = SBUF;//读取接收数据
- RI=0;//接收中断信号清零,表示将继续接收
- }
- void Uart1Send(uchar c)
- {
- SBUF=c;
- while(!TI);//等待发送完成信号(TI=1)出现
- TI=0;
- }
- //延时函数大概是1s钟
- void DelaySec(int sec)
- {
- uint i , j= 0;
- for(i=0; i<sec; i++)
- {
- for(j=0; j<40000; j++)
- {
-
- }
- }
- }
- void main() //主函数
- {
- uchar i = 0;
- EA = 1; //开总中断
- ConfigTimer0(2); //配置T0定时2ms
-
- Ds1302_Init();
- Init1602();//初始化显示
-
- HW1=1; // 红外检测
- yuyin_1=1;
- yuyin_2=1;
- yuyin_3=1;
- beng=1;
- DelaySec(1);//延时约1秒
-
- while(1) //进入循环
- {
- if(set==0) //只有在非设置状态时,
- {
- Ds1302_Read_Time();
- display_NYR(time_buf1,full,flag2);
- }
- else //if(set==1)
- {
- delay_nms(180); //延时180ms
- display_NYR(time_buf1,full,flag2);
- }
- if(flag1s==1) //1s延时
- {
- flag1s=0;
-
- if(yuyin_1==0)
- {
- yuyin_1=1;
- }
- if(yuyin_2==0)
- {
- yuyin_2=1;
- }
- if(yuyin_3==0)
- {
- yuyin_3=1;
- }
- if((flag1==1)&&(flag2==1)) //
- {
- kaigai_yanshi++; //开盖延时
- if(kaigai_yanshi>10)
- {
- kaigai_yanshi=0;
- flag2=0; // 箱盖关闭标志
- StartMotor(180); //关闭箱盖
- flag5=1; //电机反传
- }
- }
- if(HW2==0) //垃圾桶已满 通知上位机
- {
- Uart1Send('F');
- Uart1Send('U');
- Uart1Send('L');
- Uart1Send('L');
- Uart1Send('\r');
- Uart1Send('\n');
- }
- }
- if(HW2==0) //垃圾桶已满
- {
- full=1;
- }
- else
- {
- full=0;
- }
- if((HW2==1)&&(beng==1)) //垃圾桶未满并且没有消毒
- {
- if(flag1==0)
- {
- if(HW1==0) //有人倒垃圾
- {
- flag5=0; //电机正传
- yuyin_1=0; //语音垃圾分类
- flag1=1; // 箱盖打开标志
- flag2=1; // 箱盖打开标志
-
- StartMotor(180); //打开箱盖
- }
- }
- }
- if(HW2==0) //垃圾桶满
- {
- if(HW1==0) //有人倒垃圾
- {
- yuyin_2=0; //垃圾桶已满
- }
- }
- if(time_buf1[5]==59)
- {
- beng=0; //启动消毒泵 1分钟
- }
- else
- {
- beng=1; //关闭消毒泵
- }
- if(beng==0)
- {
- if(HW1==0) //有人倒垃圾
- {
- yuyin_3=0; //垃圾桶消毒
- }
- }
- Key(); //扫描按键
-
-
- }
- }
复制代码
Proteus仿真和Keil程序下载: 见2楼
|