目录

  • 硬知识
    • DS1302 简介
    • DS1302 使用
      • 控制寄存器
      • 日历/时钟寄存器
      • DS1302 的读写时序
    • 电路设计
  • 示例程序
    • DS1302.c
    • DS1302.h
    • 测试程序
      • main.c
      • 实验现象

普中51-单核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0


硬知识

摘自《普中 51 单片机开发攻略》、《DS1302中文手册》。

DS1302 简介

DS1302 是 DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和 31 字节静态 RAM,通过简单的串行接口与单片机进行通信。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。时钟操作可通过AM/PM 指示决定采用 24 或 12 小时格式。DS1302 与 单片机之间能简单地采用同步串行的方式进行通信,仅需用到三根通信线:
       ①RES 复位
       ②I/O 数据线
       ③SCLK 串行时钟。
       时钟/RAM 的读/写数据以一个字节或多达 31 个字节的字符组方式通信。DS1302 工作时功耗很低,保持数据和时钟信息时功率小于 1mW。 DS1302 由 DS1202 改进而来增加了以下的特性:双电源管脚用于主电源和 备份电源供应,Vcc1 为可编程涓流充电电源,附加七个字节存储器。它广泛应用于电话、传真、便携式仪器以及电池供电的仪器仪表等产品领域下面。
       主要的性能指标:
★ 实时时钟具有能计算 2100 年之前的秒、分、时、日、星期、月、年的 能力,还有闰年调整的能力;
★ 31 个 8 位暂存数据存储 RAM;
★ 串行 I/O 口方式使得管脚数量最少;
★ 宽范围工作电压 2.0 ~ 5.5V;
★ 工作在 2.0V 时,电流小于 300nA;
★ 读/写时钟或 RAM 数据时有两种传送方式单字节传送和多字节传送字符组 方式;
★ 8 脚 DIP 封装或可选的 8 脚 SOIC 封装根据表面装配;
★ 简单 3 线接口;
★ 与 TTL 兼容 Vcc=5V;
★ 可选工业级温度范围-40~+85;

  1. VCC2:主电源引脚
  2. X1、X2:DS1302 外部晶振引脚,通常需外接 32.768K 晶振
  3. GND:电源地
  4. CE:使能引脚,也是复位引脚(新版本功能变)。
  5. I/O:串行数据引脚,数据输出或者输入都从这个引脚
  6. SCLK:串行时钟引脚
  7. VCC1:备用电源

DS1302 使用

操作 DS1302 的大致过程,就是将各种数据写入 DS1302 的寄存器,以设置 它当前的时间的格式。然后使 DS1302 开始运作,DS1302 时钟会按照设置情况 运转,再用单片机将其寄存器内的数据读出。再用液晶显示,就是我们常说的简 易电子钟。所以总的来说 DS1302 的操作分 2 步(显示部分属于液晶显示的内容, 不属于 DS1302 本身的内容),但是在讲述操作时序之前,我们要先看看寄存器, DS1302 有一个控制寄存器、12 个日历、时钟寄存器和 31 个 RAM。

控制寄存器

控制寄存器用于存放 DS1302 的控制命令字,DS1302 的 RST 引脚回到高电平后写入的第一个字节就为控制命令。它用于对 DS1302 读写过程进行控制,格式如下:

       上图是 DS1302 的寄存器样式,我们看到:

  1. 第 7 位永远都是 1;
  2. 第 6 位,1 表示 RAM,寻址内部存储器地址;0 表示 CK,寻址内部寄存器;
  3. 第 5 到第 1 位,为 RAM 或者寄存器的地址;
  4. 最低位,高电平表示 RD,即下一步操作将要“读”;低电平表示 W,即 下一步操作将要“写”。



       比如要读秒寄存器则命令为 1000 0001,反之写为 1000 0000。

日历/时钟寄存器

DS1302 共有 12 个寄存器,其中有 7 个与日历、时钟相关,存放的数据为 BCD 码形式。格式如下:


       秒寄存器:低四位为秒的个位,高的次三位为秒的十位。最高位 CH 为 DS1302 的运行标志,当 CH=0 时,DS1302 内部时钟运行,反之 CH=1 时停止;
       小时寄存器:时寄存器。最高位为 12/24 小时的格式选择位,该位为 1 时表示 12 小时格式。当设置为 12 小时显示格式时,第 5 位的高电平表示下午 (PM);而当设置为 24 小时格式时,第 5 位位具体的时间数据。
       写保护寄存器:当该寄存器最高位 WP 为 1 时,DS1302 只读不写,所以要在往 DS1302 写数据之前确保 WP 为 0。
       慢充电寄存器(涓细电流充电)寄存器:我们知道,当 DS1302 掉电时,可以马上调用外部电源保护时间数据。该寄存器就是配置备用电源的充电选项的。 其中高四位(4 个 TCS)只有在 1010 的情况下才能使用充电选项;低四位的情 况与 DS1302 内部电路有关。

在日历/时钟寄存器中都是以 BCD 码存放数据,BCD 码是通过 4 位二进制码来表示 1 位十进制中的 0~9 这 10 个数码。 如下所示:

DS1302 的读写时序

在控制指令字输入后的下一个 SCLK 时钟的上升沿时,数据被写入 DS1302, 数据输入从低位(位 0)开始。同样,在紧跟 8 位的控制指令字后的下一个 SCLK 脉冲的下降沿读出 DS1302 的数据,读出数据时从低位 0 位到高位 7。其时序图如下所示:

       上图就是 DS1302 的三个时序:复位时序,单字节写时序,单字节读时序;
        CE(RST):复位时序,即在 RST 引脚产生一个正脉冲,在整个读写器件, RST 要保持高电平,一次字节读写完毕之后,要注意把 RST 返回低电平准备下次 读写周期;
       单字节读时序:注意读之前还是要先对寄存器写命令,从最低位开始写;可以看到,写数据是在 SCLK 的上升沿实现,而读数据在 SCLK 的下降沿实现。所以, 在单字节读时序中,写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了!这个就是 DS1302 操作中最特别的地方。 当然读出来的数据也是最低位开始。
       单字节写时序:两个字节的数据配合 16 个上升沿将数据写入即可。

程序注意事项:
        ★要记得在操作 DS1302 之前关闭写保护;
        ★注意用延时来降低单片机的速度以配合器件时序;
        ★DS1302 读出来的数据是 BCD 码形式,要转换成我们习惯的 10 进制,转换方法在源程序里;
        ★读取字节之前,将 IO 设置为输入口,读取完之后,要将其改回输出口;
        ★在写程序的时候,建议实现开辟数组(内存空间)来集中放置 DS1302 的 一系列数据,方便以后扩展键盘输入。

电路设计

示例程序

stdint.h见【51单片机快速入门指南】1:基础知识和工程创建
       软件SPI程序见【51单片机快速入门指南】5:软件SPI
       串口部分见【51单片机快速入门指南】3.3:USART 串口通信
       根据时序图,写入时都是模式1,读取时先是模式1,之后是模式0。

DS1302.c

#include "./Soft_SPI/Soft_SPI.h"
#include <STC89C5xRC.H>
#include "DS1302.h"sbit DS1302_CS = P3^5;//DS1302_CS拉高 移植时需修改
void DS1302_CS_H()
{DS1302_CS = 1;
}//DS1302_CS拉低 移植时需修改
void DS1302_CS_L()
{DS1302_CS = 0;
}//---存储顺序是秒分时日月周年---//
uint8_t gDS1302_TIME[7] = {0};//---DS1302写入时分秒的地址命令---//
//---秒分时日月周年-------//
code uint8_t gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};/*******************************************************************************
Num2BCD
数字转BCD码(两位数)
*******************************************************************************/
#define Num2BCD(value) (((value/10)<<4)|(value%10))/*******************************************************************************
* 函 数 名       : reversed
* 函数功能       : 倒序一个字节
*******************************************************************************/
uint8_t reversed(uint8_t raw)
{uint8_t i, value = 0;for(i = 0; i < 8; i++){value <<= 1;value |= (raw & 0x01);raw >>= 1;}return value;
}/*******************************************************************************
* 函 数 名       : ds1302_write_byte
* 函数功能       : DS1302写单字节
* 输    入       : addr:地址/命令dat:数据
* 输    出         : 无
*******************************************************************************/
void ds1302_write_byte(uint8_t addr,uint8_t dat)
{   addr = reversed(addr);dat = reversed(dat);DS1302_CS_L();DS1302_CS_H();SOFT_SPI_RW_MODE1(addr);SOFT_SPI_RW_MODE1(dat);DS1302_CS_L();
}/*******************************************************************************
* 函 数 名       : ds1302_read_byte
* 函数功能       : DS1302读单字节
* 输    入       : addr:地址/命令
* 输    出         : 读取的数据
*******************************************************************************/
uint8_t ds1302_read_byte(uint8_t addr)
{uint8_t temp  = 0;addr = reversed(addr);DS1302_CS_H();   SOFT_SPI_RW_MODE1(addr);temp = SOFT_SPI_RW_MODE0(0xff);DS1302_CS_L();return reversed(temp);
}/*******************************************************************************
* 函 数 名       : ds1302_init
* 函数功能       : DS1302初始化时间
* 输    入       : 无
* 输    出         : 无
*******************************************************************************/
void ds1302_init(uint8_t YY, uint8_t MM, uint8_t DD, uint8_t hh, uint8_t mm, uint8_t ss, uint8_t ww)
{uint8_t i;ds1302_write_byte(0x8e, 0x00);gDS1302_TIME[0] = Num2BCD(ss);gDS1302_TIME[1] = Num2BCD(mm);gDS1302_TIME[2] = Num2BCD(hh);gDS1302_TIME[3] = Num2BCD(DD);gDS1302_TIME[4] = Num2BCD(MM);gDS1302_TIME[5] = Num2BCD(ww);gDS1302_TIME[6] = Num2BCD(YY);for(i = 0; i < 7; i++){ds1302_write_byte(gWRITE_RTC_ADDR[i], gDS1302_TIME[i]);  }ds1302_write_byte(0x8e, 0x80);
}/*******************************************************************************
* 函 数 名       : ds1302_read_time
* 函数功能       : DS1302读取时间
* 输    入       : 无
* 输    出         : 无
*******************************************************************************/
void ds1302_read_time(void)
{uint8_t i;for(i = 0; i < 7; i++){gDS1302_TIME[i] = ds1302_read_byte(gWRITE_RTC_ADDR[i] | 0x01); }
}

DS1302.h

#ifndef DS1302_H_
#define DS1302_H_#include "stdint.h"#define Second()  ((int16_t)(gDS1302_TIME[0]&0x0f)+((gDS1302_TIME[0]&0x70)>>4)*10)
#define Minute()    ((int16_t)(gDS1302_TIME[1]&0x0f)+((gDS1302_TIME[1]&0x70)>>4)*10)
#define Hour()      ((int16_t)(gDS1302_TIME[2]&0x0f)+((gDS1302_TIME[2]&0x30)>>4)*10)
#define Date()      ((int16_t)(gDS1302_TIME[3]&0x0f)+((gDS1302_TIME[3]&0x30)>>4)*10)
#define Month()     ((int16_t)(gDS1302_TIME[4]&0x0f)+((gDS1302_TIME[4]&0x10)>>4)*10)
#define Year()      ((int16_t)(gDS1302_TIME[6]&0x0f)+((gDS1302_TIME[6]&0xF0)>>4)*10)
#define Week()      ((int16_t)(gDS1302_TIME[5]&0x0f))extern uint8_t gDS1302_TIME[];void ds1302_write_byte(uint8_t addr,uint8_t dat);
uint8_t ds1302_read_byte(uint8_t addr);
void ds1302_init(uint8_t YY, uint8_t MM, uint8_t DD, uint8_t hh, uint8_t mm, uint8_t ss, uint8_t ww);
void ds1302_read_time(void);#endif

测试程序

main.c

#include <STC89C5xRC.H>
#include "intrins.h"
#include "stdint.h"
#include "DS1302.h"
#include "USART.h"void Delay1ms()     //@22.1184MHz
{unsigned char i, j;_nop_();i = 4;j = 146;do{while (--j);} while (--i);
}void Delay_ms(int i)
{while(i--)Delay1ms();
}void main(void)
{ds1302_init(21, 12, 3, 22, 42, 28, 5); //配置为21年12月03日22时42分28秒 星期5USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 22118400, 115200, DOUBLE_BAUD_ENABLE, USART_TIMER_1);while(1){    Delay_ms(1000);ds1302_read_time();printf("%d年%d月%d日%d时%d分%d秒", Year(), Month(), Date(), Hour(), Minute(), Second());printf(" 星期%d\r\n", Week());}
}

实验现象

打开串口,可见如下数据:

此程序也可在Proteus中正常仿真:

【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片相关推荐

  1. 【51单片机快速入门指南】5.3:SPI控制晶联讯JLX12864G_08602 LCD屏幕

    目录 示例程序 JLX12864G_08602.c JLX12864G_08602.h JLX12864G_08602_Font.c JLX12864G_08602_Font.h 测试程序 main. ...

  2. 【51单片机快速入门指南】2.4:74HC595、LED点阵屏及其SPI控制

    目录 硬知识 IO 口扩展方式-串转并 74HC595 芯片介绍 硬件设计 测试源码 HC74595.c HC74595.h main.h 实验现象 SPI控制 普中51-单核-A2 STC89C52 ...

  3. 【51单片机快速入门指南】3.3:USART 串口通信

    目录 快速使用 硬知识 串行口相关寄存器 串行口控制寄存器SCON和PCON 串行口数据缓冲寄存器SBUF 从机地址控制寄存器SADEN和SADDR 与串行口中断相关的寄存器IE和IPH.IP 串行口 ...

  4. 【51单片机快速入门指南】4.2: SSD1306 OLED屏(0.96寸、1.3寸)的I2C控制详解

    目录 硬知识 SSD1306简介 I2C 接口 从机地址位(SA0) I2C 总线写数据 命令解码器 晶振电路和显示时间发生器 复位 图形显示数据RAM (GDDRAM) 命令表 基本命令表 部分指令 ...

  5. 【51单片机快速入门指南】6.4:DHT11、DHT22单总线温湿度传感器

    目录 硬知识 DHT11 DHT22 通信协议 读取步骤 数据解读 DHT11 DHT22 示例程序 DHT11_22.c DHT11_22.h 测试程序 main.c 实验现象 DHT11 DHT2 ...

  6. 【51单片机快速入门指南】4.6:I2C 与 PCF8563实时时钟日历芯片

    目录 硬知识 概述 特性 功能描述 报警功能模式 定时器模式 CLKOUT输出 复位低电压检测器和时钟监视器 低电压检测器和时钟监视器 寄存器结构 寄存器概述 BCD编码格式寄存器概述 Control ...

  7. 【51单片机快速入门指南】6.3:DS18B20 单总线数字温度计的多路读取

    目录 硬知识 DS18B20介绍 时序 初始化时序 写时序 读时序 命令 ROM 操作命令 ROM 搜索举例 存贮器操作命令 示例程序 DS18B20.c DS18B20.h 测试程序 定时器中断服务 ...

  8. 【51单片机快速入门指南】6.1:LCD1602的八线、四线控制及自定义符号,完美兼容Proteus仿真

    目录 硬知识 显示特性 接口定义 操作时序 写操作时序 读操作时序 寄存器 忙标志位BF 地址计数器(AC) 显示数据寄存器(DDRAM) CGROM CGRAM 指令 清屏指令 光标归位指令 进入模 ...

  9. 【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展

    目录 硬知识 IO 扩展芯片 TCA6416A TAC6416A 的寄存器 IO 输入寄存器 IO 输出寄存器 IO 反相寄存器 IO 方向寄存器 TCA6416A 的操作 TCA6416A 写数据 ...

最新文章

  1. 在互联网圈混,怎么能不知道这9个Java方向公众号
  2. c# winform做简单的折线图(VS2017)
  3. Scala伴生类和伴生对象
  4. think python 2ed_Think Python 2ed 笔记(二)
  5. 使用Python批量随机化文件名
  6. 成为软件高手的几个忌讳(转贴)
  7. 服装关键点检测算法(CNN/STN)含(4点、6点以及8点)
  8. Android webview 下载文件(文件名,扩展名)
  9. 【圆梦名企第三季】4月12日软件业“人才留湘 引才入湘”专项行动
  10. 《生物化学与分子生物学》----酶促反应动力学----听课笔记(九)
  11. SAS9.4更新sid,有效期至2022年11月30日
  12. 什么是固态硬盘及其优缺点【转】
  13. oracle数据库监听说法正确,Oracle数据库错题合集
  14. Scrum立会报告+燃尽图(Beta阶段第二周第一次)
  15. Unity报错之【ArgumentOutOfRangeException: Index was out of range........】
  16. 精确率、准确率、召回率
  17. 好消息: 《微信商城开发实战》 已经由电子工业出版社出版发行啦
  18. Vue 3.0 全家桶
  19. 金融量化ushare模块
  20. 89、常见气体的爆炸极限

热门文章

  1. hmailserver批量添加用户
  2. 使用Docker镜像和仓库
  3. 报告显示Q2 Android平板电脑全球市场份额达67%
  4. asp.net中MaintainScrollPositionOnPostback属性的使用
  5. 相似图像搜索的哈希算法思想及实现(差值哈希算法和均值哈希算法)
  6. 数据挖掘—朴素贝叶斯分类算法(Java实现)
  7. leetcode面试题 17.15. 最长单词
  8. leetcode357. 计算各个位数不同的数字个数(回溯)
  9. SSRS:之为用户“NT AUTHORITY\NETWORK SERVICE”授予的权限不足,无法执行此操作。 (rsAccessDenied)...
  10. Python 获取服务器的CPU个数