DS1302
DS1302 包含 31 字节通用 RAM
3 线串行数据通信接口
如图所示
给了三根线
- 1.CE
- 2.IO
- 3.SCLK
单字节操作模式
-
- 向 DS1302 传输一个字节的控制指令
-
- 第 7 位为 1,第 0 位为读写位
-
- 第 6 位为 1 时,操作 31 字节 RAM,为 0 时操作时钟寄存器
如图可知
-
- CE 在操作时需保持拉高
-
- SLCK 上升沿写入,下降沿读取
-
- IO 写数据
/*
* @Author: cuihaonan
* @Email: devcui@outlook.com
* @Date: 2021-04-05 15:50:57
* @LastEditTime: 2021-04-05 16:00:07
* @LastEditors: cuihaonan
* @Description: Basic description
* @FilePath: /sdcc-include/src/DS1302/include/DS1302.h
* @LICENSE: NONE
*/
#ifndef __DS1302_H__
#define __DS1302_H__
extern void WrByte_1302(unsigned char dat);
extern unsigned char RdByte_1302(void);
extern void WrSingle_1302(unsigned char addr,unsigned char dat);
extern unsigned char RdSingle_1302(unsigned char addr);
#endif
/*
* @Author: cuihaonan
* @Email: devcui@outlook.com
* @Date: 2021-04-05 15:51:02
* @LastEditTime: 2021-04-05 16:02:00
* @LastEditors: cuihaonan
* @Description: Basic description
* @FilePath: /sdcc-include/src/DS1302/include/DS1302.c
* @LICENSE: NONE
*/
#include "./DS1302.h"
#include "../../../include/STC89xx.h"
SBIT(CE_LINE, _P0, 5);
SBIT(IO_LINE, _P0, 4);
SBIT(SCLK_LINE, _P0, 3);
void WrByte_1302(unsigned char dat)
{
unsigned char j;
unsigned int flag;
for (j = 1; j <= 8; j++)
{
// 拿到当前位的数据
flag = dat & 0x01;
// 放到IO线上
IO_LINE = flag;
// 上升沿
SCLK_LINE = 0;
SCLK_LINE = 1;
// 将数据移动到下一位
dat >>= 1;
}
// 拉低CE
}
unsigned char RdByte_1302(void)
{
unsigned char dat;
unsigned int flag;
unsigned char j;
for (j = 1; j <= 8; j++)
{
// 下降沿
SCLK_LINE = 1;
SCLK_LINE = 0;
// 从IO线上读数据
flag = IO_LINE;
// 读取的数据放到最前面
dat = (dat >> 1) | (flag << 7);
}
return dat;
}
void WrSingle_1302(unsigned char addr, unsigned char dat)
{
// 拉高CE
CE_LINE = 1;
// 写入地址和控制命令
WrByte_1302(addr);
// 写入数据
WrByte_1302(dat);
// 拉低CE完成时序
CE_LINE = 0;
// 最后拉低SCLK(恢复初始化)
SCLK_LINE = 0;
}
unsigned char RdSingle_1302(unsigned char addr)
{
unsigned char dat;
// 拉高CE
CE_LINE = 1;
// 写入指令和地址
WrByte_1302(addr);
dat = RdByte_1302();
// 拉低CE
CE_LINE = 0;
return dat;
}
时钟寄存器
-
- 9 个寄存器地址 0x81/0-0x91/0
-
- 0x81-0x8D 分别为 秒,分,时,天,月,周,年
-
- 0x81 4-6 为 10 秒,0-3 为 1 秒,7 为运行标志位,1 计时停止,0 计时开始。
-
- 0x82 7 为 12/24 小时制,5 为 AM/PM,4 为 1 小时
-
- 剩下的自己琢磨
-
- 第 8 个寄存器 0x8F/8E 为保护寄存器,bit7 =1 写保护,bit7=0 可写
/*
* @Author: cuihaonan
* @Email: devcui@outlook.com
* @Date: 2021-04-05 15:50:57
* @LastEditTime: 2021-04-05 16:17:16
* @LastEditors: cuihaonan
* @Description: Basic description
* @FilePath: /sdcc-include/src/DS1302/include/DS1302.h
* @LICENSE: NONE
*/
#ifndef __DS1302_H__
#define __DS1302_H__
extern void WrByte_1302(unsigned char dat);
extern unsigned char RdByte_1302(void);
extern void WrSingle_1302(unsigned char addr, unsigned char dat);
extern unsigned char RdSingle_1302(unsigned char addr);
extern void Init_1302(unsigned char *time);
extern void GetTime(unsigned char *currentTime);
#endif
void Init_1302(unsigned char *time)
{
unsigned char j;
CE_LINE = 0;
SCLK_LINE = 0;
// 解除写保护
WrSingle_1302(0x8E, 0x00);
for (j = 0; j <= 6; j++)
{
// 写入7个时钟数据
WrSingle_1302(0x80 + 2 * j, time[j]);
}
}
void GetTime(unsigned char *currentTime)
{
unsigned char j;
CE_LINE = 0;
SCLK_LINE = 0;
for (j = 0; j <= 6; j++)
{
*currentTime = RdSingle_1302(0x81 + 2 * j);
currentTime++;
}
}
应用
P03 是 SCLK
P04 是 IO
P05 是 CLOCK
/*
* @Author: cuihaonan
* @Email: devcui@outlook.com
* @Date: 2021-04-05 15:50:40
* @LastEditTime: 2021-04-05 18:28:05
* @LastEditors: cuihaonan
* @Description: Basic description
* @FilePath: /sdcc-include/src/DS1302/main.c
* @LICENSE: NONE
*/
#include "./include/DS1302.h"
#include "./include/1602.h"
#include "../../include/STC89xx.h"
#include "../../include/mcs51/lint.h"
// 振率
#define FOSC 11059200
// 定时器初始值
#define T_1ms (65536 - FOSC / 12 / 1000)
SBIT(FM, _P0, 0);
SBIT(DU, _P0, 6);
SBIT(WE, _P0, 7);
// 500ms标志位
unsigned char T_flag = 0;
// 字符临时存储变量
unsigned char CurrentTime[23] = "";
unsigned char SetTime[7] = {0x56, 0x58, 0x23, 0x01, 0x06, 0x02, 0x21};
unsigned char str[23] = "";
void main()
{
P10 = 1;
Init_1602();
P2 = 0xFF;
WE = 1;
WE = 0;
TMOD = 0x01;
TL0 = T_1ms;
TH0 = T_1ms >> 8;
TR0 = 1;
ET0 = 1;
EA = 1;
Init_1302(SetTime);
while (1)
{
if (T_flag) //500ms
{
T_flag = 0;
GetTime(CurrentTime);
str[0] = '2';
str[1] = '0';
str[2] = (CurrentTime[6] >> 4) + '0';
str[3] = (CurrentTime[6] & 0x0F) + '0';
str[4] = '-';
str[5] = (CurrentTime[4] >> 4) + '0';
str[6] = (CurrentTime[4] & 0x0F) + '0';
str[7] = '-';
str[8] = (CurrentTime[3] >> 4) + '0';
str[9] = (CurrentTime[3] & 0x0F) + '0';
str[10] = '0';
str[11] = (CurrentTime[2] >> 4) + '0';
str[12] = (CurrentTime[2] & 0x0F) + '0';
str[13] = ':';
str[14] = (CurrentTime[1] >> 4) + '0';
str[15] = (CurrentTime[1] & 0x0F) + '0';
str[16] = ':';
str[17] = (CurrentTime[0] >> 4) + '0';
str[18] = (CurrentTime[0] & 0x0F) + '0';
str[19] = ' ';
str[20] = (CurrentTime[5] >> 4) + '0';
str[21] = (CurrentTime[5] & 0x0F) + '0';
str[22] = '0';
Disp_1602_str(1, 4, str);
Disp_1602_str(2, 3, str + 11);
}
}
}
void timmer0() __interrupt(1)
{
if(P10 == 1){
P10 = 0;
}else{
P10 = 1;
}
static unsigned int T_500ms = 0;
TL0 = T_1ms;
TH0 = T_1ms >> 8;
T_500ms++;
if (T_500ms >= 500)
{
T_500ms = 0;
T_flag = 1;
}
}
突发操作模式
上面我们讲解的是以单字节的模式,从 1302 中连续读取时间数据。仔细的
同学可能会发现一个问题,就是我们连续读 7 个时间寄存器是有先后顺序的,会
有读错数据的风险。例如我们要读的时间为 23 时 59 分 59 秒,最开始时我们把
59 秒读出来了,如果刚好在你读完的时候 59 秒变成了 00 秒,59 分变成了 00 分,
23 时变成了 00 时,接下来把分、时依次读出来,因此我们读出来的时间为 00
时 00 分 59 秒,很显然这个时间是不对的。下面我们讲解的突发操作模式有效的
解决了这个问题。
在突发操作读模式下,当 DS1302 收到突发读数据指令,DS1302 首先会把 8
个时间寄存器的数据同时读出存放在 8 个二级时间寄存器中,然后依次把 8 个二
级时间寄存器的数据输出给单片机,突发读专用指令为 0xBF。同样,当我们需
要写 DS1302 时,当收到突发写指令后,DS1302 将接收到的 8 个连续数据存储
到 8 个二级时间寄存器中,然后同时将 8 各数据写到时间寄存器中,突发写专用
指令为 0xBE。根据上述原理,编写突发写模式和突发读模式函数如下图所示。
//突发写模式
void WrBurst_1302(unsigned char *SetTime)
{
unsigned char j;
// 拉高CE
CE_LINE = 1;
// Burst模式专用指令
WrByte_1302(0xBE);
for (j = 0; j < 6; j++)
{
// 写入7位时钟数据
WrByte_1302(SetTime[j]);
}
WrByte_1302(0);
// 拉低CE
CE_LINE = 0;
}
void RdBurst_1302(unsigned char *CurrentTime)
{
unsigned char j;
// 拉高CE
CE_LINE = 1;
// Brust模式读专用指令
WrByte_1302(0xBF);
for (j = 0; j <= 6; j++)
{
// 读取一个字节数据
*CurrentTime = RdByte_1302();
CurrentTime++;
}
// 拉低CE
CE_LINE = 0;
}