RYMCU

NO16.实时时钟DS1302实验-NEBULA-VSCODE

devcui 2 年前
# nebula-vscode

所属作品集

DS1302

DS1302 包含 31 字节通用 RAM
3 线串行数据通信接口

image.png

image.png

如图所示
给了三根线

  • 1.CE
  • 2.IO
  • 3.SCLK

单字节操作模式

image.png

    1. 向 DS1302 传输一个字节的控制指令
    1. 第 7 位为 1,第 0 位为读写位
    1. 第 6 位为 1 时,操作 31 字节 RAM,为 0 时操作时钟寄存器

image.png

如图可知

    1. CE 在操作时需保持拉高
    1. SLCK 上升沿写入,下降沿读取
    1. 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;
}

时钟寄存器

image.png

    1. 9 个寄存器地址 0x81/0-0x91/0
    1. 0x81-0x8D 分别为 秒,分,时,天,月,周,年
    1. 0x81 4-6 为 10 秒,0-3 为 1 秒,7 为运行标志位,1 计时停止,0 计时开始。
    1. 0x82 7 为 12/24 小时制,5 为 AM/PM,4 为 1 小时
    1. 剩下的自己琢磨
    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++;
    }
}

应用

image.png

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;
}

所属作品集

后发布评论