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