百度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的引腳功能圖
.....................................................................................
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; } } }