為好朋友東東設計了個單片機熱水鍋爐自動溫度控制系統(tǒng)。因為他家的熱水鍋爐因溫度太低,沒及時加熱,爆過幾 次。也有因加熱過頭,燒干水,化了管子。東東很快做好了實物,程序得到驗證,兩人皆大歡喜。
1.下限5°C時加熱器加熱,上限40°C時停止。溫度下降,直到下限時重新加熱。
2.溫度70°C時冷卻水泵工作,溫度降到45°C時停止。下次仍為70°C時水泵工作。
3.加熱/水泵 按鈕可切換切換加熱器和冷卻泵的設定及顯示(HTR為加熱器,CTP為冷卻水泵)。
程序中對兩組上下限設定做成可調的,方便實際使用中對上下限的細調。
E:\DPJ_C\18B20LCD\DD2\18B20DD2.C
- //2012 05 04
- #include<reg51.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit RS=P2^0;
- sbit RW=P2^1;
- sbit E=P2^2;
- sbit BF=P0^7;
- sbit DQ=P3^3;
- sbit KEY0=P1^0;
- sbit KEY1=P1^1;
- sbit KEY2=P1^2;
- sbit KEY3=P1^3;
- sbit HTR=P1^4; //加熱器
- sbit CTP=P1^5; //冷卻泵
- uchar h_TH=40,h_TL=5,p_TH=70,p_TL=45;
- uchar code digit[12]={"0123456789- "};
- uchar code digit1[15]={"011233445677889"};
- uchar code digit2[16]={"0112234456677889"};
- uchar code Now[]={"Now:"};
- uchar code TH[]={"TH"};
- uchar code TL[]={"TL"};
- uchar code Cent[]={0xdf,0x43}; //溫度單位℃
- bit flag1,flag2,flag3; //flag1溫度為負的標志 flag2電熱標志 flag3 水泵標志
- /*****************************************************
- us 延時子函數
- ***************************************************/
- void ds18b20_delay(uchar us)
- {
- while(us--);
- }
- /*****************************************************
- ms 延時子函數
- ***************************************************/
- void delay(uint ms)
- {
- uchar i;
- while(ms--)
- for(i=0;i<123;i++);
- }
- /*****************************************************
- 判斷液晶模塊的忙碌狀態(tài)
- ***************************************************/
- bit BusyTest()
- {
- bit result;
- RS=0;
- RW=1;
- E=1;
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四個機器周期,給硬件反應時間
- result=BF;
- E=0; //將E恢復低電平
- return result;
- }
- /*****************************************************
- 將模式設置指令或顯示地址寫入液晶模塊
- ***************************************************/
- void WriteCmd (uchar dictate)
- {
- while(BusyTest()==1); //如果忙就等待
- RS=0;
- RW=0;
- E=0;
- _nop_();
- _nop_(); //空操作兩個機器周期,給硬件反應時間
- P0=dictate;
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四個機器周期,給硬件反應時間
- E=1;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- E=0;
- }
- /*****************************************************
- 函數功能:指定字符顯示的實際地址
- 入口參數:x
- ***************************************************/
- void WriteAdd(uchar x)
- {
- WriteCmd(x|0x80); //顯示位置的確定方法規(guī)定為"80H+地址碼x"
- }
- /*****************************************************
- 將數據(字符的標準ASCII碼)寫入液晶模塊
- ***************************************************/
- void WriteData(uchar y)
- {
- while(BusyTest()==1);
- RS=1; //RS為高電平,RW為低電平時,可以寫入數據
- RW=0;
- E=0; //E置低電平(根據表8-6,寫指令時,E為高脈沖,
- // 就是讓E從0到1發(fā)生正跳變,所以應先置"0"
- P0=y; //將數據送入P0口,即將數據寫入液晶模塊
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四個機器周期,給硬件反應時間
- E=1; //E置高電平
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四個機器周期,給硬件反應時間
- E=0; //當E由高電平跳變成低電平時,液晶模塊開始執(zhí)行命令
- }
- /*****************************************************
- LCD1602 初始化
- ***************************************************/
- void LcdInitiate(void)
- {
- delay(15); //延時15ms,首次寫指令時應給LCD一段較長的反應時間
- WriteCmd(0x38); //顯示模式設置:16×2顯示,5×7點陣,8位數據接口
- delay(5); //延時5ms ,給硬件一點反應時間
- WriteCmd(0x38);
- delay(5); //延時5ms ,給硬件一點反應時間
- WriteCmd(0x38); //連續(xù)三次,確保初始化成功
- delay(5); //延時5ms ,給硬件一點反應時間
- WriteCmd(0x0c); //顯示模式設置:顯示開,無光標,光標不閃爍
- delay(5); //延時5ms ,給硬件一點反應時間
- // WriteCmd(0x06); //顯示模式設置:光標右移,字符不移
- delay(5); //延時5ms ,給硬件一點反應時間
- WriteCmd(0x01); //清屏幕指令,將以前的顯示內容清除
- delay(5); //延時5ms ,給硬件一點反應時間
- }
- /************************************************************************
- 以下是DS18B20的操作程序
- ************************************************************************/
- /*****************************************************
- DS18B20初始化
- ***************************************************/
- void Init_DS18B20()
- {
- uchar x=0;
- DQ=1;
- ds18b20_delay(8);
- DQ=0;
- ds18b20_delay(80);
- DQ=1;
- ds18b20_delay(14);
- x=DQ;
- ds18b20_delay(20);
- }
- /*****************************************************
- 函數功能:寫一個字節(jié)
- 入口參數:
- ***************************************************/
- void WriteOneChar(uchar dat)
- {
- uchar i;
- for(i=8;i>0;i--)
- {
- DQ=0;
- if(dat&0x01==0x01)
- DQ=1;
- else
- DQ=0;
- ds18b20_delay(5);
- DQ=1;
- ds18b20_delay(1);
- dat>>=1;
- }
- }
- /*****************************************************
- 讀一個字節(jié)
- ***************************************************/
- uchar ReadOneChar()
- {
- uchar dat=0,i;
- for(i=8;i>0;i--)
- {
- dat>>=1;
- DQ=0;
- ds18b20_delay(1);
- DQ=1;
- if(DQ==1)
- dat|=0x80;
- else
- dat&=0x7f;
- ds18b20_delay(4);
- }
- return(dat);
- }
- /*****************************************************
- 顯示Now:
- ***************************************************/
- void display_Now()
- {
- uchar i;
- WriteAdd(0x00); //寫顯示地址,將在第1行第1列開始顯示
- for(i=0;i<4;i++)
- WriteData(Now[i]);
- delay(50); //延時1ms給硬件一點反應時間
- }
- /*****************************************************
- 顯示溫度的小數點
- ***************************************************/
- void display_dot(void)
- {
- WriteAdd(0x07); //寫顯示地址,將在第1行第10列開始顯示
- WriteData('.'); //將小數點的字符常量寫入LCD
- delay(50); //延時1ms給硬件一點反應時間
- }
- /*****************************************************
- 顯示溫度的單位(°C)
- ***************************************************/
- void display_cent(void)
- {
- uchar i;
- WriteAdd(0x09); //寫顯示地址,將在第1行第13列開始顯示
- for(i=0;i<2;i++)
- WriteData(Cent[i]); //將字符常量寫入LCD
- WriteAdd(0x45);
- for(i=0;i<2;i++)
- WriteData(Cent[i]);
- WriteAdd(0x4e);
- for(i=0;i<2;i++)
- WriteData(Cent[i]);
- }
- /*****************************************************
- 顯示溫度的整數部分
- ***************************************************/
- void display_temp1(uchar x)
- {
- uchar j,k,l; //j,k,l分別儲存溫度的百位、十位和個位
- j=x/100; //取百位
- k=(x%100)/10; //取十位
- l=x%10; //取個位
- WriteAdd(0x04); //寫顯示地址,將在第1行第5列開始顯示
- if(flag1==1)
- {
- WriteData(digit[10]); //將"-" 號寫入LCD
- }
- else
- if(j==0)
- {j=11;}
- WriteData(digit[j]); //將百位數字的字符常量寫入LCD
- if(j==0&&k==0)
- {k=11;}
- WriteData(digit[k]); //將十位數字寫入LCD
- WriteData(digit[l]); //將個位數字寫入LCD
- delay(50);
- }
- /*****************************************************
- 顯示溫度的小數部分
- ***************************************************/
- void display_temp2(uchar x)
- {
- WriteAdd(0x08); //寫顯示地址,將在第2行第11列開始顯示
- if(flag1==1)
- {
- WriteData(digit1[x]); //溫度為負,將小數部分的第一位數字寫入LCD
- }
- else
- WriteData(digit2[x]); //溫度為正,將小數部分的第一位數字寫入LCD
- }
- /*****************************************************
- 顯示溫度設定部分
- ***************************************************/
- void display_THTL ()
- {
- uchar i,hhh,hhl,phh,phl,hlh,hll,plh,pll;
- hhh=h_TH/10;
- hhl=h_TH%10;
- phh=p_TH/10;
- phl=p_TH%10;
- hlh=h_TL/10;
- hll=h_TL%10;
- plh=p_TL/10;
- pll=p_TL%10;
- WriteAdd(0x40); //第2行第1個字節(jié)開始
- for(i=0;i<2;i++)
- WriteData(TH[i]);
- WriteAdd(0x43);
- if(flag2)
- {
- WriteData(digit[phh]);
- WriteData(digit[phl]);
- }
- else
- {
- WriteData(digit[hhh]);
- WriteData(digit[hhl]);
- }
- WriteAdd(0x49); //第2行第10個字節(jié)開始
- for(i=0;i<2;i++)
- WriteData(TL[i]);
- WriteAdd(0x4c);
- if(flag2)
- {
- WriteData(digit[plh]);
- WriteData(digit[pll]);
- WriteAdd(0x0d);
- WriteData('C');
- WriteAdd(0x0e);
- WriteData('T');
- WriteAdd(0x0f);
- WriteData('P');
- }
- else
- {
- WriteData(digit[hlh]);
- WriteData(digit[hll]);
- WriteAdd(0x0d);//也可以這樣的寫法
- WriteData('H');
- WriteAdd(0x0e);
- WriteData('T');
- WriteAdd(0x0f);
- WriteData('R');
- }
- }
- /*****************************************************
- 準備讀溫度
- ***************************************************/
- void ReadyReadTemp()
- {
- Init_DS18B20(); //將DS18B20初始化
- WriteOneChar(0xCC); // 跳過讀序號列號的操作
- WriteOneChar(0x44); // 啟動溫度轉換
- //for(time=0;time<100;time++); //溫度轉換需要一點時間
- Init_DS18B20(); //將DS18B20初始化
- WriteOneChar(0xCC); //跳過讀序號列號的操作
- WriteOneChar(0xBE); //讀取溫度寄存器,前兩個分別是溫度的低位和高位
- }
- /*****************************************************
- 函數功能:按鍵掃描子函數
- ***************************************************/
- void keyscan()
- {
- while(!KEY0) //加熱/水泵切換
- {
- delay(10);
- if(KEY0)
- flag2=!flag2;
- }
- while(!KEY1) //上限/下限切換
- {
- delay(10);
- if(KEY1)
- flag3=!flag3;
- }
- while(!KEY2) //設置溫度加
- {
- delay(10);
- if(KEY2)
- {
- if(flag2)
- {
- if(flag3)
- p_TL++;
- else
- p_TH++;
- }
- else
- {
- if(flag3)
- h_TL++;
- else
- h_TH++;
- }
- }
- }
- while(!KEY3) //設置溫度減
- {
- delay(10);
- if(KEY3)
- {
- if(flag2)
- {
- if(flag3)
- p_TL--;
- else
- p_TH--;
- }
- else
- {
- if(flag3)
- h_TL--;
- else
- h_TH--;
- }
- }
- }
- }
- /*****************************************************
- 主函數
- ***************************************************/
- void main()
- {
- uint temp;
- uchar TL; //儲存暫存器的溫度低位
- uchar TH; //儲存暫存器的溫度高位
- uchar TN; //儲存溫度的整數部分
- uchar TD; //儲存溫度的小數部分
- LcdInitiate(); //將液晶初始化
- delay(5); //延時5ms給硬件一點反應時間
- display_Now();
- display_dot(); //顯示溫度的小數點
- display_cent(); //顯示 ℃
- HTR=1;
- CTP=1;
- while(1)
- {
- keyscan();
- ReadyReadTemp(); //讀溫度準備
- TL=ReadOneChar(); //先讀溫度值低位
- TH=ReadOneChar(); //后讀溫度值高位
- ds18b20_delay(150);
- if(TN<h_TL)
- HTR=0;
- if(TN>h_TH)
- HTR=1;
- if(TN>p_TH)
- CTP=0;
- if(TN<p_TL)
- CTP=1;
- // if(TH&0xf8==0xf8) //TH高5 位為1,溫度值為負 。負數一直調試未成,原來是忽視了優(yōu)先等級。改成if((TH&0XF8)==0XF8),負溫度就正常了。
- // {
- // flag1=1;
- // TL=~(TL)+0x01;
- // TH=~TH;
- // }
- // else
- temp=TH;
- temp=temp<<8|TL;
- TN=temp*0.0625;
- // flag1=0;
- TD=TL&0x0f;
- display_THTL();
- display_temp1(TN); //顯示溫度的整數部分
- display_temp2(TD); //顯示溫度的小數部分
- delay(10);
- }
- }
復制代碼
|