DS18B20,是一款強大的測溫傳感器,具有體積小,硬件開銷低,抗干擾能力強,精度高的特點,所以是開發(fā)中必不可少的一個芯片,為了方便大家上手
DS18B20溫度傳感器是DALLAS公司生產(chǎn)的1-wire式單總線器件,具有線路簡單,體積小的特點,用它組成的溫度測量系統(tǒng)線路非常簡單,只要求一個端口即可實現(xiàn)通信。溫度測量范圍在-55℃~+125℃之間,分辨率可以從9~12位選擇,內(nèi)部還有溫度上、下限報警設(shè)置。每個DS18B20芯片都有唯一的序列號,所以可以利用多個DS18B20同時連接在同一條總線上,組成多點測溫系統(tǒng)。但最多只能連接8個,如果數(shù)量過多,會使供電電源電壓過低,從而造成信號傳輸?shù)牟环€(wěn)定。
DS18B20 的初始化:
根據(jù) DS18B20 的通訊協(xié)議,主機(jī)(單片機(jī))控制 DS18B20 完成溫度轉(zhuǎn)換必須經(jīng)過三個步驟:每一次讀寫之前都要對 DS18B20 進(jìn)行復(fù)位操作,復(fù)位成功后發(fā)送一條 ROM 指令,最后發(fā)送 RAM 指令,這樣才能對 DS18B20 進(jìn)行預(yù)定的操作。復(fù)位要求主 CPU 將數(shù)據(jù)線下拉 500 微秒,然后釋放,當(dāng) DS18B20 收到信號后等待 16~60 微秒左右,后發(fā)出 60~240 微秒的存在低脈沖,主 CPU 收到此信號表示復(fù)位成功。
(1) 先將數(shù)據(jù)線 DQ 置高電平“1”。
?。?) 延時(該時間要求的不是很嚴(yán)格,但是盡可能的短一點)
?。?) 數(shù)據(jù)線拉到低電平“0”。
(4) 延時 750 微秒(該時間的時間范圍可以從 480 到 960 微秒)。
?。?) 數(shù)據(jù)線拉到高電平“1”。
?。?) 延時等待(如果初始化成功則在 15 到 60 微妙時間之內(nèi)產(chǎn)生一個由 DS18B20 所返回的低電平“0”。據(jù)該狀態(tài)可以來確定它的存在,但是應(yīng)注意不能無限的進(jìn)行等待,不然會使程序進(jìn)入死循環(huán),所以要進(jìn)行超時控制)。
(7) 若 CPU 讀到了數(shù)據(jù)線上的低電平“0”后,還要做延時,其延時的時間從發(fā)出的高電平算起(第(5)步的時間算起)最少要 480 微秒。
?。?) 將數(shù)據(jù)線再次拉高到高電平“1”后結(jié)束。
初始化程序如下:
uchar Init_DS18B20()
{
uchar status; //status 為 DS18B20 返回的狀態(tài)
DQ = 1;
Delay(8);
DQ = 0;
Delay(90);
DQ = 1;
Delay(8);
status=DQ;
Delay(100);
DQ = 1;
return status;
}
DS18B20 應(yīng)用舉例(一)
如下圖所示:DQ 通過 4.7K 上拉電阻外接正電源(由于單總線為開漏所以需要外接一個 4.7K 的上拉電阻),并連接單片機(jī) P3.3 口。
本例中,1602LCD 顯示 DS18B20 所測量的外部溫度,調(diào)節(jié) DS18B20 模擬改變外界溫度時,新的溫度將刷新顯示在 LCD 上
C 程序如下:
由于本例僅保存一位小數(shù),溫度小數(shù)位對照表 df_Table[]將 0000~1111 對應(yīng)的 16 個不同的小數(shù)進(jìn)行四舍五入,例如,當(dāng)讀取的溫度低字節(jié)低 4 位為 0101 時,對應(yīng)的溫度應(yīng)為 2 -2 +2-4 =0.3125≈0.3,因此數(shù)組第 5 個元素(對應(yīng) 0101)的值為 3;又如,如果低 4 位為 0110,對應(yīng)的溫度為 2 -2 +2-3 =0.375≈0.4,因此,數(shù)組第 6 個元素(對應(yīng) 0110)取值為 4。
#include #include
#define uint unsigned int
#define uchar unsigned char
#define delay4us() {_nop_();_nop_();_nop_();_nop_();} //12MHZ 系統(tǒng)頻率下,延時 4us
sbit DQ = P3^3;
sbit LCD_RS = P2^0;
sbit LCD_RW = P2^1;
sbit LCD_EN = P2^2;
uchar code Temp_Disp_Title[]={“Current Temp : ”}; //1602 液晶第一行顯示內(nèi)容
uchar Current_Temp_Display_Buffer[]={“ TEMP: ”}; //1602 液晶第二行顯示內(nèi)容
uchar code df_Table[]={ 0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9 }; //溫度小數(shù)位對照表
uchar CurrentT = 0; //當(dāng)前讀取的溫度整數(shù)部分
uchar Temp_Value[]={0x00,0x00}; //從 DS18B20 讀取的溫度值
uchar Display_Digit[]={0,0,0,0}; //待顯示的各溫度數(shù)位
bit DS18B20_IS_OK = 1; //DS18B20 正常標(biāo)志
void DelayXus(uint x) //延時 1
{
uchar i;
while(x--)
{
for(i=0;i《200;i++);
}
}
bit LCD_Busy_Check() //LCD 忙標(biāo)志,返回值為 1602LCD 的忙標(biāo)志位,為 1 表示忙
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delay4us();
result = (bit)(P0&0x80);
LCD_EN=0;
return result;
}
void Write_LCD_Command(uchar cmd) //1602LCD 寫指令函數(shù)
{
while(LCD_Busy_Check());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0; _
nop_();
_nop_();
P0 = cmd;
delay4us();
LCD_EN = 1;
delay4us();
LCD_EN = 0;
}
void Write_LCD_Data(uchar dat) //1602LCD 寫數(shù)據(jù)函數(shù)
{
while(LCD_Busy_Check());
LCD_RS = 1;
LCD_RW = 0;
.LCD_EN = 0;
P0 = dat; delay4us();
LCD_EN = 1;
delay4us();
LCD_EN = 0;
}
void LCD_Initialise() //1602LCD 初始化
{
Write_LCD_Command(0x01);
DelayXus(5);
Write_LCD_Command(0x38);
DelayXus(5);
Write_LCD_Command(0x0c);
DelayXus(5);
Write_LCD_Command(0x06);
DelayXus(5);
{
void Set_LCD_POS(uchar pos) //1602LCD 設(shè)置顯示位置
}
Write_LCD_Command(pos|0x80);
}
void Delay(uint x) //延時 2
{
while(x--);
}
uchar Init_DS18B20() //初始化(或者說復(fù)位)DS18B20
{
uchar status;
DQ = 1;
Delay(8);
DQ = 0;
Delay(90);
DQ = 1;
Delay(8);
status=DQ;
Delay(100);
DQ = 1;
return status;
}
uchar ReadOneByte() //從 DS18B20 讀一字節(jié)數(shù)據(jù)
{
uchar i,dat=0;
DQ = 1;
_nop_();
for(i=0;i《8;i++)
{
DQ = 0;
dat 》》= 1;
DQ = 1;
_nop_();
_nop_();
if(DQ)
dat |= 0X80;
Delay(30);
DQ = 1;
}
return dat;
void WriteOneByte(uchar dat) //從 DS18B20 寫一字節(jié)數(shù)據(jù)
{
uchar i;
for(i=0;i《8;i++)
{
DQ = 0;
DQ = dat& 0x01;
Delay(5);
DQ = 1; dat 》》= 1;
}
}
void Read_Temperature() //從 DS18B20 讀取溫度值
{
if(Init_DS18B20()==1) //DS18B20 故障
DS18B20_IS_OK=0;
else
{
WriteOneByte(0xcc); //跳過序列號命令
WriteOneByte(0x44); //啟動溫度轉(zhuǎn)換命令
Init_DS18B20(); //復(fù)位 DS18B20(每一次讀寫之前都要對 DS18B20 進(jìn)行復(fù)位操作)
WriteOneByte(0xcc); //跳過序列號命令
WriteOneByte(0xbe); //讀取溫度寄存器
Temp_Value[0] = ReadOneByte(); //讀取溫度低 8 位(先讀低字節(jié),再讀高字節(jié),)
Temp_Value[1] = ReadOneByte();//讀取溫度高 8 位 (每次只能讀一個字節(jié)) DS18B20_IS_OK=1; //DS18B20 正常
}
}
void Display_Temperature() //在 1602LCD 上顯示當(dāng)前溫度
{
uchar i;
uchar t = 150, ng = 0; //延時值與負(fù)數(shù)標(biāo)志
if((Temp_Value[1]&0xf8)==0xf8) //高字節(jié)高 5 位如果全為 1,則為負(fù)數(shù),為負(fù)數(shù)時取反
{ //加 1,并設(shè)置負(fù)數(shù)標(biāo)志為 1
Temp_Value[1] = ~Temp_Value[1];
Temp_Value[0] = ~Temp_Value[0]+1;
if(Temp_Value[0]==0x00) //若低字節(jié)進(jìn)位,則高字節(jié)加 1
Temp_Value[1]++;
ng = 1; //設(shè)置負(fù)數(shù)標(biāo)志為 1
}
Display_Digit[0] = df_Table[Temp_Value[0]&0x0f]; //查表得到溫度小數(shù)部分
}
}
//獲取溫度整數(shù)部分(低字節(jié)低 4 位清零,高 4 位右移 4 位)+(高字節(jié)高 5 位清零, //低三位左移 4 位)
CurrentT = ((Temp_Value[0]&0xf0)》》4) | ((Temp_Value[1]&0x07)《《4);
/ //將溫度整數(shù)部分分解為 3 位待顯示數(shù)字
Display_Digit[3] = CurrentT/100;
Display_Digit[2] = CurrentT%100/10;
Display_Digit[1] = CurrentT%10;
//刷新 LCD 緩沖 //加字符 0 是為了將待數(shù)字轉(zhuǎn)化為字符顯示
Current_Temp_Display_Buffer[11] = Display_Digit[0] + ‘0’;
Current_Temp_Display_Buffer[10] = ‘?!?
Current_Temp_Display_Buffer[9] = Display_Digit[1] + ‘0’;
Current_Temp_Display_Buffer[8] = Display_Digit[2] + ‘0’;
Current_Temp_Display_Buffer[7] = Display_Digit[3] + ‘0’;
if(Display_Digit[3] == 0) //高位為 0 時不顯示
Current_Temp_Display_Buffer[7] = ‘ ’;
if(Display_Digit[2] == 0&&Display_Digit[3]==0) //高位為 0,且次高位為 0,則次高位不顯示
Current_Temp_Display_Buffer[8] = ‘ ’;
//負(fù)號顯示在恰當(dāng)位置
if(ng)
{
if(Current_Temp_Display_Buffer[8] == ‘ ’)
Current_Temp_Display_Buffer[8] = ‘-’;
else
if(Current_Temp_Display_Buffer[7] == ‘ ’)
Current_Temp_Display_Buffer[7] = ‘-’;
else
Current_Temp_Display_Buffer[6] = ‘-’;
}
Set_LCD_POS(0x00); //第一行顯示標(biāo)題
for(i=0;i《16;i++)
{
Write_LCD_Data(Temp_Disp_Title[i]);
}
Set_LCD_POS(0x40); //第二行顯示當(dāng)前溫度
for(i=0;i《16;i++)
{
Write_LCD_Data(Current_Temp_Display_Buffer[i]);
}
//顯示溫度符號
Set_LCD_POS(0x4d);
Write_LCD_Data(0x00);
Set_LCD_POS(0x4e);
Write_LCD_Data(‘C’);
}
void main() //主函數(shù)
{
LCD_Initialise();
Read_Temperature();
Delay(50000);
Delay(50000);
while(1)
{
Read_Temperature();
if(DS18B20_IS_OK)
Display_Temperature();
DelayXus(100);
}
}
Proteus 仿真運行結(jié)果如下:
DS18B20的應(yīng)用實例二
#include《reg51.h》
sbit DQ=P3^0;
sbit d1=P2^0;
sbit d2=P2^1;
#define uchar unsigned char
#define uint unsigned int
uchar temp_value;
uchar code table[]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};
void delay_18B20(uint i)
{
while(i--);
}
void Init_DS18B20(void)
{
uchar x=0;
DQ = 1; //DQ復(fù)位
delay_18B20(8); //稍做延時
DQ = 0; //單片機(jī)將DQ拉低
delay_18B20(80); //精確延時 大于 480us
DQ = 1; //拉高總線
delay_18B20(14);
x=DQ; //稍做延時后 如果x=0則初始化成功 x=1則初始化失敗
delay_18B20(20);
}
uchar ReadOneChar(void)
{
uchar i=0;
uchar dat = 0;
for (i=8;i》0;i--)
{
DQ = 0; // 給脈沖信號
dat》》=1;
DQ = 1; // 給脈沖信號
if(DQ)
dat|=0x80;
delay_18B20(4);
}
return(dat);
}
void WriteOneChar(uchar dat)
{
uchar i=0;
for (i=8; i》0; i--)
{
DQ = 0;
DQ = dat&0x01;
delay_18B20(5);
DQ = 1;
dat》》=1;
}
}
void ReadTemp(void)
{
uchar a=0;
uchar b=0;
uchar t=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳過讀序號列號的操作
WriteOneChar(0x44); // 啟動溫度轉(zhuǎn)換
delay_18B20(100); // this message is wery important
Init_DS18B20();
WriteOneChar(0xCC); //跳過讀序號列號的操作
WriteOneChar(0xBE); //讀取溫度寄存器等(共可讀9個寄存器) 前兩個就是溫度
delay_18B20(100);
a=ReadOneChar(); //讀取溫度值低位
b=ReadOneChar(); //讀取溫度值高位
temp_value=b《《4;
temp_value+=(a&0xf0)》》4;
}
void display (uchar num0,uchar num1)
{ P2=0XFD;
P0=table[num1];
delay_18B20(20);
P2=0XFE;
P0=table[num0];
delay_18B20(20);
}
main()
{
uchar a ,b ;
while(1)
{
ReadTemp();
b=temp_value/10; //十位
a=temp_value%10; //個位
display(b,a);
}
}