【藍橋杯單片機12】實時時鍾DS1302的基本操作


【藍橋杯單片機12】實時時鍾DS1302的基本操作

www.xmf393.com / 廣東職業技術學院 歐浩源

      實時時鍾DS1302幾乎是藍橋杯“單片機設計與開發”每年必考的內容,雖然在競賽現場有提供一個底層讀寫寄存器的庫文件,但是作為備賽階段,你應該搞清楚底層讀寫時序的代碼實現。你會使用庫文件開發,不一定會自己寫底層;你會自己寫驅動,就一定會使用庫文件開發。你使用庫文件開發的過程中碰到問題,或者需要調整時序的時候,如果沒有過硬的功夫,那只能懵逼了。

1、什么是DS1302?
      DS1302是美國DALLAS公司推出的高性能、低功耗的實時時鍾,附加31字節的靜態RAM,采用SP三線接口與MCU進行同步通信,並可采用突發方式一次傳送多個字節的時鍾參數和RAM數據。實時時鍾可提供秒、分、時、日、星期、月和年,一個月小於31天時可以自動調整,並具有潤年補償功能。
      簡單來說,DS1302可以理解為一個電子手,里面帶有一個31字節的內存。當然,基本的使用方法和我們平時使用電子手表差不多,你可以設定時間,也可以讀取時間,只不過這些工作是通過SPI接口有MCU去完成而已。
      在DS1302中有兩塊存儲器:日歷時鍾寄存器和今天RAM存儲器。前者用於記錄實時時間,后者用於記錄其他數據。對於基本計時應用,重點關注的是日歷時鍾寄存器。設定時間參數就是往這些寄存器寫入內容,讀取實時時間也是從這些寄存器讀出數據。

2、日歷時鍾寄存器
      DS1302有關日歷和時鍾的寄存器有12個,我們最常用的有7個。

      什么是BCD碼?
      就是用十六進制來表示十進制。什么意思?怎么理解?
      例如,十六進制數0x13的值為整數19,但BCD碼表示的是整數13。

3、控制字的格式
      DS1302將地址和讀寫控制放到一個字節里面,形成一個控制字,格式如下:

      通過上面的控制字格式,大家就可以明白為什么DS1302讀寄存器和寫寄存器的地址是不一樣的了,因為這個地址包含了讀寫控制位。為了方便程序設計,我們把讀寄存器地址寫寄存器地日歷時鍾寄存器方面用三個數組定義。

4、接口時序的實現
      DS1302的基本操作實際上非常簡單,只有兩個操作:其一是設定時間參數其二是讀取實時時間。不管是那個操作,MCU都要通過SPI接口進行數據交互,而SPI接口有其規定的時序,這個必須參考數據手冊。
      控制字從最低位開始輸出在控制字指令輸入后的下一個SCLK時鍾信號的上升沿,數據被寫入DS1302,數據的輸入從最低位開始;在控制字指令輸入后的下一個SCLK時鍾信號的下降沿,數據從DS1302讀出,數據的讀出也是從最低位到最高位。
<1> 單字節寫的時序

      底層驅動代碼實現可參考如下:

void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{
        unsigned char n;
        RST = 0;
        _nop_();
        SCLK = 0;
        _nop_();
        RST = 1;
        _nop_();        

        for (n=0; n<8; n++)         //發送要寫入數據的內存地址
        {
                DSIO = addr & 0x01;
                addr >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }
        for (n=0; n<8; n++)         //將指定內容寫入該地址的內存
        {
                DSIO = dat & 0x01;
                dat >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }                 
        RST = 0;
        _nop_();
}

 

<2> 單字節讀的時序

      底層驅動代碼實現可參考如下:

unsigned char DS1302_ReadByte(unsigned char addr)
{
        unsigned char n,dat,tmp;
        RST = 0;
        _nop_();
        SCLK = 0;
        _nop_();
        RST = 1;
        _nop_();

        for(n=0; n<8; n++)         //發送要讀出數據的內存地址
        {
                DSIO = addr & 0x01;
                addr >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }
        
        for(n=0; n<8; n++)         //讀出該地址內存的數據
        {
                tmp = DSIO;
                dat = (dat>>1) | (tmp<<7);
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }

        RST = 0;
        _nop_();
        SCLK = 1;
        _nop_();
        DSIO = 0;
        _nop_();
        DSIO = 1;
        _nop_();
        return dat;        
}

      有了上面兩個底層的SPI接口數據讀寫代碼,那么DS1302的基本操作就很容易實現了。

5、單元實訓題目

6、實現源碼參考

#include "reg52.h"  
#include "intrins.h"

sbit HC138_A = P2^5;        
sbit HC138_B = P2^6;        
sbit HC138_C = P2^7;        

sbit SCLK = P1^7; 
sbit RST =         P1^3; 
sbit DSIO = P2^3;
unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
unsigned char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
unsigned char TIME[7] = {0x30, 0x50, 0x23, 0x17, 0x02, 0x06, 0x18};

unsigned char code SMG_NoDot[18] = 
    {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
     0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
     0xbf,0x7f};

void DelaySMG(unsigned int time)
{
        while(time--);
}

void Init74HC138(unsigned char n)
{
        switch(n)
        {
                case 4:
                        HC138_A = 0;
                        HC138_B = 0;
                        HC138_C = 1;
                        break;
                case 5:
                        HC138_A = 1;
                        HC138_B = 0;
                        HC138_C = 1;
                        break;
                case 6:
                        HC138_A = 0;
                        HC138_B = 1;
                        HC138_C = 1;
                        break;
                case 7:
                        HC138_A = 1;
                        HC138_B = 1;
                        HC138_C = 1;
                        break;
                case 8:
                        HC138_A = 0;
                        HC138_B = 0;
                        HC138_C = 0;
                        break;
        }
}

void DispaySMG_Bit(unsigned char value, unsigned char pos)
{
        Init74HC138(6);
        P0 = (0x01 << pos);
        Init74HC138(7);
        P0 = value;
}

void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{
        unsigned char n;
        RST = 0;
        _nop_();
        SCLK = 0;
        _nop_();
        RST = 1;
        _nop_();        

        for (n=0; n<8; n++)
        {
                DSIO = addr & 0x01;
                addr >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }
        for (n=0; n<8; n++)
        {
                DSIO = dat & 0x01;
                dat >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }                 
        RST = 0;
        _nop_();
}

unsigned char DS1302_ReadByte(unsigned char addr)
{
        unsigned char n,dat,tmp;
        RST = 0;
        _nop_();
        SCLK = 0;
        _nop_();
        RST = 1;
        _nop_();

        for(n=0; n<8; n++)
        {
                DSIO = addr & 0x01;
                addr >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }
        
        for(n=0; n<8; n++)
        {
                tmp = DSIO;
                dat = (dat>>1) | (tmp<<7);
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }

        RST = 0;
        _nop_();
        SCLK = 1;
        _nop_();
        DSIO = 0;
        _nop_();
        DSIO = 1;
        _nop_();
        return dat;        
}

void DS1302_Config()
{
        unsigned char n;
        DS1302_WriteByte(0x8E,0x00); 
        for (n=0; n<7; n++) 
        {
                DS1302_WriteByte(WRITE_RTC_ADDR[n],TIME[n]);        
        }
        DS1302_WriteByte(0x8E,0x80); 
}

void DS1302_ReadTime()
{
        unsigned char n;
        for (n=0; n<7; n++) 
        {
                TIME[n] = DS1302_ReadByte(READ_RTC_ADDR[n]);
        }                
}

void XMF_ShowRealTime()
{

        DispaySMG_Bit(SMG_NoDot[TIME[2]/16],0);        
        DelaySMG(500);
        DispaySMG_Bit(0xff,0);                        
        DispaySMG_Bit(SMG_NoDot[TIME[2]&0x0f],1);
        DelaySMG(500);
        DispaySMG_Bit(0xff,1);
        DispaySMG_Bit(SMG_NoDot[16],2);
        DelaySMG(500);
        DispaySMG_Bit(0xff,2);

        DispaySMG_Bit(SMG_NoDot[TIME[1]/16],3);
        DelaySMG(500);
        DispaySMG_Bit(0xff,3);
        DispaySMG_Bit(SMG_NoDot[TIME[1]&0x0f],4);
        DelaySMG(500);
        DispaySMG_Bit(0xff,4);
        DispaySMG_Bit(SMG_NoDot[16],5);
        DelaySMG(500);
        DispaySMG_Bit(0xff,5);

        DispaySMG_Bit(SMG_NoDot[TIME[0]/16],6);
        DelaySMG(500);
        DispaySMG_Bit(0xff,6);
        DispaySMG_Bit(SMG_NoDot[TIME[0]&0x0f],7);
        DelaySMG(500);
        DispaySMG_Bit(0xff,7);
}

main()
{
        DS1302_Config();
        while(1)
        {
                DS1302_ReadTime();
                XMF_ShowRealTime();
        }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM