恒溫控制器系統(tǒng)概述
該恒溫控制器系統(tǒng)包含以下幾個(gè)功能:
- 可按鍵設(shè)定溫度
- 可顯示當(dāng)前溫度和用戶設(shè)定溫度
- 有升溫、降溫模塊
- 可最終達(dá)到恒溫
仿真軟件
- Keil 5
- Proteus 8.6
系統(tǒng)設(shè)計(jì)
電路設(shè)計(jì)
恒溫控制系統(tǒng)一共有6個(gè)模塊,分別是主控芯片模塊、按鍵輸入模塊、設(shè)定溫度顯示模塊、當(dāng)前溫度顯示模塊、溫度采集模塊和升溫、降溫模塊。
- 按鍵輸入模塊:該模塊由4*3的矩陣鍵盤和1個(gè)確認(rèn)按鈕構(gòu)成。系統(tǒng)剛開始啟動后,用戶通過矩陣鍵盤輸入想要設(shè)定的溫度(0°~99°),輸入完畢后按下確認(rèn)鍵,然后將該溫度數(shù)據(jù)傳送給主控芯片AT89C51;
- 設(shè)定溫度顯示模塊:該模塊由一個(gè)2位8段LED數(shù)碼管構(gòu)成,主控芯片AT89C51使用P3口控制該數(shù)碼管的段選,使用P2.4和P2.5兩個(gè)端口來控制該數(shù)碼管的位選。主控芯片AT89C51將從矩陣鍵盤得到的設(shè)定溫度信息,通過2位8段LED數(shù)碼管顯示出來;
- 溫度采集模塊;該模塊由一個(gè)DS18B20溫度傳感器構(gòu)成。使用DS18B20溫度傳感器采集當(dāng)前的溫度,并將該溫度信息傳送給主控芯片AT89C51;
- 當(dāng)前溫度顯示模塊:該模塊由兩個(gè)74HC573鎖存器和一個(gè)4位8段LED數(shù)碼管構(gòu)成,主控芯片AT89C51使用P2.6和P2.7控制兩個(gè)74HC573鎖存器的片選,兩個(gè)鎖存器的輸入口均與主控芯片的P0口相連,并使用一個(gè)100歐的排阻作為P0口的上拉電阻,兩個(gè)鎖存器的輸出口分別與4位8段LED數(shù)碼管的段選口與位選口相連;
- 升溫、降溫模塊:該模塊由一個(gè)綠色LED和一個(gè)紅色LED構(gòu)成,綠色LED負(fù)責(zé)降溫,每閃爍一次溫度下降0.5°,紅色LED負(fù)責(zé)升溫,每閃爍一次溫度上升0.5°。主控芯片AT89C51根據(jù)當(dāng)前溫度和用戶設(shè)定溫度之間的差值,來控制升溫還是降溫,以達(dá)到恒溫的目的。
軟件代碼編寫
程序的具體流程如下:
- 硬件初始化,關(guān)閉所有的數(shù)碼管;
- 進(jìn)行兩次按鍵掃描循環(huán),分別獲取用戶設(shè)定溫度的十位和個(gè)位,獲取完畢后,判斷確認(rèn)鍵是否被按下,如果用戶按下確認(rèn)鍵則進(jìn)入到主程序循環(huán)中;
while(ok) //用戶設(shè)定溫度 { while(key1 == 15) { key1 = keyscan(); delay(50); } while(key2 == 15) { key2 = keyscan(); delay(50); } delay(100);//等待確認(rèn)鍵 } //鍵盤掃描 uchar keyscan() { uchar temp,key; key = 15; // 默認(rèn)值,如果沒有按鍵按下key就為該默認(rèn)值 P1 = 0xfe; //掃描第一行 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { delay(10); // 延時(shí)消抖 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { temp = P1; switch(temp) //掃描列 { case 0xee: key = 1; break; case 0xde: key = 2; break; case 0xbe: key = 3; break; } while(temp!=0xf0) //等待按鍵釋放 { temp = P1; temp = temp & 0xf0; } } } P1 = 0xfd; //掃描第二行 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { delay(10); // 延時(shí)消抖 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { temp = P1; switch(temp) //掃描列 { case 0xed: key = 4; break; case 0xdd: key = 5; break; case 0xbd: key = 6; break; } while(temp!=0xf0) //等待按鍵釋放 { temp = P1; temp = temp & 0xf0; } } } P1 = 0xfb; //掃描第三行 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { delay(10); // 延時(shí)消抖 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { temp = P1; switch(temp) //掃描列 { case 0xeb: key = 7; break; case 0xdb: key = 8; break; case 0xbb: key = 9; break; } while(temp!=0xf0) //等待按鍵釋放 { temp = P1; temp = temp & 0xf0; } } } P1 = 0xf7; //掃描第四行 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { delay(10); // 延時(shí)消抖 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { temp = P1; switch(temp) //掃描列 { case 0xe7: key = 0; break; case 0xd7: key = 0; break; case 0xb7: key = 0; break; } while(temp!=0xf0) //等待按鍵釋放 { temp = P1; temp = temp & 0xf0; } } } return key; }
- 在主程序循環(huán)中,首先調(diào)用dis_set()函數(shù)顯示用戶設(shè)定溫度;
for(i=20;i>0;i--) dis_set(key1, key2); //顯示用戶設(shè)定的溫度 //顯示設(shè)定溫度函數(shù) void dis_set(uchar k1, uchar k2) { display2(1, k1); display2(2, k2); display2(0, k1); } //設(shè)定溫度數(shù)據(jù)顯示函數(shù) void display2(uchar num, uchar tem_data) { if(num==0) { S1 = 1; S2 = 1; delay(5); } if(num==1) { S1 = 0; S2 = 1; P3 = table[tem_data]; //table為 0-9的16進(jìn)制編碼表 delay(5); } else if(num==2) { S1 = 1; S2 = 0; P3 = table[tem_data]; delay(5); } }
然后再從溫度傳感器獲取當(dāng)前溫度,獲取當(dāng)前溫度的流程如下圖所示,先調(diào)用DSreset()函數(shù)進(jìn)行溫度傳感器的初始化,再調(diào)用temwrite()函數(shù),對傳感器寫入溫度轉(zhuǎn)換的指令,進(jìn)行溫度獲取和轉(zhuǎn)換,然后調(diào)用get_tem()函數(shù)對傳感器寫入讀取寄存器指令,從寄存器中讀取存儲的溫度數(shù)據(jù),并對該數(shù)據(jù)進(jìn)行精度轉(zhuǎn)換處理,最后獲得一個(gè)保留了1位小數(shù)的當(dāng)前溫度數(shù)據(jù);
temchange(); //獲取當(dāng)前溫度 //溫度獲取和轉(zhuǎn)換函數(shù) void temchange(void) { DSreset(); delay(1); temwrite(0xcc); //寫跳過ROM指令 temwrite(0x44); //寫溫度轉(zhuǎn)換指令 } //讀取寄存器中存儲的溫度數(shù)據(jù) uint get_tem(void) { uchar l8,h8; DSreset(); delay(1); temwrite(0xcc); //寫跳過ROM指令 temwrite(0xbe); //寫讀寄存器指令 l8 = temread(); //讀低8位數(shù)據(jù) h8 = temread(); //讀高8位數(shù)據(jù) tem = h8; tem = tem<<8; tem = tem|l8; //合成一個(gè)16位數(shù)據(jù) f_tem = tem*0.0625; tem = f_tem*10+0.5; //*10用于保留1位小數(shù)點(diǎn),+0.5用于四舍五入 return (tem); }
DS18B20溫度傳感器的基本操作代碼如下,各項(xiàng)操作要嚴(yán)格遵守DS18B20溫度傳感器的時(shí)序圖,延時(shí)時(shí)間要足夠,可以根據(jù)使用的主控芯片適當(dāng)?shù)匦薷难h(huán)的次數(shù)來調(diào)整延時(shí)。
初始化
//溫度傳感器初始化 uint DSreset(void) { uint i; DS = 0; i = 73; while(i>0) i--; DS = 1; i = 0; while(DS) {//等待DS18B20拉低總線 delay(1); i++; if(i>10) { return 0;//初始化失敗 } } DS = 1; return 1;//初始化成功 }
讀1位數(shù)據(jù)
//讀1位數(shù)據(jù) bit temreadbit(void) { uint i; bit tem_bitdata; DS = 0; i++; //延時(shí) DS = 1; i++; i++; tem_bitdata = DS; i = 10; while(i>0) i--; return(tem_bitdata); }
讀1字節(jié)數(shù)據(jù)
//讀1字節(jié)數(shù)據(jù) uchar temread(void) { uint i; uchar j,tem_data; for(i=1;i<=8;i++) { j = temreadbit(); tem_data = (j<<7)|(tem_data>>1); //移位,讓最低位在最后面 } return (tem_data); }
寫1字節(jié)數(shù)據(jù)
//寫1字節(jié)數(shù)據(jù) void temwrite(uchar tem_data) { uint i; uchar j; bit send_bitdata; for(j=1;j<=8;j++) { send_bitdata = tem_data&0x01; //取要發(fā)送數(shù)據(jù)的最低位 tem_data = tem_data>>1; //右移一位 if(send_bitdata) //寫1 { DS = 0; i++; i++; DS = 1; i = 10; while(i>0) i--; } else //寫0 { DS = 0; i = 10; while(i>0) i--; DS = 1; i++; i++; } } }
- 獲取完當(dāng)前溫度,調(diào)用dis_tem()函數(shù)顯示當(dāng)前溫度;
for(i=20;i>0;i--) //顯示當(dāng)前溫度 dis_tem(get_tem()); //顯示當(dāng)前溫度函數(shù) void dis_tem(uint t) { uchar i; i = t/100; //取溫度的十位 display1(1,i); i = t%100/10; //取溫度的個(gè)位 display1(2,i+10); i = t%10; //取溫度的小數(shù)點(diǎn)后一位 display1(3,i); } //當(dāng)前溫度數(shù)據(jù)顯示函數(shù) void display1(uchar num, uchar tem_data) { WE = 1; //選位,低電平有效 P0 = ~((0x01)<<(num)); WE = 0; DU = 1; //選段,高電平有效 P0 = table[tem_data]; DU = 0; delay(10); }
- 將當(dāng)前溫度和用戶設(shè)定溫度傳入deal()函數(shù),進(jìn)行恒溫控制,在恒溫控制函數(shù)deal()中,根據(jù)判斷當(dāng)前溫度和用戶設(shè)定溫度之間的差值進(jìn)行不同的處理,如果當(dāng)前溫度小于用戶設(shè)定溫度,就進(jìn)行升溫處理,即紅燈閃爍一次,每閃爍一次溫度上升0.5°,如果當(dāng)前溫度大于用戶設(shè)定溫度,就進(jìn)行降溫處理,即綠燈閃爍一次,每閃爍一次溫度下降0.5°,如果當(dāng)前溫度與用戶設(shè)定溫度想等,則不做處理,只顯示溫度;
void deal(uint t, uint t_set) { uchar i; if(tt_set) { work(15, 0x40); //降溫 } else { i = 15; while(i--) { dis_tem(tem_set); dis_set(key1, key2); } } } //升溫、降溫模塊 void work(uint s, uchar led) { uchar i; if(led==0x20) { i = s; led0 = ~(led0); //燈亮 tem = tem+5; while(i--) { dis_tem(tem); dis_set(key1, key2); } led0 = ~(led0); //燈滅 i = s; while(i--) { dis_tem(tem); dis_set(key1, key2); } } else { i = s; led1 = ~(led1); //燈亮 tem = tem-5; while(i--) { dis_tem(tem); dis_set(key1, key2); } led1 = ~(led1); //燈滅 i = s; while(i--) { dis_tem(tem); dis_set(key1, key2); } } }
- 進(jìn)行一次恒溫控制后,系統(tǒng)又回到主程序循環(huán)的起始點(diǎn),不斷重復(fù)上述3-5步驟,使溫度保持在用戶設(shè)定的溫度,達(dá)到恒溫的效果。