13_单片机_DS1302实时时钟

1. DS1302是由美国DALLAS公司(现已被Maxim Integrated收购)推出的具有涓细电流充电能力的低功耗实时时钟芯片。实时时钟(RTC)计数秒,分、时、日、月、周、年,直到2100年。使用简易SPI协议。

 可参考零件数据表:https://www.mouser.cn/ProductDetail/Analog-Devices-Maxim-Integrated/DS1302Z%2bTR?qs=1eQvB6Dk1viuIIED1JtXWw%3D%3D

2. 单片机接线图如下

 

 3. 地址/指令 字节:

 a. 每次启动数据传输,MSB(Bit7)必须置为1;如果为0,则禁用DS1302的写入

 b. Bit6:置为1,则指定RAM数据;若为0,则指定时钟/日历数据

 c. Bit5~Bit1:输入或输出的寄存器;

 d.Bit0:置为1,读取操作;若为0,则写入操作

 注意:字节都是从LSB开始输入

 

 4. 时序图与数据传输

 规则:CE(也被称为RST)须处于高电平,在时钟(SCLK)的上升沿,数据(I/O)会被写入;在时钟(SCLK)下降沿,数据(I/O)被读出

 

 5. 寄存器地址/定义

 

6. 操作步骤

6.1. 写操作 write(command, data)

  a. CE & SCLK 复位(为0);

  b. CE 置为1,延时;

  **********写入command**********

  c. 将数据放到I/O上;

  d. 制造时钟上升沿,SCLK=1;

  e. 延时,SCLK=0,延时; (芯片传输需要点时间)

  f. 如此循环8次……

  **********写入data**********

  写入data的操作步骤和command是一样的

  最后,CE=0,SCLK=0

6.2. 读操作 read(command)

  a. CE & SCLK 复位(为0);

  b. CE 置为1,延时;

  **********写入command**********

  c. 将数据放到I/O上;

  d. 制造时钟上升沿,SCLK=1;

  e. 延时,SCLK=0,延时; (芯片传输需要点时间)

  f. 如此循环8次……

  **********读取data**********

  制造时钟下降沿,SCLK=0,但是需要注意的是:单字节写(Write)有16个脉冲,而单字节读(Read)只有15个脉冲,当最后一个Command的上升沿之后,紧随之后的下降沿,就可以读取数据。如下图的时序图

 7. BCD码(Binary Coded Decimal)

 DS1302寄存器的数据是以BCD码格式进行存储的。用4位二进制表示十进制数,如:0b0001 0011 = 0x13 = 13 (BCD表示10进制)

8. 实验:利用串口打印RTC时间

 a. UART 头文件 

 1 #ifndef __UART_H__
 2 #define __UART_H__
 3 
 4 #include <REG51.H>
 5 
 6 /***************函数声明**********************/
 7 void uart_init(void);
 8 void SendOneByte(unsigned char c);
 9 
10 
11 #endif
View Code

 b. UART 源文件

 1 #include "uart.h"
 2 
 3 
 4 /*****************************************************************
 5 * Function        : uart_init
 6 * Description    : 串口初始化
 7 * Parameters    : None
 8 * Return Value: None
 9 *****************************************************************/
10 void uart_init(void)
11 {
12     TMOD = 0x20;
13     SCON = 0x50;
14     TH1 = 0xF3;
15     TL1 = TH1;
16     PCON = 0x80;    // 加倍波特率4800
17     EA = 1;
18     ES = 1;
19     TR1 = 1;
20 }
21 
22 /*****************************************************************
23 * Function        : SendOneByte
24 * Description    : 通过串口发送1个字节
25 * Parameters    : None
26 * Return Value: None
27 *****************************************************************/
28 void SendOneByte(unsigned char c)
29 {
30     SBUF = c;
31     while(!TI);
32     TI = 0;
33 }
34 
35 void UARTInterrupt(void) interrupt 4
36 {
37 }
View Code

 c. DS1302 头文件

 1 #ifndef __DS1302_H__
 2 #define __DS1302_H__
 3 
 4 
 5 #include <REG51.H>
 6 #include <intrins.h>
 7 
 8 #ifndef uchar
 9 #define uchar unsigned char
10 #endif
11 
12 /*******************函数声明**************************/
13 void ds1302_write(uchar addr, uchar dat);
14 uchar ds1302_read(uchar addr);
15 void ds1302_init(void);
16 void rtc_read(void);
17 
18 /*******************全局变量*************************/
19 extern uchar TIME_CURRENT[7];    
20 
21 
22 #endif
View Code

 C语言关键字extern,外部变量(也称为全局变量),全局静态存储区

 d. DS1302 源文件

  1 #include "ds1302.h"
  2 
  3 sbit DSIO=P3^4;
  4 sbit RST=P3^5;
  5 sbit SCLK=P3^6;
  6 
  7 uchar code RTC_ADDR_READ[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
  8 uchar code RTC_ADDR_WRITE[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
  9 
 10 // BCD码,秒、分、时、日、月、周、年,2023/4/22 周六 20:38:00
 11 uchar TIME_CURRENT[7] = {0, 0x38, 0x20, 0x22, 0x04, 0x06, 0x23};
 12 
 13 /*****************************************************************
 14 * Function        : ds1302_write
 15 * Description    : 往DS1302写入数据
 16 * Parameters    : addr,dat
 17 * Return Value: None
 18 *****************************************************************/
 19 void ds1302_write(uchar addr, uchar dat)
 20 {
 21     uchar i = 0;
 22     
 23     RST = 0;
 24     _nop_();
 25     SCLK = 0;
 26     _nop_();
 27     
 28     RST = 1;                                // CE置1
 29     _nop_();
 30     
 31     // 写入command
 32     for(i=0; i<8; i++)
 33     {
 34         DSIO = addr & 0x01;        // 从LSB开始传输
 35         addr >>= 1;                        // addr右移1位,再赋值addr
 36         SCLK = 1;
 37         _nop_();                            // 延时
 38         SCLK = 0;
 39         _nop_();
 40     }
 41     
 42     for(i=0; i<8; i++)
 43     {
 44         DSIO = dat & 0x01;
 45         dat >>= 1;
 46         SCLK = 1;
 47         _nop_();
 48         SCLK = 0;
 49         _nop_();
 50     }
 51     
 52     RST = 0;                            // 完成CE复位(置0)
 53     _nop_();
 54 }
 55 
 56 /*****************************************************************
 57 * Function        : ds1302_read
 58 * Description    : 从DS1302中读取数据
 59 * Parameters    : addr
 60 * Return Value: val
 61 *****************************************************************/
 62 uchar ds1302_read(uchar addr)
 63 {
 64     uchar i = 0;
 65     uchar tmp=0, val=0;
 66     
 67     RST = 0;
 68     _nop_();
 69     SCLK = 0;
 70     _nop_();
 71     
 72     RST = 1;                                // CE置1
 73     _nop_();
 74     
 75     // 写入command
 76     for(i=0; i<8; i++)
 77     {
 78         DSIO = addr & 0x01;        // 从LSB开始传输
 79         addr >>= 1;                        // addr右移1位,再赋值addr
 80         SCLK = 1;
 81         _nop_();                            // 延时
 82         SCLK = 0;
 83         _nop_();
 84     }
 85     
 86     _nop_();
 87     
 88     for(i=0; i<8; i++)
 89     {
 90         tmp = DSIO;                        // 从LSB 开始接收
 91         // val = (val>>1) | (tmp<<7);
 92         val |= (tmp<<i);
 93         
 94         SCLK = 1;
 95         _nop_();
 96         SCLK = 0;
 97         _nop_();
 98     }
 99     
100     RST = 0;
101     _nop_();
102     
103     SCLK = 1;
104     _nop_();
105     DSIO = 0;
106     _nop_();
107     DSIO = 1;
108     _nop_();
109     
110     return val;
111 }
112 
113 /*****************************************************************
114 * Function        : ds1302_init
115 * Description    : 写入当前时间至DS1302中
116 * Parameters    : None
117 * Return Value: None
118 *****************************************************************/
119 void ds1302_init(void)
120 {
121     uchar i = 0;
122     
123     ds1302_write(0x8e, 0x00);    //关闭写保护
124     
125     // 写入当前时间
126     for(i=0; i<7; i++)
127     {
128         ds1302_write(RTC_ADDR_WRITE[i], TIME_CURRENT[i]);
129     }
130     
131     ds1302_write(0x8e, 0x80);    //开启写保护
132 }
133 
134 /*****************************************************************
135 * Function        : rtc_read
136 * Description    : 从DS1302中,实时读取数据
137 * Parameters    : None
138 * Return Value: None
139 *****************************************************************/
140 void rtc_read(void)
141 {
142     uchar i = 0;
143     
144     for(i=0; i<7; i++)
145     {
146         TIME_CURRENT[i] = ds1302_read(RTC_ADDR_READ[i]);
147     }
148 }
View Code

 DS1302 发生的错误是:读取数据时,移位方向错误,导致串口打印出全为0

 e. main 主函数

 1 #include "uart.h"
 2 #include "ds1302.h"
 3 
 4 /*****************************************************************
 5 * Function        : delay300ms
 6 * Description    : 延时300毫秒
 7 * Parameters    : None
 8 * Return Value: None
 9 *****************************************************************/
10 void delay300ms(void)   
11 {
12     unsigned char a,b,c;
13     for(c=5;c>0;c--)
14         for(b=212;b>0;b--)
15             for(a=140;a>0;a--);
16 }
17 
18 /*****************************************************************
19 * Function        : uart_print_time
20 * Description    : 通过串口打印实时时钟
21 * Parameters    : None
22 * Return Value: None
23 *****************************************************************/
24 void uart_print_time(void)
25 {
26     unsigned char i=0;
27     
28     rtc_read();
29     for(i=0; i<7; i++)
30     {
31         SendOneByte(TIME_CURRENT[i]);
32     }
33     delay300ms();
34 }
35 
36 /*****************************************************************
37 * Function        : main
38 * Description    : 主函数
39 * Parameters    : None
40 * Return Value: None
41 *****************************************************************/
42 void main(void)
43 {
44     ds1302_init();
45     uart_init();
46     
47     while(1)
48     {
49         uart_print_time();
50     }
51     
52     /*********验证串口**********
53     for(i=0;i<256;i++)
54     {
55         SendOneByte(i);
56         delay100ms();
57     }
58     */
59 }
View Code

 记录下~~

posted on 2023-04-22 22:06  Ivan2023  阅读(117)  评论(0)    收藏  举报