找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 7186|回復(fù): 15
打印 上一主題 下一主題
收起左側(cè)

玩轉(zhuǎn)DS1302和DS18B20

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
對(duì)于市面上的大多數(shù)51單片機(jī)開發(fā)板來(lái)說(shuō)。ds1302和ds18b20應(yīng)該是比較常見的兩種外圍芯片。ds1302是具有SPI總線接口的時(shí)鐘芯片。ds18b20則是具有單總線接口的數(shù)字溫度傳感器。下面讓我們分別來(lái)認(rèn)識(shí)并學(xué)會(huì)應(yīng)用這兩種芯片。
首先依舊是看DS1302的datasheet中的相關(guān)介紹。

上面是它的一些基本的應(yīng)用介紹。
下面是它的引腳的描述。

下面是DS1302的時(shí)鐘寄存器。我們要讀取的時(shí)間數(shù)據(jù)就是從下面這些數(shù)據(jù)寄存器中讀取出來(lái)的。當(dāng)我們要想調(diào)整時(shí)間時(shí),可以把時(shí)間數(shù)據(jù)寫入到相應(yīng)的寄存器中就可以了。

這是DS1302內(nèi)部的31個(gè)RAM寄存器。在某些應(yīng)用場(chǎng)合我們可以應(yīng)用到。如我們想要做一個(gè)帶定時(shí)功能的鬧鐘。則可以把鬧鐘的時(shí)間寫入到31個(gè)RAM寄存器中的任意幾個(gè)。當(dāng)單片機(jī)掉電時(shí),只要我們的DS1302的備用電池還能工作,那么保存在其中的鬧鐘數(shù)據(jù)就不會(huì)丟失~~

由于對(duì)于這些器件的操作基本上按照數(shù)據(jù)手冊(cè)上面提供的時(shí)序圖和相關(guān)命令字來(lái)進(jìn)行操作就可以了。因此在我們應(yīng)用這些器件的時(shí)候一定要對(duì)照著手冊(cè)上面的要求來(lái)進(jìn)行操作。如果覺得還不夠放心的話?梢缘骄W(wǎng)上下載一些參考程序。對(duì)著手冊(cè)看別人的程序,看別人的思路是怎么樣的。
     DS1302和單片機(jī)的連接很簡(jiǎn)單。只需一根復(fù)位線,一根時(shí)鐘線,一根數(shù)據(jù)線即可。同時(shí)它本身還需要接一個(gè)32.768KHz的晶振來(lái)提供時(shí)鐘源。對(duì)于晶振的兩端可以分別接一個(gè)6PF左右的電容以提高晶振的精確度。同時(shí)可以在第8腳接上一個(gè)3.6V的可充電的電池。當(dāng)系統(tǒng)正常工作時(shí)可以對(duì)電池進(jìn)行涓流充電。當(dāng)系統(tǒng)掉電時(shí),DS1302由這個(gè)電池提供的能量繼續(xù)工作。
     下面讓我們來(lái)驅(qū)動(dòng)它。
     sbit io_DS1302_RST  = P2^0 ;
     sbit io_DS1302_IO     = P2^1 ;
     sbit io_DS1302_SCLK = P2^2 ;
     
     //-------------------------------------常數(shù)宏---------------------------------//
    #define DS1302_SECOND_WRITE        0x80          //寫時(shí)鐘芯片的寄存器位置
    #define DS1302_MINUTE_WRITE        0x82
    #define DS1302_HOUR_WRITE        0x84
    #define DS1302_WEEK_WRITE        0x8A
    #define DS1302_DAY_WRITE        0x86
    #define DS1302_MONTH_WRITE        0x88
    #define DS1302_YEAR_WRITE        0x8C

    #define DS1302_SECOND_READ        0x81          //讀時(shí)鐘芯片的寄存器位置
    #define DS1302_MINUTE_READ        0x83
    #define DS1302_HOUR_READ        0x85
    #define DS1302_WEEK_READ        0x8B
    #define DS1302_DAY_READ        0x87
    #define DS1302_MONTH_READ        0x89
    #define DS1302_YEAR_READ        0x8D
//-----------------------------------操作宏----------------------------------//
    #define DS1302_SCLK_HIGH         io_DS1302_SCLK = 1 ;
    #define    DS1302_SCLK_LOW             io_DS1302_SCLK = 0 ;
     
    #define DS1302_IO_HIGH             io_DS1302_IO   = 1 ;
    #define DS1302_IO_LOW             io_DS1302_IO   = 0 ;
    #define DS1302_IO_READ           io_DS1302_IO

    #define DS1302_RST_HIGH             io_DS1302_RST  = 1 ;
    #define DS1302_RST_LOW           io_DS1302_RST  = 0 ;




/******************************************************
* 保存時(shí)間數(shù)據(jù)的結(jié)構(gòu)體         *
******************************************************/
struct
{
    uint8 Second ;
    uint8 Minute ;
    uint8 Hour ;
    uint8 Day ;
    uint8 Week ;
    uint8 Month ;
    uint8 Year ;
}CurrentTime ;



/******************************************************************************
* Function:    static void v_DS1302Write_f( uint8 Content )        *
* Description:向DS1302寫一個(gè)字節(jié)的內(nèi)容            *
* Parameter:uint8 Content :    要寫的字節(jié)            *
*                        *
******************************************************************************/

static void v_DS1302Write_f( uint8 Content )
{
    uint8 i ;
    for( i = 8 ; i > 0 ; i-- )
    {
        if( Content & 0x01 )
        {
            DS1302_IO_HIGH
        }
        else
        {
            DS1302_IO_LOW
        }
        Content >>= 1 ;

        DS1302_SCLK_HIGH   
        DS1302_SCLK_LOW
    }
}


/******************************************************************************
* Function:    static uint8 v_DS1302Read_f( void )          *
* Description: 從DS1302當(dāng)前設(shè)定的地址讀取一個(gè)字節(jié)的內(nèi)容    *
* Parameter:                    *
* Return:    返回讀出來(lái)的值(uint8)                 *
******************************************************************************/
static uint8 v_DS1302Read_f( void )
{
    uint8 i, ReadValue ;
    DS1302_IO_HIGH
    for( i = 8 ; i > 0 ; i-- )
    {
         ReadValue >>= 1 ;
          if( DS1302_IO_READ )
         {
             ReadValue |= 0x80 ;
         }
         else
         {
             ReadValue &= 0x7f ;
         }

         DS1302_SCLK_HIGH
         DS1302_SCLK_LOW
         
    }
    return ReadValue ;
}

/******************************************************************************
* Function:    void v_DS1302WriteByte_f( uint8 Address,  uint8 Content )     *
* Description:  從DS1302指定的地址寫入一個(gè)字節(jié)的內(nèi)容               *
* Parameter:  Address:    要寫入數(shù)據(jù)的地址            *
*    Content:    寫入數(shù)據(jù)的具體值            *
* Return:                                                                                                                *
******************************************************************************/
void v_DS1302WriteByte_f( uint8 Address,  uint8 Content )
{
    DS1302_RST_LOW
    DS1302_SCLK_LOW
    DS1302_RST_HIGH     

    v_DS1302Write_f( Address ) ;
    v_DS1302Write_f( Content ) ;

    DS1302_RST_LOW
    DS1302_SCLK_HIGH
}

/******************************************************************************
* Function:    uint8 v_DS1302ReadByte_f( uint8 Address )                          *
* Description:從DS1302指定的地址讀出一個(gè)字節(jié)的內(nèi)容        *
* Parameter:Address:    要讀出數(shù)據(jù)的地址            *
*                         *
* Return:        指定地址讀出的值(uint8)         *
******************************************************************************/
uint8 v_DS1302ReadByte_f( uint8 Address )
{
    uint8 ReadValue ;
    DS1302_RST_LOW
    DS1302_SCLK_LOW
    DS1302_RST_HIGH     

    v_DS1302Write_f( Address ) ;
    ReadValue = v_DS1302Read_f() ;

    DS1302_RST_LOW
    DS1302_SCLK_HIGH
    return ReadValue ;
}
/******************************************************************************
* Function:    void v_ClockInit_f( void )             *
* Description:初始化寫入DS1302時(shí)鐘寄存器的值(主程序中只需調(diào)用一次即可) *
* Parameter:                                                                                                                                        *
*                                               *
* Return:                            *
******************************************************************************/
void v_ClockInit_f( void )
{
    if( v_DS1302ReadByte_f( 0xc1) != 0xf0 )
    {
        v_DS1302WriteByte_f( 0x8e, 0x00 ) ;     //允許寫操作
        v_DS1302WriteByte_f( DS1302_YEAR_WRITE, 0x08 ) ;     //年
        v_DS1302WriteByte_f( DS1302_WEEK_WRITE, 0x04 ) ;     //星期
        v_DS1302WriteByte_f( DS1302_MONTH_WRITE, 0x12 ) ;     //月
        v_DS1302WriteByte_f( DS1302_DAY_WRITE, 0x11 ) ;          //日
        v_DS1302WriteByte_f( DS1302_HOUR_WRITE, 0x13 ) ;     //小時(shí)
        v_DS1302WriteByte_f( DS1302_MINUTE_WRITE, 0x06 ) ;     //分鐘
        v_DS1302WriteByte_f( DS1302_SECOND_WRITE, 0x40 ) ;     //秒
        v_DS1302WriteByte_f( 0x90, 0xa5 ) ;                      //充電
    v_DS1302WriteByte_f( 0xc0, 0xf0 ) ;             //判斷是否初始化一次標(biāo)識(shí)寫入
        v_DS1302WriteByte_f( 0x8e, 0x80 ) ;                      //禁止寫操作
    }
}
/******************************************************************************
* Function:    void v_ClockUpdata_f( void )             *
* Description:讀取時(shí)間數(shù)據(jù),并保存在結(jié)構(gòu)體CurrentTime中         *
* Parameter:                                                                                                                                                       *
*                        *
* Return:                                                                                                                                          *
******************************************************************************/
void v_ClockUpdata_f( void )
{
    CurrentTime.Second = v_DS1302ReadByte_f( DS1302_SECOND_READ ) ;
    CurrentTime.Minute = v_DS1302ReadByte_f( DS1302_MINUTE_READ ) ;
    CurrentTime.Hour   = v_DS1302ReadByte_f( DS1302_HOUR_READ ) ;
    CurrentTime.Day    = v_DS1302ReadByte_f( DS1302_DAY_READ ) ;
    CurrentTime.Month  = v_DS1302ReadByte_f( DS1302_MONTH_READ ) ;
    CurrentTime.Week   = v_DS1302ReadByte_f( DS1302_WEEK_READ ) ;
    CurrentTime.Year   = v_DS1302ReadByte_f( DS1302_YEAR_READ ) ;
}

有了上面的這些函數(shù)我們就可以對(duì)DS1302進(jìn)行操作了。當(dāng)我們想要獲取當(dāng)前時(shí)間時(shí),只需要調(diào)用v_ClockUpdata_f( void )這個(gè)函數(shù)即可。讀取到的時(shí)間數(shù)據(jù)保存在CurrentTime這個(gè)結(jié)構(gòu)體中。至于如何把時(shí)間數(shù)據(jù)在數(shù)碼管或者是液晶屏上顯示出來(lái)我相信大家應(yīng)該都會(huì)了吧^_^.

看看顯示效果如何~~


下面再讓我們看看DS18B20吧。
DS18B20是單總線的數(shù)字溫度傳感器。其與單片機(jī)的接口只需要一根數(shù)據(jù)線即可。當(dāng)然連線簡(jiǎn)單意味著軟件處理上可能要麻煩一點(diǎn)。下面來(lái)看看它的優(yōu)點(diǎn):

看看它的靚照。外形和我們常用的三極管沒有什么兩樣哦。
   
DS18B20的內(nèi)部存儲(chǔ)器分為以下幾部分
ROM:存放該器件的編碼。前8位為單線系列的編碼(DS18B20的編碼是19H)后面48位為芯片的唯一序列號(hào)。在出場(chǎng)的時(shí)候就已經(jīng)設(shè)置好,用戶無(wú)法更改。最后8位是以上56位的CRC碼。
RAM:DS18B20的內(nèi)部暫存器共9個(gè)字節(jié)。其中第一個(gè)和第二個(gè)字節(jié)存放轉(zhuǎn)換后的溫度值。第二個(gè)和第三個(gè)字節(jié)分別存放高溫和低溫告警值。(可以用RAM指令將其拷貝到EEPROM中)第四個(gè)字節(jié)為配置寄存器。第5~7個(gè)字節(jié)保留。第9個(gè)字節(jié)為前8個(gè)字節(jié)的CRC碼。
  
DS18B20的溫度存放如上圖所示。其中S位符號(hào)位。當(dāng)溫度值為負(fù)值時(shí),S = 1 ,反之則S = 0 。我們把得到的溫度數(shù)據(jù)乘上對(duì)應(yīng)的分辨率即可以得到轉(zhuǎn)換后的溫度值。
DS18B20的通訊協(xié)議:
    在對(duì)DS18B20進(jìn)行讀寫編程時(shí),必須嚴(yán)格保證讀寫的時(shí)序。否則將無(wú)法讀取測(cè)溫結(jié)果。根據(jù)DS18B20的通訊協(xié)議,主機(jī)控制DS18B20完成溫度轉(zhuǎn)換必須經(jīng)過(guò)3個(gè)步驟:每一次讀寫之前都要對(duì)DS18B20進(jìn)行復(fù)位,復(fù)位成功后發(fā)送一條ROM指令,最后發(fā)送RAM指令。這樣才能對(duì)DS18B20進(jìn)行預(yù)定的操作。
復(fù)位要求主機(jī)將數(shù)據(jù)線下拉500us,然后釋放,DS18B20收到信號(hào)后等待16~160us然后發(fā)出60~240us的存在低脈沖,主機(jī)收到此信號(hào)表示復(fù)位成功。

上圖即DS18B20的復(fù)位時(shí)序圖。
下面是讀操作的時(shí)序圖
  
這是寫操作的時(shí)序圖

下面讓我們來(lái)看看它的驅(qū)動(dòng)程序如何寫吧。

sbit io_DS18B20_DQ  = P2^3 ;
#define DS18B20_DQ_HIGH  io_DS18B20_DQ = 1 ;
#define DS18B20_DQ_LOW   io_DS18B20_DQ = 0 ;
#define DS18B20_DQ_READ  io_DS18B20_DQ

/*******************************************************************
* 保存溫度值的數(shù)組.依次存放正負(fù)標(biāo)志,溫度值十位,個(gè)位,和小數(shù)位        *
*******************************************************************/
uint8 Temperature[ 4 ] ;

void v_Delay10Us_f( uint16 Count )
{
    while( --Count )
    {
        _nop_();
    }
}

/**************************************************************************
* Function:        uint8 v_Ds18b20Init_f( void )                                 *
* Description:    初始化DS18B20                                                 *
* Parameter:                                                                  *
*                                                                          *
* Return:        返回初始化的結(jié)果(0:復(fù)位成功   1:復(fù)位失敗)                         *
**************************************************************************/
uint8 v_Ds18b20Init_f( void )
{
    uint8 Flag ;
    DS18B20_DQ_HIGH          //稍作延時(shí)
    v_Delay10Us_f( 3 ) ;
    DS18B20_DQ_LOW           //總線拉低

    v_Delay10Us_f( 80 ) ; //延時(shí)大于480us

    DS18B20_DQ_HIGH       //總線釋放

    v_Delay10Us_f( 15 ) ;

    Flag = DS18B20_DQ_READ ;   //如果Flag為0,則復(fù)位成功,否則復(fù)位失敗
    return Flag ;
}
/******************************************************************************
* Function:        void v_Ds18b20Write_f( uint8 Cmd )                                 *
* Description:    向DS18B20寫命令                                                 *
* Parameter:    Cmd:    所要寫的命令                                              *
*                                                                              *
* Return:                                                                         *
******************************************************************************/
void v_Ds18b20Write_f( uint8 Cmd )
{
    uint8 i ;
    for( i = 8 ; i > 0 ; i-- )
    {
        DS18B20_DQ_LOW             //拉低總線,開始寫時(shí)序
        DS18B20_DQ_READ = Cmd & 0x01  ;     //控制字的最低位先送到總線
        v_Delay10Us_f( 5 ) ;             //稍作延時(shí),讓DS18B20讀取總線上的數(shù)據(jù)
        DS18B20_DQ_HIGH             //拉高總線,1bit寫周期結(jié)束
        Cmd >>= 1 ;
    }
}



/******************************************************************************
* Function:        uint8 v_Ds18b20Read_f( void )                                      *
* Description:    向DS18B20讀取一個(gè)字節(jié)的內(nèi)容                                     *
* Parameter:                                                                       *
*                                                                              *
* Return:        讀取到的數(shù)據(jù)                                                     *
******************************************************************************/
uint8 v_Ds18b20Read_f( void )
{
    uint8 ReadValue, i ;
    for( i = 8 ; i > 0 ; i-- )
    {
        DS18B20_DQ_LOW     
        ReadValue >>= 1 ;
        DS18B20_DQ_HIGH
        if( DS18B20_DQ_READ == 1 )
        ReadValue |= 0x80 ;
        v_Delay10Us_f( 3 ) ;
    }
    return ReadValue ;
}

/******************************************************************************
* Function:        uint16 v_Ds18b20ReadTemp_f( void )                                  *
* Description:    讀取當(dāng)前的溫度數(shù)據(jù)(只保留了一位小數(shù))                                 *
* Parameter:                                                                        *
*                                                                                 *
* Return:        讀取到的溫度值                                                     *
******************************************************************************/
uint16 v_Ds18b20ReadTemp_f( void )
{
    uint8 TempH, TempL ;
    uint16 ReturnTemp ;
     
/*    if( v_Ds18b20Init_() ) return ;  //復(fù)位失敗,在這里添加錯(cuò)誤處理的代碼      */
    v_Ds18b20Init_f() ;            /復(fù)位DS18B20
    v_Ds18b20Write_f( 0xcc ) ;    //跳過(guò)ROM
    v_Ds18b20Write_f( 0x44 ) ;         //啟動(dòng)溫度轉(zhuǎn)換
    v_Ds18b20Init_f() ;            
    v_Ds18b20Write_f( 0xcc ) ;    //跳過(guò)ROM
    v_Ds18b20Write_f( 0xbe ) ;    //讀取DS18B20內(nèi)部的寄存器內(nèi)容
    TempL = v_Ds18b20Read_f() ;     //讀溫度值低位(內(nèi)部RAM的第0個(gè)字節(jié))
    TempH = v_Ds18b20Read_f() ;     //讀溫度值高位(內(nèi)部RAM的第1個(gè)字節(jié))
    ReturnTemp = TempH ;
    ReturnTemp <<= 8 ;
    ReturnTemp |= TempL ;     //溫度值放在變量ReturnTemp中
    return ReturnTemp ;
}
/******************************************************************************
* Function:    void v_TemperatureUpdate_f( void )        *
* Description:讀取當(dāng)前的溫度數(shù)據(jù)并轉(zhuǎn)化存放在數(shù)組Temperature(只保留了一位小數(shù)) *
* Parameter:                                                                                                                                           *
*                            *
* Return:                                                                                                                                             *
******************************************************************************/
void v_TemperatureUpdate_f( void )
{
    uint8 Tflag = 0 ;
    uint16 TempDat ;
    float Temp ;
    TempDat = v_Ds18b20ReadTemp_f() ;
    if( TempDat & 0xf000 )
    {
        Tflag = 1 ;                           
        TempDat = ~TempDat + 1 ;
    }
    Temp = TempDat * 0.0625    ;           
    TempDat = Temp * 10          ;         
    Temperature[ 0 ] = Tflag ;          //溫度正負(fù)標(biāo)志
    Temperature[ 1 ] = TempDat / 100  + '0' ;       //溫度十位值
    Temperature[ 2 ] = TempDat % 100 / 10 + '0' ;  //溫度個(gè)位值
    Temperature[ 3 ] = TempDat % 10         + '0' ;//溫度小數(shù)位
}
如果想獲取當(dāng)前的溫度數(shù)據(jù),在主函數(shù)中調(diào)用v_TemperatureUpdate_f( void )就可以了。溫度數(shù)據(jù)就保存到Temperature中去了。至于如何顯示,就不用多說(shuō)了吧~@_@~
   
時(shí)間和溫度一起顯示出來(lái)看看

OK,至此ds18b20和ds1302的應(yīng)用告一段落。如果有不懂的,記得多看datasheet,多交流。

評(píng)分

參與人數(shù) 2黑幣 +20 收起 理由
bh4djj + 12 贊一個(gè)!
wrty0 + 8 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏9 分享淘帖 頂1 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:262 發(fā)表于 2013-9-6 14:47 | 只看該作者
好東東我頂,51hei(51黑)單片機(jī)論壇有你更精彩.
回復(fù)

使用道具 舉報(bào)

板凳
ID:53421 發(fā)表于 2013-10-4 01:41 | 只看該作者
學(xué)習(xí)了,慢慢消化。感謝!
回復(fù)

使用道具 舉報(bào)

地板
ID:55611 發(fā)表于 2013-10-5 12:51 | 只看該作者
玩轉(zhuǎn)DS1302和DS18B20
回復(fù)

使用道具 舉報(bào)

5#
ID:55611 發(fā)表于 2013-10-5 12:51 | 只看該作者
好好學(xué)習(xí),天天向上
回復(fù)

使用道具 舉報(bào)

6#
ID:55613 發(fā)表于 2013-10-6 15:08 | 只看該作者
樓主,我是剛剛接觸單片機(jī)什么多不懂。能否講了詳細(xì)點(diǎn)。溫度顯示如何寫在1602時(shí)間后面謝謝
回復(fù)

使用道具 舉報(bào)

7#
ID:52286 發(fā)表于 2013-10-13 23:46 | 只看該作者
支持支持!!
回復(fù)

使用道具 舉報(bào)

8#
ID:57793 發(fā)表于 2013-12-17 21:52 | 只看該作者
謝謝分享
回復(fù)

使用道具 舉報(bào)

9#
ID:55219 發(fā)表于 2013-12-21 20:49 | 只看該作者
頂一下。。。。。
回復(fù)

使用道具 舉報(bào)

10#
ID:58213 發(fā)表于 2014-2-11 14:46 | 只看該作者
謝謝分享
回復(fù)

使用道具 舉報(bào)

11#
ID:58936 發(fā)表于 2014-2-17 11:28 | 只看該作者
樓主厲害,我也想學(xué)習(xí)這個(gè)。
回復(fù)

使用道具 舉報(bào)

12#
ID:56665 發(fā)表于 2014-2-17 23:17 | 只看該作者
在網(wǎng)上買了幾片DS1302做時(shí)鐘,誤差比用定時(shí)器中斷做的時(shí)鐘誤差還大,不知道是IC問題還是晶振問題。
回復(fù)

使用道具 舉報(bào)

13#
ID:69408 發(fā)表于 2015-10-18 11:01 | 只看該作者
學(xué)習(xí)不同的方法使用DS1302,不錯(cuò),謝謝樓主分享!
回復(fù)

使用道具 舉報(bào)

14#
ID:103999 發(fā)表于 2016-1-24 22:06 | 只看該作者
有木有匯編的程序
回復(fù)

使用道具 舉報(bào)

15#
ID:158995 發(fā)表于 2017-1-5 10:43 | 只看該作者
不錯(cuò),能不能講講多點(diǎn)測(cè)溫系統(tǒng)呢
回復(fù)

使用道具 舉報(bào)

16#
ID:225059 發(fā)表于 2017-11-8 16:29 | 只看該作者
寫入后,其他功能正常使用,但是分鐘不論是寫入還是讀取 都是顯示為0, 年月日星期顯示的都是正確的
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表