新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32的DS18B20的驅動移植

        STM32的DS18B20的驅動移植

        作者: 時間:2018-08-01 來源:網絡 收藏

        把DS18B20的驅動移植到STM32上來

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

        下面說下幾個關鍵點吧:

        首先是延時的問題,STM32上若用軟件延時的話不太好算時間,所以要么用定時器要么用SysTick這個定時器來完成延時的計算。相比之下用SysTick來的簡單方便點。

        接著是STM32 IO腳的配置問題,因為51是雙向的IO,所以作為輸入輸出都比較方便。STM32的IO是準雙向的IO,網上查了下資料,說將STM32的IO配置成開漏輸出,然后外接上拉即可實現雙向IO。于是我也按規定做了,但調了老半天都不成功,是因為DS18B20沒有響應的信號。在煩躁之際只有試下將接DQ的IO分別拉低和拉高看能不能讀入正確的信號。結果果然是讀入數據不對,原來我將IO配成開漏輸出后相當然的以為讀數據是用GPIO_ReadOutputDataBit(),這正是問題所在,后來將讀入的函數改為GPIO_ReadInputDataBit()就OK了。現在溫度是現實出來了,但跟我家里那臺德勝收音機上顯示的溫度相差2度,都不知道是哪個準了,改天再找個溫度計驗證下。

        下面引用一段DS18B20的時序描述,寫的很詳細:

        DS18B20的控制流程

        根據DS18B20的通信協議,DS18B20只能作為從機,而系統作為主機,控制DS18B20完成一次溫度轉換必須經過3個步驟:復位、發送ROM指令、發送RAM指令。每次對DS18B20的操作都要進行以上三個步驟。

        復位過程為:將數據線拉低至少480uS,然后釋放數據線,等待15-60uS讓DS18B20接收信號,DS18B20接收到信號后,會把數據線拉低60-240uS,主機檢測到數據線被拉低后標識復位成功;

        發送ROM指令:ROM指令表示主機對系統上所接的全部DS18B20進行尋址,以確定對那一個DS18B20進行操作,或者是讀取某個DS18B20的ROM序列號。

        發送RAM指令:RAM指令用于單片機對DS18B20內部RAM進行操作,如讀取寄存器的值,或者設置寄存器的值。

        具體的RAM和RAM指令請查閱DS18B20的數據手冊。下面簡單介紹:

        1、ROM操作命令:DS18B20采用一線通信接口。因為一線通信接口,必須在先完成ROM設定,否則記憶和控制功能將無法使用。一旦總線檢測到從屬器件的存在,它便可以發出器件ROM操作指令,所有ROM操作指令均為8位長度,主要提供以下功能命令:

        1 )讀ROM(指令碼0X33H):當總線上只有一個節點(器件)時,讀此節點的64位序列號。如果總線上存在多于一個的節點,則此指令不能使用。

        2 )ROM匹配(指令碼0X55H):此命令后跟64位的ROM序列號,總線上只有與此序列號相同的DS18B20才會做出反應;該指令用于選中某個DS18B20,然后對該DS18B20進行讀寫操作。

        3 )搜索ROM(指令碼0XF0H):用于確定接在總線上DS18B20的個數和識別所有的64位ROM序列號。當系統開始工作,總線主機可能不知道總線上的器件個數或者不知道其64位ROM序列號,搜索命令用于識別所有連接于總線上的64位ROM序列號。

        4 )跳過ROM(指令碼0XCCH):此指令只適合于總線上只有一個節點;該命令通過允許總線主機不提供64位ROM序列號而直接訪問RAM,以節省操作時間。

        5 )報警檢查(指令碼0XECH):此指令與搜索ROM指令基本相同,差別在于只有溫度超過設定的上限或者下限值的DS18B20才會作出響應。只要DS18B20一上電,告警條件就保持在設置狀態,直到另一次溫度測量顯示出非告警值,或者改變TH或TL的設置使得測量值再一次位于允許的范圍之內。儲存在EEPROM內的觸發器用于告警。

        2、RAM指令

        DS18B20有六條RAM命令:

        1)溫度轉換(指令碼0X44H):啟動DS18B20進行溫度轉換,結果存入內部RAM。

        2)讀暫存器(指令碼0XBEH):讀暫存器9個字節內容,此指令從RAM的第1個字節(字節0)開始讀取,直到九個字節(字節8,CRC值)被讀出為止。如果不需要讀出所有字節的內容,那么主機可以在任何時候發出復位信號以中止讀操作。

        3)寫暫存器(指令碼0X4EH):將上下限溫度報警值和配置數據寫入到RAM的2、3、4字節,此命令后跟需要些入到這三個字節的數據。

        4)復制暫存器(指令碼0X48H):把暫存器的2、3、4字節復制到EEPROM中,用以掉電保存。

        5)重新調E2RAM(指令碼0XB8H):把EEROM中的溫度上下限及配置字節恢復到RAM的2、3、4字節,用以上電后恢復以前保存的報警值及配置字節。

        6)讀電源供電方式(指令碼0XB4H):啟動DS18B20發送電源供電方式的信號給主CPU。對于在此命令送至DS18B20后所發出的第一次讀出數據的時間片,器件都會給出其電源方式的信號。“0”表示寄生電源供電。“1”表示外部電源供電。

        下面是結合實際測試總結出來的DS18B20的操作流程:

        1、DS18B20的初始化

        (1) 先將數據線置高電平“1”。

        (2) 延時(該時間要求的不是很嚴格,但是盡可能的短一點)。

        (3) 數據線拉到低電平“0”。

        (4) 延時490微秒(該時間的時間范圍可以從480到960微秒)。

        (5) 數據線拉到高電平“1”。

        (6)延時等待(如果初始化成功則在15到60毫秒時間之內產生一個由DS18B20所返回的低電平“0”。據該狀態可以來確定它的存在,但是應注意不能無限的進行等待,不然會使程序進入死循環,所以要進行超時控制)。

        (7)若CPU讀到了數據線上的低電平“0”后,還要做延時,其延時的時間從發出的高電平算起(第(5)步的時間算起)最少要480微秒。

        (8) 將數據線再次拉高到高電平“1”后結束。

        2、DS18B20的寫操作

        (1) 數據線先置低電平“0”。

        (2) 延時確定的時間為2(小于15)微秒。

        (3) 按從低位到高位的順序發送字節(一次只發送一位)。

        (4) 延時時間為62(大于60)微秒。

        (5) 將數據線拉到高電平,延時2(小于15)微秒。

        (6) 重復上(1)到(6)的操作直到所有的字節全部發送完為止。

        (7) 最后將數據線拉高。

        3、 DS18B20的讀操作

        (1)將數據線拉高“1”。

        (2)延時2微秒。

        (3)將數據線拉低“0”。

        (4)延時2(小于15)微秒。

        (5)將數據線拉高“1”,同時端口應為輸入狀態。

        (6)延時4(小于15)微秒。

        (7)讀數據線的狀態得到1個狀態位,并進行數據處理。

        (8)延時62(大于60)微秒。

        順便把程序也貼上來吧,給大家參考下。

        使用的方法:

        只要調用一次 ds18b20_start() 來初始化DS18B20,然后每次讀溫度時直接調用 ds18b20_read()就可以了。如

        ds18b20_start();

        while(1)

        {

        for(i=1000000;i>0;i--);

        val = ds18b20_read();

        }

        view plaincopy to clipboardprint?

        //========================================================

        // DS18B20.C By ligh

        //========================================================

        #include STM32Lib\stm32f10x.h

        #include DS18B20.h

        #define EnableINT()

        #define DisableINT()

        #define DS_PORT GPIOA

        #define DS_DQIO GPIO_Pin_1

        #define DS_RCC_PORT RCC_APB2Periph_GPIOA

        #define DS_PRECISION 0x7f //精度配置寄存器 1f=9位; 3f=10位; 5f=11位; 7f=12位;

        #define DS_AlarmTH 0x64

        #define DS_AlarmTL 0x8a

        #define DS_CONVERT_TICK 1000

        #define ResetDQ() GPIO_ResetBits(DS_PORT,DS_DQIO)

        #define SetDQ() GPIO_SetBits(DS_PORT,DS_DQIO)

        #define GetDQ() GPIO_ReadInputDataBit(DS_PORT,DS_DQIO)

        static unsigned char TempX_TAB[16]={0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};

        void Delay_us(u32 Nus)

        {

        SysTick->LOAD=Nus*9; //時間加載

        SysTick->CTRL|=0x01; //開始倒數

        while(!(SysTick->CTRL(116))); //等待時間到達

        SysTick->CTRL=0X00000000; //關閉計數器

        SysTick->VAL=0X00000000; //清空計數器

        }

        unsigned char ResetDS18B20(void)

        {

        unsigned char resport;

        SetDQ();

        Delay_us(50);

        ResetDQ();

        Delay_us(500); //500us (該時間的時間范圍可以從480到960微秒)

        SetDQ();

        Delay_us(40); //40us

        //resport = GetDQ();

        while(GetDQ());

        Delay_us(500); //500us

        SetDQ();

        return resport;

        }

        void DS18B20WriteByte(unsigned char Dat)

        {

        unsigned char i;

        for(i=8;i>0;i--)

        {

        ResetDQ(); //在15u內送數到數據線上,DS18B20在15-60u讀數

        Delay_us(5); //5us

        if(Dat 0x01)

        SetDQ();

        else

        ResetDQ();

        Delay_us(65); //65us

        SetDQ();

        Delay_us(2); //連續兩位間應大于1us

        Dat >>= 1;

        }

        }

        unsigned char DS18B20ReadByte(void)

        {

        unsigned char i,Dat;

        SetDQ();

        Delay_us(5);

        for(i=8;i>0;i--)

        {

        Dat >>= 1;

        ResetDQ(); //從讀時序開始到采樣信號線必須在15u內,且采樣盡量安排在15u的最后

        Delay_us(5); //5us

        SetDQ();

        Delay_us(5); //5us

        if(GetDQ())

        Dat|=0x80;

        else

        Dat=0x7f;

        Delay_us(65); //65us

        SetDQ();

        }

        return Dat;

        }

        void ReadRom(unsigned char *Read_Addr)

        {

        unsigned char i;

        DS18B20WriteByte(ReadROM);

        for(i=8;i>0;i--)

        {

        *Read_Addr=DS18B20ReadByte();

        Read_Addr++;

        }

        }

        void DS18B20Init(unsigned char Precision,unsigned char AlarmTH,unsigned char AlarmTL)

        {

        DisableINT();

        ResetDS18B20();

        DS18B20WriteByte(SkipROM);

        DS18B20WriteByte(WriteScratchpad);

        DS18B20WriteByte(AlarmTL);

        DS18B20WriteByte(AlarmTH);

        DS18B20WriteByte(Precision);

        ResetDS18B20();

        DS18B20WriteByte(SkipROM);

        DS18B20WriteByte(CopyScratchpad);

        EnableINT();

        while(!GetDQ()); //等待復制完成 ///////////

        }

        void DS18B20StartConvert(void)

        {

        DisableINT();

        ResetDS18B20();

        DS18B20WriteByte(SkipROM);

        DS18B20WriteByte(StartConvert);

        EnableINT();

        }

        void DS18B20_Configuration(void)

        {

        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(DS_RCC_PORT, ENABLE);

        GPIO_InitStructure.GPIO_Pin = DS_DQIO;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //開漏輸出

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //2M時鐘速度

        GPIO_Init(DS_PORT, GPIO_InitStructure);

        }

        void ds18b20_start(void)

        {

        DS18B20_Configuration();

        DS18B20Init(DS_PRECISION, DS_AlarmTH, DS_AlarmTL);

        DS18B20StartConvert();

        }

        unsigned short ds18b20_read(void)

        {

        unsigned char TemperatureL,TemperatureH;

        unsigned int Temperature;

        DisableINT();

        ResetDS18B20();

        DS18B20WriteByte(SkipROM);

        DS18B20WriteByte(ReadScratchpad);

        TemperatureL=DS18B20ReadByte();

        TemperatureH=DS18B20ReadByte();

        ResetDS18B20();

        EnableINT();

        if(TemperatureH 0x80)

        {

        TemperatureH=(~TemperatureH) | 0x08;

        TemperatureL=~TemperatureL+1;

        if(TemperatureL==0)

        TemperatureH+=1;

        }

        TemperatureH=(TemperatureH4)+((TemperatureL0xf0)>>4);

        TemperatureL=TempX_TAB[TemperatureL0x0f];

        //bit0-bit7為小數位,bit8-bit14為整數位,bit15為正負位

        Temperature=TemperatureH;

        Temperature=(Temperature8) | TemperatureL;

        DS18B20StartConvert();

        return Temperature;

        }

        //============================================

        // DS18B20.H

        //============================================

        #ifndef __DS18B20_H

        #define __DS18B20_H

        #define SkipROM 0xCC //跳過ROM

        #define SearchROM 0xF0 //搜索ROM

        #define ReadROM 0x33 //讀ROM

        #define MatchROM 0x55 //匹配ROM

        #define AlarmROM 0xEC //告警ROM

        #define StartConvert 0x44 //開始溫度轉換,在溫度轉換期間總線上輸出0,轉換結束后輸出1

        #define ReadScratchpad 0xBE //讀暫存器的9個字節

        #define WriteScratchpad 0x4E //寫暫存器的溫度告警TH和TL

        #define CopyScratchpad 0x48 //將暫存器的溫度告警復制到EEPROM,在復制期間總線上輸出0,復制完后輸出1

        #define RecallEEPROM 0xB8 //將EEPROM的溫度告警復制到暫存器中,復制期間輸出0,復制完成后輸出1

        #define ReadPower 0xB4 //讀電源的供電方式:0為寄生電源供電;1為外部電源供電

        void ds18b20_start(void);

        unsigned short ds18b20_read(void);

        #endif

        • STM32單片機中文官網
        • STM32單片機官方開發工具
        • STM32單片機參考設計


        關鍵詞: 單片機

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 平果县| 三台县| 宁南县| 吉木萨尔县| 建德市| 盐源县| 金山区| 修水县| 阜平县| 长岭县| 农安县| 南汇区| 庄河市| 彰化市| 西藏| 息烽县| 嘉禾县| 南乐县| 石阡县| 随州市| 康保县| 封开县| 昌乐县| 海城市| 宣汉县| 平顺县| 来宾市| 庄浪县| 扶沟县| 凤阳县| 冷水江市| 平原县| 板桥市| 霍邱县| 靖安县| 甘泉县| 尚志市| 靖宇县| 沁水县| 石家庄市| 舟山市|