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
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 }
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
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 }
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 }
记录下~~
浙公网安备 33010602011771号