這是經過普中開發板試驗正確的程序,很穩定。溫度檢測用DS18b20,顯示用DS1602,1602第一行顯示設定溫度上限值和下限值,第二行顯示檢測溫度值。獨立按鍵K1接P1.0用以設定溫度,K2接P1.1用以設定溫度上限值,K3接P1.2用以設定溫度下限值。晶振11.0592MHz或12MHz。
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit IO_18B20=P3^7; //DS18B20的數據IO口
sbit EN_1602=P2^7; //1602時序操作:使能
sbit RS_1602=P2^6; //1602時序操作:讀寫選擇端R/W=L
sbit RW_1602=P2^5; //1602時序操作:寫狀態或寫數據選擇端RS=L
sbit GND=P2^4;
sbit K1=P1^0; //設置鍵
sbit K2=P1^1; //增加鍵
sbit K3=P1^2; //減少鍵
sbit buzzer=P1^7;
uchar S1num;//秒、分、時、星期、日、月、年
uchar data Display[5];
uchar tflag; //溫度正負標志
uchar L_ge=2;
char L_shi=2;
uchar H_ge=4;
uchar H_shi=2;
uchar H_bai=0;
uint T_Value; //溫度值
bit keyflag=0;
//void readtime();
void delay(uint z) //延時子程序
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void delay_18B20(unsigned int i) //18B20延時1微秒
{
while(i--);
}
/*********************將地址命令和時鐘數據傳送DS1602***************/
void write_1602dat(uchar dat) /*時鐘數據傳送P0*/
{
RS_1602=1; //1602的rs為0時,接收命令,為1時接收數據
P0=dat; //把void write_shu(uchar shu)中的COM中的數據給P0口
delay(5);
EN_1602=1;
delay(5);
EN_1602=0;
delay(5);
}
void write_1602com(uchar com) /*地址命令傳送P0*/
{
RS_1602=0; //1602的rs為0時,接收命令,為1時接收數據
P0=com; //把void write_com(uchar com)中的COM中的數據給P0口
delay(5);
EN_1602=1;
delay(5);
EN_1602=0;
delay(5);
}
/************************地址和數據過度緩沖函數**********************/
void Write1602(uchar add,uchar dat) /*寫入地址和時鐘數據函數*/
{
write_1602com(add); //寫入地址函數
write_1602dat(dat); //寫入時鐘數據函數
}
/****************************1602初始化*******************************/
void init_1602() /*定義一個初始化子程序*/
{
EN_1602=0;
RW_1602=0;
write_1602com(0x38); //將0x38賦com,設置顯示模式:4位總線、雙行顯示、顯示5x7的點陣字符
write_1602com(0x0e); //將0x0e賦com,設置光標:開顯示、無光標,光標不閃爍
write_1602com(0x06); //將0x06賦com,寫一個數據,指針自動加1,整屏不移動,N=1、S=0
write_1602com(0x80); //將0x80賦com,設置數據指針起點,第一行左邊第一個字符
write_1602com(0x01); //將0x01賦com,清屏
Write1602(0x80+0x40+1,(0x54)); //第2行第2位,設定'符號T'
Write1602(0x80+0x40+2,(0x65)); //第2行第3位,設定'符號e'
Write1602(0x80+0x40+3,(0x6d)); //第2行第4位,設定'符號m'
Write1602(0x80+0x40+4,(0x70)); //第2行第5位,設定'符號p'
Write1602(0x80+0x40+5,':'); //第2行第6位,設定':'
Write1602(0x80+0x40+13,(0xdf)); //第2行第14位,設定'0'
Write1602(0x80+0x40+14,'C'); //第2行第15位,設定'C'
Write1602(0x80,(0x48)); //第1行第1位,設定'H'
Write1602(0x80+1,':'); //第1行第2位,設定':'
Write1602(0x80+6,(0xdf)); //第1行第7位,設定'溫度符號'
Write1602(0x80+7,'C'); //第1行第8位,設定'溫度符號'
Write1602(0x80+9,(0x4c)); //第1行第10位,設定'L'
Write1602(0x80+10,':'); //第1行第11位,設定':'
Write1602(0x80+14,(0xdf)); //第1行第15位,設定'溫度符號'
Write1602(0x80+15,'C'); //第1行第16位,設定'溫度符號'
}
/***********************ds1820溫度顯示子函數*********************/
void Ds1820RST() /*ds1820復位*/
{
unsigned char x=0;
IO_18B20 = 1; //IO_1302復位
delay_18B20(4); //延時
IO_18B20 = 0; //DQ拉低
delay_18B20(100); //精確延時大于480us
IO_18B20 = 1; //拉高
delay_18B20(40);
}
uchar Read18B20() /*讀數據*/
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
IO_18B20 = 0; //給脈沖信號
dat>>=1;
IO_18B20 = 1; //給脈沖信號
if(IO_18B20) dat|=0x80;
delay_18B20(10);
}
return(dat);
}
void Write18B20(uchar wdata) /*寫數據*/
{
unsigned char i=0;
for (i=8; i>0; i--)
{
IO_18B20 = 0;
IO_18B20 = wdata&0x01; //從最低位輸入
delay_18B20(10);
IO_18B20 = 1;
wdata>>=1;
}
}
read_temp() /*讀取溫度值并轉換*/
{
uchar Temp_L,Temp_H;
Ds1820RST(); //Ds1820復位(初始化)
Write18B20(0xcc); //跳過讀序列號
Write18B20(0x44); //啟動溫度轉換
Ds1820RST(); //Ds1820復位(初始化)
Write18B20(0xcc); //跳過讀序列號
Write18B20(0xbe); //讀取溫度
Temp_L=Read18B20();
Temp_H=Read18B20();
T_Value=Temp_H;
T_Value<<=8;
T_Value=T_Value|Temp_L;
if(T_Value<0x0fff)
tflag=0;
else
{
T_Value=~T_Value+1;
tflag=1;
}
T_Value=T_Value*(0.625); //T_Value是2進制,每一個單位'1'=0.625度
return(T_Value);
}
/**************************檢測溫度值顯示***********************/
void ds1820disp() /*溫度值顯示*/
{
uchar Symbol;
read_temp();
Display[0]=T_Value/1000+0x30; //分解百位數
Display[1]=T_Value%1000/100+0x30; //分解十位數
Display[2]=T_Value%100/10+0x30; //分解個位數
Display[3]=T_Value%10+0x30; //分解小數點后第1位
if(tflag==0)
Symbol=0x2b;//正溫度不顯示符號,地址來源液晶屏字符表
else
Symbol=0x2d;//負溫度顯示負號:-,地址來源液晶屏字符表
/* if(Display[0]==0x30)
{
Display[0]=0x20;//如果百位為0,不顯示,地址來源液晶屏字符表
if(Display[1]==0x30)
{
Display[1]=0x20;//如果百位為0,十位為0也不顯示,地址來源液晶屏字符表
}
}*/
write_1602com(0x80+0x40+6); //符號顯示地址
write_1602dat(Symbol); //顯示符號
write_1602com(0x80+0x40+7); //溫度百位顯示地址
write_1602dat(Display[0]); //顯示測量溫度百位
write_1602com(0x80+0x40+8); //溫度十位顯示地址
write_1602dat(Display[1]); //顯示測量溫度十位
write_1602com(0x80+0x40+9); //溫度個位顯示地址
write_1602dat(Display[2]); //顯示測量溫度個位
write_1602com(0x80+0x40+10); //溫度小數點位顯示地址
write_1602dat(0x2e); //顯示小數點,地址來源液晶屏字符表
write_1602com(0x80+0x40+11); //溫度小數位顯示地址
write_1602dat(Display[3]); //顯示測量溫度小數點后第1位
Write1602(0x80+11,'+'); //將ASC碼
Write1602(0x80+2,'+'); //將ASC碼
}
void L_ge_xs() //低溫度設定
{
Write1602(0x80+13,0x30+L_ge); //將ASC碼
}
void L_shi_xs() //低溫度設定
{
Write1602(0x80+12,0x30+L_shi); //將ASC碼
}
void H_ge_xs() //低溫度設定
{
Write1602(0x80+5,0x30+H_ge); //將ASC碼
}
void H_shi_xs() //低溫度設定
{
Write1602(0x80+4,0x30+H_shi); //將ASC碼
}
void H_bai_xs() //低溫度設定
{
Write1602(0x80+3,0x30+H_bai); //將ASC碼
}
void compare()
{
uint H_value=(H_bai*100)+(H_shi*10)+H_ge;
uint L_value=(L_shi*10)+L_ge;
T_Value=T_Value/10;
if(T_Value>=H_value)
{
buzzer=0;
delay(2000);
buzzer=1;
delay(2000);
}
if(T_Value<=L_value)
{
buzzer=0;
delay(2000);
buzzer=1;
delay(2000);
}
}
/*********************鍵盤掃描****************************/
void key_scan() /*鍵盤掃描*/
{
if(K1==0) //key時鐘設置鍵,K1=0時,說明設置鍵key按下
{
delay(20); //延時5ms,防止抖動
if(K1==0); //在檢測一次,防止誤動作
{
while(!K1); //判斷功能鍵是否放開
S1num++; //K1按下次數檢測變量+1
if(S1num==9) //如果鍵值key1n+1=9執行下一句,如果鍵值key1n+1!=9執行switch(key1n)
S1num=1; //設置按鍵共有秒、分、時、星期、日、月、年、返回,8個功能循環
switch(S1num) //如果S1num=1執行case 1,如果S1num=2執行case 2,以此類推
{
case 1:
keyflag=1; //K1鍵按下檢測標記,keyflag=1,說明K1鍵被按下
write_1602com(0x80+14);
write_1602com(0x0f); break; //開顯示、開光標、光標閃爍
case 2: write_1602com(0x80+13); break; //光標選擇
case 3: write_1602com(0x80+12); break;
case 4: write_1602com(0x80+6); break;
case 5: write_1602com(0x80+5); break;
case 6: write_1602com(0x80+4); break;
case 7: write_1602com(0x80+3); break;
case 8: S1num=0;
keyflag=0;
write_1602com(0x0c);//不顯示光標
break;
}
}
}
if(S1num!=0) //如果key按下次數檢測變量S1num!=0,說明時鐘調整還在進行,可以檢測K1鍵
{
if(K2==0) //K2鍵是時鐘調整增加鍵,如果K1==0,K2鍵被按下,可以向下運行
{
delay(5); //延時5ms
while(!K2); //K2==0取反K2=1,進入大循環
switch(S1num) //如果S1num=1執行case 1,如果S1num=2執行case 2,以此類推
{
case 1: L_ge++;
if(L_ge==10) L_ge=0x00;
Write1602(0x80+13,0x30+L_ge); //將ASC碼
break;
case 2: L_shi++;
if(L_shi==10) L_shi=0x00;
Write1602(0x80+12,0x30+L_shi); //將ASC碼
break;
case 3:
Write1602(0x80+11,'+'); //將ASC碼
break;
case 4: H_ge++;
if(H_ge==10) H_ge=0x00;
Write1602(0x80+5,0x30+H_ge); //將ASC碼
break;
case 5: H_shi++;
if(H_shi==10) H_shi=0x00;
Write1602(0x80+4,0x30+H_shi); //將ASC碼
break;
case 6: H_bai++;
if(H_bai==10) H_bai=0x00;
Write1602(0x80+3,0x30+H_bai); //將ASC碼
break;
case 7:
Write1602(0x80+2,'+'); //將ASC碼
break;
default:break;
}
}
if(K3==0)
{
delay(5);
while(!K3);
switch(S1num)
{
case 1: L_ge--;
if(L_ge==-1) L_ge=9;
Write1602(0x80+13,0x30+L_ge); //將ASC碼
break;
case 2: L_shi--;
if(L_shi==-1) L_shi=9;
Write1602(0x80+12,0x30+L_shi); //將ASC碼
break;
case 3:
Write1602(0x80+11,(0x2d)); //將ASC碼
break;
case 4: H_ge--;
if(H_ge==-1) H_ge=9;
Write1602(0x80+5,0x30+H_ge); //將ASC碼
break;
case 5: H_shi--;
if(H_shi==-1) H_shi=9;
Write1602(0x80+4,0x30+H_shi); //將ASC碼
break;
case 6: H_bai--;
if(H_bai==-1) H_bai=9;
Write1602(0x80+3,0x30+H_bai); //將ASC碼
break;
case 7:
Write1602(0x80+2,'-'); //將ASC碼
default: break;
}
}
}
}
/*****************************主函數*****************************/
void main()
{
GND=0;
delay(100);
init_1602();
while(1)
{
key_scan();
if(keyflag==0)
{
L_ge_xs();
L_shi_xs();
H_ge_xs(); //低溫度設定
H_shi_xs(); //低溫度設定
H_bai_xs(); //低溫度設定
ds1820disp();
compare();
}
}
} |