51微控制器學習筆記:使用DS1302晶片製作電子鐘

xouou_53320發表於2013-02-15
百度ds1302 寫道
DS1302 是美國DALLAS公司推出的一種高效能、低功耗、帶RAM的實時時鐘電路,它可以對年、月、日、週日、時、分、秒進行計時,具有閏年補償功能,工作電壓為2.5V~5.5V。採用三線介面與CPU進行同步通訊,並可採用突發方式一次傳送多個位元組的時鐘訊號或RAM資料。DS1302內部有一個31×8的用於臨時性存放資料的RAM暫存器。DS1302是DS1202的升級產品,與DS1202相容,但增加了主電源/後備電源雙電源引腳,同時提供了對後備電源進行涓細電流充電的能力。
DS1302的引腳排列,其中Vcc1為後備電源,VCC2為主電源。在主電源關閉的情況下,也能保持時鐘的連續執行。DS1302由Vcc1或Vcc2兩者中的較大者供電。當Vcc2大於Vcc1+0.2V時,Vcc2給DS1302供電。當Vcc2小於Vcc1時,DS1302由Vcc1供電。X1和X2是振盪源,外接32.768kHz晶振。RST是復位/片選線,通過把RST輸入驅動置高電平來啟動所有的資料傳送。RST輸入有兩種功能:首先,RST接通控制邏輯,允許地址/命令序列送入移位暫存器;其次,RST提供終止單位元組或多位元組資料傳送的方法。當RST為高電平時,所有的資料傳送被初始化,允許對DS1302進行操作。如果在傳送過程中RST置為低電平,則會終止此次資料傳送,I/O引腳變為高阻態。上電執行時,在Vcc>2.0V之前,RST必須保持低電平。只有在SCLK為低電平時,才能將RST置為高電平。I/O為序列資料輸入輸出端(雙向),後面有詳細說明。SCLK為時鐘輸入端。 下圖為DS1302的引腳功能圖
.....................................................................................

 


 我在淘寶上花了幾塊錢買了個山寨的1302模組,湊合著可以用,

但是模組上的sclk,io,RST這3個腳沒有上拉電阻,自己加上去了,汗!

不加上拉電阻,顯示的時鐘很容易發生錯誤

好了不多說,貼程式碼

本程式只顯示時間,沒有年份和月份... 

#include "my51.h"
#include "smg.h"
#include "ds1302.h"

void main()			   //ds1302顯示時鐘
{
    ds1302_initSet();//初始化
	//ds1302_stop();   停掉1302,進入省電模式
    while(1)
    {
        ds1302_readRTC();_nop_();	//讀取時鐘資料
        displaySMG(ds1302_processTimeData());//處理資料並送數碼管顯示
    }
}

 

#ifndef _DS1302_H
#define _DS1302_H

#include "my51.h"

sbit rst=P3^4;  //片選匯流排
sbit sda=P3^5; //資料匯流排
sbit scl=P3^6;  //時鐘線

extern u8 data smgWela[7];	 //數碼管顯示引數
extern u8 data timeData[7];  //年,周,月,日,時,分,秒的初值

//void ds1302_setUnCharger()    //充電控制,禁止充電
//void ds1302_stop() ;         	//暫停ds1302,進入超低功耗模式
u8* ds1302_processTimeData();   //處理時鐘資料,送給數碼管顯示
void ds1302_readRTC();     //讀取所有時鐘資料的BCD碼
void ds1302_initSet() ;     //設定初始化資料
u8 ds1302_readData(u8 addr); //從ds1302讀一個位元組,讀的時候會先寫地址
void ds1302_writeByte(u8 dat);   //寫一個位元組
void ds1302_writeData(u8 addr,u8 dat); //向指定地址暫存器寫資料

#endif

 

#include "ds1302.h"

data u8 timeData[7]={10,6,4,17,11,20,55};
code u8 writeAddr[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80};//寫年周月日時分秒暫存器地址指令
code u8 readAddr[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};//讀的指令地址

void ds1302_writeData(u8 addr,u8 dat) //向指定地址暫存器寫資料
{
    rst=0; _nop_();
    scl=0; _nop_();
    rst=1; _nop_();
    ds1302_writeByte(addr); //先寫入地址
    ds1302_writeByte(dat);
    rst=0;_nop_(); //關閉
    sda=1;         //釋放
    scl=1; 
}

void ds1302_writeByte(u8 dat)   //寫一個位元組
{
    u8 i=0;
    for(i=0;i<8;i++)
    {
        scl=0;              //時鐘線拉低
        sda=dat&0x01; 		//資料從最低位開始賦值
        dat>>=1;
        scl=1;_nop_();      //上升沿寫入一位  
    }
}

u8 ds1302_readData(u8 addr) //從ds1302讀一個位元組,讀的時候會先寫地址
{
    u8 i,value=0;
    rst=0;_nop_();
    scl=0;_nop_();
	sda=1;_nop_();
    rst=1;_nop_();
    ds1302_writeByte(addr); //先寫入要讀的地址
	_nop_();
	sda=1;_nop_();
    for(i=0;i<8;i++)
    {
        value>>=1;
        scl=0;_nop_();  //下降沿開始後提取有效資料 
        if(sda)         //讀資料
        {
            value|=0x80;//高電平手動置位儲存資料,
        }               //低電平資料value最高位預設已經是0
        scl=1;          //為下一次讀取資料做準備
    }
    rst=0;
    return value;
} 
 
void ds1302_initSet()      //設定初始化資料
{
    u8 i,j;
    for(i=0;i<7;i++)//將初始化資料處理成BCD碼
    {
        j = timeData[i] / 10;
        timeData[i]=timeData[i]%10;
        timeData[i]=timeData[i]+j*16;
    }
	ds1302_writeData(0x8e,0x00);  //清除防寫
    for(i=0;i<7;i++)
    {   //將時鐘日曆資料經過轉換後的BCD碼寫到7個時鐘日曆暫存器中
        ds1302_writeData(writeAddr[i],timeData[i]); 
    }
	ds1302_writeData(0x90,0x5c); //禁止充電,降低功耗,針對不可充電電池
	//ds1302_writeData(0x90, 0xa6);//開啟充電,用一個二極體,用4k電阻
	ds1302_writeData(0x8e,0x80); //使能防寫
}
   
void ds1302_readRTC()     //讀取所有時鐘資料的BCD碼
{
    u8 i;
    for(i=0;i<7;i++) 
    {   //讀取的時候會把時鐘日曆的7個暫存器中的資料全部讀取,並儲存到timeData[]
        timeData[i]=ds1302_readData(readAddr[i]);
    }
}

u8* ds1302_processTimeData()  //顯示時鐘,暫時只顯示時間
{
    smgWela[5]=timeData[6] & 0x0f;//提取低4位
    smgWela[4]=timeData[6] >> 4;//提取高4位
    smgWela[3]=timeData[5]& 0x0f;
    smgWela[2]=timeData[5]>> 4;
    smgWela[1]=timeData[4]& 0x0f;
    smgWela[0]=timeData[4]>> 4;
	smgWela[6]=0xf5; //0xf5是小數點的位置
    return smgWela;
}

 /*
void ds1302_stop()          	//暫停ds1302
{
   ds1302_writeData(0x8e,0x00); //清除防寫
   ds1302_writeData(writeAddr[6],0x80); //暫停ds1302,進入超低功耗模式
   ds1302_writeData(0x8e,0x80); //使能防寫
} */ 

/*   
void ds1302_setUnCharger()          //充電控制,禁止充電
{
   ds1302_writeData(0x8e,0x00); //清除防寫
   ds1302_writeData(0x90,0x5c); //禁止充電,降低功耗
   ds1302_writeData(0x8e,0x80); //使能防寫
}*/


 

#ifndef _51SMG_H_
#define _51SMG_H_

#include "my51.h"

sbit dula =P2^6;  		//段選鎖存器控制  控制筆段
sbit wela =P2^7;  		//位選鎖存器控制  控制位置
extern u8 data smgWela[7]; //第一位到第六位,最後一個是小數點位置控制

#define dark	0x11//在段中,0x11是第17號元素,0x00是低電平,數碼管不亮,即table[17]
#define dotDark 0xff//小數點全暗

void displaySMG(u8* pWela); //數碼管顯示函式,引數是陣列指標

#endif

 

#include "smg.h"
#include "my51.h"

static u8 code table[]= { 		//0~F外加小數點和空輸出的數碼管編碼
	0x3f , 0x06 , 0x5b , 0x4f , // 0 1 2 3
	0x66 , 0x6d , 0x7d , 0x07 , // 4 5 6 7
	0x7f , 0x6f , 0x77 , 0x7c , // 8 9 A B
	0x39 , 0x5e , 0x79 , 0x71 , // C D E F
	0x80 , 0x00 ,0x40           // . 空 負號    空為第17號元素
 };

/*  由於此表只能一次顯示一個小數點,故已註釋掉,僅供查詢
	例如想要第一個和第六個數碼管小數點同時點亮,
	則執行 pWela->dot = 0xfe & 0xdf  即可
	u8 code dotTable[]={   //小數點位置,某一位置0時,小數點亮
	0xff ,                 //全暗
	0xfe , 0xfd , 0xfb ,   //1 2 3
	0xf7 , 0xef , 0xdf     //4 5 6                    
};*/

u8 data smgWela[7]={0,0,0,0,0,0,0}; //第一位到第六位,最後一個是小數點位置控制

//P0口的數碼管位選控制鎖存器只用了低6位,我們保留高2位的資料,留作它用
void displaySMG(u8* pWela)
{
	u8 i=0;	
    //控制6位數碼管顯示函式,不顯示的位用引數dark
    u8 preState=P0|0x3f;  //儲存高2位狀態,其中最高位是ADC0804的片選訊號
	wela=0;dula=0;_nop_();//先鎖定資料,防止吳亮及位選鎖存器高2位資料被改變
		
	P0=0;  		 	      //由於數碼管是共陰極的,陽極送低電平,燈不亮
    dula=1;_nop_();
    dula=0;	  	 	      //段選資料清空並鎖定

    P0=preState;  		  //共陰極數碼管是陰極置高不亮,低6位置1,高2位保留	
    wela=1;_nop_();		  //注:wela和dula上電預設為1		 
    wela=0;		  		  //位選鎖定,初始保留高2位的資料,低6位置高不亮

	for(i=0;i<6;i++)	  //顯示6位數碼管
	{
		P0=table[pWela[i]]|(((1<<i) & pWela[6])?0x00:0x80);
	    dula=1;_nop_();	     //送段資料,疊加小數點的顯示,0x00點亮小數點
	    dula=0;
	    
	   	P0=preState&~(1<<i); //不影響高2位資料,低6位是數碼管位選,低電平有效
	    wela=1;	_nop_();	 //送位選號
	    wela=0;	
	    delayms(1);			 //稍作延時,讓燈管亮起來			
		{  //消除疊影及誤亮,陰極置1不亮,低6位置1,高2位保留並鎖定
	        P0=preState;
	        wela=1;	_nop_();			
	        wela=0;	
	    }
	}
}

 
 

相關文章