DS1302是低功耗帶RAM的實時時鐘電路, 常見的SOP8封裝體積很小, 它可以對年月日周時分秒進行計時, 具有閏年補償功能, 工作電壓為2.0V-5.5V, 采用三線接口與CPU進行同步通信, 并可采用突發方式一次傳送多個字節的時鐘信號或RAM數據. DS1302內部有一個31byte的用于臨時性存放數據的RAM寄存器. DS1302是DS1202的升級產品, 與DS1202兼容, 但增加了主電源/后備電源雙電源引腳, 同時提供了對后備電源進行涓細電流充電的能力. 幾個需要知道的點: - 不帶溫度補償, 所以在溫度變化大的環境, 走時誤差會比較大, 需要有校對機制
- 三線接口機制與SPI相似, 但不是SPI, 因為它在同一根線上實現的雙向IO
- 自身不帶電源/電容, 掉電即重置, 需要自己管理好主電備電
- 備電的充電方式是可以通過寄存器控制的, 分三級控制, 第一級開關, 第二級可選1級或2級二極管降壓, 第三級可選三種阻值
- 額外的31個byte的存儲可以自由讀寫
- burst read有兩處, 一處是8個字節的control+時間, 另一處是31字節的ram, 都是一次性全部讀取, 但是可以編程控制讀到第幾個字節就停止.
- 讀取的結果是BCD碼, 要轉換
Vcc1和Vcc2DS1302的引腳中Vcc2為主電源, Vcc1為后備電源. 在主電源關閉的情況下, 也能保持時鐘的連續運行. DS1302由Vcc1或Vcc2兩者中的較大者供電, 當Vcc2大于Vcc1+0.2V時, Vcc2給DS1302供電, 當Vcc2小于Vcc1時, DS1302由Vcc1供電. 注意: 供電不要低于3.6V, 否則在秒進位時容易出現時間清零. 如果是在VCC端串聯電阻限流, 電阻不要超過3K. RST腳RST是復位/片選線, 通過把RST輸入驅動置高電平來啟動所有的數據傳送. - 當RST為高電平時, 允許地址/命令序列送入移位寄存器, 所有的數據傳送被初始化, 允許對DS1302進行操作
- 提供終止單字節或多字節數據傳送的方法, 如果在傳送過程中RST置為低電平,則會終止此次數據傳送,I/O引腳變為高阻態
- 上電運行時, 在Vcc>2.0V之前RST必須保持低電平. 只有在SCLK為低電平時, 才能將RST置為高電平.
寫入邏輯:- 將RST先拉低
- 將SCLK拉低(如果不拉低, 且本來是高電平, 則瞬間就發出了一個bit, 這時還沒放數據)
- 將RST拉高, 形成一個上升沿
- 在IO口放入一個bit (字節發送順序:從低位到高位)
- 將SCLK拉高, 形成上升沿, 這時候DS1302就會將IO口的數據移入它的寄存器
- 拉低SCLK, 為下一個字節做準備
- IO口再放一個bit, 再拉高, 直到發送完所有的16個字節
- 最后拉低RST, 完成寫入過程
寄存器地址與時間相關的寄存器從0x80到0x8F, 其中偶數為寫地址, 奇數為讀地址, 共控制8個字節, 這8個字節可以通過burst方式一次性讀出 - #define DS1302_W_SECOND 0x80
- #define DS1302_W_MINUTE 0x82
- #define DS1302_W_HOUR 0x84
- #define DS1302_W_DAY 0x86
- #define DS1302_W_MONTH 0x88
- #define DS1302_W_WEEK 0x8A
- #define DS1302_W_YEAR 0x8C
- #define DS1302_W_PROTECT 0x8E
- #define DS1302_R_SECOND 0x81
- #define DS1302_R_MINUTE 0x83
- #define DS1302_R_HOUR 0x85
- #define DS1302_R_DAY 0x87
- #define DS1302_R_MONTH 0x89
- #define DS1302_R_WEEK 0x8B
- #define DS1302_R_YEAR 0x8D
- #define DS1302_R_PROTECT 0x8F
復制代碼
與控制相關的寄存器為如下幾個, 也是偶數寫奇數讀, 這些只能單個讀寫
- #define DS1302_W_TK_CHARGER 0x90
- #define DS1302_W_CLK_BURST 0xBE
- #define DS1302_W_RAM_BURST 0xFE
- #define DS1302_R_TK_CHARGER 0x91
- #define DS1302_R_CLK_BURST 0xBF
- #define DS1302_R_RAM_BURST 0xFF
復制代碼片內的31個字節RAM起始地址為0xC0, 這31個字節可以通過burst方式一次性讀出 - #define DS1302_RAM_SIZE 0x31 // Ram Size in bytes
- #define DS1302_RAM_START 0xC0 // First byte Address
復制代碼
使用STC12 MCU讀取DS1302接線圖, 測試中可以只接Vcc2或Vcc1, 可以串電阻或串二極管限流,
DS1302-sch3.png (171.57 KB, 下載次數: 54)
下載附件
2021-8-27 11:05 上傳
實際的測試板, 接DS1302使用的是SOP8的測試座, 避免焊接, 中間的萬能板僅僅是為了用一個IC座外接晶振, 可以忽略其他元件
DS1302-test2.jpg (125.82 KB, 下載次數: 67)
下載附件
2021-8-27 11:05 上傳
測試座里的DS1302
DS1302-test1.jpg (94.84 KB, 下載次數: 49)
下載附件
2021-8-27 11:06 上傳
代碼例子, 包含單個讀, 單個寫, burst讀時間, burst讀RAM, 基于 HML_FwLib_STC12 封裝庫. 因為是非標準SPI, 所以實際上只用到了串口打印, 直接把這個方法拎出來也行, 就不需要引入這個封裝庫了. - /*****************************************************************************/
- /**
- * 連接方式
- * | | |
- * | --------- | ------------ |
- * |1:Vcc2 VCC | 8:Vcc1 |
- * |2:X1 OCS | 7:SCLK P1_0 |
- * |3:X2 OCS | 6:I/O P1_1 |
- * |4:GND GND | 5:RST/CE P1_2 |
- *
- *****************************************************************************/
- #include "hml/hml.h"
- #include <stdio.h>
- #define DS1302_W_SECOND 0x80
- #define DS1302_W_MINUTE 0x82
- #define DS1302_W_HOUR 0x84
- #define DS1302_W_DAY 0x86
- #define DS1302_W_MONTH 0x88
- #define DS1302_W_WEEK 0x8A
- #define DS1302_W_YEAR 0x8C
- #define DS1302_W_PROTECT 0x8E
- #define DS1302_W_TK_CHARGER 0x90
- #define DS1302_W_CLK_BURST 0xBE
- #define DS1302_W_RAM_BURST 0xFE
- #define DS1302_R_SECOND 0x81
- #define DS1302_R_MINUTE 0x83
- #define DS1302_R_HOUR 0x85
- #define DS1302_R_DAY 0x87
- #define DS1302_R_MONTH 0x89
- #define DS1302_R_WEEK 0x8B
- #define DS1302_R_YEAR 0x8D
- #define DS1302_R_PROTECT 0x8F
- #define DS1302_R_TK_CHARGER 0x91
- #define DS1302_R_CLK_BURST 0xBF
- #define DS1302_R_RAM_BURST 0xFF
- #define DS1302_RAM_SIZE 0x31 // Ram Size in bytes
- #define DS1302_RAM_START 0xC0 // First byte Address
- #define HEX2BCD(v) ((v) % 10 + (v) / 10 * 16)
- #define BCD2HEX(v) ((v) % 16 + (v) / 16 * 10)
- #define DS1302_SCK P1_0
- #define DS1302_IO P1_1
- #define DS1302_RST P1_2
- const uint8_t READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
- const uint8_t WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
- uint8_t BUF[8] = { 0 };
- // Write one byte to DS1302
- void DS1302_WriteByte(uint8_t writeByte)
- {
- for(uint8_t i=0; i < 8; i++)
- {
- if(1 == (writeByte & 0x01)){
- DS1302_IO = 1;
- }else{
- DS1302_IO = 0;
- }
- DS1302_SCK = 1;
- DS1302_SCK = 0;
- writeByte >>= 1; // From low to high
- }
- }
-
- // Read one byte from DS1302
- uint8_t DS1302_ReadByte(void)
- {
- uint8_t dat, readByte = 0;
- for(uint8_t i = 0; i < 8; i++)
- {
- //dat = DS1302_IO;
- //readByte = (readByte>>1) | (dat << 7); // From low to high
- readByte >>= 1;
- if(DS1302_IO)
- {
- readByte |= 0x80;
- }
- DS1302_SCK = 1;
- DS1302_SCK = 0;
- }
- return readByte;
- }
- void DS1302_WriteReg(uint8_t addr, uint8_t value)
- {
- DS1302_RST = 0;
- DS1302_SCK = 0;
- DS1302_RST = 1;
- DS1302_WriteByte(addr);
- DS1302_WriteByte(value);
- DS1302_SCK = 1;
- DS1302_RST = 0;
- }
-
- uint8_t DS1302_ReadReg(uint8_t addr)
- {
- uint8_t readByte = 0;
- DS1302_RST = 0;
- DS1302_SCK = 0;
- DS1302_RST = 1;
- DS1302_WriteByte(addr);
- readByte = DS1302_ReadByte();
- DS1302_SCK = 1;
- DS1302_RST = 0;
- return readByte;
- }
- void DS1302_ReadBurst(uint8_t cmd, uint8_t len, uint8_t *buf)
- {
- uint8_t readByte = 0;
- DS1302_RST = 0;
- DS1302_SCK = 0;
- DS1302_RST = 1;
- DS1302_WriteByte(cmd);
- while(len--)
- *buf++ = DS1302_ReadByte();
- DS1302_SCK = 1;
- DS1302_RST = 0;
- }
- void DS1302_Init(void)
- {
- DS1302_WriteReg(DS1302_W_PROTECT, 0x00); // write unprotect
- DS1302_WriteReg(DS1302_W_TK_CHARGER, 0x01); // stop charger
- DS1302_WriteReg(0XC0, 0x00);
- DS1302_WriteReg(0XC2, 0x01);
- DS1302_WriteReg(0XC4, 0x02);
- DS1302_WriteReg(0XC6, 0x03);
- DS1302_WriteReg(DS1302_W_PROTECT, 0x80); // write protect
- }
- void DS1302_print(uint8_t dat)
- {
- printf_tiny("%x%x ", dat >> 4, dat & 0x0F);
- }
- void DS1302_printBuf(uint8_t len)
- {
- for(uint8_t i = 0; i < len; i++)
- {
- printf_tiny("%x%x ", BUF[i] >> 4, BUF[i] & 0x0F);
- }
- printf_tiny("\n");
- }
- void main(void)
- {
- UTIL_enablePrintf();
- DS1302_Init();
- while(1)
- {
- uint8_t dat = DS1302_ReadReg(DS1302_R_SECOND);
- DS1302_print(dat);
- dat = DS1302_ReadReg(DS1302_R_MINUTE);
- DS1302_print(dat);
- dat = DS1302_ReadReg(DS1302_R_HOUR);
- DS1302_print(dat);
- printf_tiny("\n");
- DS1302_ReadBurst(DS1302_R_CLK_BURST, 8, BUF);
- DS1302_printBuf(8);
- DS1302_ReadBurst(DS1302_R_RAM_BURST, 8, BUF);
- DS1302_printBuf(8);
- sleep(491);
- }
- }
復制代碼
我的8051筆記都在這個標簽下: https://www.cnblogs.com/milton/tag/8051/
|