關於時鍾模塊DS1302的使用心得


最近在做萬年歷,用到實時時鍾DS1302模塊,花了兩天時間看資料和寫驅動,想記錄一下我的學習經過,順便做一下總結。

首先就是在圖書館查各種資料,於是查到的大多是這些,主要時硬件方面的資料:

 

 

其實能查到很多資料,但是能為我們所用的不是很多。在使用一個芯片時,我一般時按照一下步驟去學習:

1、芯片介紹;

2、查看引腳定義;

3、外圍電路

4、分析時序圖;

5、模仿着編寫驅動程序,然后自己動手寫驅動。

6、實現功能。

下面我就按照這個順序去學習這款芯片;

一、芯片介紹

DS1302是DALLAS(達拉斯)公司出的一款涓流充電時鍾芯片,2001年DALLAS被MAXIM(美信)收購,因此我們看到的DS1302的數據手冊既有DALLAS的標志,又有MAXIM的標志;
DS1302實時時鍾芯片廣泛應用於電話、傳真、便攜式儀器等產品領域,他的主要性能指標如下:
1、DS1302是一個實時時鍾芯片,可以提供秒、分、小時、日期、月、年等信息,並且還有軟年自動調整的能力,可以通過配置AM/PM來決定采用24小時格式還是12小時格式。
2、擁有31字節數據存儲RAM。
3、串行I/O通信方式,相對並行來說比較節省IO口的使用。
4、DS1302的工作電壓比較寬,大概是2.0V~5.5V都可以正常工作。采用雙電源供電,當主電源比備用電源高0.2V時,由主電源供電,否則采用備用電源,一般是一個紐扣電池。
5、DS1302這種時鍾芯片功耗一般都很低,它在工作電壓2.0V的時候,工作電流小於300nA。
6、DS1302共有8個引腳,有兩種封裝形式,一種是DIP-8封裝,芯片寬度(不含引腳)是300mil,一種是SOP-8封裝,有兩種寬度,一種是150mil,一種是208mil。

二、引腳定義

三、外圍電路

一般與單片機IO口相連時要加上拉電阻,提高 IO 口的驅動能力,這樣信號比較穩定,計時也比較准確。

四、分析時序圖

這是單字節寫入的時序圖,可見,先拉高使能端,進行使能選擇,然后在時鍾上升沿寫入一個字節。

DS1302在進行讀寫操作時最少讀寫兩個字節,第一個是控制字節,就是一個命令,說明是讀還是寫操作,第二個時需要讀寫的數據。

對於單字節寫,只有在SCLK為低電平時才能將 CE 置高電平,所以剛開始將SCLK 置低,CE置高,然后把需要寫入的字節送入 IO口,然后跳變SCLK,在SCLK下降沿時,寫入數據

 

五、編寫驅動程序

有了 上面的分析,我們就可以學着編寫驅動程序了,可以把驅動程序分為幾個模塊來寫,由底層慢慢往上累加,比如,我們先編寫單個字節的讀寫操作,在編寫整個數據的讀寫,

#include "DS1302.h"

//*******************
void ds1302_writebyte(uchar byte){
    uint i;
    uint t = 0x01;
    for(i=0;i<8;i++){
        SCIO = byte & t;        
        t<<=1;
        DOWN();       //下降沿完成一個位的操作
    }
    SCIO = 1;//確保釋放io引腳
}
//********************
void ds1302_writedata(uchar addr,uchar data_){
    
    CE = 0;        nop();    
    SCLK = 0;    nop();    
    CE = 1;        nop();    //使能片選信號
    ds1302_writebyte((addr<<1)|0x80);    //方便后面寫入
    ds1302_writebyte(data_);
    CE = 0;        nop();//傳送數據結束

}
//*************************
uchar ds1302_readbyte(){
    uint i;
    uchar data_ = 0;
    uint t = 0x01;     
    for(i=0;i<7;i++){     //c51好像不支持直接在for循環里面直接定義變量

        if(SCIO){

            data_ = data_ | t;    //低位在前,逐位讀取,剛開始不對,估計是這個的問題
        }                
        t<<=1;
        DOWN();
    }
     return data_;
}


//************************
uchar ds1302_readdata(uchar addr){

    uchar data_ = 0;

    CE = 0;     nop();
    SCLK = 0;  nop();
    CE = 1;      nop();
    ds1302_writebyte((addr<<1)|0x81);
    data_ = ds1302_readbyte();
    CE = 0;       nop();
    SCLK = 1;  nop();
    SCIO = 0;  nop();
    SCIO = 1;  nop();

    return data_;
}

//*********************
void init_ds1302(){

     uchar i;
     CE = 0;   //初始化引腳
     SCLK = 0; 
     i  = ds1302_readdata(0x00);  //讀取秒寄存器,秒在最低位
     if((i & 0x80 != 0)){

         ds1302_writedata(7,0x00); //撤銷寫保護,允許寫入數據
        for(i = 0;i<7;i++){

            ds1302_writedata(i,init_time[i]);
        }
     }    
}

//**************
void ds1302_readtime(){       //讀取時間
      uint i;
      for(i = 0;i<7;i++){

             init_time[i] = ds1302_readdata(i);
      }
}

其中頭文件為:

#ifndef __DS1302_H
#define __DS1302_H

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


#define uint unsigned int
#define uchar unsigned char
#define nop() _nop_()

#define UP() {SCLK = 0;nop();SCLK = 1;nop();} //上升沿  ,使用宏定義函數時最后一定家分號
#define DOWN() {SCLK = 1;nop();SCLK = 0;nop();} //下降沿

 //這個模塊內沒有集成上拉電阻,使用時最好接上2
sbit CE = P2^5;//RET,使能輸入引腳,當讀寫時,置高位
sbit SCIO = P2^6;//IO     ,雙向通信引腳,讀寫數據都是通過這個完成
sbit SCLK = P2^7;//SCLK,時鍾信號


//為什么有時候好好的,也會出錯顯示少了分號呢?還氣人啊!!!!

void ds1302_writebyte(uchar byte);//寫一個字節; 
void ds1302_writedata(uchar addr,uchar data_);//給某地址寫數據,data是c51內部的關鍵字,表示將變量定義在數據存儲區,故此處用data_;
uchar ds1302_readbyte();//讀一個字節
uchar ds1302_readdata(uchar addr);//讀取某寄存器數據     ;
void init_ds1302();
void ds1302_readtime();


extern uchar init_time[];

#endif

 

六、功能實現

 功能實現就簡單了,就是加上主函數嘛,然后加上我們可以親眼看見並感知的模塊,比如用數碼管顯示時間:

#include "DS1302.h"

#define DIG P0
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;



uchar init_time[] = {0x50,0x15,0x14,0x22,0x10,0x06,0x17};//初始化的時間    //秒 分 時 日 月 周 年 
uchar code DIG_CODE[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //數碼管數字表
uint disp[8]={0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f};//把要顯示的數字傳給他    
uchar Num=0;
uint count_flag = 0;     //中斷溢出次數

void time0_init();//定時器0初始化
void display();//數碼管顯示時間

void main(void){
    
     init_ds1302();     //初始化時寫入起始時間
     time0_init();

     while(1){
            display();
     }
}

//***************
void display(){
            
     ds1302_readtime();    //讀取時間
    disp[7] = DIG_CODE[init_time[0]&0x0f];
    disp[6] = DIG_CODE[init_time[0]>>4];
    disp[5] = 0X40;        //顯示一個橫線
    disp[4] = DIG_CODE[init_time[1]&0x0f];
    disp[3] = DIG_CODE[init_time[1]>>4];
    disp[2] = 0X40;
    disp[1] = DIG_CODE[init_time[2]&0x0f];
    disp[0] = DIG_CODE[init_time[2]>>4];
}
//******************
void time0_init(){

    TMOD=0X02;//選擇為定時器模式,工作方式2,8位自動重裝模式,僅用TRX打開啟動。
    TH0=0X9C;    //給定時器賦初值,定時100us,0x9c就是156,就是還需計數100次產生溢出,就是0.1ms
    TL0=0X9C;    
    ET0=1;//打開定時器0中斷允許
    EA=1;//打開總中斷
    TR0=1;//打開定時器
}

void DigDisplay() interrupt 1    //中斷入口函數,掃描以實現動態顯示
{
//定時器在工作方式二會自動重裝初,所以不用在賦值。
//    TH0=0X9c;//給定時器賦初值,定時0.1ms
//    TL0=0X00;

    count_flag++;    
    if(count_flag==1)
    {
        count_flag = 0;
        DIG=0; 
        switch(Num)     //位選,選擇點亮的數碼管,
        {
            case(7):
                LSA=0;LSB=0;LSC=0; break;
            case(6):
                LSA=1;LSB=0;LSC=0; break;
            case(5):
                LSA=0;LSB=1;LSC=0; break;
            case(4):
                LSA=1;LSB=1;LSC=0; break;
            case(3):
                LSA=0;LSB=0;LSC=1; break;
            case(2):
                LSA=1;LSB=0;LSC=1; break;
            case(1):
                LSA=0;LSB=1;LSC=1; break;
            case(0):
                LSA=1;LSB=1;LSC=1; break;    
        }

        DIG=disp[Num]; //段選,選擇顯示的數字。
        Num++;
        if(Num>7)
            Num=0;
    }    
}

 

 總結一下:

這個芯片基本上不是很難,但是想要用的靈活,用的上手,還是得多練的,最好是先把上面的驅動程序對着時序圖自己分析一遍,然后自己親手編寫一下。

還有就是看數據手冊,一個芯片所能用到的數據,在數據手冊上基本都能查到。資料誰都能查到,就看怎么用了。


免責聲明!

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



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