這個51單片機做的智能垃圾桶具備以下功能:
自動感應開蓋:通過紅外傳感器(來人檢測)感應人體,觸發箱蓋開關電路自動打開箱蓋。
箱滿檢測:另一路紅外傳感器(箱滿檢測)識別桶內垃圾是否裝滿,滿時會觸發提示。
語音提示:支持 3 種語音播報:
提示垃圾分類
提示垃圾桶已滿
提示正在消毒
消毒功能:通過消毒泵電路,可對桶內進行消毒操作。
參數設置:借助按鍵電路(設置 / 增加 / 減小),可調整系統參數。
顯示功能:通過 LCD 顯示電路,展示時間、狀態等信息(搭配時鐘電路提供時間基準)。
上位機交互:支持與模擬上位機通信,可傳輸數據或接收控制指令。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei.png (69.03 KB, 下載次數: 0)
下載附件
2025-11-25 16:48 上傳
單片機源程序如下:- //宏定義
- #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樓
|