【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片
目錄
- 硬知識(shí)
- DS1302 簡(jiǎn)介
- DS1302 使用
- 控制寄存器
- 日歷/時(shí)鐘寄存器
- DS1302 的讀寫(xiě)時(shí)序
- 電路設(shè)計(jì)
- 示例程序
- DS1302.c
- DS1302.h
- 測(cè)試程序
- main.c
- 實(shí)驗(yàn)現(xiàn)象
普中51-單核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
硬知識(shí)
???????摘自《普中 51 單片機(jī)開(kāi)發(fā)攻略》、《DS1302中文手冊(cè)》。
DS1302 簡(jiǎn)介
???????DS1302 是 DALLAS 公司推出的涓流充電時(shí)鐘芯片,內(nèi)含有一個(gè)實(shí)時(shí)時(shí)鐘/日歷和 31 字節(jié)靜態(tài) RAM,通過(guò)簡(jiǎn)單的串行接口與單片機(jī)進(jìn)行通信。實(shí)時(shí)時(shí)鐘/日歷電路提供秒、分、時(shí)、日、周、月、年的信息,每月的天數(shù)和閏年的天數(shù)可自動(dòng)調(diào)整。時(shí)鐘操作可通過(guò)AM/PM 指示決定采用 24 或 12 小時(shí)格式。DS1302 與 單片機(jī)之間能簡(jiǎn)單地采用同步串行的方式進(jìn)行通信,僅需用到三根通信線(xiàn):
???????①RES 復(fù)位
???????②I/O 數(shù)據(jù)線(xiàn)
???????③SCLK 串行時(shí)鐘。
???????時(shí)鐘/RAM 的讀/寫(xiě)數(shù)據(jù)以一個(gè)字節(jié)或多達(dá) 31 個(gè)字節(jié)的字符組方式通信。DS1302 工作時(shí)功耗很低,保持?jǐn)?shù)據(jù)和時(shí)鐘信息時(shí)功率小于 1mW。 DS1302 由 DS1202 改進(jìn)而來(lái)增加了以下的特性:雙電源管腳用于主電源和 備份電源供應(yīng),Vcc1 為可編程涓流充電電源,附加七個(gè)字節(jié)存儲(chǔ)器。它廣泛應(yīng)用于電話(huà)、傳真、便攜式儀器以及電池供電的儀器儀表等產(chǎn)品領(lǐng)域下面。
???????主要的性能指標(biāo):
★ 實(shí)時(shí)時(shí)鐘具有能計(jì)算 2100 年之前的秒、分、時(shí)、日、星期、月、年的 能力,還有閏年調(diào)整的能力;
★ 31 個(gè) 8 位暫存數(shù)據(jù)存儲(chǔ) RAM;
★ 串行 I/O 口方式使得管腳數(shù)量最少;
★ 寬范圍工作電壓 2.0 ~ 5.5V;
★ 工作在 2.0V 時(shí),電流小于 300nA;
★ 讀/寫(xiě)時(shí)鐘或 RAM 數(shù)據(jù)時(shí)有兩種傳送方式單字節(jié)傳送和多字節(jié)傳送字符組 方式;
★ 8 腳 DIP 封裝或可選的 8 腳 SOIC 封裝根據(jù)表面裝配;
★ 簡(jiǎn)單 3 線(xiàn)接口;
★ 與 TTL 兼容 Vcc=5V;
★ 可選工業(yè)級(jí)溫度范圍-40~+85;
DS1302 使用
???????操作 DS1302 的大致過(guò)程,就是將各種數(shù)據(jù)寫(xiě)入 DS1302 的寄存器,以設(shè)置 它當(dāng)前的時(shí)間的格式。然后使 DS1302 開(kāi)始運(yùn)作,DS1302 時(shí)鐘會(huì)按照設(shè)置情況 運(yùn)轉(zhuǎn),再用單片機(jī)將其寄存器內(nèi)的數(shù)據(jù)讀出。再用液晶顯示,就是我們常說(shuō)的簡(jiǎn) 易電子鐘。所以總的來(lái)說(shuō) DS1302 的操作分 2 步(顯示部分屬于液晶顯示的內(nèi)容, 不屬于 DS1302 本身的內(nèi)容),但是在講述操作時(shí)序之前,我們要先看看寄存器, DS1302 有一個(gè)控制寄存器、12 個(gè)日歷、時(shí)鐘寄存器和 31 個(gè) RAM。
控制寄存器
???????控制寄存器用于存放 DS1302 的控制命令字,DS1302 的 RST 引腳回到高電平后寫(xiě)入的第一個(gè)字節(jié)就為控制命令。它用于對(duì) DS1302 讀寫(xiě)過(guò)程進(jìn)行控制,格式如下:
???????上圖是 DS1302 的寄存器樣式,我們看到:
???????比如要讀秒寄存器則命令為 1000 0001,反之寫(xiě)為 1000 0000。
日歷/時(shí)鐘寄存器
???????DS1302 共有 12 個(gè)寄存器,其中有 7 個(gè)與日歷、時(shí)鐘相關(guān),存放的數(shù)據(jù)為 BCD 碼形式。格式如下:
???????秒寄存器:低四位為秒的個(gè)位,高的次三位為秒的十位。最高位 CH 為 DS1302 的運(yùn)行標(biāo)志,當(dāng) CH=0 時(shí),DS1302 內(nèi)部時(shí)鐘運(yùn)行,反之 CH=1 時(shí)停止;
???????小時(shí)寄存器:時(shí)寄存器。最高位為 12/24 小時(shí)的格式選擇位,該位為 1 時(shí)表示 12 小時(shí)格式。當(dāng)設(shè)置為 12 小時(shí)顯示格式時(shí),第 5 位的高電平表示下午 (PM);而當(dāng)設(shè)置為 24 小時(shí)格式時(shí),第 5 位位具體的時(shí)間數(shù)據(jù)。
???????寫(xiě)保護(hù)寄存器:當(dāng)該寄存器最高位 WP 為 1 時(shí),DS1302 只讀不寫(xiě),所以要在往 DS1302 寫(xiě)數(shù)據(jù)之前確保 WP 為 0。
???????慢充電寄存器(涓細(xì)電流充電)寄存器:我們知道,當(dāng) DS1302 掉電時(shí),可以馬上調(diào)用外部電源保護(hù)時(shí)間數(shù)據(jù)。該寄存器就是配置備用電源的充電選項(xiàng)的。 其中高四位(4 個(gè) TCS)只有在 1010 的情況下才能使用充電選項(xiàng);低四位的情 況與 DS1302 內(nèi)部電路有關(guān)。
???????在日歷/時(shí)鐘寄存器中都是以 BCD 碼存放數(shù)據(jù),BCD 碼是通過(guò) 4 位二進(jìn)制碼來(lái)表示 1 位十進(jìn)制中的 0~9 這 10 個(gè)數(shù)碼。 如下所示:
DS1302 的讀寫(xiě)時(shí)序
???????在控制指令字輸入后的下一個(gè) SCLK 時(shí)鐘的上升沿時(shí),數(shù)據(jù)被寫(xiě)入 DS1302, 數(shù)據(jù)輸入從低位(位 0)開(kāi)始。同樣,在緊跟 8 位的控制指令字后的下一個(gè) SCLK 脈沖的下降沿讀出 DS1302 的數(shù)據(jù),讀出數(shù)據(jù)時(shí)從低位 0 位到高位 7。其時(shí)序圖如下所示:
???????上圖就是 DS1302 的三個(gè)時(shí)序:復(fù)位時(shí)序,單字節(jié)寫(xiě)時(shí)序,單字節(jié)讀時(shí)序;
??????? CE(RST):復(fù)位時(shí)序,即在 RST 引腳產(chǎn)生一個(gè)正脈沖,在整個(gè)讀寫(xiě)器件, RST 要保持高電平,一次字節(jié)讀寫(xiě)完畢之后,要注意把 RST 返回低電平準(zhǔn)備下次 讀寫(xiě)周期;
???????單字節(jié)讀時(shí)序:注意讀之前還是要先對(duì)寄存器寫(xiě)命令,從最低位開(kāi)始寫(xiě);可以看到,寫(xiě)數(shù)據(jù)是在 SCLK 的上升沿實(shí)現(xiàn),而讀數(shù)據(jù)在 SCLK 的下降沿實(shí)現(xiàn)。所以, 在單字節(jié)讀時(shí)序中,寫(xiě)命令的第八個(gè)上升沿結(jié)束后緊接著的第八個(gè)下降沿就將要讀寄存器的第一位數(shù)據(jù)讀到數(shù)據(jù)線(xiàn)上了!這個(gè)就是 DS1302 操作中最特別的地方。 當(dāng)然讀出來(lái)的數(shù)據(jù)也是最低位開(kāi)始。
???????單字節(jié)寫(xiě)時(shí)序:兩個(gè)字節(jié)的數(shù)據(jù)配合 16 個(gè)上升沿將數(shù)據(jù)寫(xiě)入即可。
??????? 程序注意事項(xiàng):
??????? ★要記得在操作 DS1302 之前關(guān)閉寫(xiě)保護(hù);
??????? ★注意用延時(shí)來(lái)降低單片機(jī)的速度以配合器件時(shí)序;
??????? ★DS1302 讀出來(lái)的數(shù)據(jù)是 BCD 碼形式,要轉(zhuǎn)換成我們習(xí)慣的 10 進(jìn)制,轉(zhuǎn)換方法在源程序里;
??????? ★讀取字節(jié)之前,將 IO 設(shè)置為輸入口,讀取完之后,要將其改回輸出口;
??????? ★在寫(xiě)程序的時(shí)候,建議實(shí)現(xiàn)開(kāi)辟數(shù)組(內(nèi)存空間)來(lái)集中放置 DS1302 的 一系列數(shù)據(jù),方便以后擴(kuò)展鍵盤(pán)輸入。
電路設(shè)計(jì)
示例程序
???????stdint.h見(jiàn)【51單片機(jī)快速入門(mén)指南】1:基礎(chǔ)知識(shí)和工程創(chuàng)建
???????軟件SPI程序見(jiàn)【51單片機(jī)快速入門(mén)指南】5:軟件SPI
???????串口部分見(jiàn)【51單片機(jī)快速入門(mén)指南】3.3:USART 串口通信
???????根據(jù)時(shí)序圖,寫(xiě)入時(shí)都是模式1,讀取時(shí)先是模式1,之后是模式0。
DS1302.c
#include "./Soft_SPI/Soft_SPI.h" #include <STC89C5xRC.H> #include "DS1302.h"sbit DS1302_CS = P3^5;//DS1302_CS拉高 移植時(shí)需修改 void DS1302_CS_H() {DS1302_CS = 1; }//DS1302_CS拉低 移植時(shí)需修改 void DS1302_CS_L() {DS1302_CS = 0; }//---存儲(chǔ)順序是秒分時(shí)日月周年---// uint8_t gDS1302_TIME[7] = {0};//---DS1302寫(xiě)入時(shí)分秒的地址命令---// //---秒分時(shí)日月周年-------// code uint8_t gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};/******************************************************************************* Num2BCD 數(shù)字轉(zhuǎn)BCD碼(兩位數(shù)) *******************************************************************************/ #define Num2BCD(value) (((value/10)<<4)|(value%10))/******************************************************************************* * 函 數(shù) 名 : reversed * 函數(shù)功能 : 倒序一個(gè)字節(jié) *******************************************************************************/ uint8_t reversed(uint8_t raw) {uint8_t i, value = 0;for(i = 0; i < 8; i++){value <<= 1;value |= (raw & 0x01);raw >>= 1;}return value; }/******************************************************************************* * 函 數(shù) 名 : ds1302_write_byte * 函數(shù)功能 : DS1302寫(xiě)單字節(jié) * 輸 入 : addr:地址/命令dat:數(shù)據(jù) * 輸 出 : 無(wú) *******************************************************************************/ void ds1302_write_byte(uint8_t addr,uint8_t dat) { addr = reversed(addr);dat = reversed(dat);DS1302_CS_L();DS1302_CS_H();SOFT_SPI_RW_MODE1(addr);SOFT_SPI_RW_MODE1(dat);DS1302_CS_L(); }/******************************************************************************* * 函 數(shù) 名 : ds1302_read_byte * 函數(shù)功能 : DS1302讀單字節(jié) * 輸 入 : addr:地址/命令 * 輸 出 : 讀取的數(shù)據(jù) *******************************************************************************/ uint8_t ds1302_read_byte(uint8_t addr) {uint8_t temp = 0;addr = reversed(addr);DS1302_CS_H(); SOFT_SPI_RW_MODE1(addr);temp = SOFT_SPI_RW_MODE0(0xff);DS1302_CS_L();return reversed(temp); }/******************************************************************************* * 函 數(shù) 名 : ds1302_init * 函數(shù)功能 : DS1302初始化時(shí)間 * 輸 入 : 無(wú) * 輸 出 : 無(wú) *******************************************************************************/ void ds1302_init(uint8_t YY, uint8_t MM, uint8_t DD, uint8_t hh, uint8_t mm, uint8_t ss, uint8_t ww) {uint8_t i;ds1302_write_byte(0x8e, 0x00);gDS1302_TIME[0] = Num2BCD(ss);gDS1302_TIME[1] = Num2BCD(mm);gDS1302_TIME[2] = Num2BCD(hh);gDS1302_TIME[3] = Num2BCD(DD);gDS1302_TIME[4] = Num2BCD(MM);gDS1302_TIME[5] = Num2BCD(ww);gDS1302_TIME[6] = Num2BCD(YY);for(i = 0; i < 7; i++){ds1302_write_byte(gWRITE_RTC_ADDR[i], gDS1302_TIME[i]); }ds1302_write_byte(0x8e, 0x80); }/******************************************************************************* * 函 數(shù) 名 : ds1302_read_time * 函數(shù)功能 : DS1302讀取時(shí)間 * 輸 入 : 無(wú) * 輸 出 : 無(wú) *******************************************************************************/ void ds1302_read_time(void) {uint8_t i;for(i = 0; i < 7; i++){gDS1302_TIME[i] = ds1302_read_byte(gWRITE_RTC_ADDR[i] | 0x01); } }DS1302.h
#ifndef DS1302_H_ #define DS1302_H_#include "stdint.h"#define Second() ((int16_t)(gDS1302_TIME[0]&0x0f)+((gDS1302_TIME[0]&0x70)>>4)*10) #define Minute() ((int16_t)(gDS1302_TIME[1]&0x0f)+((gDS1302_TIME[1]&0x70)>>4)*10) #define Hour() ((int16_t)(gDS1302_TIME[2]&0x0f)+((gDS1302_TIME[2]&0x30)>>4)*10) #define Date() ((int16_t)(gDS1302_TIME[3]&0x0f)+((gDS1302_TIME[3]&0x30)>>4)*10) #define Month() ((int16_t)(gDS1302_TIME[4]&0x0f)+((gDS1302_TIME[4]&0x10)>>4)*10) #define Year() ((int16_t)(gDS1302_TIME[6]&0x0f)+((gDS1302_TIME[6]&0xF0)>>4)*10) #define Week() ((int16_t)(gDS1302_TIME[5]&0x0f))extern uint8_t gDS1302_TIME[];void ds1302_write_byte(uint8_t addr,uint8_t dat); uint8_t ds1302_read_byte(uint8_t addr); void ds1302_init(uint8_t YY, uint8_t MM, uint8_t DD, uint8_t hh, uint8_t mm, uint8_t ss, uint8_t ww); void ds1302_read_time(void);#endif測(cè)試程序
main.c
#include <STC89C5xRC.H> #include "intrins.h" #include "stdint.h" #include "DS1302.h" #include "USART.h"void Delay1ms() //@22.1184MHz {unsigned char i, j;_nop_();i = 4;j = 146;do{while (--j);} while (--i); }void Delay_ms(int i) {while(i--)Delay1ms(); }void main(void) {ds1302_init(21, 12, 3, 22, 42, 28, 5); //配置為21年12月03日22時(shí)42分28秒 星期5USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 22118400, 115200, DOUBLE_BAUD_ENABLE, USART_TIMER_1);while(1){ Delay_ms(1000);ds1302_read_time();printf("%d年%d月%d日%d時(shí)%d分%d秒", Year(), Month(), Date(), Hour(), Minute(), Second());printf(" 星期%d\r\n", Week());} }實(shí)驗(yàn)現(xiàn)象
打開(kāi)串口,可見(jiàn)如下數(shù)據(jù):
此程序也可在Proteus中正常仿真:
總結(jié)
以上是生活随笔為你收集整理的【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ue 清理缓存_【PM项目管理系统】PM
- 下一篇: OpenType的Adobe字体开发工具