新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > PIC16F877A驅(qū)動DS18B20溫度采集芯片

PIC16F877A驅(qū)動DS18B20溫度采集芯片

作者: 時(shí)間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
今天開始驅(qū)動DS18B20溫度采集芯片!

從網(wǎng)上收集的資料

本文引用地址:http://2s4d.com/article/201611/317655.htm

DS18B20的內(nèi)部結(jié)構(gòu)

DS18B20內(nèi)部結(jié)構(gòu)主要由四部分組成:64位光刻ROM、溫度傳感器、非揮發(fā)的溫度報(bào)警觸發(fā)器TH和TL、配置寄存器。DS18B20的管腳排列如下:

DQ為數(shù)字信號輸入/輸出端;GND為電源地;VDD為外接供電電源輸入端(在寄生電源接線方式時(shí)接地)。

光刻ROM中的64位序列號是出廠前被光刻好的,它可以看作是該DS18B20的地址序列碼。64位光刻ROM的排列是:開始8位(28H)是產(chǎn)品類型標(biāo)號,接著的48位是該DS18B20自身的序列號,最后8位是前面56位的循環(huán)冗余校驗(yàn)碼(CRC=X8+X5+X4+1)。光刻ROM的作用是使每一個(gè)DS18B20都各不相同,這樣就可以實(shí)現(xiàn)一根總線上掛接多個(gè)DS18B20的目的。

DS18B20中的溫度傳感器可完成對溫度的測量,以12位轉(zhuǎn)化為例:用16位符號擴(kuò)展的二進(jìn)制補(bǔ)碼讀數(shù)形式提供,以0.0625℃/LSB形式表達(dá),其中S為符號位。

這是12位轉(zhuǎn)化后得到的12位數(shù)據(jù),存儲在18B20的兩個(gè)8比特的RAM中,二進(jìn)制中的前面5位是符號位,如果測得的溫度大于0,這5位為0,只要將測到的數(shù)值乘于0.0625即可得到實(shí)際溫度;如果溫度小于0,這5位為1,測到的數(shù)值需要取反加1再乘于0.0625即可得到實(shí)際溫度。

例如+125℃的數(shù)字輸出為07D0H,+25.0625℃的數(shù)字輸出為0191H,-25.0625℃的數(shù)字輸出為FF6FH,-55℃的數(shù)字輸出為FC90H。

DS18B20溫度傳感器的存儲器

DS18B20溫度傳感器的內(nèi)部存儲器包括一個(gè)高速暫存RAM和一個(gè)非易失性的可電擦除的E2RAM,后者存放高溫度和低溫度觸發(fā)器TH、TL和結(jié)構(gòu)寄存器。

暫存存儲器包含了8個(gè)連續(xù)字節(jié),前兩個(gè)字節(jié)是測得的溫度信息,第一個(gè)字節(jié)的內(nèi)容是溫度的低八位,第二個(gè)字節(jié)是溫度的高八位。第三個(gè)和第四個(gè)字節(jié)是TH、TL的易失性拷貝,第五個(gè)字節(jié)是結(jié)構(gòu)寄存器的易失性拷貝,這三個(gè)字節(jié)的內(nèi)容在每一次上電復(fù)位時(shí)被刷新。第六、七、八個(gè)字節(jié)用于內(nèi)部計(jì)算。第九個(gè)字節(jié)是冗余檢驗(yàn)字節(jié)。

該字節(jié)各位的意義如下:

TM R1 R0 1 1 1 1 1

低五位一直都是1 ,TM是測試模式位,用于設(shè)置DS18B20在工作模式還是在測試模式。在DS18B20出廠時(shí)該位被設(shè)置為0,用戶不要去改動。R1和R0用來設(shè)置分辨率,如下表所示:(DS18B20出廠時(shí)被設(shè)置為12位)

分辨率設(shè)置表:

R1R0分辨率溫度最大轉(zhuǎn)換時(shí)間
009位93.75ms
0110位187.5ms
1011位375ms
1112位750ms

根據(jù)DS18B20的通訊協(xié)議,主機(jī)控制DS18B20完成溫度轉(zhuǎn)換必須經(jīng)過三個(gè)步驟:每一次讀寫之前都要對DS18B20進(jìn)行復(fù)位,復(fù)位成功后發(fā)送一條ROM指令,最后發(fā)送RAM指令,這樣才能對DS18B20進(jìn)行預(yù)定的操作。復(fù)位要求主CPU將數(shù)據(jù)線下拉500微秒,然后釋放,DS18B20收到信號后等待16~60微秒左右,后發(fā)出60~240微秒的存在低脈沖,主CPU收到此信號表示復(fù)位成功。

DS1820使用中注意事項(xiàng)

  DS1820雖然具有測溫系統(tǒng)簡單、測溫精度高、連接方便、占用口線少等優(yōu)點(diǎn),但在實(shí)際應(yīng)用中也應(yīng)注意以下幾方面的問題:

  (1)較小的硬件開銷需要相對復(fù)雜的軟件進(jìn)行補(bǔ)償,由于DS1820與微處理器間采用串行數(shù)據(jù)傳送,因此,在對DS1820進(jìn)行讀寫編程時(shí),必須嚴(yán)格的保證讀寫時(shí)序,否則將無法讀取測溫結(jié)果。在使用PL/M、C等高級語言進(jìn)行系統(tǒng)程序設(shè)計(jì)時(shí),對DS1820操作部分最好采用匯編語言實(shí)現(xiàn)。

  (2)在DS1820的有關(guān)資料中均未提及單總線上所掛DS1820數(shù)量問題,容易使人誤認(rèn)為可以掛任意多個(gè)DS1820,在實(shí)際應(yīng)用中并非如此。當(dāng)單總線上所掛DS1820超過8個(gè)時(shí),就需要解決微處理器的總線驅(qū)動問題,這一點(diǎn)在進(jìn)行多點(diǎn)測溫系統(tǒng)設(shè)計(jì)時(shí)要加以注意。

  (3)連接DS1820的總線電纜是有長度限制的。試驗(yàn)中,當(dāng)采用普通信號電纜傳輸長度超過50m時(shí),讀取的測溫?cái)?shù)據(jù)將發(fā)生錯誤。當(dāng)將總線電纜改為雙絞線帶屏蔽電纜時(shí),正常通訊距離可達(dá)150m,當(dāng)采用每米絞合次數(shù)更多的雙絞線帶屏蔽電纜時(shí),正常通訊距離進(jìn)一步加長。這種情況主要是由總線分布電容使信號波形產(chǎn)生畸變造成的。因此,在用DS1820進(jìn)行長距離測溫系統(tǒng)設(shè)計(jì)時(shí)要充分考慮總線分布電容和阻抗匹配問題。

  (4)在DS1820測溫程序設(shè)計(jì)中,向DS1820發(fā)出溫度轉(zhuǎn)換命令后,程序總要等待DS1820的返回信號,一旦某個(gè)DS1820接觸不好或斷線,當(dāng)程序讀該DS1820時(shí),將沒有返回信號,程序進(jìn)入死循環(huán)。這一點(diǎn)在進(jìn)行DS1820硬件連接和軟件設(shè)計(jì)時(shí)也要給予一定的重視。

經(jīng)過1天半的奮戰(zhàn)終于完成了DS18B20組網(wǎng)的驅(qū)動!不過只是兩點(diǎn)的組網(wǎng),不過多點(diǎn)組網(wǎng)應(yīng)該也不存在技術(shù)上難題!

下面是驅(qū)動程序

頭文件

#ifndef DS18B20_H
#define DS18B20_H
#include "main.h"
//define port and port direction registor
#define Dout RD0
#define DoutDir TRISD0
//define command word
#define ROM_READ 0x33
#define ROM_MATCH 0x55
#define ROM_SKIP 0xCC
#define ROM_SERCH 0xF0
#define ROM_ALARM 0xEC

#define MEM_WRITE 0x4E
#define MEM_READ 0xBE
#define MEM_COPY 0x48
#define MEM_CONVERT 0x44
#define MEM_RECALL 0xB8
#define POWER_READ 0xB4
//define function
void configure_ds18b20(uchar flag) ;//configure the accuration of thermometer
uchar init_ds18b20() ;//初始化ds18b20
uchar read_ds18b20() ;//read a byte from ds18b20
void write_ds18b20(uchar data) ;//write a byte to ds18b20
void get_sequence(uchar *seq) ;//acquire the rom sequence of ds18b20
char get_configure() ;//acquire the configuration of accuration of thermometer
uint get_temp() ;//capture temperature from ds18b20
float process_temp(uint data) ;//process the return value of the get_temp function

void start_convert() ;//start thermometer convert
uint read_temp() ;
void match_rom(uchar data[8]) ;
uint test(const uchar *data) ;//read temperature from ds18b20 specified by data
#endif

子程序

#include "ds18b20.h"

const char crc_code[256]={
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
};
uchar init_ds18b20()
{
uchartemp=0 ;
DoutDir=0 ;
Dout=1 ;
DelayUs(1) ;
Dout=0 ;
DelayUs(600) ;
Dout=1 ;
DoutDir=1 ;
while(Dout) ;
while(!Dout) ///這里使用了超時(shí)設(shè)置
{
DelayUs(24)
if(temp==10)
{
if(Dout)
{
DoutDir=0 ;
return 1 ;
}
else
{
return 0 ;
}
}
temp++ ;
}
DoutDir=0 ;
return 1 ;
}

uchar read_ds18b20()
{
uchar temp,i ;
temp= 0 ;
DoutDir=0 ;
for(i=0;i<8;i++)
{
Dout=1 ;
DelayUs(1) ;
temp=temp>>1 ;
Dout=0 ;
DelayUs(1) ;
Dout=1 ;
DoutDir=1 ;
DelayUs(8) ;
if(Dout)
temp=temp|0x80 ;
DelayUs(60) ;
DoutDir=0 ;
}
Dout=1 ;
return temp ;
}

void write_ds18b20(uchar data)
{
uchar temp ,i ;
DoutDir=0 ;
for(i=0;i<8;i++)
{
temp=data&0x01 ;
if(temp)
{
Dout=0 ;
DelayUs(2) ;
Dout=1 ;
DelayUs(57) ;
}
else
{
Dout=0 ;
DelayUs(57) ;
Dout=1 ;
DelayUs(2) ;
}
data=data>>1 ;
}
Dout=1 ;
}

uint get_temp()
{
uchar th,tl ;
uint temp ;
th=0 ;
tl=0 ;
init_ds18b20() ;
write_ds18b20(ROM_SKIP) ;
write_ds18b20(MEM_CONVERT) ;
init_ds18b20() ;
write_ds18b20(ROM_SKIP) ;
write_ds18b20(MEM_READ) ;
tl=read_ds18b20() ;
th=read_ds18b20() ;
if(!(th&0xf0))
{
th=th&07 ;
temp=th*256+tl ;
return temp ;
}
else
{th=th&0x07 ;
temp=th*256+tl ;
return temp ;
}
}

void get_sequence(uchar *seq)
{
uchar i ;
uchar *temp ;
temp=seq ;
init_ds18b20() ;
write_ds18b20(ROM_READ) ;
for(i=0;i<8;i++)
{
*temp++=read_ds18b20() ;
}
return ;
}

char get_configure()
{
char temp,i ;
i=0 ;
init_ds18b20() ;
write_ds18b20(ROM_SKIP) ;
write_ds18b20(MEM_READ) ;
temp=0 ;
while(++i)
{
temp=read_ds18b20() ;
if(i==5)
return temp ;
}
}

float process_temp(uint data)
{
return data*0.0625 ;
}

void configure_ds18b20(uchar flag)
{
uchar tmp1,tmp2 ;
init_ds18b20() ;
write_ds18b20(ROM_SKIP) ;
write_ds18b20(MEM_READ) ;
tmp1=read_ds18b20() ;
tmp2=read_ds18b20() ;
tmp1=read_ds18b20() ;//get TH
tmp2=read_ds18b20() ;//get Tl
init_ds18b20() ;// reset bus
write_ds18b20(ROM_SKIP) ;//skip rom
write_ds18b20(MEM_WRITE) ;//write command
write_ds18b20(tmp1) ;//
write_ds18b20(tmp2) ;//
switch(flag)
{
case 0 :
write_ds18b20(0x1F) ;
break ;
case 1 :
write_ds18b20(0x3F) ;
break ;
case 2 :
write_ds18b20(0x5F) ;
break ;
case 3 :
write_ds18b20(0x7F) ;
break ;
default :
write_ds18b20(0x1F) ;
break ;
}
init_ds18b20() ;//reset bus
write_ds18b20(ROM_SKIP) ;//skip rom
write_ds18b20(MEM_COPY) ;//copy ram to eeprom
write_ds18b20(MEM_RECALL) ;//recopy eeprom to ram
}

uchar crc_check(uchar *data)
{
uchar temp ,i;
uchar *p=data ;
//complement ;
temp=0 ;
for(i=0;i<7;i++)
{
temp=crc_code[temp^*p] ;
p++ ;
}
if(temp==data[7])
return 1 ;
else
return 0 ;
}

void start_convert()
{
init_ds18b20() ;
write_ds18b20(ROM_SKIP) ;
write_ds18b20(MEM_CONVERT) ;
}
uint read_temp()
{
uchar tl,th ;
uint temp ;
tl=0 ;
th=0 ;
//init_ds18b20() ;
//write_ds18b20(0xcc) ;//note that dont skip rom command here ;
write_ds18b20(MEM_READ) ;
tl=read_ds18b20() ;
th=read_ds18b20() ;
if(!(th&0xf0))
{
th=th&07 ;
temp=th*256+tl ;
return temp ;
}
else
{th=th&0x07 ;
temp=th*256+tl ;
return temp ;
}
}

void match_rom(uchar data[8])
{
//uchar *temp=data ;
uchar i ;
init_ds18b20() ;
write_ds18b20(ROM_MATCH) ;
for(i=0;i<8;i++)
write_ds18b20(data[i]) ;
}

uint test(const uchar *data)//注意這里一定要用const關(guān)鍵字
{
uint temp ;
uchar t,tl,th;
tl=0 ;
th=0 ;
//start_convert() ;
init_ds18b20() ;
write_ds18b20(ROM_MATCH) ;
for(t=0;t<8;t++)
{
write_ds18b20(*data++) ;
}
write_ds18b20(MEM_READ) ;
tl=read_ds18b20() ;
th=read_ds18b20() ;

if(!(th&0xf0))
{
th=th&07 ;
temp=th*256+tl ;
return temp ;
}
else
{th=th&0x07 ;
temp=th*256+tl ;
return temp ;
}
}

主程序

#include
#include


#include "main.h"
#include "t232.h"

#include "ds18b20.h"
const uchar rom1[8]={0x28,0x94,0xB8,0x1A,0x02,0x00,0x00,0x6E} ;
const uchar rom2[8]={0x28,0x4B,0xE6,0x1A,0x02,0x00,0x00,0xB9} ;
void init_all()
{
asm("clrwdt");
init_232() ;
}

void main()
{
const char str[]="hello world!" ;
uchar dat[16],td;
uint data[2] ;
init_all() ;
//get ID of DS18b20
//init_ds18b20() ;
//write_ds18b20(0x33) ;
//for(t=0;t<8;t++)
//{
//td=read_ds18b20() ;
//put_char(td) ;
//}

//configure_ds18b20(3) ;//configure the accuration of thermometer
//td=get_configure() ;
//put_char(td) ;

while(1)
{
start_convert() ;
data[0]=test(rom1) ;
data[1]=test(rom2) ;
DelayMs(70) ;
sprintf(dat,"temp1 %d temp2 %d",data[0],data[1]) ;
send_str(dat) ;
}
}
使用DS18B20中容易出現(xiàn)的問題:

1、讀出的溫度值不變,可能是硬件方面的問題,使用寄生電源方式很容易出現(xiàn)這種問題!建議使用獨(dú)立電源供電,同時(shí)別忘了接4.7K上拉電阻 ;

2、DS18B20讀寫時(shí)序很重要,其實(shí)驅(qū)動DS18B20只需要寫好三個(gè)函數(shù)就可以了,一個(gè)初始化函數(shù),一個(gè)讀字節(jié)函數(shù),一個(gè)寫字節(jié)函數(shù),如果這兩個(gè)函數(shù)驗(yàn)證通過了,你也就成功了一半了,DS18B20的其他功能均是封裝這3個(gè)函數(shù)來實(shí)現(xiàn)的!只需要按照功能的使用命令即可!



評論


技術(shù)專區(qū)

關(guān)閉