我的單片機(jī)智能溫控風(fēng)扇制作,優(yōu)點(diǎn)是比較詳細(xì)(尤其是代碼的解釋),可能對論壇同好來說不值一提,不管怎樣,分享一下。我上傳了c文件、hex、還有uvproj和pdsprj的仿真。還有doc和pdf。
最后也做出來了實(shí)際電路。
第一次發(fā)帖,不知道說啥,發(fā)幾張圖吧。
1.完成電路原理圖的設(shè)計(jì):本設(shè)計(jì)以STC89C52 單片機(jī)作為控制核心,采用高精度溫度傳感器DS18B20 檢測環(huán)境溫度,把經(jīng)過ADC 轉(zhuǎn)換模塊輸出的數(shù)字溫度信號發(fā)送給STC89C52 單片機(jī)進(jìn)行處理,在LCD 顯示屏上顯示當(dāng)前環(huán)境溫度值和用按鍵預(yù)設(shè)的每個檔位溫度值,并采用PWM 脈寬調(diào)制方式改變直流風(fēng)扇電機(jī)的轉(zhuǎn)速。系統(tǒng)結(jié)構(gòu)如圖 1系統(tǒng)結(jié)構(gòu)所示。 圖 1系統(tǒng)結(jié)構(gòu)
2.用Proteus軟件畫電路原理圖,設(shè)計(jì)相關(guān)硬件,并通過Keil編輯C語言程序,并將編譯后生成的HEX文件放在所畫的硬件電路中仿真。 3.仿真成功后,焊接與調(diào)試電路板。 4.安裝驅(qū)動,將程序燒錄至單片機(jī),觀察并調(diào)試直至達(dá)到設(shè)計(jì)要求。 二、設(shè)計(jì)要求1.讀取DB18B20溫度傳感器數(shù)據(jù) 2.風(fēng)扇根據(jù)溫度變化自動調(diào)節(jié)轉(zhuǎn)速檔位:當(dāng)前溫度在小于下限為0檔;在上下 限之間為1檔,大于上限為2檔。 3. 按一次K1進(jìn)入溫度上限設(shè)置,K2,K3設(shè)置溫度的增加或者減少;按兩次K1進(jìn)入溫度下限設(shè)置,K2,K3設(shè)置溫度的增加或減少;按三次K1退出設(shè)置模式。 4. 1602顯示屏顯示當(dāng)前溫度、設(shè)置溫度的上下限,風(fēng)扇當(dāng)前檔位,進(jìn)入設(shè)置模式后在相應(yīng)位置用光標(biāo)顯示。 三、設(shè)計(jì)過程(包括設(shè)計(jì)仿真圖)- STC89C52 單片機(jī)最小系統(tǒng)
這張圖顯示了:單片機(jī)最小系統(tǒng)理應(yīng)有的晶振和復(fù)位電路,這芯片里有ROM和RAM,所以也不加入片外的數(shù)據(jù)存儲器和程序存儲器了。 本實(shí)驗(yàn)要用的三個按鈕資源接在了P3.5,P3.6,P3.7口,同時連接時線與接在單片機(jī)外部中斷口INT0之上,這里我用了觸發(fā)中斷,原因就是硬件可以自動清零,而且電平中斷的硬件設(shè)置還是比較麻煩的。(此處靈感來自于單片機(jī)原理與應(yīng)用及C51程序設(shè)計(jì)第三版清華大學(xué)出版社的例題7.9) 電機(jī) P3.3口處,可以看到標(biāo)簽為motorDC;溫度傳感器P3.4,可以看見DSPORT標(biāo)簽。 LCD的數(shù)據(jù)口是P1,可以看見我用總線連接,自動標(biāo)好了D7-D0,對應(yīng)了LCD的8根數(shù)據(jù)線。P2.5,P2.6,P2.7對應(yīng)了LCD的RS,RW,E這三個端口。 
程序主函數(shù)大致意義如下:外部中斷0初始化 液晶初始化 循環(huán)以下: 小燈顯示 液晶顯示 風(fēng)扇轉(zhuǎn)動 讀取溫度 讀取按鈕 計(jì)算擋位 中斷程序: 按鈕設(shè)置
小燈顯示
1.LED0
LED0用來顯示按鈕1也就是設(shè)置按鈕按了幾下:
void led(){
if(flag==0) LED0=0;
if(flag==1) LED0=1;
if(flag==2) {LED0=1;delay(250);LED0=0;delay(250);LED0=1;}}
flag
意義
0
默認(rèn)是0,按鈕沒按,或者已經(jīng)按了3下,小燈泡不亮
1
按了一下設(shè)置按鈕,小燈泡亮,意味進(jìn)入了上限溫度調(diào)整狀態(tài)
2
按了兩下設(shè)置按鈕,小燈泡閃爍,意味進(jìn)入了下限溫度調(diào)整狀態(tài)
2.LED1
void int0() interrupt 0 {
LED1=0;
keySet();
delay(500);
LED1=1;
}
LED1:只要你按了任何一個鍵,意味著進(jìn)入了中斷,LED1都會閃一下

即得到右圖的畫面: 代碼解析: 1. 幾個端口的設(shè)置: #define LCD1602_DATAPINS P1 sbit LCD1602_E=P2^7; sbit LCD1602_RW=P2^6; sbit LCD1602_RS=P2^5; 2.局部變量講解 unsigned char printData[8] = {0,0,':',0,0,0,0,' '}; unsigned char Prompt[4][2]= {{'U','L'},{'L','L'},{'C','T'},{'G','R'}}; 這個就是等一會放8個小塊的字符數(shù)組,前面兩個字符會被Prompt替換。順便一提,這幾個英文字符分別為:上限(Upper Limit)和下限(Lower Limit),當(dāng)前溫度(Current Temperature),擋位(GeaR)。第3-7個字符等一會會被LcdDisplay() 召喚calNumPrint()給替換掉。 3.寫命令/數(shù)據(jù)操作 void Lcd1602_WriteCom(uchar com); void Lcd1602_WriteData(uchar dat) ;這兩個得按照這個時序圖來,沒什么好說的,這個是抄廠家給的例程,毫無創(chuàng)新,畢竟對時序不敏感。 5. void calNumPrint(int temp); 這個就是用來填入printData4-7位。 | | if(temp>0)printData[3]='+'; elseprintData[3]='-'; | 判斷溫度的正負(fù),理論上DS18B20 的測量范圍為 -55 ℃ ~+ 125 ℃ | for( i=4; i<7; i++) { dividend=1; for( j=6-i; j>0; j--)dividend*=10; printData[ i]=temp/dividend%10+'0';} | 就是為了根據(jù)所給的溫度填寫4-6位,之所以有dividend和下面的一條for語句是為了安全地(雖然可能沒有必要)確保只截取了一位 | | |
6. void Lcd1602_Init(); 

初始化,main()函數(shù)用的,不加這個你開不了LCD,更別提設(shè)定LCD的種種工作模式細(xì)節(jié)。這個是廠家給的例程,意義注釋有。
7. void LcdDisplay(int temp);

這個自創(chuàng)函數(shù)值得大說特說,1602一共16列2行,每一行放兩個8列1行的小塊。所以用了一個for循環(huán)for( loop=0; loop<4; loop++) 專門循環(huán)放這四個小塊,每一次循環(huán)都得改提示符,然后進(jìn)入選擇根據(jù)當(dāng)前循環(huán)分支語句,loop為0和1是溫度的上下限,調(diào)用calNumPrint函數(shù)算3-7個位置究竟是什么;loop為2得換行了,然后calNumPrint算當(dāng)前的溫度怎么顯示;3時是擋位,不是溫度所以不能調(diào)用calNumPrint,我直接3-5位為空格,第6位直接算擋位顯示即可。最后每輪循環(huán)把算出的printData這一個字節(jié)八位ASCII符號送入LCD1602_WriteData讓LCD顯示即可。這個函數(shù)封裝和調(diào)用精致,沒有多余代碼殘余;缺點(diǎn)也有,有點(diǎn)費(fèi)時間。 電機(jī)的驅(qū)動是由NPN以及PNP兩個不同類型的晶體管組成的復(fù)合管,復(fù)合后可等效為一個NPN晶體管,但是它理想情況下,能夠獲得兩個原本兩個管的乘積的放大倍數(shù),這樣就可以有足夠的電流驅(qū)動集電極之上的直流電機(jī)旋轉(zhuǎn)。
如何根據(jù)擋位來控制單片機(jī)的轉(zhuǎn)動速率?只要單片機(jī)輸出占空比可調(diào)的方波,即PWM信號即可控制電機(jī)兩端的電壓發(fā)生變化,從而實(shí)現(xiàn)電機(jī)轉(zhuǎn)速的控制。占空比越大,所得到的平均電壓也就越大,幅值也就越大;占空比越小,所得到的平均電壓也就越小,幅值也就越小。我們利用軟件延時的方法調(diào)節(jié)占空比,當(dāng)高電平延時時間到的時候,對I/O口電位取反,使變成低電平,再進(jìn)行延時,低電平延時時間到,再進(jìn)行取反使其轉(zhuǎn)化成為高電平,如此循環(huán)得到PWM信號。1.Ds18b20ReadTemp() | | | | | | tml = Ds18b20ReadByte(); tmh = Ds18b20ReadByte(); | | currtemp = tmh; currtemp <<= 8; currtemp |= tml; | | if(currtemp<0) {currtemp=currtemp-1; currtemp=~currtemp; } tp=currtemp; currtemp=tp*0.0625+0.5; | 轉(zhuǎn)化溫度為攝氏度,字節(jié)是溫度的補(bǔ)碼,所以其中正負(fù)有不同的處理,并且四舍五入 |
2.Ds18b20ChangeTemp() | | |
| |
| Ds18b20WriteByte(0xcc);Ds18b20WriteByte(0x44); | | | |
3.uchar Ds18b20Init() 做為從器件的DS18B20在一上電后就一直在檢測總線上是否有480-960微秒的低電平出現(xiàn),如果有,在總線轉(zhuǎn)為高電平后等待15-60微秒后將總線電平拉低60-240微秒做出響應(yīng)存在脈沖,告訴主機(jī)本器件已做好準(zhǔn)備。 | | DSPORT = 0;i = 100;while(i--); | | | 釋放總線變?yōu)楦唠娖剑缘却郎馗械某晒匾唬駝t回零 |
4.void Ds18b20WriteByte(uchar dat): 寫周期最少為60微秒,最長不超過120微秒。寫周期一開始做為主機(jī)先把總線拉低1微秒表示寫周期開始。隨后若主機(jī)想寫0,則將總線置為低電平,若主機(jī)想寫1,則將總線置為高電平,持續(xù)時間最少60微秒直至寫周期結(jié)束,然后釋放總線為高電平至少1微秒給總線恢復(fù) 。而DS18B20則在檢測到總線被拉底后等待15微秒然后從15us到45us開始對總線采樣,在采樣期內(nèi)總線為高電平則為1,若采樣期內(nèi)總線為低電平則為0。 | | 重復(fù)以下步驟八次,因?yàn)橐桶宋?/div> | | | | | | | | | | | | |
5.uchar Ds18b20ReadByte() 讀周期是從主機(jī)把單總線拉低1微秒之后就得釋放單總線為高電平,以讓DS18B20把數(shù)據(jù)傳輸?shù)絾慰偩上。作為從機(jī)DS18B20在檢測到總線被拉低1微秒后,便開始送出數(shù)據(jù),若是要送出0就把總線拉為低電平直到讀周期結(jié)束。若要送出1則釋放總線為高電平。主機(jī)在一開始拉低總線1微秒后釋放總線,然后在包括前面的拉低總線電平1微秒在內(nèi)的15微秒時間內(nèi)完成對總線進(jìn)行采樣檢測,采樣期內(nèi)總線為低電平則確認(rèn)為0。采樣期內(nèi)總線為高電平則確認(rèn)為1。完成一個讀時序過程,至少需要60微秒才能完成。 | | | | | | |
| | | |
| | | 如果這位有輸入,就讀入到byte上,從最低一位開始讀取 | | | | |
6.void Ds18b20ReadTempCom() | | | | Ds18b20WriteByte(0xcc);Ds18b20WriteByte(0xbe); | |
7.各個函數(shù)之間的關(guān)系
1.void keySet() 此函數(shù)中根據(jù)nowkey選擇不同的分支,想見表。其中,default就是nowkey==0,什么也不做,case 1情況下稍后再提,先講一下case 2或者3究竟做了什么:tempLim[0]是溫度上限,tempLim[1]是溫度下限,flag-1只可能為1或者2; value[0]是正一,value[1]是負(fù)一,nowkey-2只可能為1或者2; 所以這里其實(shí)就是改上/下限值與+/-:用flag區(qū)分到底是上/下限值,用nowkey區(qū)分到底是+/-。最后還要檢查上限不小于下限,如果下限比上限還要大,那么讓上限和下限趨同。可以參考下面兩張狀態(tài)表理清思路。 | | | | | flag現(xiàn)為1,此狀態(tài)標(biāo)識進(jìn)入上限模式 | | flag現(xiàn)為2,此狀態(tài)標(biāo)識進(jìn)入下限模式 | | flag現(xiàn)為0,此狀態(tài)標(biāo)識進(jìn)入默認(rèn)模式 |
| keyset()根據(jù)keyscan()做出判斷 | | | | | | 根據(jù)flag、nowkey來改上/下限值與+/- |
2. uchar keyscan()
電路圖可以看到三個按鈕分別接了P3.5,P3.6,P3.7;同時它們線與接入外部中斷零,當(dāng)外部中斷零檢測到低電平時候,中斷調(diào)用keySet(),keySet()又會召喚keyscan(),keyscan()的用處就是返回為nowkey,這是去抖處理后判斷的按下的按鈕符號。 
根據(jù)currtemp和tempLim[0/1]也就是當(dāng)前溫度和上下限值判斷在哪一個擋位,更改全局變量gears以作為結(jié)果:大于等于上限就開二檔;小于上限,大于等于下限開一檔;比下限還小就是零檔。四、設(shè)計(jì)結(jié)果(硬件實(shí)現(xiàn)結(jié)果圖,包括各個部件) 當(dāng)前溫度24度,默認(rèn)的上限和下限設(shè)置是35度和25度,所以當(dāng)前擋位為零檔,電機(jī)當(dāng)前KRPM為正0.02,零檔沒開。D1是暗的因?yàn)闆]有按設(shè)置按鈕。 當(dāng)前溫度被調(diào)整為27度,所以當(dāng)前擋位為一檔,電機(jī)現(xiàn)在走走停停。
按設(shè)置按鈕(第一個按鈕)一次,D1變亮。再按第二個加法按鈕三下,第三個減法按鈕一下,上限加一三次后又減一,結(jié)果如圖UL:+037;擋位隨之變1,風(fēng)扇開始忽慢忽快地轉(zhuǎn)動。按按鈕時候可以觀察到D2因?yàn)檫M(jìn)入中斷而閃動一次,不按時恢復(fù)。 再按設(shè)置按鈕(第一個按鈕)一次,D1開始閃動(圖里面變暗是因?yàn)殪o態(tài)捕捉到的是變暗的時候)。再按第二個加法按鈕一下,第三個減法按鈕三下,下限減一三次后又加一,結(jié)果如圖LL:+023;擋位不變,風(fēng)扇繼續(xù)忽慢忽快地轉(zhuǎn)動。按按鈕時候可以觀察到D2因?yàn)檫M(jìn)入中斷而閃動一次,不按時恢復(fù)。 當(dāng)前溫度被調(diào)整為50度時候,當(dāng)前擋位變?yōu)?檔,電機(jī)全力旋轉(zhuǎn),LCD有相應(yīng)顯示。
在經(jīng)過硬件、軟件的單獨(dú)調(diào)試之后,即可進(jìn)入硬件和軟件聯(lián)合仿真調(diào)試的階段。將下圖中統(tǒng)一發(fā)放的元件進(jìn)行焊接,并用杜邦線按照仿真示意圖連接。
五、實(shí)驗(yàn)器件(器件清單)
1) 萬用板(小) 一塊
2) 7015風(fēng)扇 一個
3) STC89C52RC單片機(jī)最小系統(tǒng)板 一塊
4) 1602液晶顯示屏 一塊
5) 10k電阻 兩個
6) 1k電阻 三個
7) DS18B20 一個
8) 8550三極管 一個
9) 8050三極管 一個
10) 排針 20針
11) 按鍵 三個
12) 杜邦線 25條
13) 焊錫若干
14) DC電源粗頭電源線 一條
15) 排座
16) CH340下載
全部資料51hei下載地址(仿真程序):
溫控風(fēng)扇.zip
(2.06 MB, 下載次數(shù): 255)
2021-3-6 15:50 上傳
點(diǎn)擊文件名下載附件
我的設(shè)計(jì) 下載積分: 黑幣 -5
|