DS1302實時時鍾模塊
芯片手冊:datasheet pdf 索引DS1302數據表
時鍾芯片DS1302含有實時時鍾/日歷和31字節靜態RAM。與單片機之間采用3線同步串行方式進行通信。
1、DS1302的引腳
PIN | 引腳說明 |
---|---|
X1、X2 | 晶振接入引腳,晶振頻率為32.768kHz |
RST | 復位引腳,高電平啟動輸入輸出,低電平結束輸入輸出 |
I/O | 數據輸入輸出引腳 |
SCLK | 串行時鍾輸入引腳 |
GND | 接地引腳 |
Vcc1,Vcc2 | 工作電源、備份工作電源 |
2、命令字節
命令字節如下圖所示:
每個數據傳輸都是由一個命令字節發起,MSB(Bit7)必須是邏輯1。如果它是0,對DS1302的寫入將被禁用。
第6位如果邏輯為0,則指定時鍾/日歷數據;如果邏輯為1,則指定RAM數據。
第1位到第五位指定要輸入或輸出的寄存器,LSB(第0位)指定邏輯0時的寫操作或邏輯0時的讀操作(輸出)。
命令字節總是從LSB開始輸入(第0位)
3、復位和時鍾控制
所有的數據傳輸都是通過驅動RST高輸入來啟動的。
RST輸入有兩個功能:
- 首先RST打開控制邏輯,允許訪問地址/命令序列的移位寄存器。
- 第二,RST信號提供了一種終止單字節或多字節數據傳輸的方法。
時鍾周期是一個由下降邊和上升邊組成的序列。對於數據輸入,數據必須在時鍾上升沿有效,數據位在時種下沿輸出。(即寫入數據是在時鍾上升沿,讀出數據在時鍾下降沿)
如果RST輸入低,所有數據傳輸終止,IO引腳進入高阻狀態,
上電時,RST必須是邏輯0,知道Vcc > 2.0V。同時,當RST被驅動到邏輯1時,SCLK必須處於邏輯0。(看下面的輸入輸出的圖,一開始都是RST低,SCLK低,然后RST高;然后才是開始數據傳輸)
4、數據輸入輸出
(1)數據輸入
在八個SCLK周期輸入一個寫命令字節之后(看上圖I/O那行,首先是8個SCLK周輸入寫命令字節),
在接下來的8個SCLK周期的上升沿上輸入一個數據字節(注意看上圖每次字節輸入都是從上升沿),
如果數據從位0開始輸入,則忽略額外的SCLK周期。
示例:
- 每次CLK拉低,IO給值,CLK拉高
- dat每次都是從最低位給IO值,所以dat要右移1位
void DS1302_WByte(uchar dat)
{
uchar i;
for(i = 8; i > 0; i--) // 從圖中也可以看到,數據是從D0開始輸入的
{
DS1302_CLK = 0; // 時鍾線給低電平
Delay4Us(); // 延時
DS1302_IO = dat & 0x01; // IO輸入一個字節
DS1302_CLK = 1; // 時鍾線拉高
dat = dat >> 1; // 數據右移一位
}
}
(2)數據輸出
在輸入一個讀命令字節的8個SCLK周期之后,在接下來的8個SCLK周期的下降邊緣輸出一個數據字節。
請注意,要傳輸的第一個數據位發生在寫入命令字節的最后一位之后的第一個下降沿。
額外的SCLK周期重傳數據字節,只要RST保持高,它們就會在不經意間發生。允許連續突出模式的讀能力。此外,IO引腳在SCLK的每個上升邊緣上是三列的。數據從第0位開始輸出。
uchar DS1302_RByte(void)
{
uchar i,temp = 0;
DS1302_IO = 1;
for(i=8; i>0; i--)
{
DS1302_CLK=0; // CLK時鍾拉低,准備取數據
Delay4Us();
temp = temp >> 1; // 先低位在高位,所以每次需要右移
if( DS1302_IO == 1) // 當IO引腳是高電平,則數據位或操作0x80
{
temp = temp | 0x80;
}
DS1302_CLK=1;
Delay4Us();
}
return temp;
}
5、其他示例函數
1)寫數據到ds1302某地址
void DS1302_W_Addr_Dat(uchar addr, uchar dat)
{
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1; // 一開始的三行原因見 3、復位和時鍾控制那邊最后一句話加粗部分
DS1302_WByte(addr); // 地址,命令
DS1302_WByte(dat); // 寫1字節數據,一個字節等於8個位
DS1302_CLK = 1;
DS1302_RST = 0;
}
2)讀ds1302某地址的數據
void DS1302_R_All(uchar addr)
{
uchar dat;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RSt = 1;
DS1302_WByte(addr | 0x01); // 地址,命令
dat = DS1302_RByte(); // 讀1字節數據
DS1302_CLK=1;
DS1302_RST=0;
return(dat);
}
3)讀時間和日期
寄存器地址
示例程序
// 定義結構體
typedef struct
{
uchar Second;
uchar Minute;
uchar Hour;
uchar Week;
uchar Day;
uchar Month;
uchar Year;
uchar DataString[9];
uchar TimeString[9];
}TIMETYPE;
// 這邊表示的是寄存器的地址
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_WEEK 0x8A
#define DS1302_DAY 0x86
#define DS1302_MONTH 0x88
#define DS1302_YEAR 0x8C
// 0x70=0111 0000, 0x0F=0000 1111
// 從上面寄存器地址圖可知,高四位是存放十位上的數,第四位是存放個位的數
void DS1302_R_All( TIMETYPE *TIME)
{
uchar Rtemp;
Rtemp = DS1302_R_Addr(DS1302_SECOND); // 秒
Time->Second = ((Rtemp&0x70)>>4)*10 + (Rtemp & 0x0F);
Rtemp = DS1302_R_Addr(DS1302_MINUTE); // 分鍾
Time->Minute = ((Rtemp&0x70)>>4)*10 + (Rtemp & 0x0F);
Rtemp = DS1302_R_Addr(DS1302_HOUR); // 小時
Time->Hour = ((Rtemp&0x70)>>4)*10 + (Rtemp & 0x0F);
Rtemp = DS1302_R_Addr(DS1302_DAY); // 天
Time->Day = ((Rtemp&0x70)>>4)*10 + (Rtemp & 0x0F);
Rtemp = DS1302_R_Addr(DS1302_WEEK); // 星期
Time->Week = ((Rtemp&0x70)>>4)*10 + (Rtemp & 0x0F);
Rtemp = DS1302_R_Addr(DS1302_MONTH); // 月
Time->Month = ((Rtemp&0x70)>>4)*10 + (Rtemp & 0x0F);
Rtemp = DS1302_R_Addr(DS1302_YEAR); // 年
Time->Year = ((Rtemp&0x70)>>4)*10 + (Rtemp & 0x0F);
}
4)ds1302初始化
void DS1302_Init(void)
{
uchar Second;
DS1302_RST = 0;
DS1302_CLK = 0;
Second = DS1302_R_Addr(DS1302_SECOND);
DS1302_W_Addr_Dat(0x8e, 0x00);
DS1302_W_Addr_Dat(0x80, Second & 0x7f);
DS1302_W_Addr_Dat(0x90, 0xa6); // DS1302寄存器配置一個二極管,4kΩ充電電阻
DS1302_W_Addr_Dat(0x8E, 0x80);
}