DS1302学习小结

DS1302实时时钟

1.BCD码的概念

BCD码亦称二进码十进制数或二-十进制代码。用4位二进制数表示一位十进制数中0~9折10个数字。表示了从0b0000~0b1001,不存在0b1010、0b1011、0b1100、0b1101、0b1110、0b1111这6个数字。分为压缩性 和非压缩型两种。

2.SPI时序

SPI是串行外围设备接口。是一种高速的、全双工的、同步通信总线。标准的SPI也仅仅使用4个引脚,分别是SSEL(片选,也写作SCS)、SCLK(时钟,也写作SCK)、MOSI(主机输出从机输入)、MISO(主机输入从机输出)。

  • SSEL:从设备片选是能信号。如果从设备是低电平使能,拉低这个引脚,从设备就会被选中。
  • SCLK:时钟信号。由主机发出。
  • MOSI:主机给从机发送指令或数据的通道。
  • MISO:主机读取从机的状态或数据的通道。

SPI通信的主机也就是单片机,在读写数据时序的过程中,有四种模式,要了解这四种模式,首先要学习两个名词。

CPOL:就是时钟极性。

通信的整个过程分为空闲时刻和通信时刻,如果SCLK在数据发送之前和之后的空闲状态都是高电平,那么就是CPOL=1,如果空闲状态SCLK是低电平,那么就是CPOL=0引用块内容

CPHA:就是时钟的相位。

同步通信的一个特点就是所有数据的变化和采样都是伴随着时钟沿进行的,也就是说数据总是在时钟的边沿附近变化或被采样。
而一个时钟周期必定包含了一个上升沿和一个下降沿,这是周期的定义所决定的,只是这两个沿的先后并无规定。又因为数据从产生的时刻到它的稳定是需要一定时间的,那么,如果主机在上升沿输出数据到 MOSI 上,从机就只能在下降沿去采样这个数据了。反之如果一方在下降沿输出数据,那么另一方就必须在上升沿采样这个数据。

  1. CPHA=1表示数据的输出是在一个时钟周期的第一个沿上,且CPOL=1是下降沿,反之是上升沿。那么数据的采样自然就在第二个沿上了。
  2. CPHA=0表示数据的采集是在一个周期的第一个沿上,同样它是什么沿由CPOL决定。那么数据的输出自然就在第二个沿上了。

    以CPOL=1/CPHA=1为例,画出时序图。
    图 2-1  SPI通信时序图
    在上图中,当数据未发送时及发送完毕后,SCK都是高电平,因此CPOL=1。可以看出在SCK第一个沿的时候,MOSI和MISO会发生变化,同时SCK第二个沿的时候,数据是稳定的,此时采样数据组最合适,即CPHA=1。注意最后隐藏的SSEL片选,这个引脚决定是哪个从机和主机通信。

    下边放其他三种情况的时序图。
    这里写图片描述

3.实时时钟芯片DS1302

  1. DS1302引脚图:
    这里写图片描述

1 脚 VCC2 是主电源正极的引脚,接+5V,2 脚 X1 和 3 脚 X2 是晶振输入和输出引脚,4 脚 GND是负极,5 脚 CE 是使能引脚,接单片机的 IO 口,6 脚 I/O 是数据传输引脚,接单片机的 IO口,7 脚 SCLK 是通信时钟引脚,接单片机的 IO口,8 脚 VCC1 是备用电源引脚。

2.引脚功能表
这里写图片描述
3.备用电源

关于备用电源的问题,可以接3V左右的电源。也可以接一个10uF的电容,这个电容就相当于一个电量很小的电池,断电后可维持DS1302g工作1分钟左右,如果想运行时间更长,可以加大点容量。如果掉点后不需要它在维持运行,可以直接悬空。

DS1302用电容作备用电源电路图如下。

这里写图片描述

4.DS1302寄存器

DS1302一条指令一个字节共8位,其中第7位(最高位)固定为1。第6位是选择RAM还是CLOCK,这里主要用时钟的功能,故为0。第5位到第1位,决定了寄存器的5位地址。第0位是读写位,写为0、读为1。
这里写图片描述
DS1302时钟的寄存器中,其中8位和时钟有关,5位地址分别为0b00000~0b00111,即0x80~0x91。

具体寄存器功能如下:
这里写图片描述

寄存器 0:最高位 CH 是一个时钟停止标志位。如果时钟电路有备用电源,上电后,我们要先检测一下这一位,如果这一位是0,那说明时钟芯片在系统掉电后,由于备用电源的供给,时钟是持续正常运行的;如果这一位是 1,那么说明时钟芯片在系统掉电后,时钟部分不工作了。剩下的7 位高 3 位是秒的十位,低 4 位是秒的个位。

寄存器 1:最高位未使用(0),剩下的 7 位中高 3 位是分钟的十位,低 4 位是分钟的个位。

寄存器 2:bit7 是 1 的话代表是 12 小时制,0 代表是 24 小时制;bit6 固定是 0,bit5 在12 小时制下 0 代表的是上午,1 代表的是下午,在 24 小时制下和 bit4 一起代表了小时的十位,低 4 位代表的是小时的个位。

寄存器 3:高 2 位固定是 0,bit5 和 bit4 是日期的十位,低 4 位是日期的个位。

寄存器 4:高 3 位固定是 0,bit4 是月的十位,低 4 位是月的个位。

寄存器 5:高 5 位固定是 0,低 3 位代表了星期。

寄存器 6:高 4 位代表了年的十位,低 4 位代表了年的个位。请特别注意,这里的 00~99 指的是 2000 年~2099 年。

寄存器 7:最高位一个写保护位,如果这一位是 1,那么是禁止给任何其它寄存器或者那 31 个字节的 RAM 写数据的。因此在写数据之前,这一位必须先写成 0。

5.DS1302的变异SPI通信方式

DS1302单字写入操作:
这里写图片描述
这里写图片描述
与CPOL=0/CPHA=0情况下的SPI操作时序对比,其中CE和SSEL的使能控制是相反的。对于SPI通信写数据都是在SCK的上升沿从机进行采样,下降沿主机发送数据。DS1302 的时序里,单片机要预先写一个字节指令,指明要写入的寄存器的地址以及后续的操作是写操作,然后再写入一个字节的数据。

单字节读操作:
这里写图片描述

6.DS1302的BURST模式

当写指令到DS1302的时候,只要将要写的5位地址全写1,即读操作用0XBF,写操作用0XBE,这样的指令送到DS1302之后,它会自动识别出来是burst模式,马上把所有的 8 个字节同时锁存到另外的 8 个字节的寄存器缓冲区内,这样时钟继续走,而我们读数据是从另外一个缓冲区内读取的。

要注意的是,不管是读还是写,只要使用时钟的 burst 模式,则必须一次性读写 8 个寄存器,要把时钟的寄存器完全读出来或者完全写进去。

在这里补充一点IO口自己迷惑过的地方:

具有上拉的准双向IO口,如果要正常读取外部信号的状态,必须首先保证自己内部输出的是1,如果输出0,则无论外部信号是1还是0,这个引脚读进来都会0。

相关代码如下:

#include<reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;

sbit DS1302_CE = P2^3;//自己做的实物中的IO端口
sbit DS1302_IO = P2^2;
sbit DS1302_CK = P2^1;

/* 发送一个字节到DS1302通信总线上 */
void DS1302ByteWrite(u8 dat)
{
    u8 mask;

    for(mask=0x01; mask!=0; mask<<=1)//从低位向高位写,逐位移出
    {
        if((mask&dat) != 0)//mask&dat=1,相与低位是1,相当于写1
            DS1302_IO = 1;
        else               //mask&dat=0,相与低位是0,相当于写0
            DS1302_IO = 0;
        DS1302_CK = 1;     //拉高时钟
        DS1302_CK = 0;     //再拉低时钟,完成一个位操作
    }
    DS1302_IO = 1;  //释放IO口

}
/* 由DS1302通信总线上读取一个字节 */
u8 DS1302ByteRead()
{
    u8 mask;
    u8 dat = 0;

    for(mask=0x01; mask!=0; mask<<=1)
    {
        if(DS1302_IO != 0)//先判断IO口状态,为高方可读入
        {
            dat |= mask; //将mask逐位读入dat
        }
        DS1302_CK = 1; //拉高时钟
        DS1302_CK = 0; //再拉低时钟,完成一个位操作
    }
    return dat;//最后返回读到的字节数据
}
/* 用单次写操作向某一寄存器写入一个字节 */
void DS1302SingleWrite(u8 reg,u8 dat)
{
    DS1302_CE = 1;//使能片选信号,读写DS1302都必须为高电平
    DS1302ByteWrite((reg<<1)|0x80);//发送写寄存器的指令
    DS1302ByteWrite(dat);//写入字节数据
    DS1302_CE = 0;//除能片选信号
}
/* 用单词读操作向寄存器读取一个字节 */
u8 DS1302SingleRead(u8 reg)
{
    u8 dat;

    DS1302_CE = 1;
    DS1302ByteWrite((reg<<1)|0x81);//寄存器左移一位,最低位或上1,则固定为1。发送读寄存器指令
    dat = DS1302ByteRead();//读取字节数据
    DS1302_CE = 0;

    return dat;
}
/* 用突发模式连续写入8个寄存器数据 */
void DS1302BurstWrite(u8 *dat)
{
    u8 i;

    DS1302_CE = 1;
    DS1302ByteWrite(0xBE);//发送突发写寄存器指令
    for(i=0; i<8; i++)//连续写8个字节
    {
        DS1302ByteWrite(dat[i]);//相当于读地址*(dat+i)
    }
    DS1302_CE = 0;
}
/* 用突发模式连续读取8个寄存器的数据 */
void DS1302BurstRead(u8 *dat)
{
    u8 i;

    DS1302_CE = 1;
    DS1302ByteWrite(0xBF);
    for(i=0; i<8; i++)
    {
        dat[i] = DS1302ByteRead();
    }
    DS1302_CE = 0;
}
/* DS1302初始化,如发生掉电则重新设置初始时间 */
void InitDS1302()
{
    u8 dat;
    u8 code InitTime[] = {
        0x00,0x00,0x12,0x21,0x08,0x02,0x18
        };//2018年8月21日 星期二 12:00:00

    DS1302_CE = 0;          //引脚默认为低电平
    DS1302_CK = 0;
    dat = DS1302SingleRead(0); //读取秒寄存器
    if((dat&0x80) != 0)        //由秒寄存器最高位CH的值判断
                               //DS1302是否已停止。为1,则需要初始化
    {
        DS1302SingleWrite(7,0x00);    //撤销写保护以允许写入数据
        DS1302BurstWrite(InitTime);   //设置DS1302为默认的初试时间
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37369201/article/details/81875689