天天看點

STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)

一、環境介紹

程式設計軟體: keil5

作業系統: win10

MCU型号: STM32F103C8T6

STM32程式設計方式: 寄存器開發 (友善程式移植到其他單片機)

溫度傳感器: DS1820

DS18B20是一個數字溫度傳感器,采用的是單總線時序與主機通信,隻需要一根線就可以完成溫度資料讀取;

DS18B20内置了64位産品序列号,友善識别身份,在一根線上可以挂接多個DS18B20傳感器,通過64位身份驗證,可以分别讀取來至不同傳感器采集的溫度資訊。

STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)
STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)

二、DS18B20介紹

2.1 DS18B20 的主要特征

1. 全數字溫度轉換及輸出。

2. 先進的單總線資料通信。

3. 最高 12 位分辨率,精度可達土 0.5 攝氏度。

4. 12 位分辨率時的最大工作周期為 750 毫秒。

5. 可選擇寄生工作方式。

6. 檢測溫度範圍為–55° C ~+125° C (–67° F ~+257° F)

7. 内置 EEPROM,限溫報警功能。

8. 64位光刻 ROM,内置産品序列号,友善多機挂接。

9. 多樣封裝形式,适應不同硬體系統。

STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)

2.2 DS18B20 引腳功能

GND 電壓地

DQ 單資料總線

VDD 電源電壓

NC 空引腳

2.3 DS18B20 工作原理及應用

       DS18B20 的溫度檢測與數字資料輸出全內建于一個晶片之上,進而抗幹擾力更強。其一個工作周期可分為兩個部分,即溫度檢測和資料處理。

18B20 共有三種形态的存儲器資源,它們分别是:ROM 隻讀存儲器,用于存放 DS18B20ID 編碼,其前 8 位是單線系列編碼(DS18B20 的編碼是19H),後面 48 位是晶片唯一的序列号,最後 8 位是以上 56 的位的 CRC 碼(備援校驗)。資料在出産時設定不由使用者更改,DS18B20 一共有 64 位 ROM。

RAM 資料暫存器,用于内部計算和資料存取,資料在掉電後丢失, DS18B20 共 9 個位元組 RAM,每個位元組為 8 位。第 1、 2 個位元組是溫度轉換後的資料值資訊,第 3、 4 個位元組是使用者 EEPROM(常用于溫度報警值儲存)的鏡像。在上電複位時其值将被重新整理。第 5 個位元組則是使用者第 3 個 EEPROM的鏡像。第 6、 7、 8 個位元組為計數寄存器,是為了讓使用者得到更高的溫度分辨率而設計的,同樣也是内部溫度轉換、計算的暫存單元。第 9 個位元組為前 8 個位元組的 CRC 碼。 EEPROM 非易失性記憶體,用于存放長期需要儲存的資料,上下限溫度報警值和校驗資料,DS18B20 共 3 位 EEPROM,并在 RAM 都存在鏡像,以友善使用者操作。

STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)

DS18B20預設工作在12位分辨率模式,轉換後得到的12位資料,存儲在DS18B20的兩個8比特的RAM中(最前面的兩個位元組),二進制中的前面5位是符号位,如果測得的溫度大于0,這5位為0,隻要将測到的數值乘于0.0625即可得到實際溫度;如果溫度小于0,這5位為1,測到的數值需要取反加1再乘于0.0625即可得到實際溫度。或者使用位運算方式提取溫度:  小數位是占用的是低4位,高位是整數位(不考慮負數情況)。

2.4 DS18B20 晶片 ROM 指令表

1.    Read ROM(讀 ROM) [33H] (方括号中的為 16 進制的指令字)

這個指令允許總線控制器讀到 DS18B20 的 64 位 ROM。隻有當總線上隻存在一個 DS18B20 的時候才可以使用此指令,如果挂接不隻一個,當通信時将會發生資料沖突

2.    atch ROM(指定比對晶片) [55H]

這個指令後面緊跟着由控制器發出了 64 位序列号,當總線上有多隻 DS18B20 時,隻有與控制發出的序列号相同的晶片才可以做出反應,其它晶片将等待下一次複位。這條指令适應單晶片和多晶片挂接。

3.    Skip ROM(跳躍 ROM 指令) [CCH]

這條指令使晶片不對 ROM 編碼做出反應,在單總線的情況之下,為了節省時間則可以選用此指令。如果在多晶片挂接時使用此指令将會出現資料沖突,導緻錯誤出現。

4.    Search ROM(搜尋晶片) [F0H]

在晶片初始化後,搜尋指令允許總線上挂接多晶片時用排除法識别所有器件的 64 位 ROM。

5.    Alarm Search(報警晶片搜尋) [ECH]

在多晶片挂接的情況下,報警晶片搜尋指令隻對附合溫度高于 TH 或小于 TL 報警條件的晶片做出反應。隻要晶片不掉電,報警狀态将被保持,直到再一次測得溫度什達不到報警條件為止。

6.    Write Scratchpad (向 RAM 中寫資料) [4EH]

這是向 RAM 中寫入資料的指令,随後寫入的兩個位元組的資料将會被存到位址 2(報警 RAM 之 TH)和位址 3(報警 RAM 之 TL)。寫入過程中可以用複位信号中止寫入。

7.    Read Scratchpad (從 RAM 中讀資料) [BEH]

此指令将從 RAM 中讀資料,讀位址從位址 0 開始,一直可以讀到位址 9,完成整個 RAM 資料的讀出。晶片允許在讀過程中用複位信号中止讀取,即可以不讀後面不需要的位元組以減少讀取時間。

8.    Copy Scratchpad (将 RAM 資料複制到 EEPROM 中) [48H]

此指令将 RAM 中的資料存入 EEPROM 中,以使資料掉電不丢失。此後由于晶片忙于 EEPROM 儲存處理,當控制器發一個讀時間隙時,總線上輸出“0”,當儲存工作完成時,總線将輸出“1”。

在寄生工作方式時必須在發出此指令後立刻超用強上拉并至少保持 10MS,來維持晶片工作。

9.    Convert T(溫度轉換) [44H]

收到此指令後晶片将進行一次溫度轉換,将轉換的溫度值放入 RAM 的第 1、 2 位址。此後由于晶片忙于溫度轉換處理,當控制器發一個讀時間隙時,總線上輸出“0”,當儲存工作完成時,總線将輸出“1”。在寄生工作方式時必須在發出此指令後立刻超用強上拉并至少保持 500MS,來維持晶片工作。

10.    Recall EEPROM(将 EEPROM 中的報警值複制到 RAM) [B8H]

此指令将 EEPROM 中的報警值複制到 RAM 中的第 3、 4 個位元組裡。由于晶片忙于複制處理,當控制器發一個讀時間隙時,總線上輸出“0”,當儲存工作完成時,總線将輸出“1”。另外,此指令将在晶片上電複位時将被自動執行。這樣 RAM 中的兩個報警位元組位将始終為 EEPROM 中資料的鏡像。

11.    Read Power Supply(工作方式切換) [B4H]

此指令發出後發出讀時間隙,晶片會傳回它的電源狀态字,“0”為寄生電源狀态,“1”為外部電源狀态。

2.5 DS18B20時序圖

2.5.1 DS18B20 複位及應答關系示意圖

STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)
STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)

每一次通信之前必須進行複位,複位的時間、等待時間、回應時間應嚴格按時序程式設計。

DS18B20 讀寫時間隙:DS18B20的資料讀寫是通過時間隙處理位和指令字來确認資訊交換的。

2.5.2  向DS18B20寫資料0和資料1
STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)

在寫資料時間隙的前 15uS 總線需要是被控制器拉置低電平,而後則将是晶片對總線資料的采樣時間,采樣時間在 15~60uS,采樣時間内如果控制器将總線拉高則表示寫“1”,如果控制器将總線拉低則表示寫“0”。

每一位的發送都應該有一個至少 15uS的低電平起始位,随後的資料“0”或“1”應該在 45uS 内完成。

整個位的發送時間應該保持在 60~120uS,否則不能保證通信的正常。

注意:  DS18B20讀寫資料都是從低位開始傳輸。

2.5.3 從DS18B20讀資料0和資料1

STM32入門開發: 編寫DS18B20溫度傳感器驅動(讀取環境溫度、支援級聯)

讀時間隙時控制時的采樣時間應該更加的精确才行,讀時間隙時也是必須先由主機産生至少1uS的低電平,表示讀時間的起始。随後在總線被釋放後的 15uS 中 DS18B20 會發送内部資料位,這時控制如果發現總線為高電平表示讀出“1”,如果總線為低電平則表示讀出資料“0”。每一位的讀取之前都由控制器加一個起始信号。

注意:必須在讀間隙開始的 15uS 内讀取資料位才可以保證通信的正确。

在通信時是以 8 位“0”或“1”為一個位元組,位元組的讀或寫是從低位開始的。

2.5.4  讀取一次溫度的順序(總線上隻有單個DS18B20情況)

1. 發送複位信号

2. 檢測回應信号

3. 發送0xCC

4. 發送0x44

5. 發送複位信号

6. 檢測回應信号

7. 寫0xcc

8. 寫0xbe

9. 循環8次讀取溫度低位元組

10. 循環8次讀取溫度高位元組

11. 合成16位溫度資料,處理

三、驅動代碼

3.1 DS18B20.c

#include "ds18b20.h"
 
/*
函數功能: DS18B20初始化
硬體連接配接: PB15
*/
void DS18B20_Init(void)
{
        RCC->APB2ENR|=1<<3; //PB
        GPIOB->CRH&=0x0FFFFFFF;
        GPIOB->CRH|=0x30000000;
        GPIOB->ODR|=1<<15; //上拉
}
 
 
/*
函數功能: 檢測DS18B20裝置是否存在
傳回值  : 1表示裝置不存在 0表示裝置正常
*/
u8 DS18B20_CheckDevice(void)  //包含了複位脈沖、檢測存在脈沖
{
        DS18B20_OUTPUT_MODE();//初始化為輸出模式
        DS18B20_OUT=0;        //産生複位脈沖
        DelayUs(750);         //産生750us的低電平
        DS18B20_OUT=1;        //釋放總線
        DelayUs(15);          //等待DS18B20回應
        if(DS18B20_CleckAck())//檢測存在脈沖
        {
                return 1;
        }
        return 0;
}
 
/*
函數功能: 檢測DS18B20裝置的存在脈沖
傳回值  : 1表示錯誤 0表示正常
*/
u8 DS18B20_CleckAck(void)
{
        u8 cnt=0;
        DS18B20_INPUT_MODE();//初始化為輸入模式
        while(DS18B20_IN&&cnt<200) //等待DS18B20響應存在脈沖
        {
                DelayUs(1);
                cnt++;
        }
        if(cnt>=200)return 1; //錯誤
        
        cnt=0;
        while((!DS18B20_IN)&&cnt<240) //等待DS18B20釋放總線
        {
                DelayUs(1);
                cnt++;
        }
        if(cnt>=240)return 1; //錯誤
        return 0;
}
 
 
/*
函數功能: 寫一個位元組
首先學會如何寫一個位。
*/
void DS18B20_WriteByte(u8 cmd)
{
        u8 i;
        DS18B20_OUTPUT_MODE(); //初始化為輸出模式
        for(i=0;i<8;i++)
      {
                DS18B20_OUT=0;  //産生寫時間間隙(寫開始)
                DelayUs(2);
                DS18B20_OUT=cmd&0x01; //發送實際的資料位
                DelayUs(60);    //等待寫完成
                DS18B20_OUT=1;  //釋放總線,準備下一次發送
                cmd>>=1;        //繼續發送下一位資料
        }
}
 
/*
函數功能: 讀一個位元組
首先學會如何讀一個位。
*/
u8 DS18B20_ReadByte(void)
{
     u8 i,data=0;   
     for(i=0;i<8;i++)
     {
            DS18B20_OUTPUT_MODE(); //初始化為輸出模式
            DS18B20_OUT=0;  //産生讀時間間隙(讀開始)
            DelayUs(2);
            DS18B20_OUT=1;  //釋放總線
            DS18B20_INPUT_MODE(); //初始化為輸入模式
            DelayUs(8);    //等待DS18B20的資料輸出
            data>>=1;      //高位補0,預設以0為準
          if(DS18B20_IN) data|=0x80;
            DelayUs(60);
            DS18B20_OUT=1;  //釋放總線,等待讀取下一位資料
     }
     return data;
}
 
 
/*
函數功能: 讀取一次DS18B20的溫度資料
返 回 值: 讀取的溫度資料
考慮的情況:  總線上隻是接了一個DS18B20的情況
*/
u16 DS18B20_ReadTemp(void)
{
      u16 temp=0;
        u8 temp_H,temp_L;
      DS18B20_CheckDevice();   //發送複位脈沖、檢測存在脈沖
        DS18B20_WriteByte(0xCC); //跳過ROM序列檢測
        DS18B20_WriteByte(0x44); //啟動一次溫度轉換
        
        //等待溫度轉換完成
        while(DS18B20_ReadByte()!=0xFF){}
        
        DS18B20_CheckDevice();   //發送複位脈沖、檢測存在脈沖
        DS18B20_WriteByte(0xCC); //跳過ROM序列檢測
        DS18B20_WriteByte(0xBE); //讀取溫度
        
        temp_L=DS18B20_ReadByte(); //讀取的溫度低位資料
        temp_H=DS18B20_ReadByte(); //讀取的溫度高位資料
        temp=temp_L|(temp_H<<8);   //合成溫度
        return temp;
}
 
       

3.2 DS18B20.h

#ifndef DS18B20_H
#define DS18B20_H
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "ds18b20.h"
#include "usart.h"
 
/*封裝接口*/
 
//初始化DS18B20為輸入模式
#define DS18B20_INPUT_MODE() {GPIOB->CRH&=0x0FFFFFFF;GPIOB->CRH|=0x80000000;}
 
//初始化DS18B20為輸出模式
#define DS18B20_OUTPUT_MODE(){GPIOB->CRH&=0x0FFFFFFF;GPIOB->CRH|=0x30000000;}
 
//DS18B20 IO口輸出
#define DS18B20_OUT PBout(15)
 
//DS18B20 IO口輸入
#define DS18B20_IN PBin(15) 
 
//函數聲明
u8 DS18B20_CleckAck(void);
u8 DS18B20_CheckDevice(void);
void DS18B20_Init(void);
u16 DS18B20_ReadTemp(void);
u8 DS18B20_ReadByte(void);
void DS18B20_WriteByte(u8 cmd);
#endif      

3.3 延時函數

/*
函數功能: 延時us機關
*/
void DelayUs(int us)
{
#ifdef  _SYSTICK_IRQ_
    int i,j;
    for(i=0;i<us;i++)
        for(j=0;j<72;j++);
#else
    u32 tmp;
    SysTick->VAL=0;         //CNT計數器值   
    SysTick->LOAD=9*us;     //9表示1us
    SysTick->CTRL|=1<<0;    //開啟定時器 
    do
    {
            tmp=SysTick->CTRL; //讀取狀态
    }while((!(tmp&1<<16))&&(tmp&1<<0));
    SysTick->VAL=0;         //CNT計數器值   
    SysTick->CTRL&=~(1<<0); //關閉定時器 
#endif  
}      

3.4 main.c 調用DS18B20讀取溫度列印到序列槽

#include "stm32f10x.h"
#include "ds18b20.h"
 
u8 DS18B20_ROM[8]; //存放DS18B20的64為ROM編碼
 
int main(void)
{
    u16 temp;
    USARTx_Init(USART1,72,115200);//序列槽1的初始化
    DS18B20_Init();   //DS18B20初始化
    
    /*1. 讀取DS18B20的64位ROM編碼*/
    //發送複位脈沖、檢測存在脈沖
    while(DS18B20_CheckDevice()) 
    {
            printf("DS18B20裝置不存在!\n");
            DelayMs(500);
    }
    //發送讀取64為ROM編碼的指令
    DS18B20_WriteByte(0x33);
    
    //循環讀取64位ROM編碼
    for(i=0;i<8;i++)
    {
            DS18B20_ROM[i]= DS18B20_ReadByte();
            printf("DS18B20_ROM[%d]=0x%X\n",i,DS18B20_ROM[i]);
    }
    
    while(1)
    {
            /*2. 同時操作總線上所有的DS18B20開始轉換溫度*/
            DS18B20_CheckDevice();   //發送複位脈沖、檢測存在脈沖
            DS18B20_WriteByte(0xCC); //跳過ROM序列檢測
            DS18B20_WriteByte(0x44); //啟動一次溫度轉換(讓總線上所有的DS18B20都轉換溫度)
            DelayMs(500);  //等待線上所有的DS18B20溫度轉換完成
            
            /*3. 單個針對性讀取每個DS18B20的溫度*/
            DS18B20_CheckDevice();   //發送複位脈沖、檢測存在脈沖
            DS18B20_WriteByte(0x55); //發送比對ROM的指令
            for(i=0;i<8;i++)         //發送64位編碼
            {
                    DS18B20_WriteByte(DS18B20_ROM[i]); 
            }
            DS18B20_WriteByte(0xBE);      //讀取溫度
            temp=DS18B20_ReadByte();      //讀取的溫度低位資料
            temp|=DS18B20_ReadByte()<<8;  //讀取的溫度高位資料
            printf("temp1=%d.%d\n",temp>>4,temp&0xF);
            printf("temp2=%f\n",temp*0.0625);
            
            DelayMs(500);
    }   
}      

繼續閱讀