標籤:
自己設計並製作了一個自動溫度控制系統
一、課題任務
設計並製作一個水溫自動控制系統,控制對象為1升淨水,容器為搪瓷器皿。水溫可以在一定範圍內由人工設定,並能在環境溫度降低時實現自動控制,以保持設定的溫度基本不變。
1.基本要求
(1)溫度定義範圍為40~90℃,最小設定分度為1℃。
(2)具有溫度顯示功能,解析度為0.1℃,顯示的絕對誤差小於1℃。
(3)當溫度達到某一設定值並穩定後,水溫的波動控制在±2℃以內。要求溫度調控達到穩定點時,必須給出聲或光提示訊號。
(4)環境溫度降低時(例如用電風扇降溫)水溫的波動控制在±2℃以內。
2.發揮部分
(1)當溫度達到某一設定值並穩定後,水溫的波動控制在±1℃以內。要求溫度調控達到穩定點時,必須給出聲或光提示訊號。
(2)採用適當的控制方法,當設定溫度突變(由35℃提高到45℃)時,在超調量不超過2℃的前提下,盡量減小系統的調節時間,並要求溫度控制的靜態誤差≤0.5℃。
(3)在設定溫度發生突變(由35℃提高到45℃)時,自動列印水溫隨時間變化的曲線。
(4)其他。
二、 方案比較與選擇
根據要求,系統至少有以下功能模組構成:
1. 溫度測量模組:
溫度測量是本系統的核心問題之一。基於單片機的溫度測量,溫度感應器毫無疑問是最佳的選擇,常見的有數字式溫度感應器和類比溫度感應器。
前者以DS18B20為代表。其採用單匯流排的介面方式與微處理器串連。僅需要一條匯流排即可實現微處理器的雙向通訊。單匯流排具有經濟性好,抗幹擾能力強,適合於惡劣環境的現場溫度測量,使用方便等優點,使使用者可輕鬆地組建感應器網路。測量溫度範圍寬,測量精度高 DS18B20 的測量範圍為 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C 範圍內,精度為 ± 0.5°C 。持多點組網功能 多個 DS18B20 可以並聯在惟一的單線上,實現多點測溫。供電方式靈活 ,DS18B20 可以通過內部寄生電路從資料線上擷取電源。因此,當資料線上的時序滿足一定的要求時,可以不接外部電源,從而使系統結構更趨簡單,可靠性更高。測量參數可配置 DS18B20 的測量解析度可通過程式設定 9~12 位。類比溫度感應器,以Pt100為代表。
DS18B20 具有體積更小、適用電壓更寬、更經濟、可選更小的封裝方式,更寬的電壓適用範圍,適合於構建自己的經濟的測溫系統,因此也就被設計者們所青睞。
2. 溫度顯示模組:
由於溫度精度以及即時性的要求,需要多位動態顯示。常見的顯示方式有兩種,一種是數位管,另一種是液晶螢幕。動態顯示是一種最常見的數位管多位顯示方法,應用非常廣泛。所有數位管段選都串連在一起的時候,動態顯示是多個數位管,交替顯示,利用人的視覺暫停作用使人看到多個數位管同時顯示的效果。就像我們看的電影是有一幀一幀的畫面顯示的,當速度夠快的時候我們看到它就是動態。當我們顯示數位管的速度夠快的時候,也就可以看到它們是同時顯示了。
1602液晶也叫1602字元型液晶,它是一種專門用來顯示字母、數字、符號的點陣型液晶模組。它是由若干個5x7或者5x11的點陣字元位組成,每個點陣字元位都可以用顯示一個字元,每位之間有一個點距的間隔,每行之間也有間隔,起到了字元間距和行間距的作用。
3. 溫度設定模組:
輕觸開關是一種電子開關,使用時,輕輕按開關按鈕就可使開關接通,當鬆開手時,開關斷開。使用3個開關,分別實現,功能轉換,設定+,設定-,即可完成所有設定操作。
4. 溫度控制模組:
控制核心選擇STC89C52。STC89C52是STC公司生產的一種低功耗、高效能CMOS8位微控制器,具有 8K 在系統可程式化Flash儲存空間。STC89C52使用經典的MCS-51核心,指令代碼完全相容傳統8051,還做了很多的改進使得晶片具有傳統51單片機不具備的功能。在單晶片上,擁有靈巧的8 位CPU 和在系統可程式化Flash,使得STC89C52為眾多嵌入式控制應用系統提供高靈活、超有效解決方案。 具有以下標準功能: 8k位元組Flash,512位元組RAM, 32 位I/O 口線,看門狗定時器,內建4KB EEPROM,MAX810複位電路,3個16 位定時器/計數器,4個外部中斷,一個7向量4級中斷結構(相容傳統51的5向量2級中斷結構),全雙工系統串列口。另外 STC89X52 可降至0Hz 靜態邏輯操作,支援2種軟體可選擇省電模式。空閑模式下,CPU 停止工作,允許RAM、定時器/計數器、串口、中斷繼續工作。掉電保護方式下,RAM內容被儲存,振蕩器被凍結,單片機一切工作停止,直到下一個中斷或硬體複位為止。最高運作頻率35MHz,6T/12T可選。能夠滿足本系統的需求。
外電路的控制,通過繼電器來完成。選用HK4100F型號,額定電壓5V的電磁式繼電器。其有如下特點。
降溫模組,由於本系統打算將加熱電路與繼電器的常開觸點,即一般情況下加熱裝置繼電器以及繼電器均斷開,因此理論上當溫度過高時,繼電器斷開,完全可以採用自然降溫使得溫度達到正常。為了使效果更好,可增加風扇或者空調裝置進行降溫。
5. 聲/光警示模組:
選用綠色和紅色LED分別作為外溫度在設定範圍內和之外的訊號標誌,對於後者可以添加蜂鳴器或者電鈴作為警示裝置,由於可能會擾民,因此添加開關,可手動控制其是否警報。
三、 電路設計
本系統先在PROTUES上進行電路初步設計以及模擬實驗。根據以上分析,設計電路如下。
主要有以下幾個部分
1. 單片機最小系統
2. 溫度顯示
3. 加熱和繼電器電路
4. 溫度擷取和設定
DS16B20 功能按鍵
5. 警示和降溫
四、 程式設計
五、 測試方案
通過KEIL編譯通過,然後在PROTUES進行模擬,測試系統運行效果。為了提高系統穩定性和可靠性,選擇在開發板上進行實際測試以及PC上的程式調試。最後硬體平台搭建,通過選擇合適規格的零件,焊接從而完成整個系統的預定功能。
六、
系統調試
通過最佳化單片機與LCD1602的介面選擇,解決了之前,由於沒有加上拉電阻導致無法顯示的問題。調整了函數結構,使得溫度即時更新,提高了系統的靈敏度和即時性。模擬效果,如所示。
七、 資料測試與處理
為了進一步與實際接近,在普中EM3_V3.0型號開發板上進行了實驗。成功實現以下功能:
(1)溫度定義範圍為0~125℃,最小設定分度為1℃。比要求的40~90℃更寬。
(2)具有溫度顯示功能,解析度為0.01℃,顯示的絕對誤差小於1℃。比要求的0.1℃提升一個數量級,絕對誤差小於要求的1℃。
(3)當溫度達到某一設定值並穩定後,水溫的波動控制在±X℃(X為0-9之間的整數,可調)以內。比要求的±2℃更靈活且更具有實用性。
(4)要求溫度調控達到穩定點時,給出光提示訊號。
(5)環境溫度不在定義範圍內時,,反應及時且快速。溫度過高,觸發器斷開,停止加熱,自然降溫,並且可以調用風扇進行降溫。溫度過低,觸發器閉合加熱,直到其達到指定溫度。
沒有實現以下功能:
(6)當設定溫度突變(由35℃提高到45℃)時,在超調量不超過2℃的前提下,盡量減小系統的調節時間,並要求溫度控制的靜態誤差≤0.5℃。
(7)在設定溫度發生突變(由35℃提高到45℃)時,自動列印水溫隨時間變化的曲線。
八、 總結
本水溫自動控制系統,較好地實現了人工設定溫度,即時顯示溫度,自動控制溫度的功能,並且結合實際應用,對一些地方進行了改進,例如提高了溫度顯示的精確度,另外實現了對“最高溫度”、“最低溫度”,“誤差範圍”的調節,使測定的範圍和波動範圍更加靈活,更具有實際運用價值。
但由於時間和能力有限,還有發揮部分一部分功能沒有實現。軟體模擬上,在PROTUES進行的模擬,效果穩定。硬體上,實現了基於普中EM3_V3開發板的運行和調試,效果穩定,此外還單獨搭建了實驗裝置平台,很不幸在多次努力嘗試之後,依然存在一些顯示問題,沒能比開發板上更好的運行。
九、 參考文獻
[1]HK4100F繼電器資料
[2]普中EM3_V3開發板資料
[3]51單片機C語言應用開發技術大全(第二版).人民郵電出版社.
十、 附錄:
A、設計電路圖(原理圖、PCB圖)
B、程式(要求有文字、注釋)
由於相關程式較長,受版面限制,故上傳至
C、相關作品圖片
#include<reg51.h>#include<intrins.h>#define uint unsigned int #define uchar unsigned char/*LCD1602顯示模組*//*用於PROTUES模擬#define LCD1602_DATAPINS P2sbit LCD1602_RS=P3^0;sbit LCD1602_RW=P3^1; sbit LCD1602_E=P3^2; */#define LCD1602_DATAPINS P0sbit LCD1602_RS=P2^6;sbit LCD1602_RW=P2^5; sbit LCD1602_E=P2^7;/*按鍵調節模組*/sbit k1=P1^1;//功能鍵sbit k2=P1^2;//加sbit k3=P1^3;//減 void keyscan();void key1_switch();void key2_add();void key3_minus();uchar k_num;void LCD1602_SetTemp(uchar add,uchar dat);uchar high=90,low=10,set_t=30,set_d=2;//這裡的資料類型可能有問題!!/*其他模組介面*/sbit DSPORT=P3^7; //溫度感應器單匯流排端sbit SPEAKER=P1^5;//蜂鳴器sbit RELAY=P1^4;//繼電器sbit COOLER=P1^7;//降溫裝置/*LCD1602相關函數*/void Delay1us(uint a);void LCD1602_WriteCom(uchar com);//LCD1602寫入8位命令子函數void LCD1602_WriteData(uchar dat);void LCD1602_Init();//LCD1602初始化子程式 void LCD1602_ShowTemp(int temp);/*DS18B20溫度感應器相關函數*/void Delay15us(uchar aa);uchar Ds18b20Init();void Ds18b20WriteByte(uchar dat);uchar Ds18b20ReadByte();void Ds18b20SwitchTemp();int Ds18b20ReadTemp();float temp_max=125.00,temp_min=-55.00;uchar ii=0,jj=0,kk=0;uchar words_h[2]={"H="};uchar words_l[2]={"L="};uchar words_s[4]={"Set="};void Sound();void Temp_control(int temp);uchar count=0;//用來解決主程式執行太快,按鍵游標來不及顯示的問題void Temp_control(int temp){unsigned int kk=400;uchar set_h,set_l;set_h=set_t+set_d;set_l=set_t-set_d;if (temp<=set_h&&temp>=set_l) //設定溫度範圍之內{ RELAY = 0; //繼電器斷開 COOLER=0;//風扇關閉}else {TR0=0;while (kk--){Sound();}RELAY = 1; //繼電器開啟,外電路(常開觸電)閉合加熱if (temp>=set_h)//溫度過高{RELAY = 0; //繼電器斷開 COOLER=1;//開啟}TR0=1;}}/*其他模組相關函數*/void Sound()//蜂鳴器{ SPEAKER=1;Delay15us(40);SPEAKER=0;Delay15us(40);}void Delay1us(uint a){uint b,c;for(c=a;c>0;c--)for(b=110;b>0;b--);}void LCD1602_WriteCom(uchar com) //寫入命令{LCD1602_E=0;LCD1602_RS=0;//0就寫指令LCD1602_RW=0; //0就是寫LCD1602_DATAPINS=com;Delay1us(10);LCD1602_E=1;Delay1us(10);LCD1602_E=0;} void LCD1602_WriteData(uchar dat)//寫入資料{LCD1602_E=0;LCD1602_RS=1;LCD1602_RW=0;LCD1602_DATAPINS=dat;Delay1us(10);LCD1602_E=1;Delay1us(10);LCD1602_E=0;}void LCD1602_Init() //LCD初始化子程式{//uint num; LCD1602_WriteCom(0x38); //開顯示LCD1602_WriteCom(0x0f); //開顯示不顯示光線標LCD1602_WriteCom(0x06); //寫一個指標加1LCD1602_WriteCom(0x01); //清屏LCD1602_WriteCom(0x80); //設定資料指標起點LCD1602_WriteCom(0x80+0x0B);for (ii=0;ii<2;ii++){LCD1602_WriteData(words_h[ii]);}LCD1602_SetTemp(13,high);LCD1602_WriteCom(0x80+0x40);for (kk=0;kk<4;kk++){LCD1602_WriteData(words_s[kk]);}LCD1602_SetTemp(4+0x40,set_t);LCD1602_WriteCom(0x80+0x47);LCD1602_WriteData(0x23); //顯示加號或減號LCD1602_WriteCom(0x80+0x48);LCD1602_WriteData(0x30+set_d);LCD1602_WriteCom(0x80+0x4B);for (jj=0;jj<2;jj++){LCD1602_WriteData(words_l[jj]);}LCD1602_SetTemp(13+0x40,low);TMOD=0X01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1;//總中斷ET0=1;TR0=1; }void Delay15us(uchar aa){do{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();aa--;}while(aa);}/*DS18B20溫度感應器相關函數*/uchar Ds18b20Init(){uchar flag;DSPORT=0; //匯流排拉低Delay15us(40);//延時480~960usDSPORT=1;Delay15us(2);flag=DSPORT;Delay15us(6);//Ds18b20發出應答訊號,延時60~240usDelay15us(25);return flag;} uchar Ds18b20ReadByte(){uchar byte,bi; uint i;for (i=0;i<8;i++){DSPORT=0;_nop_();_nop_();_nop_();_nop_(); //保持低電平至少1us,但不能低於15usDSPORT=1;bi=DSPORT;//讀取一位元據,迴圈8次為一個位元組byte = (byte >> 1) | (bi << 7);//將byte左移一位,然後與上右移7位後的bi,8次合成一個位元組Delay15us(4);}return byte;} void Ds18b20WriteByte(uchar dat){ uint i; for (i=0;i<8;i++) { DSPORT=0;_nop_();DSPORT=dat&0x01;//一位一位得讀,從最低位開始Delay15us(5);DSPORT=1;_nop_();dat>>=1; }} void Ds18b20SwitchTemp(){Ds18b20Init();Delay15us(7);Ds18b20WriteByte(0xcc);//跳過ROM指令Ds18b20WriteByte(0x44);//啟動溫度轉換指令} int Ds18b20ReadTemp(){int temp=0;uchar temp_h,temp_l;Ds18b20SwitchTemp();Ds18b20Init();Delay1us(1);Ds18b20WriteByte(0xcc); //跳過ROM操作命令Ds18b20WriteByte(0xbe); //發送讀取溫度命令temp_l = Ds18b20ReadByte();//讀取溫度值共16位,先讀低位元組temp_h = Ds18b20ReadByte();temp= temp_h;temp<<=8;temp|= temp_l;return temp;} void LCD1602_ShowTemp(int temp){float tt;uchar show[5]={0,0,0,0,0};if (temp<0)//溫度為負{LCD1602_WriteCom(0x80);//寫地址 80表示初始地址 LCD1602_WriteData('-'); //顯示負temp=temp-1;temp=~temp;tt=temp;temp=tt*0.0625*100;}else//溫度為正{LCD1602_WriteCom(0x80);//寫地址 80表示初始地址 LCD1602_WriteData('+'); //顯示正tt=temp;temp=tt*0.0625*100;}show[0]=temp/10000;show[1]=temp%10000/1000;show[2]=temp%1000/100;show[3]=temp%100/10;show[4]=temp%10;LCD1602_WriteCom(0x82);LCD1602_WriteData('0'+show[0]); //百位 LCD1602_WriteCom(0x83);LCD1602_WriteData('0'+show[1]); //十位 LCD1602_WriteCom(0x84);LCD1602_WriteData('0'+show[2]); //個位 LCD1602_WriteCom(0x85);LCD1602_WriteData('.');LCD1602_WriteCom(0x86);LCD1602_WriteData('0'+show[3]); //十分位LCD1602_WriteCom(0x87);LCD1602_WriteData('0'+show[4]); //百分位LCD1602_WriteCom(0x88);LCD1602_WriteData(0xdf);LCD1602_WriteCom(0x89);LCD1602_WriteData('C');LCD1602_WriteCom(0x0C);temp=temp/100;Temp_control(temp);}void key1_switch()//功能切換{uchar set_h,set_l;set_h=set_t+set_d;set_l=set_t-set_d;//k1鍵指令if(k1==0){Delay1us(10);//延時消抖if(k1==0){k_num++;while(!k1);//按鍵沒有鬆開if(k_num==1){TR0=0; //關掉計時器,使得游標得以顯示LCD1602_WriteCom(0x80+0x46);LCD1602_WriteCom(0x0f);Delay15us(6);}if(k_num==2){LCD1602_WriteCom(0x80+0x48);LCD1602_WriteCom(0x0f);Delay15us(6);}if(k_num==3){LCD1602_WriteCom(0x80+0x0F);LCD1602_WriteCom(0x0f);Delay15us(6);}if(k_num==4){LCD1602_WriteCom(0x80+0x4F);LCD1602_WriteCom(0x0f);Delay15us(6);}if(k_num==5){k_num=0;LCD1602_WriteCom(0x0C);//游標不顯示if (high<low) //用來default{ high=90; low=40;//恢複預設值} if(set_h>high||set_l<low) { high=90; low=10;//恢複預設值 set_t=30; set_d=2;//恢複預設值 } TR0=1;//計時器重新開啟,使得螢幕得以重新整理}}}}void key2_add()//功能加{if(k_num!=0){if(k2==0){Delay1us(5);if(k2==0){while(!k2);if(k_num==1){set_t++;if (set_t>=high) set_t=high; LCD1602_SetTemp(4+0x40,set_t); LCD1602_WriteCom(0x80+0x46);}if(k_num==2){set_d++;if (set_d>9) set_d=0;LCD1602_WriteCom(0x80+0x48);LCD1602_WriteData(0x30+set_d);LCD1602_WriteCom(0x80+0x48);}if(k_num==3){high++;if (high>=temp_max) high=0; LCD1602_SetTemp(13,high); LCD1602_WriteCom(0x80+0x0F);// LCD1602_WriteCom(0x80+0x40+8);}if(k_num==4){low++;if (low>=temp_max) low=0; LCD1602_SetTemp(13+0x40,low); LCD1602_WriteCom(0x80+0x4F);// LCD1602_WriteCom(0x80+0x40+13);}}}}}void key3_minus()//功能減{if(k_num!=0){if(k3==0){Delay1us(5);if(k3==0){while(!k3);if(k_num==1){if (set_t<=0)set_t=high+1;set_t--; LCD1602_SetTemp(4+0x40,set_t); LCD1602_WriteCom(0x80+0x46);}if(k_num==2){if (set_d<=0) set_d=10;set_d--;LCD1602_WriteCom(0x80+0x48);LCD1602_WriteData(0x30+set_d);LCD1602_WriteCom(0x80+0x48);}if(k_num==3){if (high<0) high=temp_max;high--; LCD1602_SetTemp(13,high); LCD1602_WriteCom(0x80+0x0F);// LCD1602_WriteCom(0x80+0x40+8);}if(k_num==4){if (low<=0)low=high;low--; LCD1602_SetTemp(13+0x40,low); LCD1602_WriteCom(0x80+0x4F);// LCD1602_WriteCom(0x80+0x40+16);}}}}}void keyscan()//按鍵檢測{ key1_switch(); key2_add(); key3_minus();}void LCD1602_SetTemp(uchar add,uchar dat)//數位管制定位置顯示{ uchar head,body,end; head=dat/100; body=dat%100/10; end=dat%10; LCD1602_WriteCom(0x80+add); LCD1602_WriteData(0x30+head); LCD1602_WriteData(0x30+body); LCD1602_WriteData(0x30+end);}void main(){LCD1602_Init();while(1){ keyscan(); }}void timer0() interrupt 1{ TH0=(65536-50000)/256;TL0=(65536-50000)%256;count++;if (count==10)//讓溫度每0.5s重新整理一次{count=0; LCD1602_ShowTemp(Ds18b20ReadTemp());}}
自己設計並製作了一個自動溫度控制系統