手把手帶做【智能垃圾桶項目】【全套開源】
1.項目介紹
1.1 功能描述
- 當物體接近垃圾桶時,垃圾桶自動打開,并有" 嘀"的一聲;當遠離垃圾桶后,自動關閉;
- 當按下按鍵時,垃圾桶也可以自動打開,并有" 嘀"的一聲;
- 當感受到震動時,也自動打開,(同上)
- 垃圾桶開時,led1 燈開,led2 燈關;當垃圾桶關時,led1 燈關,led2 燈開
1.2 所需器件
- SG90舵機,超聲波模塊HC-SR04,震動傳感器,蜂鳴器
模塊不熟悉沒關系,下面的描述和代碼都很詳細;
2.元器件器件描述
2.1 STC89C51/52
為了快速做出項目,我們一邊介紹項目所需元器件,一邊寫代碼,原理類的東西帶過一下。
首先,基本的led1、led2,key1。
#include<reg51.h>
sbit led1 = P3^7; //固定的口
sbit led2 = P3^6; //固定的口
sbit key1 = P2^1; //固定的口
這些口請參考你使用的單片機的原理圖,不同單片機不一樣
比如我使用的單片機
大家根據(jù)自己使用的單片機原理圖接對應硬件的引腳。
- 代碼塊
void led1_ON() //led1亮,led2滅
{
led1 = 1;
led2 = 0;
}
void led2_ON() //led2滅,led2亮
{
led1 = 0;
led2 = 1;
}
這兩個點燈函數(shù)之后也會用到,用來做為開關垃圾桶的標志。
1.2 超聲波測距模塊
我使用的是HC-SR04
大家在某寶或者某夕夕上面買就ok了,幾塊錢。
-
接線參考:
-
四個引腳VCC接 5/3.3V,GND 接地。
-
Trig、Echo 兩個引腳隨便接沒有被占用的引腳,我接的是 P1.5 和 P1.6;
sbit Trig = P1^5; //發(fā)生超聲波 sbit Echo = P1^6; //接收超聲波
-
-
超聲波測距原理
超聲波測距模塊是用來測量距離的一種產品,通過發(fā)送和收超聲波,利用時間差和聲音傳播速度, 計算出模塊到前方障礙物的距離.
配置好引腳后,trig 和 echo 就可以在軟件成面,就是通過代碼的方式進行操作。
-
怎么發(fā)送和接收超聲波呢?
- 1、發(fā)送波的條件:給trig一個至少10us的高電平,也就是
trig = 1
的狀態(tài)至少10us;
- 2、已經(jīng)發(fā)送波了的標志(也就是開始計時的標志):Echo信號,自動由低電平跳到高電平,表示開始發(fā)送波了;
- 3、當波接觸到物體,波會返回過來,當波返回過來被HC-SR01接收到后,Echo信號就會跳轉到低電平,表示回來了;
- 4、我們可以利用計數(shù)器,以及Echo的信號變化來計算距離;當發(fā)出波,Echo第一次變化,啟動計數(shù)器;當接收到信號,Echo第二次變化,關閉計數(shù)器;從而得出來回所需時間。
- 通過時間,音度340m/s,距離 = (速度*時間)/ 2;
- 1、發(fā)送波的條件:給trig一個至少10us的高電平,也就是
大家看著看不懂也沒關系,我們有代碼
- 模塊代碼介紹
先獲取一下延時函數(shù)
打開STC-ISP,按照我的操作就ok了
不會用STC-ISP也沒關系,直接復制代碼一樣得
void Delay10us() //@11.0592MHz //發(fā)射超聲波最短時間
{
unsigned char i;
i = 2;
while (--i);
}
下面是這個器件操作的大頭:利用到了定時器/計數(shù)器1
定時器/計數(shù)器如果不太明白,大家可以參考我之前寫的博客:
<定時器中斷&外部中斷 區(qū)別聯(lián)系-CSDN博客>
- 模塊參考代碼介紹
sbit Trig = P1^5; //發(fā)生超聲波
sbit Echo = P1^6; //接收超聲波
void Timer1Init() // @11.0592MHz
{
TMOD &= 0x0F; //設置定時器模式 //選擇定時器1
TMOD |= 0x10; //與運算,可以參考我另一篇博客(下面會介紹),看不懂也沒關系,直接C、V就好
TL1 = 0x00; //設置定時初始值
TH1 = 0x00; //設置定時初始值
//不著急開始計數(shù),寄存器的操作在后面 getDis( )函數(shù)
}
void startHC() //發(fā)射超聲波
{
Trig = 0; //Trig 硬件層面接好后,軟件 sbit 了 一個引腳后,就可以直接賦值;
Trig = 1;
Delay10us(); //延時10us,//前面介紹過,直接copy
Trig = 0;
}
float getDis() //獲得距離 //這里是難點,根據(jù)Echo信號的變化來獲取距離
{
float TIME;//時間
TL1 = 0x00; //設置定時初始值
TH1 = 0x00; //設置定時初始值
startHC(); //準備啟動
while(Echo==0); //等待高電平,跳出循環(huán)
TR1 = 1;
while(Echo==1);//等待低電平,跳出循環(huán)
TR1 = 0;
TIME = (TH1 * 256 + TL1)* 1.085; //us
//340m/s == 340 00cm/1000ms == 34cm/ms == 0.034cm/us == 0.017cm/us
//計數(shù)器的計數(shù)一次最大的時間是71ms,根據(jù)公式可以知道,一次計數(shù),超聲波最遠可以傳播12m
return TIME * 0.017; //最大12m來回,器件HC-SR04說明書的測量距離是 2cm-4m;
}
超聲波測距模塊就這么一些,在后面我們會在垃圾桶上裝一共這樣的模塊,來檢查我們的的手離垃圾桶的距離,通過距離來控制下面我們要講的舵機,通過舵機控制垃圾桶的開關。
2.3 舵機模塊
我使用的是SG90
網(wǎng)上都可以買的到的
-
參考接線
-
三個引腳VCC接 5V,GND 接地。舵機需要的電壓大一點;
-
PWM信號腳 隨便接沒有被占用的引腳,我接的是 P1.1;
sbit sg90_con = P1^1; //舵機
-
-
怎么控制舵機呢?
通過PWM信號來控制
-
PWM波的頻率不能太高,大約50HZ,即周期=1/頻率=1/50=0.02s,20ms左右
0.5ms-------------0度; 2.5% 占空比
1.0ms------------45度; 5.0% 占空比
1.5ms------------90度; 7.5% 占空比
2.0ms-----------135度; 10.0% 占空比
2.5ms-----------180度; 12.5% 占空比
-
占空比:占空比指的是在一個周期中,高電平狀態(tài)占整個周期的百分比。
給PWM信號引腳 不同頻率的脈沖,便可以調控PWM的占空比;
我們設置20ms為一個周期,0.5ms 為最小單元,定義標識符
int cnt
來計數(shù),沒過0.5ms,計數(shù)加一cnt++
;這樣一來,我們就可以通過標識符來方便的控制舵機旋轉角度;
-
模塊參考代碼介紹
sbit sg90_con = P1^1; //舵機 int jd,jd_bak; //0.5的倍數(shù) //用jd,和jd_bak 標識符來控制舵機旋轉角度,jd指的是(角度),jd_bak指的是(之前的角度) //jd_bak的設置,是為了讓使各各模塊結合在一起后,舵機更加穩(wěn)定所做出的操作; int cnt; //計數(shù) void Time0Init() //定時器0來配合舵機PWM操作 @11.0592MHz { //最小時間單元0.5ms(人為設置的) //1. 配置定時器0工作模式位16位計時 TMOD &= 0xF0; //設置定時器模式 //選擇定時器1 TMOD |= 0x01; //2. 給初值,定一個0.5出來 TL0=0x33; TH0=0xFE; //3. 開始計時 TR0 = 1; TF0 = 0; //4. 打開定時器0中斷 ET0 = 1; //5. 打開總中斷EA EA = 1; } void sg90_0_Init() //初始化舵機 { jd = 1; //初始角度是0度(使舵機恢復原始狀態(tài)),0.5ms,溢出1就是0.5ms,高電平 cnt = 0; sg90_con = 1;//一開始從高電平開始 } void Time0Handler() interrupt 1 //舵機 定時器0-中斷 { cnt++; //統(tǒng)計爆表的次數(shù). cnt=1的時候,報表了1 //重新給初值,定時器復位; TL0=0x33; TH0=0xFE; //控制PWM波 if(cnt < jd) //jd是全局變量,比較方便 { sg90_con = 1;//控制舵機PWM信號的高低電平 } else { sg90_con = 0; } if(cnt == 40){//爆表40次,經(jīng)過了20ms cnt = 0; //40 * 0.5ms = 20ms sg90_con = 1; } }
2.4 震動傳感器模塊
我用的是SW-18010P
-
引腳介紹
- VCC 和 GND 就不說了,當不震動時,AO 口輸出高電平;當產品震動時,AO口輸出低電平;DO口在這里不用;
- 我們可以用四角螺絲刀條件傳感器的靈敏度;當傳感器觸發(fā)后,開關信號指示燈就會亮起。
-
參考接線
-
AO口可以,隨便接沒有被占用的引腳,我是將AO口接在P3.2上
sbit vibrate = P3^2;
-
-
為了使程序更加穩(wěn)定,防高靈敏度誤觸影響程序運行,我們使用外部中斷0,來對震動傳感器的觸發(fā)進行操作
-
模塊參考代碼介紹
int make_vibrate = 0; //震動標志位(全局)
void EX0_Init() //外部中斷初始化
{
//EA = 1;//因為前面以及打開過 EA 中斷總開關了,我們這邊就把他省略
EX0 = 1; //打開外部中斷0 開關
IT0 = 0; //IT0 = 0時 低電平觸發(fā)
//IT = 1 的話就是下降言觸發(fā)
}
void Ex0_Handler() interrupt 0 //震動傳感器,外部中斷0
{
make_vibrate = 1; //震動 標志位改變,進而影響震動傳感器的狀態(tài);
}
2.5 蜂鳴器模塊
我使用的是低電平觸發(fā)的蜂鳴器,都大差不差,隨便到某寶買就行。
-
接線參考
-
VCC GND就不說了,I/O口,隨便接沒有被占用的引腳,我將 I/O 接在了P2.3
sbit beep = P2^3; // 蜂鳴器 開蓋就響
-
蜂鳴器比較簡單;
接下來我們把上述各種器件整合,寫開蓋函數(shù),關蓋函數(shù),和main函數(shù);
3.開關蓋函數(shù)和main
3.1 開關蓋函數(shù)
直接上代碼
void openDustbin() //開蓋
{
jd = 3; //90度 1.5ms高電平;根據(jù)前面講得,20ms里面,1.5ms高電平,舵機轉90度
if(jd_bak != jd)//當當前設置的角度標志位,與前一個角度標志位不一樣時,執(zhí)行給語句;
//目的解決物體一直放在垃圾桶前面時,舵機抽搐的問題。
{
cnt = 0; //抽搐的原因
beep = 0; //蜂鳴器響一下
Delay150ms(); //響150ms
beep = 1; //蜂鳴器停
Delay1000ms(); //延時1s,開關也要時間
jd_bak = jd;//這一次的角度,變成了下一次的上一次。
}
}
void closeDustbin() //關蓋
{
jd = 1; //0度,歸位
cnt = 0; //計數(shù)的標志位置零
jd_bak = jd;//這一次的角度,變成了下一次的上一次。
Delay150ms();
}
再補幾個延時函數(shù)
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 8;
j = 1;
k = 243;
do{
do{
while (--k);
} while (--j);
} while (--i);
}
void Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do{
do{
while (--k);
} while (--j);
} while (--i);
}
3.2 main函數(shù)
下面我們寫最主要的代碼,來調用前面的函數(shù);
- 調節(jié)距離函數(shù)
void setDis(float distance) //設置想要的距離,物體到達傳感器多長距離,觸發(fā)開蓋
{
Delay150ms();//這邊加一個延時,目的是怕當物體一直在超聲波傳感器前面時,傳感器啟動頻繁,導致產生過載;讓傳感器休息一下;
if(Dis < distance || key1 == 0 || make_vibrate == 1)//小于10cm 或者按下按鍵key1 開蓋
{
led1_ON();//點燈led1,關燈led2,標志,開蓋成功!
openDustbin();//開蓋函數(shù)
make_vibrate = 0; //震動傳感器的標志位置零,重新開始
}
else
{
led2_ON();//點燈led2,關燈led1,標志,關蓋
closeDustbin(); //關蓋函數(shù)
//make_vibrate = 0;
}
}
- 在
main()
函數(shù)中調用這個函數(shù),通過傳參便捷調節(jié)觸發(fā)距離; -
main()
函數(shù)
int main()
{
Time0Init(); //初始化定時器
Timer1Init();
EX0_Init(); //外部中斷 震動傳感器
sg90_0_Init(); //舵機的初始化
while(1)
{
Dis = getDis();
setDis(10); //設置開蓋距離參數(shù),
}
}
我們用到了定時器0 控制制舵機PWM,定時器1 計算超聲波傳播路徑,外部中斷0 結合了震動傳感器文章來源:http://www.zghlxwxcb.cn/news/detail-794412.html
4.代碼整合
#include<reg51.h>
sbit led1 = P3^7; //固定的口
sbit led2 = P3^6; //固定的口
sbit key1 = P2^1; //固定的口
sbit Trig = P1^5; //發(fā)生超聲波
sbit Echo = P1^6; //接收超聲波
sbit sg90_con = P1^1; //舵機
sbit vibrate = P3^2;
sbit beep = P2^3; // 蜂鳴器 開蓋就響
int jd,jd_bak; //0.5的倍數(shù)
int cnt; //計數(shù)
int make_vibrate = 0;
float Dis; //超聲波距離
void Delay10us() //@11.0592MHz //發(fā)射超聲波最短時間
{
unsigned char i;
i = 2;
while (--i);
}
void Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do{
do{
while (--k);
} while (--j);
} while (--i);
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Timer1Init() //10微秒 //10us 超聲波 @11.0592MHz
{
TMOD &= 0x0F; //設置定時器模式 //選擇定時器1
TMOD |= 0x10;
TL1 = 0x00; //設置定時初始值
TH1 = 0x00; //設置定時初始值
//不著急開始計數(shù)
}
void Time0Init() //舵機定時器0 0.5ms @11.0592MHz
{
//1. 配置定時器0工作模式位16位計時
TMOD &= 0xF0; //設置定時器模式 //選擇定時器1
TMOD |= 0x01;
//2. 給初值,定一個0.5出來
TL0=0x33;
TH0=0xFE;
//3. 開始計時
TR0 = 1;
TF0 = 0;
//4. 打開定時器0中斷
ET0 = 1;
//5. 打開總中斷EA
EA = 1;
}
void sg90_0_Init()
{
jd = 1; //初始角度是0度,0.5ms,溢出1就是0.5,高電平
cnt = 0;
sg90_con = 1;//一開始從高電平開始
}
void EX0_Init()
{
EX0 = 1;
IT0 = 0; //低電平觸發(fā)
//1的話就是下降言觸發(fā)
}
void startHC() //發(fā)射超聲波
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
float getDis() //獲得距離
{
float TIME;//時間
TL1 = 0x00; //設置定時初始值
TH1 = 0x00; //設置定時初始值
startHC(); //準備啟動
while(Echo==0); //等待高電平,跳出循環(huán)
TR1 = 1;
while(Echo==1);//等待低電平,跳出循環(huán)
TR1 = 0;
TIME = (TH1 * 256 + TL1)* 1.085; //us
//340m/s = 340 00cm/1000ms == 34cm/ms == 0.034cm/us == 0.017cm/us
return TIME * 0.017;//最大12m來回,器件HC是 2cm-4m
}
void led1_ON() //亮led1
{
led1 = 1;
led2 = 0;
}
void led2_ON() //亮led2
{
led1 = 0;
led2 = 1;
}
void openDustbin() //開蓋
{
jd = 3; //90度 1.5ms高電平
if(jd_bak != jd)
{
cnt = 0; //抽搐的原因
beep = 0;
Delay150ms();
beep = 1;
Delay1000ms();
jd_bak = jd;
}
}
void closeDustbin() //關蓋
{
jd = 1; //0度
cnt = 0;
jd_bak = jd;
Delay150ms();
}
void setDis(float distance) //設置距離
{
Delay150ms();
if(Dis < distance || key1 == 0 || make_vibrate == 1)//小于10cm 或者按下按鍵key1 開蓋
{
led1_ON();
openDustbin();
make_vibrate = 0;
}
else
{
led2_ON();
closeDustbin();
//make_vibrate = 0;
}
}
int main()
{
Time0Init(); //初始化定時器
Timer1Init();
EX0_Init(); //外部中斷 震動傳感器
sg90_0_Init(); //舵機的初始化
while(1)
{
Dis = getDis();
setDis(10); //設置開蓋距離參數(shù),
}
}
void Time0Handler() interrupt 1 //舵機 _中斷
{
cnt++; //統(tǒng)計爆表的次數(shù). cnt=1的時候,報表了1
//重新給初值
TL0=0x33;
TH0=0xFE;
//控制PWM波
if(cnt < jd){
sg90_con = 1;
}else
{
sg90_con = 0;
}
if(cnt == 40){//爆表40次,經(jīng)過了20ms
cnt = 0; //當100次表示1s,重新讓cnt從0開始,計算下一次的1s
sg90_con = 1;
}
}
void Ex0_Handler() interrupt 0 //震動傳感器,外部中斷0
{
make_vibrate = 1; //震動 標志位改變
}
主要還是大家要注意接線,代碼模塊還是比較簡單的;文章來源地址http://www.zghlxwxcb.cn/news/detail-794412.html
到了這里,關于智能垃圾桶項目【課程設計】【全套開源】的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!