【蓝桥杯】单片机学习(11)——实时时钟DS1302

一、SPI通信协议

1、SPI接口

UARTI2CSPI 是单片机系统中常见的三种通信协议。SPI,即串行外围设备接口(Serial Peripheral Interface)。

  • SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。主要是在CPU和外围低速器件之间进行 同步串行数据传输,在主器件的移位脉冲下,数据按位传输,高位在前,地位在后,为全双工通信,数据传输速度比I2C要快,可以达到几Mbps。
  • SPI通信原理比I2C简单,采用主从方式通信,通常只有一个主机和一个或者多个从机。标准的SPI是4根线,分别如下:
    ① SSEL(也写作SCS):从设备片选使能信号。如果从设备是低电平使能,当拉低这个引脚后,从设备就会被选中,主机和这个被选中的从机进行通信
    ② SCLK(也写作SCK):时钟信号,由主机产生。类似于I2C通信的SCL。
    ③ MOSI(Master Output / Slave Input):主机输出从机输入,主机给从机发送指令或者数据的通道。
    ④ MISOI(Master Input / Slave Output):主机输入从机输出,主机读取从机状态或者数据的通道。

在某些情况下也可以只使用两根线或者三根线的SPI进行通信,但一般提及SPI时,都指标准SPI,即4根线的模式。

SPI内部硬件接口图示如下:
SPI内部接口硬件图示

2、读写数据时序模式

SPI通信的主机是单片机,在读写数据的时序过程中,通过CPOL和CPHA控制组合共有四种模式。

  • CPOL:Clock Polarity,即时钟极性。SCLK在发送数据前后的空闲状态为高电平,则CPOL=1,空闲状态SCLK为低电平,则CPOL=0
  • CPHA:Clock Phase,即时钟相位。CPHA=1表示数据的输出是在一个时钟周期的第一个沿上;CPHA=0表示数据的采样是在一个时钟周期的第一个沿。

怎么理解CPHA时钟相位这个概念呢?主机和从机要交换数据,就要确定好主机什么时候输出数据到MOSI上,从机在什么时刻采样这个数据;或者从机什么时候输出数据到MISO上,主机在什么时候采样这个数据。同步通信的特点之一是:所有数据的变化和采样都是伴随着时钟沿进行,这意味着数据总是在时钟的边沿附近变化或被采样。由时钟周期的定义可以知道,一个时钟周期包含了一个上升沿和一个下降沿(无前后规定)。并且数据从产生到稳定需要时间,所以如果主机在上升沿输出数据到MOSI,从机就只能在下降沿采样这个数据,反之亦然。

  • CPOL = 1,CPHA = 1

在这里插入图片描述

  • CPOL = 0,CPHA = 1

在这里插入图片描述

  • CPOL = 1,CPHA = 0

在这里插入图片描述

  • CPOL = 0,CPHA = 0
    在这里插入图片描述

3、SPI和UART、I2C简单比较

SPI 比 I2C 速度更快,并且简单的多。它没有起始、停止和应答。UART通信和SPI通信都是只负责通信,不管是否成功,而I2C却要通过应答信息来获取通信成功(失败)的信息。所以I2C相对UART和SPI更为复杂。

二、实时时钟芯片DS1302

1、DS1302的主要性能指标

(1)DS1302实时时钟能够计算2100年之前的秒、分、时、日、日期、星期、月、年(闰年可自动调整)。还可以通过配置AM/PM来决定采用24小时格式还是12小时格式。
(2)内部含有31个字节静态数据存储RAM。
(3)串行I/O通信方式,使得管脚少,简单SPI仅3线接口。
(4)工作电压范围教宽:2.0~5.5V。
(5)工作电流小,功耗低:工作电压为2.0V时,小于300nA。
(6)时钟或RAM数据的读/写有两种传送方式:单字节传送和多字节传送方式。
(7)采用8脚DIP封装(双列直插式封装)或SOIC封装。
(8)供电电压Vcc=5V时,与标准TTL兼容,可与单片机通信。
(9)具有涓流充电能力。
(10)采用主电源和备份电源双电源供应。备用电源可以是电池或者大电容,确保在系统掉电的情况下,时钟还可以走。

DS1302封装图:
DS1302封装图

2、DS1302的硬件信息

DS1302引脚图如下:
DS1302引脚图各引脚功能如下:
在这里插入图片描述
其中只有5脚(CE使能)、6脚(I/O)、7脚(SCLK时钟)需要接到单片机的I/O口上。

DS1302的典型电路如下:
在这里插入图片描述
需要注意的是晶振电路。它使用的是32.768K的晶振,晶振外部不需要额外添加其他电容或者电阻。时钟的精度首先取决于晶振的精度以及晶振的引脚负载电容。如果晶振不准或者负载电容过大(小),就会导致时钟误差过大。其次需要考虑晶振的温漂。晶振的精度会随着温度的变化而变化。在实际系统中,常通过校对来减少这种误差的影响。

3、DS1302的寄存器介绍

(1) 命令字

DS1302一条指令一个字节共8位。第7位(最高位)固定为1(0无效);第6位是RAM/CLOCK选择端,这里主要学习CLOCK时钟的使用,所以第6位为0;第5位到第1位是寄存器的地址;第0位是读写控制位,1读0写。命令字节如下:

在这里插入图片描述

(2) 寄存器

DS1302有8个和时钟有关的寄存器,如下:

DS1302时钟寄存器
(表格从上到下依次为寄存器0到寄存器7)

  • 寄存器0:最高位CH是时钟停止标志位。通过该位判断时钟在单片机系统掉电后是否正常运行(0为有备用电源,正常运行)。剩余7位的高3位是秒的十位,低4位是秒的个位。由于DS1302内部是BCD码,秒的十位最大是5,所以3个二进制位足够。
  • 寄存器1:最高位未使用,剩余7位的高3位是分钟的十位,低4位是分钟的个位。
  • 寄存器2:bit7为1代表采用12小时制,为0表示24小时制;bit6固定为0;bit5在12小时制下,0表示上午,1表示下午,在24小时制下,和bit4一起表示小时的十位;低4位表示小时的个位。
  • 寄存器3:高两位固定是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。

4、DS1302通信时序介绍

(1) 单字节写操作时序 (单片机向DS1302内写入)

  • 先写入寄存器地址,再写入待写字节

在这里插入图片描述
(2)单字节读操作时序(单片机从DS1302读取数据)

  • 先写入寄存器地址,再读取该寄存器的数据

在这里插入图片描述
注:①该时序图上的箭头方向都是针对DS1302而言的。
②应该先读取I/O线上的数据,再拉高SCK(时钟线)产生上升沿。

5、Burst 模式

DS1302寄存器中,与时间相关的寄存器有7个,分别依次对应秒、分、时、日期、月、星期、年。在读取这7个寄存器的过程中,无论怎样读,都会有时间差,在极端的情况下就会出现错误。例如当前时间是00:00:59,先读秒,读到的秒是59,然后再去读分钟。但是在读完秒准备去读分钟的这段时间内,刚好时间进位了,变成了00:01:59,这个错误就很明显了。

为了解决这个问题,芯片厂家提供了Burst的模式。这里主要学习时钟突发模式(RAM突发模式暂时忽略)。

当向DS1302内写入寄存器地址时,只要将写的5位地址都写1,即读操作用0xBF,写操作用0xBE,这时DS1302就能识别出是Burst模式,马上把所有的8个字节同时锁存到另外的8个字节的寄存器缓冲区内,这样时钟继续走,而我们读取的是另一个缓冲区内的数据。写数据同理,Burst模式下,我们是先把数据写到这个缓冲区内,最终DS1302会把这个缓冲区内的数据一次性送到它的时钟寄存器内。

从以上叙述不难看出,在DS1302时钟的Burst模式下,必须一次性读或者写8个字节,要把时钟的寄存器全部读出来或者完全写进去。

三、模块化代码

DS1302.h

// An highlighted block
var foo = 'bar';

DS1302.c

//发送一个字节到DS1302通信总线上
void DS1302ByteWrite(u8 dat)
{
    u8 i;
    for(i=0;i<8;i++)
    {
        DS1302_SCK = 0;
        DS1302_IO = dat & 0x01;
        DS1302_SCK = 1;
        dat>>=1;
    }
    DS1302_IO = 0;//确保释放I/O引脚
}

//从DS1302通信总线上读取一个字节
u8 DS1302ByteRead()
{
    u8 i;
    u8 dat = 0;
    for(i=0;i<8;i++)
    {
        DS1302_SCK = 0;
        dat>>=1;        //先读的数据依次右移至最低位
        if(DS1302_IO)
        {
            dat|=0x80;  
        }
        DS1302_SCK = 1;
    }
    DS1302_IO = 0;//确保释放I/O引脚
    return dat;
}

//向某一寄存器写入一个字节
void DS1302Write(u8 reg,u8 dat)
{
    DS1302_CE = 0;
    DS1302_SCK = 0;
    DS1302_CE = 1;
    DS1302ByteWrite(WriteAddr[reg]);
    DS1302ByteWrite(dat);
    DS1302_CE = 0;
}

//从某一寄存器读取一个字节
u8 DS1302Read(u8 reg)
{
    u8 dat = 0;
    DS1302_CE = 1;
    DS1302ByteWrite(WriteAddr[reg]);
    dat = DS1302ByteRead();  
    DS1302_CE = 0;
    
    return dat;  
}

//用Burst突发模式连续写入8个寄存器数据
void DS1302BurstWrite(u8 *dat)
{
    u8 i;
    DS1302_CE = 1;
    DS1302ByteWrite(0xBE);
    for(i=0;i<8;i++)
    {
        DS1302ByteWrite(dat[i]);
    }
    DS1302_CE = 0;
}

//用Burst突发模式连续读取8个寄存器数据
void DS1302BurstRead(u8 *dat)
{
    u8 i;
    DS1302_CE = 1;
    DS1302ByteWrite(0xBF);
    for(i=0;i<8;i++)
    {
       dat[i] = DS1302ByteRead();
    }
    DS1302_CE = 0;
}

前一篇: 单片机学习(10)——I2C通信协议与E2PROM

下一篇: 单片机学习(12)——温度传感器DS18B20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值