#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ=P3^7; //ds18b20與單片機連接口
sbit RS=P3^0; //1602寫數據/寫命令選擇端口
//RS=1寫數據,即要顯示的內容
//RS=0寫命令,即一些LCD設置命令
sbit RW=P3^1; //1602讀/寫選擇端,RW=0為寫模式
sbit EN=P3^2; //給EN一個高脈沖,將數據送入液晶控制器,完成寫操作
uchar code str1[]={"^_^ Zhang Chao"};
uchar code str2[]={" T= "};
uchar data disdata[5];//百、十、個、小數位
uint tvalue; //溫度值
uchar tflag; //溫度正負標志
/*************************lcd1602設置子函數*******************************************************************/
void delay1ms(uint ms) //延時1毫秒子函數,形參為ms(不夠精確的)
{ unsigned int i,j;
for(i=0;i<ms;i++)
for(j=0;j<110;j++);
}
void wr_com(uchar com)//lcd寫控制指令子函數,形參為com
{
delay1ms(1); //調用延時子函數,并用實參1代替延時子函數中的形參ms
RS=0; //RS=0進入寫命令狀態,即一些LCD設置命令
RW=0; //RW=0為寫模式
EN=0; //EN=0時不能完成寫操作
P2=com; //把要設置的指令碼com送給P2口
delay1ms(1);
EN=1; //給EN一個高脈沖,將數據送入液晶控制器,完成寫操作
delay1ms(1);
EN=0; //EN=0時不能完成寫操作
}
void wr_dat(uchar dat)//lcd寫顯示數據子函數,形參為dat {
delay1ms(1);
RS=1; //RS=1進入寫數據狀態,即要顯示的內容
RW=0; //RW=0為寫模式
EN=0; //EN=0時不能完成寫操作
P2=dat; //把要顯示的數據dat送給P2口
delay1ms(1);
EN=1; //給EN一個高脈沖,將數據送入液晶控制器,完成寫操作
delay1ms(1);
EN=0; //EN=0時不能完成寫操作
}
void lcd_init() //lcd初始化設置子函數,不帶參數,0x38是顯示模式設置,其余是顯示開/關及光標設置,無順序
{
delay1ms(15);
wr_com(0x38); //調用寫控制指令子函數,并用實參"0011 1000"代替形參com
//0x38表示設置為16*2顯示,每個塊為5*7點陣,8位數據接口
delay1ms(5); wr_com(0x08); //調用寫控制指令子函數,并用實參"0000 1000"代替形參com
//0x08表示設置為關顯示、不顯示光標、光標不閃爍
delay1ms(5);
wr_com(0x01); //調用寫控制指令子函數,并用實參"0000 0001"代替形參com
//0x01表示顯示數據清屏(數據指針清0,所有顯示清0)
delay1ms(5);
wr_com(0x06);//調用寫控制指令子函數,并用實參"0000 0110"代替形參com
//0x06表示當讀或寫一個字符后地址指針加1,且光標加1;當寫一個字符時,整屏顯示不移動
delay1ms(5);
wr_com(0x0c);//調用寫控制指令子函數,并用實參"0000 1100"代替形參com
//0x0c打開顯示、不顯示光標、光標不閃爍
delay1ms(5);
}
void display(uchar *p)//lcd顯示字符串子函數
{
while(*p!='\0') //測試是否等于'\0',即判斷是否結尾
{ wr_dat(*p); //顯示指針所指的字符串
p++; //指針加1
delay1ms(1);
}
}
init_play()//初始化顯示子函數
{
lcd_init(); //調用lcd初始化設置子函數,對LCD進行初始化
wr_com(0x80); //調用寫控制指令子函數,并用實參"1000 0000"代替形參com
//并將數據指針定位到第一行第一個字符處
display(str1);//從第一行第一個字符處顯示字符串str1
wr_com(0x80+0x40);//調用寫控制指令子函數,并用實參"1000 0000"代替形參com
//并將數據指針定位到第二行第一個字符處
display(str2); //從第二行第一個字符處顯示字符串str2
}
/**************************************************************************************************************/ /******************************ds18b20程序******************************************************************/
void delay_18b20(uint i)//延時1微秒
{
while(i--);
}
void ds18b20rst() //ds18b20初始化子函數
//要求"數據線拉高-延時-數據線拉低-延時大于480微妙-數據線拉高-延時等待"
{
uchar x=0;
DQ = 1; //信號線DQ復位
delay_18b20(4); //延時
DQ = 0; //DQ拉低
delay_18b20(100); //精確延時大于480us
DQ = 1; //拉高
delay_18b20(40);
}
void ds18b20wr(uchar wdata)/*寫數據子函數,無返回值,含參數*/ {
uchar i=0;
for (i=8; i>0; i--)//要寫完一個字節,故需要重復8次以下操作
{
DQ = 0; //數據線拉低
DQ = wdata&0x01;//wdata是一個形參,將其與0000 0001進行按位與
//按從低到高的順序發送數據(一次發送一位)
delay_18b20(10);
DQ = 1; //最后將數據線拉高
wdata>>=1; //將wdata右移1位
}
}
uchar ds18b20rd() //讀數據子函數,是有返回值dat
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)//要讀完一個字節,故需要重復8次以下操作
{ DQ = 0; //給脈沖信號
dat>>=1;
DQ = 1; //給脈沖信號
if(DQ)
dat|=0x80;
delay_18b20(10);
}
return(dat); //返回dat
}
read_temp() //讀取溫度值并轉換的子函數,有返回值溫度值tvalue
{
uchar a,b;
ds18b20rst(); //調用ds18b20初始化子函數
ds18b20wr(0xcc);//調用寫數據子函數,向ds18b20寫命令0xcc
//ccH表示跳過ROM讀序列號,適用于單機工作,直接向18b20發送溫度變換命令
ds18b20wr(0x44);//調用寫數據子函數,向ds18b20寫命令0x44 //44H表示啟動ds18b20溫度轉換,結果自行存入9字節的RAM中
ds18b20rst(); //調用ds18b20初始化子函數
ds18b20wr(0xcc);//同上
ds18b20wr(0xbe);//調用寫數據子函數,向ds18b20寫命令0xbe
//beH表示讀取RAM中9字節的溫度數據
a=ds18b20rd(); //調用讀數據子函數,并將所得數據給a
b=ds18b20rd(); //
tvalue=b; //把b的值給tvalue
tvalue<<=8; //tvalue左移8位
tvalue=tvalue|a;//tvalue與a進行按位或
if(tvalue<0x0fff)//
tflag=0; //前五位為0時,讀取的溫度為正,標志位為0,此時只要
//將測得數值乘以0.0625即可得到實際溫度
else //前五位為1時,讀取的溫度為負,標志位為1,此時需要
{ //將測得數值取反后再加1,再乘以0.0625即可得到實際溫度
tvalue=~tvalue+1;
tflag=1; //此時表示負溫度 }
tvalue=tvalue*(0.625);//溫度值擴大10倍,精確到1位小數
return(tvalue); //返回溫度值
}
/*************************************************************************************************************/
/************************溫度值顯示**************************************************************************/
void ds18b20disp()//溫度值顯示
{
uchar flagdat;
disdata[0]=tvalue/1000+0x30; //百位數
disdata[1]=tvalue%1000/100+0x30;//十位數
disdata[2]=tvalue%100/10+0x30; //個位數
disdata[3]=tvalue%10+0x30; //小數位
if(tflag==0)
flagdat=0x2b; //正溫度顯示符號:+
else flagdat=0x2d; //負溫度顯示負號:-
if(disdata[0]==0x30)
{
disdata[0]=0x20; //如果百位為0,不顯示
if(disdata[1]==0x30)
{
disdata[1]=0x20; //如果百位為0,十位為0也不顯示
}
}
wr_com(0x80+0x46); //定位數據指針的位置:第二行第六個字符處
wr_dat(flagdat); //顯示符號位
wr_com(0x80+0x47); //定位數據指針的位置:第二行第七個字符處
wr_dat(disdata[0]); //顯示百位
wr_com(0x80+0x48); //定位數據指針的位置:第二行第八個字符處
wr_dat(disdata[1]); //顯示十位
wr_com(0x80+0x49); //定位數據指針的位置:第二行第九個字符處
wr_dat(disdata[2]); //顯示個位 wr_com(0x80+0x4a); //定位數據指針的位置:第二行第十個字符處
wr_dat(0x2e); //顯示小數點
wr_com(0x80+0x4b); //定位數據指針的位置:第二行第十一個字符處
wr_dat(disdata[3]); //顯示小數位
}
/**************************************************************************************************************/
/********************主程序*********************************************************************************/
void main()
{
init_play(); //調用lcd初始化顯示子函數
while(1)
{
read_temp(); //調用ds18b20讀取溫度
ds18b20disp(); //調用溫度顯示子函數
}
}
|