新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > PIC16F877A驅動DS18B20溫度采集芯片

        PIC16F877A驅動DS18B20溫度采集芯片

        作者: 時間:2016-11-09 來源:網絡 收藏
        今天開始驅動DS18B20溫度采集芯片!

        從網上收集的資料

        本文引用地址:http://www.104case.com/article/201611/317655.htm

        DS18B20的內部結構

        DS18B20內部結構主要由四部分組成:64位光刻ROM、溫度傳感器、非揮發的溫度報警觸發器TH和TL、配置寄存器。DS18B20的管腳排列如下:

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

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

        DS18B20中的溫度傳感器可完成對溫度的測量,以12位轉化為例:用16位符號擴展的二進制補碼讀數形式提供,以0.0625℃/LSB形式表達,其中S為符號位。

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

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

        DS18B20溫度傳感器的存儲器

        DS18B20溫度傳感器的內部存儲器包括一個高速暫存RAM和一個非易失性的可電擦除的E2RAM,后者存放高溫度和低溫度觸發器TH、TL和結構寄存器。

        暫存存儲器包含了8個連續字節,前兩個字節是測得的溫度信息,第一個字節的內容是溫度的低八位,第二個字節是溫度的高八位。第三個和第四個字節是TH、TL的易失性拷貝,第五個字節是結構寄存器的易失性拷貝,這三個字節的內容在每一次上電復位時被刷新。第六、七、八個字節用于內部計算。第九個字節是冗余檢驗字節。

        該字節各位的意義如下:

        TM R1 R0 1 1 1 1 1

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

        分辨率設置表:

        R1R0分辨率溫度最大轉換時間
        009位93.75ms
        0110位187.5ms
        1011位375ms
        1112位750ms

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

        DS1820使用中注意事項

          DS1820雖然具有測溫系統簡單、測溫精度高、連接方便、占用口線少等優點,但在實際應用中也應注意以下幾方面的問題:

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

          (2)在DS1820的有關資料中均未提及單總線上所掛DS1820數量問題,容易使人誤認為可以掛任意多個DS1820,在實際應用中并非如此。當單總線上所掛DS1820超過8個時,就需要解決微處理器的總線驅動問題,這一點在進行多點測溫系統設計時要加以注意。

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

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

        經過1天半的奮戰終于完成了DS18B20組網的驅動!不過只是兩點的組網,不過多點組網應該也不存在技術上難題!

        下面是驅動程序

        頭文件

        #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) ///這里使用了超時設置
        {
        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關鍵字
        {
        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中容易出現的問題:

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

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



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 沙雅县| 西华县| 蒙阴县| 博乐市| 林甸县| 娄烦县| 轮台县| 铁力市| 公安县| 宜宾县| 达拉特旗| 枣庄市| 马尔康县| 江山市| 黄石市| 淅川县| 巴塘县| 三门峡市| 井研县| 谢通门县| 灵武市| 柯坪县| 荥经县| 临桂县| 上犹县| 曲沃县| 毕节市| 安达市| 盐山县| 平远县| 淮北市| 昌宁县| 江陵县| 西宁市| 天长市| 桂阳县| 富平县| 介休市| 恩施市| 黄石市| 象州县|