DS1302;12.1 概述;DS1302實(shí)時時鐘芯片我真的為她著迷呀;12.2芯片介紹;VCC2;GND;VCC1;SCLK;I/O;RST工作電源電源地后備電源時鐘 信號數(shù)據(jù)輸入輸出;我在看視頻教程時,老時覺得很奇怪的,為什么老師會;SCLK是串行時鐘信號的輸入,而I/O則是串行數(shù);12.3時序分析;以上是 DS1302一個字節(jié)寫入的時序圖;上升沿有效
第12章DS1302
12.1概述
DS1302 實(shí)時時鐘芯片我真的為她著迷呀。什么原因?qū)е挛覟樗裕孔约航佑|后您自然而然會明白的。本片筆記的手法與前幾章寫筆記的手法明顯而外的不同,因?yàn)榻榻B DS1302芯片不像是介紹單片機(jī)內(nèi)部的資源一樣,都有參考步驟可言,但設(shè)置DS1302的方法太多樣化了,讓新手很不容易。
12.2芯片介紹
VCC2
GND
VCC1
SCLK
I/O
RST工作電源電源地后備電源時鐘信號數(shù)據(jù)輸入輸出復(fù)位信號|片選信號
我 在看視頻教程時,老時覺得很奇怪的,為什么老師會把RST信號說成片選信號呢?這也難怪的,因?yàn)樵贒S1302的時序圖,RST信號的角色有如片選信號。 眾多的芯片中,往往最后的PIN都是工作電源的輸入??墒荄S1302卻是很奇特,VCC2是工作電源的輸入而VCC1卻是后備電源的輸入,或者是充電的 電流的經(jīng)過,更詳細(xì)的介紹在后面的內(nèi)容會繼續(xù)介紹。
SCLK是串行時鐘信號的輸入,而I/O則是串行數(shù)據(jù)輸入輸出。X1,X2是晶振32.768kHz的輸入,數(shù)據(jù)手冊中有記錄晶振的兩端需無極電容,手冊中的記錄是6pf,但是在眾多的AVR學(xué)習(xí)板中會看到23pf,27pf的出現(xiàn)。
12.3時序分析
以上是DS1302一個字節(jié)寫入的時序圖。第一個字節(jié)是地址字節(jié),第二個字節(jié)是數(shù)據(jù)字節(jié)。RST信號必須拉高,否則數(shù)據(jù)的輸入是無效的。換一句話說,RST信號控制數(shù)據(jù)|時間信號輸入的開始和結(jié)束。地址字節(jié)和數(shù)據(jù)字節(jié)的讀取時
上升沿有效,而且是由LSB開始讀入。
讀一個字節(jié)和寫一個字節(jié)有明顯的不一樣,先是寫地址字節(jié),然后再讀數(shù)據(jù)字節(jié),寫地址字節(jié)時上升沿有效,而讀數(shù)據(jù)字節(jié)時下降沿有效,當(dāng)然前提是RST信號必須拉高。寫地址字節(jié)和讀數(shù)據(jù)字節(jié)同是LSB開始。
再 重申一次,讀一個字節(jié)和寫一個字節(jié)是不一樣,在寫一個字節(jié)的時候,AVR的IO口一直保持輸出狀態(tài),相反的在讀一個字節(jié)的時候AVR的IO口先是輸出狀 態(tài),然后是輸入狀態(tài),且必須改變時鐘信號的順序。(補(bǔ)充一點(diǎn)題外話,我在編輯時序的時候,由于疏忽了一點(diǎn)“小錯誤”,后果卻是很嚴(yán)重。)
12.3DS1302時鐘|日期|控制|爆發(fā)寄存器
在介紹DS1302的時序圖中不都是,先地址字節(jié),然后數(shù)據(jù)字節(jié)碼?那么地址字節(jié)和數(shù)據(jù)字節(jié)又有什么關(guān)系呢?(看看下面的圖)
上面的圖說明了每個寄存器的定義和地址字節(jié),而每個地址字節(jié)的LSB可以是0或者1,邏輯0代表寫,邏輯1代表讀。如果忽略每個地址字節(jié)的LSB,十六進(jìn)制則是0x80+i,而i每一次累加2。我們一個一個寄存器來看吧:
第一:秒鐘寄存器地址字節(jié);0x80
其 實(shí)呀,我很佩服該芯片的設(shè)計(jì)人員,將芯片設(shè)計(jì)得很貼心,為什么呢?因?yàn)槊腌娂拇嫫鳎擞涗浢腌娨酝?,還控制了DS1302的時鐘開關(guān)(晶振開始工作,或 者晶振禁止工作)。該位第7位CH,當(dāng)寫入邏輯1時DS1302停止工作,時間的計(jì)時保持最后一次的狀態(tài),如果寫入邏輯0DS1302則開始工作,時間從 最后一次狀態(tài)中繼續(xù)計(jì)時。
換成另一句話說,每一次寫入秒鐘,都會使DS1302工作,但這又是為什么呢?秒鐘寄存器是八位寄存器,高四位中 的BIT4~BIT6(BIT7除外)記錄十位,而低四位記錄個位。秒鐘的計(jì)算最多也是59,如果換成十六進(jìn)制的話是0x59。所以呢,最高位基本上都是 用不到,但我們每一次向秒鐘寄存器進(jìn)行初始化的時候,都會很自然的把最高位BIT7記錄成0,CH位為邏輯0,DS1302就開始工作。
第二:分鐘寄存器地址字節(jié);0x82
八位寄存器,高四位記錄十位(BIT7除外),低四位記錄個位
第三:時鐘寄存器地址字節(jié);0x84
八 位寄存器,高四位記錄十位(BIT7,BIT6除外),低四位記錄個位。時鐘寄存器的最高位,決定了時間是以24小時制,還是12小時制。邏輯1為12小 時致,邏輯0為24小時致。至于24小時致是默認(rèn)的,為什么這么說呢?該解釋與秒鐘寄存器很相似,因?yàn)槊恳淮挝覀優(yōu)闀r鐘寄存器賦值的時候,由于時鐘最大值 是23小時(0x23),還是11小時(0x11),自然而然最高位我們都會賦0值。
第四:日寄存器地址字節(jié):0x86
八位寄存器,高四位記錄十位(實(shí)際上僅有BIT4~5被使用),低四位記錄個位。第五:月寄存器地址字節(jié):0x88
八位寄存器,高四位記錄十位(實(shí)際上僅有BIT4被使用),低四位記錄個位。第六:周寄存器地址字節(jié):0x8A
八位寄存器,僅有低四位被使用(BIT0~3),用來記錄個位。
第七:年寄存器地址字節(jié):0x8C
八位寄存器,高四位記錄十位,低四位記錄個位。
第八:控制寄存器地址字節(jié):0x8E
八位寄存器,僅BIT7有用,BIT7亦即WP位(WriteProtect),邏輯0解除寫保護(hù),邏輯1開啟寫保護(hù)。換一句話說,每一次寫其他寄存器WP位必須先置0。
第九:充電寄存器?(TrickleCharge)地址字節(jié):0x90
這是開啟細(xì)流充電的寄存器,寫保留。后面有詳細(xì)的解釋。
第十:爆發(fā)寄存器?(BurstMode)地址字節(jié):0x92
這個寄存器的功能可以用軟件來模擬,無視他把。
.4DS1302的RAM1212.4
DS1302真的很厚道,還設(shè)立了31個字節(jié)的RAM空間,RAM空間的開始地址字節(jié)是0x94。RAM空間可以讓使用著任意發(fā)揮,你可以把它當(dāng)做外存儲器,但是前提DS1302必須一直供電。要訪問任意空間也很簡單,如下表:
嗯,使用RAM空間的方法很自由,自己發(fā)揮想象力吧。
12.5細(xì)流充電TrickleCharge
在前幾個Article,介紹了DS1302有后備供電的輸入,亦即VCC1引腳,DS1302允許透過控制內(nèi)部的充電寄存器,經(jīng)VCC2向VCC1
流入的充電細(xì)流(很小很小的電流)。我們看一看Hj-2G的硬件布局吧:
VCC2連接的5v是工作電壓,VCC1連接的3v是后備工作電壓。充電寄存器就控制VCC2流向VCC1之間的“阻值”和“二極管的降壓”。
在這里補(bǔ)充一些題外話:當(dāng)VCC2有電源輸入時,VCC1是停止供電的,但同一時間也可以為VCC1進(jìn)行細(xì)流充電(這要看VCC1是否連接著可充電電池)。一旦
VCC2停止供電,VCC1就開始工作,與此同時細(xì)流充電就變成沒有意義了。
以 上是TrickleCharge的概念圖,充電控制寄存器的高四位(BIT7~4)是TCS,TrickleChargerSelect位,僅1010才 會開啟充電功能。而BIT3~2是DS,DiodeSelect位,01選擇一個diode,10選擇兩個diode串聯(lián)。BIT1~0是 RS,ResistorSelect位,兩位組成了3個阻值的選擇。瀏覽下表:
RS位組合的阻值選擇表細(xì)流公式
渴求細(xì)流的公式可以由上右表求出,阻值位R1,diodedrop為二極管的降壓,0.7v(一個二極管),1.4(串聯(lián)二極管)。不過我比較有愛,將他分成六個等級,為了編程更方便。#defineLV6
#defineLV5
#defineLV4
#defineLV3
#defineLV2
#defineLV10xA50xA90xA60xAA0xA70xAB//0.7降壓,2k阻值,2.15mA//1.4降壓,2k阻值,1.80mA
//0.7降壓,4k阻值,1.07mA//1.7降壓,4k
阻值,0.90mA
//0.7降壓,8k阻值,0.50mA//1.4降壓,8k阻值,0.45mA
12.6DS1302的地址字節(jié)
DS1302的地址字節(jié),也可以作為命令字節(jié)。A0~A4是用來選擇地址的位,而BIT0是制定該地址字節(jié)是寫入還是讀取,BIT6是作為選擇RAM還是CLOCK的區(qū)別。其實(shí)這也沒有什么困難的啦。
慧 爭電子免費(fèi)共享資料、歡迎復(fù)制共享、沒有版權(quán);12.7簡單歸納;控制DS1302的是RST信號,拉低無效,拉高有;12.8DS1302頭文件的理 解;自帶來的DS1302頭文件,沒有自己定義的好;首先是按寄存器的地址字節(jié),聲明的宏定義;#defineCLKOFF0x80#define;以上 的宏定義,是作為配置時使用的;IO口的宏定義,可以使程式的可達(dá)性更高;接
慧爭電子免費(fèi)共享資料、歡迎復(fù)制共享、沒有版權(quán)。HJ-2G多功能AVR/51二合一開發(fā)板學(xué)習(xí)筆記
12.7簡單歸納
控 制DS1302的是RST信號,拉低無效,拉高有效。而DS1302是串行輸入,串行讀入。寫入一個字節(jié)和讀取一個字節(jié)的時序不同。寫入一個字節(jié)都是上跳 沿有效,讀入一個字節(jié)先是上跳沿有效,然后下降沿有效。地址字節(jié)也可稱為命令字節(jié),BIT6控制了對RAM/CLOCK的訪問控制,而BIT0決定了地 址|命令字節(jié)的寫入還是讀出的特性。DS1302有31個字節(jié)的RAM空間。除此之外,還有細(xì)流充電的功能。秒寄存器決定了DS1302開始工作與否,而 時鐘寄存器有12小時制和24小時制之分。每當(dāng)要寫入任何一個寄存器|RAM空間,寫入控制寄存器的WP位必須置0,解除寫保護(hù)。
12.8DS1302頭文件的理解
自 帶來的DS1302頭文件,沒有自己定義的好。這一章筆記,主要是以頭文件的方式解釋。這是我認(rèn)為,新手最簡單習(xí)得的辦法。//命令,地 址#defineSEC0x80#defineMIN0x82#defineHOUR0x84#defineDAY0x86#defineMONTH0x88#defineWEEK0x8A#defineYEAR0x8C#defineCTRL0x8E#defineCHRG0x90#defineBRUST0xBE#defineRAM0xC0
首先是按寄存器的地址字節(jié),聲明的宏定義。SEC為開始,亦即0x80,隨后都是+2。宏定義中的地址字節(jié)沒有包括了,BIT0寫/讀的控制位。//配置
#defineCLKOFF0x80#defineCLKON0x00#defineT120x80#defineT240x00#defineLOCK0x80#defineUNLOCK0x00#defineLV60xA5#defineLV50xA9#defineLV40xA6#defineLV30xAA#defineLV20xA7#defineLV10xAB
以上的宏定義,是作為配置時使用的。自己看著明白吧,很簡單而已。
IO口的宏定義,可以使程式的可達(dá)性更高。
接下來要為寫一個字節(jié)函數(shù),和讀一個字節(jié)函數(shù)做介紹。
//DS1302寫一個字節(jié)函數(shù)
voidDS1302_Write(unsignedcharAdd,unsignedcharData){
unsignedchari;
DDRB|=BIT(IO);
PORTB&=~BIT(SCLK);PORTC|=BIT(RST);Add&=0xfe;
//IO為輸出
//時鐘信號拉低<==這個很重要//拉高RST信號
//將Add亦即地址字節(jié)的LSB設(shè)置為0
for(i=0;i<8;i++)//寫地址|命令字節(jié),上跳沿有效{
PORTB&=~BIT(SCLK); //時鐘信號拉低if(Add&0x01)PORTB|=BIT(IO);//判斷地址字節(jié)的最低位,1位拉高IOelsePORTB& amp;=~BIT(IO);//否則拉低IOPORTB|=BIT(SCLK);//時鐘信號拉高Add>>=1;//地址字節(jié)左移一位
}
for(i=0;i<8;i++)//寫數(shù)據(jù)字節(jié),上跳沿有效{
PORTB&=~BIT(SCLK);
if(Data&0x01)PORTB|=BIT(IO);elsePORTB&=~BIT(IO);PORTB|=BIT(SCLK);Data>>=1;
}
PORTC&=~BIT(RST);//拉低RST信號,結(jié)束寫一個字節(jié)。}
//時鐘信號拉低
//判斷數(shù)據(jù)字節(jié)的最低位,1位拉高IO//否則拉低IO//時鐘信號拉高//數(shù)據(jù)字節(jié)左移一位
函 數(shù)完全是依照時序圖寫的,該函數(shù)帶有兩個參數(shù),Add和Data,顧名思義就是如字面上的意思,地址字節(jié)和數(shù)據(jù)字節(jié)。地址字節(jié)需經(jīng)過0xfe與云散,取得 xxxxxxx0寫字節(jié)|命令的特征。寫地址和寫數(shù)據(jù)字節(jié)都是下降沿有效。有一點(diǎn)需要注意的是:當(dāng)RST信號還沒有拉高之前,必須把時鐘信號初始化|拉 第,這一點(diǎn)很重要請注意。(我就是在這一點(diǎn)犯了“小錯誤”)
這是讀一個字節(jié)的函數(shù),帶unsignedchar返回型,但僅有一個參數(shù),那 即是Add:地址字節(jié)。Add寫入之前必須經(jīng)過0x01的與運(yùn)算,為了就是取得xxxxxxx1的地址|命令的讀特征。在RST拉高之前,和寫一個字節(jié)函 數(shù)一樣的注意點(diǎn),就是必須先將時鐘信號拉低,不然的話函數(shù)會失敗。
還有另一個注意點(diǎn)就是IO的狀態(tài),在寫地址|命令字節(jié)的時候必須設(shè)置位輸出狀態(tài),而當(dāng)讀取數(shù)據(jù)之前必須將IO設(shè)置位高祖態(tài)輸入狀態(tài)。程式的最后就是返回從IO讀到的數(shù)據(jù)。
補(bǔ)充,寫一個字節(jié)函數(shù),和讀一個字節(jié)函數(shù)是最基礎(chǔ)和最重要的函數(shù),不允許有錯誤出現(xiàn),不然的話,一切的設(shè)定都徒勞無功。
//模擬BURST函數(shù),讀取數(shù)據(jù)|時間
voidDS1302_Get_Timer(unsignedchar*pTimer){
unsignedchari,j;
for(i=0,j=0;i<7;i++,j+=2)
pTimer[i]=DS1302_Read((0x80+j));
}
//i循環(huán)次數(shù),j地址
//將數(shù)據(jù)一一讀入時間數(shù)組
上 面兩個函數(shù)是連續(xù)寫時間,和連續(xù)讀時間函數(shù)。只要明白數(shù)組傳遞的規(guī)則,基本上好似很簡單就看懂了。但是有一個條件,就是必須按照以下的數(shù)組順 序:unsignedcharTimer[]={0x40,0x59,0x23,0x31,0x12,0x07,0x09};//秒分時日月周年 unsignedcharBuffer[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//緩沖數(shù)組Timer數(shù)組是 用于連續(xù)寫入,而Buffer數(shù)組是用于連續(xù)讀取。
//開啟寫保護(hù)函數(shù)voidProtect(){
DS1302_Write(CTRL,LOCK);}
//解除寫保護(hù)函數(shù)voidUnprotect(){
DS1302_Write(CTRL,UNLOCK);}
啟動寫保護(hù)和關(guān)閉寫保護(hù)的函數(shù)也很容易明白。自己看著辦吧。
細(xì)流充電啟動和關(guān)閉函數(shù),關(guān)閉方?jīng)]有什么特別,而啟動方比較特別,帶有Level的參數(shù),實(shí)際上是對細(xì)流充電控制寄存器寫入相關(guān)的值而已,而Level已經(jīng)宏定義了,就是Lv1~Lv6.
//寫入RAM函數(shù)
voidDS1302_RAM_Write(unsignedcharN,unsignedcharData){
if(N<32)//RAM地址不可以超過31
DS1302_Write(RAM+N,Data);
}
//讀取RAM函數(shù)
unsignedcharDS1302_RAM_Read(unsignedcharN){
if(N<32)//RAM地址不可以超過31
returnDS1302_Read(RAM+N);
}
依然是那句話,很容易明白的函數(shù)。部比較不同的是,if語句預(yù)防萬一了訪問無效地址字節(jié)和越界訪問。
DS1302 應(yīng)用IO口的初始化函數(shù),很簡單,而且;//DS1302啟動函數(shù)voidClock_On;DS1302_Write(SEC,CLKON);; //DS1302停止函數(shù)voidClock_Of;DS1302_Write(SEC,CLKOFF);啟動工作和關(guān)閉工作的函數(shù);//設(shè)時間為12小 時制函數(shù);//該函數(shù)沒有什么用處,24小時制為默認(rèn),為了演;DS1
DS1302應(yīng)用IO口的初始化函數(shù),很簡單,而且程式也注釋了。
//DS1302啟動函數(shù)voidClock_On(){
DS1302_Write(SEC,CLKON);}
//DS1302停止函數(shù)voidClock_Off(){
DS1302_Write(SEC,CLKOFF);}
啟動工作和關(guān)閉工作的函數(shù)。
//設(shè)時間為12小時制函數(shù)
//該函數(shù)沒有什么用處,24小時制為默認(rèn),為了演示voidSet12(){
DS1302_Write(HOUR,T12);}
//設(shè)時間為24小時制函數(shù)
//該函數(shù)沒有什么用處,24小時制為默認(rèn),為了演示voidSet24(){
DS1302_Write(HOUR,T24);}
該函數(shù)沒有實(shí)際的用處,編輯出來時為了演示·解釋·明白而已。
慧爭電子免費(fèi)共享資料、歡迎復(fù)制共享、沒有版權(quán)。HJ-2G多功能AVR/51二合一開發(fā)板學(xué)習(xí)筆記
.9實(shí)例程式:1212.9
這里我就不編輯什么程式了,寫了幾個實(shí)例,自己看看吧~很簡單而已,因?yàn)槭褂肈S1302的方法太自由了。
實(shí)例程式1:
==============================================================//1200-DS1302_Driver.c
//DS1302最基本的驅(qū)動程式//akuei202-01-10#include"iom16v.h"#include"macros.h"#include"DS1302.h"#include"USART.h"voidDelay(unsignedcharx){
while(x--);}
voidmain(){
unsignedcharTimer[]= {0x02,0x35,0x23,0x15,0x11,0x07,0x33};//秒分時日月周年unsignedcharBuffer[]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00};unsignedcharTemp,Temp1,Temp2;inti;
DS1302_IO_Init();USART_Init();
//初始化DS1302的設(shè)置//Unprotect();Unprotect();Clock_Off();Set24();
//DS1302_Set_Timer(Timer);Protect();
//連續(xù)讀時間
/*//讀任意一個寄存器while(1){
Temp=DS1302_Read(YEAR);Temp1=((Temp>>4)&0x07);Temp2=(Temp&0x0f);
USART_Send('0'+Temp1);
//讀年寄存器//取十位//取個位//串口發(fā)送
一個很簡單的實(shí)例程式,介紹了很多的設(shè)置辦法。
慧爭電子免費(fèi)共享資料、歡迎復(fù)制共享、沒有版權(quán)。HJ-2G多功能AVR/51二合一開發(fā)板學(xué)習(xí)筆記
實(shí)例程式2
==============================================================//1201-DS1302_RTC.c
//DS1302最基本的驅(qū)動程式//akuei204-01-10#include"iom16v.h"#include"macros.h"#include"DS1302.h"#include"USART.h"//延遲函數(shù)
voidDelay(unsignedcharx){
while(x--);}
//主函數(shù)voidmain(){
unsignedcharTimer[]= {0x40,0x59,0x23,0x31,0x12,0x07,0x09};//秒分時日月周年unsignedcharBuffer[]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00};//緩沖數(shù)組unsignedcharTemp,Temp1,Temp2; //緩沖變量inti,j,k;//for循環(huán)變量
DS1302_IO_Init();USART_Init();
//初始化DS1302的設(shè)置Unprotect();Clock_Off();Set24();
DS1302_Set_Timer(Timer);//Charge_On(LV3);Clock_On();Protect();
//DS1302引腳初始化//USART初始化
//解除寫保護(hù)//時鐘關(guān)閉
//設(shè)置為24小時制
//設(shè)定時間
//充電開啟,等級3,大約1mA//時鐘啟動,秒種從00計(jì)數(shù)開始//開啟寫保護(hù)
while(1){
for(k=0,j=0;k<7;k++,j+=2)
年
{
Temp=DS1302_Read(0x80+j);Temp1=((Temp>>4)&0x07);Temp2=(Temp&0x0f);
//讀取時間//取十位//取個位
//循環(huán)7次,分別讀取秒分時日月周
這是另一個的實(shí)例程式。怎樣編寫程式都不重要,最重要是編程的目的。以上兩個實(shí)例程式我都使用了串口發(fā)送函數(shù),而一般的實(shí)例程式都是使用1602液晶。見仁見智吧。
最后附上USART.h和完整的DS1302.h頭文件(注意:只是適合HJ-2G)
==============================================================
//DS1302.h//命令,地址#defineSEC#defineMIN#defineDAY#define
0x800x820x86
#defineHOUR0x84
MONTH0x88
#defineWEEK0x8A#defineYEAR0x8C#defineCTRL0x8E#defineCHRG0x90#defineBRUST0xBE#defineRAM//配置
#defineCLKOFF0x80#defineCLKON0x00#defineT12#defineT24#defineLOCK#defineLV6#defineLV5#defineLV4#defineLV3#defineLV2
0x800x000x800xA50xA90xA60xAA0xA7
//0.7降壓,2k阻值,2.15mA//1.4降壓,2k阻值,1.80mA//0.7降壓,4k阻值,1.07mA//1.7降壓,4k阻值,0.90mA//0.7降壓,8k阻值,0.50mA
0xC0
#defineUNLOCK0x00
//USART.h; //波特率,晶振;#defineBAUD9600;#defineFXTAL11059200;//串口接收完畢中斷觸發(fā)聲 明;#pragmainterrupt_handler;//變量定義:接收緩沖變量,接收標(biāo)志位;unsignedcharRX_Buffer=0x; //函數(shù)聲明;voidUSART_Send(unsignedc;//串口IO初
//USART.h
//波特率,晶振
#defineBAUD9600
#defineFXTAL11059200
//串口接收完畢中斷觸發(fā)聲明
#pragmainterrupt_handlerUSART_Received_Ir:12
//變量定義:接收緩沖變量,接收標(biāo)志位
unsignedcharRX_Buffer=0x00,RX_Flag=0;
//函數(shù)聲明
voidUSART_Send(unsignedchar);
//串口IO初始化函數(shù)
voidUSART_IO_Init()
{
DDRD|=BIT(PD1);//PD1:TX為輸出狀態(tài)
}