輕松學(xué)PIC之DS1302時鐘篇
出處:maychang 發(fā)布于:2011-08-31 11:40:07
大家好,通過前一期的學(xué)習(xí),我們已經(jīng)對ICD2 仿真燒寫器和增強型PIC 實驗板的使用方法及學(xué)習(xí)方式有所了解與熟悉,學(xué)會了如何用單片機來控制發(fā)光管、繼電器、蜂鳴器、按鍵、數(shù)碼管、RS232串口、步進(jìn)電機、溫度傳感器、I2C 總線、SPI 總線等資源,體會到了學(xué)習(xí)板的易用性與易學(xué)性,這一期我們將介紹市面上常見的時鐘芯片DS1302 的應(yīng)用。
一、DS1302時鐘芯片簡介
DS1302 是DALLAS 公司推出的涓流充電時鐘芯片,內(nèi)含一個實時時鐘/ 日歷和31 字節(jié)靜態(tài)RAM,可以通過串行接口與單片機進(jìn)行通信。實時時鐘/ 日歷電路提供秒、分、時、日、星期、月、年的信息,每個月的天數(shù)和閏年的天數(shù)可自動調(diào)整,時鐘操作可通過AM/PM 標(biāo)志位決定采用24 或12 小時時間格式。DS1302 與單片機之間能簡單地采用同步串行的方式進(jìn)行通信,僅需三根I/O 線:復(fù)位(RST)、I/O 數(shù)據(jù)線、串行時鐘(SCLK)。時鐘/RAM 的讀/寫數(shù)據(jù)以一字節(jié)或多達(dá)31 字節(jié)的字符組方式通信。
DS1302 工作時功耗很低,保持?jǐn)?shù)據(jù)和時鐘信息時,功耗小于1mW。
1. DS1302 的內(nèi)部結(jié)構(gòu)
DS1302 的外部引腳功能說明如圖1 所示。

圖1 DS1302封裝圖
DS1302 的內(nèi)部結(jié)構(gòu)如圖2 所示,主要組成部分為:移位寄存器、控制邏輯、振蕩器、實時時鐘以及RAM。雖然數(shù)據(jù)分成兩種,但是對單片機的程序而言,其實是一樣的,就是對特定的地址進(jìn)行讀寫操作。

圖2 DS1302的內(nèi)部結(jié)構(gòu)圖
DS1302 含充電電路,可以對作為后備電源的可充電電池充電,并可選擇充電使能和串入的二極管數(shù)目,以調(diào)節(jié)電池充電電壓。不過對我們目前而言,需要熟悉的是和時鐘相關(guān)部分的功能,對于其它參數(shù)請參閱數(shù)據(jù)手冊。
2. DS1302 的工作原理
DS1302 工作時為了對任何數(shù)據(jù)傳送進(jìn)行初始化,需要將復(fù)位腳(RST)置為高電平且將8 位地址和命令信息裝入移位寄存器。數(shù)據(jù)在時鐘(SCLK)的上升沿串行輸入,前8 位指定訪問地址,命令字裝入移位寄存器后,在之后的時鐘周期,讀操作時輸出數(shù)據(jù),寫操作時輸出數(shù)據(jù)。時鐘脈沖的個數(shù)在單字節(jié)方式下為8+8(8 位地址+8 位數(shù)據(jù)),在多字節(jié)方式下為8 加多可達(dá)248 的數(shù)據(jù)。
3. DS1302 的寄存器和控制命令
對DS1302 的操作就是對其內(nèi)部寄存器的操作,DS1302 內(nèi)部共有12 個寄存器,其中有7 個寄存器與日歷、時鐘相關(guān),存放的數(shù)據(jù)位為BCD 碼形式。
此外,DS1302 還有年份寄存器、控制寄存器、充電寄存器、時鐘突發(fā)寄存器及與RAM 相關(guān)的寄存器等。
時鐘突發(fā)寄存器可性順序讀寫除充電寄存器以外的寄存器。日歷、時間寄存器及控制字如表1 所示。
表1 日歷、時鐘寄存器與控制字對照表

一位RD/W 為“0”時表示進(jìn)行寫操作,為“1”時表示讀操作。
DS1302 內(nèi)部寄存器列表如表2 所示。
DS1302 內(nèi)部的RAM 分為兩類,一類是單個RAM 單元,共31 個,每個單元為一個8 位的字節(jié),其命令控制字為COH~FDH,其中奇數(shù)為讀操作,偶數(shù)為寫操作;再一類為突發(fā)方式下的RAM,此方式下可性讀寫所有的RAM 的31 個字節(jié),命令控制字為FEH(寫)、FFH(讀)。
表2 DS14302內(nèi)部主要寄存器分布表

我們現(xiàn)在已經(jīng)知道了控制寄存器和RAM 的邏輯地址,接著就需要知道如何通過外部接口來訪問這些資源。單片機是通過簡單的同步串行通訊與DS1302通訊的,每次通訊都必須由單片機發(fā)起,無論是讀還是寫操作,單片機都必須先向DS1302 寫入一個命令幀,位BIT7 固定為1,BIT6 決定操作是針對RAM 還是時鐘寄存器,接著的5 個BIT 是RAM或時鐘寄存器在DS1302 的內(nèi)部地址,一個BIT表示這次操作是讀操作抑或是寫操作。
物理上,DS1302 的通訊接口由3 個口線組成,即RST,SCLK,I/O。其中RST 從低電平變成高電平啟動數(shù)據(jù)傳輸過程,SCLK 是時鐘線,I/O 是數(shù)據(jù)線。具體的讀寫時序參考圖3,但是請注意,無論是哪種同步通訊類型的串行接口,都是對時鐘信號敏感的,而且一般數(shù)據(jù)寫入有效是在上升沿,讀出有效是在下降沿(DS1302 正是如此的,但是在芯片手冊里沒有明確說明),如果不是特別確定,則把程序設(shè)計成這樣:平時SCLK 保持低電平,在時鐘變動前設(shè)置數(shù)據(jù),在時鐘變動后讀取數(shù)據(jù),即數(shù)據(jù)操作總是在SCLK 保持為低電平的時候,相鄰的操作之間間隔有一個上升沿和一個下降沿。

圖3 DS1302的命令字結(jié)構(gòu)
通過前文的原理介紹,我們已經(jīng)對DS1302 時鐘芯片的特性以及工作原理有了大致地了解,但當(dāng)我們拿到一個時鐘器件時要正確地應(yīng)用它還是一時不知如何下手,比如我們要做一個簡單的時間顯示,需要怎么辦呢?首先,時鐘芯片與單片機的連接非常簡單,一般來說,我們只需要將IIC 器件的復(fù)位“RST”、數(shù)據(jù)“I/O”、時鐘“SCLK”端與單片機的I/O 口相連,就可以進(jìn)行時間、日期數(shù)據(jù)的寫入或讀取了?,F(xiàn)在,我們來一起看一個使用DS1302 做時間顯示的例子,通過一個實例,相信會給大家?guī)硪粋€感性的認(rèn)識。
首先, 我們來看一下增強型PIC 實驗板上DS1302 器件的接口電路,因為我們需要將軟件和硬件相結(jié)合進(jìn)行考慮如何來編程,完成該實驗的硬件原理圖如圖4 所示,U2 為實驗板上DS1302 芯片,“I/O”
與單片機的RB5 口相連,“SCLK”與單片機RB6 相連,“RST”與單片機RB7 相連,七段數(shù)碼管D5、D7、D8 組成了顯示單元,字形碼的數(shù)據(jù)通過RC 口送入,各數(shù)碼管的顯示片選信號分別不同的RA 口進(jìn)行控制。

圖4 硬件原理圖
對于單機軟件的編程,我們使用MPLab IDE 軟件來進(jìn)行C 語言編程,它是我們的編程環(huán)境,同時我們可以通過使用ICD2 仿真燒寫器和增強型PIC 實驗板連接進(jìn)行程序的仿真調(diào)試和燒寫步驟,具體的操作步驟,我們已經(jīng)在前幾期做了詳細(xì)的說明和介紹,在此就不再重復(fù)說明,讀者朋友可以參閱以前的文章或直接登陸我們的網(wǎng)站查看資料?,F(xiàn)在我們可以輸入程序代碼進(jìn)行調(diào)試了,我們在MPLab IDE 軟件中新建工程,加入源程序代碼,同時進(jìn)行芯片型號的選擇和配置位的設(shè)置,我們實驗所用的芯片型號為PIC16F877A。編寫的程序代碼如下,其中程序流程圖如圖5 所示,實際運行效果如圖6 所示。

圖5 軟件流程

圖6 DS1302 實驗演示圖
二、軟件代碼
/*************************************************/
/*DS1302 讀寫演示程序 */
/* 目標(biāo)器件:PIC16F877A */
/* 晶振:4.0MHZ */
/* 編譯環(huán)境:MPLAB V7.51 */
/**************************************************/
#include<pic.h>
#define i_o RB5
#define sclk RB6
#define rst RB7
unsigned char time_rx @ 0x30;
// 定義接收寄存器
static volatile bit time_rx7 @ (unsigned)&time_rx*8+7;
// 接收寄存器的位
/***************************************************
子函數(shù)定義
**************************************************/
void port_init(); // 申明引腳初始化函數(shù)
void ds1302_init(); // 申明DS1302 初始化函數(shù)
void set_time(); // 申明設(shè)置時間函數(shù)
void get_time(); // 申明讀取時間函數(shù)
void display(); // 申明顯示函數(shù)
void time_write_1(unsigned char time_tx);
// 申明寫一個字節(jié)函數(shù)
unsigned char time_read_1();
// 申明讀一個字節(jié)函數(shù)
void delay(); // 申明延時函數(shù)
/***************************************************
時間和日期存放表
**************************************************/
const char table[]={0x00,0x30,0x12,0x8,0x3,0x06,0x06,0x00};
char table1[7];
/**************************************************
共陰LED 段碼表
**************************************************/
const char table2[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
void main()
{
port_init(); // 調(diào)用引腳初始化函數(shù)
TRISC =0x00;
ds1302_init(); // 調(diào)用DS1302 初始化函數(shù)
set_time(); // 調(diào)用設(shè)置時間函數(shù)
while(1)
{
get_time(); // 調(diào)用取時間函數(shù)
display(); // 調(diào)用顯示函數(shù)
}
}
void ds1302_init() // DS1302 初始化函數(shù)子程序
{
sclk=0; // 拉低時鐘信號
rst =0; // 復(fù)位DS1302
rst=1; // 使能DS1302
time_write_1(0x8e); // 發(fā)控制命令
time_write_1(0); // 允許寫DS1302
rst=0; // 復(fù)位
}
void set_time() // 設(shè)置時間函數(shù)子程序
{
int i; // 定義循環(huán)變量
rst=1; // 使能DS1302
time_write_1(0xbe); // 時鐘多字節(jié)寫命令
for(i=0;i<8;i++) // 連續(xù)寫8 個字節(jié)數(shù)據(jù)
{
time_write_1(table[i]); // 調(diào)用寫一個字節(jié)函數(shù)
delay();
}
rst=0; // 復(fù)位
}
void get_time() // 讀取時間函數(shù)子程序
{
int i; // 設(shè)置循環(huán)變量
rst=1; // 使能DS1302
time_write_1(0xbf); // 發(fā)送多字節(jié)讀取命令
for(i=0;i<7;i++) // 連續(xù)讀取7 個字節(jié)數(shù)據(jù)
{
table1[i]=time_read_1();
// 調(diào)用讀取1 個字節(jié)數(shù)據(jù)的函數(shù)
delay();
}
rst=0; // 復(fù)位DS1302
}
void time_write_1(unsigned char time_tx)
{
int j; // 設(shè)置循環(huán)變量
for(j=0;j<8;j++) // 連續(xù)寫8bit
{
i_o=0; // 先設(shè)置數(shù)據(jù)為0
sclk=0; // 時鐘信號拉低
if(time_tx&0x01) // 判斷待發(fā)送的數(shù)據(jù)位是0 或1
{
i_o=1; // 待發(fā)送數(shù)據(jù)位是1
}
time_tx=time_tx》1; // 待發(fā)送的數(shù)據(jù)右移1 位
sclk=1; // 拉高時鐘信號
}
sclk=0; // 寫完一個字節(jié),拉低時鐘信號
}
unsigned char time_read_1()
{
int j; // 設(shè)置循環(huán)變量
TRISB5=1; // 設(shè)置數(shù)據(jù)口方向為輸入
for(j=0;j<8;j++) // 連續(xù)讀取8bit
{
sclk=0; // 拉低時鐘信號
time_rx=time_rx》1; // 接收寄存器右移1 位
time_rx7=i_o;
// 把接收到的數(shù)據(jù)放到接收寄存器的位sclk=1; // 拉高時鐘信號
}
TRISB5=0; // 恢復(fù)數(shù)據(jù)口方向為輸出
sclk=0; // 拉低時鐘信號
return(time_rx); // 返回讀取到的數(shù)據(jù)
}
void port_init()
{
TRISA=0x00; // 設(shè)置A 口全輸出
TRISC=0X00; // 設(shè)置C 口全輸出
TRISB=0x00;
}
void display() // 顯示子程序
{
int i; // 定義查表變量
i=table1[0]&0x0f; // 求秒的個位
PORTC=table2[i]; // 送C 口顯示
PORTA=0xFD; // 點亮秒的個位
delay(); // 延長一段時間,保證亮度
i=table1[0]&0xf0; // 求秒的十位
i=i》4; // 右移4 位
PORTC=table2[i]; // 送C 口顯示
PORTA=0xFE; // 點亮秒的十位
delay(); // 延長一段時間,保證亮度
i=table1[1]&0x0f; // 求分的個位
PORTC=table2[i]&0x7f;
// 送C 口顯示,并顯示小數(shù)點
PORTA=0xF7; // 點亮分的個位
delay(); // 延時一定時間,保證亮度
i=table1[1]&0xf0; // 求分的十位
i=i》4;
PORTC=table2[i]; // 送C 口顯示
PORTA=0xFB; // 點亮分的十位
delay(); // 延長一段時間,保證亮度
i=table1[2]&0x0f; // 求時的個位
PORTC=table2[i]&0x7f;
// 送C 口顯示,并加上小數(shù)點
PORTA=0xDF; // 點亮?xí)r的個位
delay(); // 延時一定時間,保證亮度
i=table1[2]&0xf0; // 求時的十位
i=i》4;
PORTC=table2[i]; // 送C 口顯示
PORTA=0xEF; // 點亮?xí)r的十位
delay(); // 延長一段時間,保證亮度
}
void delay() // 延時程序
{
int i; // 定義整形變量
for(i=100;i--;); // 延時
}
看到這里,相信你現(xiàn)在已經(jīng)可以完成一些簡單的電子鐘實驗,DS1302 的原理與使用我們講到這里。
增強型PIC 實驗板系統(tǒng)資源豐富,可做實驗有:6 位LED 數(shù)碼管、8 路LED、直控鍵盤、蜂鳴器喇叭、繼電器試驗、I2C 總線接口、SPI 總線接口、160X 液晶、128X64 液晶、紅外接收頭接口、步進(jìn)電機驅(qū)動接口、AD 模/ 數(shù)轉(zhuǎn)換接口、串行時鐘芯片DS1302、溫度傳感器DS18B20 接口、RS232 串口通訊、外擴展接口以便外接更多的實驗資源。
版權(quán)與免責(zé)聲明
凡本網(wǎng)注明“出處:維庫電子市場網(wǎng)”的所有作品,版權(quán)均屬于維庫電子市場網(wǎng),轉(zhuǎn)載請必須注明維庫電子市場網(wǎng),http://www.58mhw.cn,違反者本網(wǎng)將追究相關(guān)法律責(zé)任。
本網(wǎng)轉(zhuǎn)載并注明自其它出處的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點或證實其內(nèi)容的真實性,不承擔(dān)此類作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。其他媒體、網(wǎng)站或個人從本網(wǎng)轉(zhuǎn)載時,必須保留本網(wǎng)注明的作品出處,并自負(fù)版權(quán)等法律責(zé)任。
如涉及作品內(nèi)容、版權(quán)等問題,請在作品發(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關(guān)權(quán)利。
- 晶體管與MOSFET的區(qū)別詳解2026/3/3 14:36:02
- 基于運算跨導(dǎo)放大器(OTA)的有源濾波器綜合方法2026/3/3 14:19:50
- 連接器鍍層種類及性能對比2026/3/3 14:05:32
- 高頻DC-DC芯片的設(shè)計要點2026/3/2 11:48:08
- 柵極電荷Qg對MOSFET開關(guān)速度的影響2026/3/2 11:29:32









