【普中51单片机开发攻略--基于普中-2普中-3普中-4】-- 第 25 章 DS1302 时钟实验

【普中51单片机开发攻略--基于普中-2普中-3普中-4】-- 第 25 章 DS1302 时钟实验 (1)实验平台普中51单片机开发板 -A2A3A4在前面章节 我们介绍了如何使用单片机 IO 口模拟 IIC 总线、 单总线时序。这一章我们来学习 DS1302 时钟芯片 该芯片是 3 线 SPI 接口 所以需要使用 51单片机的 3 个 IO 口模拟 SPI 时序与 DS1302 时钟芯片通信 将时钟日历数据读取出来。 开发板上集成了 1 个 DS1302 时钟模块 可使用它设计一个多功能电子时钟。 本章要实现的功能是 系统运行时 数码管上显示电子时钟时分秒 格式为“XX-XX-XX” 。 学习本章可以参考前面的实验章节内容。 本章分为如下几部分内容25.1 DS1302 时钟芯片介绍25.1.1 DS1302 简介25.1.2 DS1302 使用25.2 硬件设计25.3 软件设计25.3.1 DS1302 读写函数25.3.2 主函数25.4 实验现象25.1 DS1302 时钟芯片介绍25.1.1 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 兼容 Vcc5V★ 可选工业级温度范围-40~85下面来看下 DS1302 芯片的管脚及功能。1 VCC2 主电源引脚2 X1、 X2 DS1302 外部晶振引脚 通常需外接 32.768K 晶振3 GND 电源地4 CE 使能引脚 也是复位引脚新版本功能变 。5 I/O 串行数据引脚 数据输出或者输入都从这个引脚6 SCLK 串行时钟引脚7 VCC1 备用电源25.1.2 DS1302 使用操作 DS1302 的大致过程 就是将各种数据写入 DS1302 的寄存器 以设置它当前的时间的格式。 然后使 DS1302 开始运作 DS1302 时钟会按照设置情况运转 再用单片机将其寄存器内的数据读出。 再用液晶显示 就是我们常说的简易电子钟。 所以总的来说 DS1302 的操作分 2 步显示部分属于液晶显示的内容不属于 DS1302 本身的内容 但是在讲述操作时序之前 我们要先看看寄存器 DS1302 有一个控制寄存器、 12 个日历、 时钟寄存器和 31 个 RAM。1 控制寄存器控制寄存器用于存放 DS1302 的控制命令字 DS1302 的 RST 引脚回到高电平后写入的第一个字节就为控制命令。 它用于对 DS1302 读写过程进行控制 格式如下上图是 DS1302 的寄存器样式 我们看到1、 第 7 位永远都是 12、 第 6 位 1 表示 RAM 寻址内部存储器地址 0 表示 CK 寻址内部寄存器3、 第 5 到第 1 位 为 RAM 或者寄存器的地址4、 最低位 高电平表示 RD 即下一步操作将要“读” 低电平表示 W 即下一步操作将要“写” 。 与 AT24C02 寄存器类似 这点要理解好 。比如要读秒寄存器则命令为 1000 0001 反之写为 1000 0000 要注意其含义。2 日历/时钟寄存器DS1302 共有 12 个寄存器 其中有 7 个与日历、 时钟相关 存放的数据为 BCD码形式。 格式如下下面对几个寄存器做下说明秒寄存器低四位为秒的个位 高的次三位为秒的十位。 最高位 CH 为DS1302 的运行标志 当 CH0 时 DS1302 内部时钟运行 反之 CH1 时停止小时寄存器时寄存器。 最高位为 12/24 小时的格式选择位 该位为 1 时表示 12 小时格式。 当设置为 12 小时显示格式时 第 5 位的高电平表示下午PM 而当设置为 24 小时格式时 第 5 位位具体的时间数据。写保护寄存器当该寄存器最高位 WP 为 1 时 DS1302 只读不写 所以要在往 DS1302 写数据之前确保 WP 为 0。慢充电寄存器涓细电流充电 寄存器我们知道 当 DS1302 掉电时 可以马上调用外部电源保护时间数据。 该寄存器就是配置备用电源的充电选项的。其中高四位4 个 TCS 只有在 1010 的情况下才能使用充电选项 低四位的情况与 DS1302 内部电路有关 具体大家可以查看“\6--开发板芯片资料\开发板芯片数据手册\DS1302 中文手册.pdf” 。前面我们提到在日历/时钟寄存器中都是以 BCD 码存放数据 那么 BCD 码是什么呢 BCD 码是通过 4 位二进制码来表示 1 位十进制中的 0~9 这 10 个数码。如下所示所以从 DS1302 中读取出来的时钟数据均为 BCD 码格式 需转换为我们习惯的 10 进制 转换方法在源程序里 后面我们会介绍。3 DS1302 的读写时序在控制指令字输入后的下一个 SCLK 时钟的上升沿时 数据被写入 DS1302数据输入从低位位 0 开始。 同样 在紧跟 8 位的控制指令字后的下一个 SCLK脉冲的下降沿读出 DS1302 的数据 读出数据时从低位 0 位到高位 7。 其时序图如下所示上图就是 DS1302 的三个时序 复位时序 单字节写时序 单字节读时序CERST 复位时序 即在 RST 引脚产生一个正脉冲 在整个读写器件 RST 要保持高电平 一次字节读写完毕之后 要注意把 RST 返回低电平准备下次读写周期单字节读时序 注意读之前还是要先对寄存器写命令 从最低位开始写 可以看到 写数据是在 SCLK 的上升沿实现 而读数据在 SCLK 的下降沿实现。 所以在单字节读时序中 写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了 这个就是 DS1302 操作中最特别的地方。当然读出来的数据也是最低位开始。单字节写时序两个字节的数据配合 16 个上升沿将数据写入即可。程序注意事项★要记得在操作 DS1302 之前关闭写保护★注意用延时来降低单片机的速度以配合器件时序★DS1302 读出来的数据是 BCD 码形式 要转换成我们习惯的 10 进制 转换方法在源程序里★读取字节之前 将 IO 设置为输入口 读取完之后 要将其改回输出口★在写程序的时候 建议实现开辟数组内存空间 来集中放置 DS1302 的一系列数据 方便以后扩展键盘输入。到这里我们就介绍完 DS1302 时钟芯片 如需更详细的介绍 请大家参考“\6--开发板芯片资料\开发板芯片数据手册\DS1302 中文手册.pdf” 。25.2 硬件设计本实验使用到硬件资源如下1 动态数码管2 DS1302动态数码管电路在前面章节都介绍过 这里就不再重复。 下面我们来看下开发板上 DS1302 时钟模块电路 如下图所示从上图中可知 DS1302 芯片的控制管脚接至单片机 P3.4-P3.6 上 在芯片的X1、 X2 管脚处外接了一个 32.768KHZ 晶振 为时钟运行提供一个稳定的时钟频率 C2 和 C3 为旁路电容 目的是消除晶振起振时产生的电感干扰。 对于本开发板无外接备用电池 如果需要可自行将外部备用电源接入第 8 脚 VCC1。25.3 软件设计本章所要实现的功能是 数码管上显示电子时钟时分秒 格式为“XX-XX-XX”。程序框架如下1 编写数码管显示功能2 编写 DS1302 时钟读写功能3 编写主函数前面的实验章节都已编写过数码管显示功能 现在对大家来说应该不是问题 所以本章软件的重点在 DS1302 时序的模拟及数据的读写上。 下面我们打开“\4--实验程序\1--基础实验\21-DS1302 时钟实验” 工程 在 App 工程组中可以看到新添加了 ds1302.c 文件里面包含了 DS1302 驱动程序 还要包含对应的头文件路径。这里我们分析几个重要函数 其他部分程序大家可以打开工程查看。25.3.1 DS1302 读写函数打开 ds1302.c 文件 代码如下#include ds1302.h #include intrins.h //---DS1302写入和读取时分秒的地址命令---// //---秒分时日月周年 最低位读写位;-------// u8 gREAD_RTC_ADDR[7] {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; u8 gWRITE_RTC_ADDR[7] {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c}; //---DS1302时钟初始化2021年5月20日星期四13点51分47秒。---// //---存储顺序是秒分时日月周年,存储格式是用BCD码---// u8 gDS1302_TIME[7] {0x47, 0x51, 0x13, 0x20, 0x04, 0x05, 0x21}; /******************************************************************************* * 函 数 名 : ds1302_write_byte * 函数功能 : DS1302写单字节 * 输 入 : addr地址/命令 dat数据 * 输 出 : 无 *******************************************************************************/ void ds1302_write_byte(u8 addr,u8 dat) { u8 i0; DS1302_RST0; _nop_(); DS1302_CLK0;//CLK低电平 _nop_(); DS1302_RST1;//RST由低到高变化 _nop_(); for(i0;i8;i)//循环8次每次写1位先写低位再写高位 { DS1302_IOaddr0x01; addr1; DS1302_CLK1; _nop_(); DS1302_CLK0;//CLK由低到高产生一个上升沿从而写入数据 _nop_(); } for(i0;i8;i)//循环8次每次写1位先写低位再写高位 { DS1302_IOdat0x01; dat1; DS1302_CLK1; _nop_(); DS1302_CLK0; _nop_(); } DS1302_RST0;//RST拉低 _nop_(); } /******************************************************************************* * 函 数 名 : ds1302_read_byte * 函数功能 : DS1302读单字节 * 输 入 : addr地址/命令 * 输 出 : 读取的数据 *******************************************************************************/ u8 ds1302_read_byte(u8 addr) { u8 i0; u8 temp0; u8 value0; DS1302_RST0; _nop_(); DS1302_CLK0;//CLK低电平 _nop_(); DS1302_RST1;//RST由低到高变化 _nop_(); for(i0;i8;i)//循环8次每次写1位先写低位再写高位 { DS1302_IOaddr0x01; addr1; DS1302_CLK1; _nop_(); DS1302_CLK0;//CLK由低到高产生一个上升沿从而写入数据 _nop_(); } for(i0;i8;i)//循环8次每次读1位先读低位再读高位 { tempDS1302_IO; value(temp7)|(value1);//先将value右移1位然后temp左移7位最后或运算 DS1302_CLK1; _nop_(); DS1302_CLK0; _nop_(); } DS1302_RST0;//RST拉低 _nop_(); DS1302_CLK1;//对于实物中P3.4口没有外接上拉电阻的此处代码需要添加使数据口有一个上升沿脉冲。 _nop_(); DS1302_IO 0; _nop_(); DS1302_IO 1; _nop_(); return value; } /******************************************************************************* * 函 数 名 : ds1302_init * 函数功能 : DS1302初始化时间 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void ds1302_init(void) { u8 i0; ds1302_write_byte(0x8E,0X00); for(i0;i7;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) { u8 i0; for(i0;i7;i) { gDS1302_TIME[i]ds1302_read_byte(gREAD_RTC_ADDR[i]); } }各函数功能在代码内有详细注释 大家可以参考注释理解。 程序开头定义了3 个数组 gREAD_RTC_ADDR、 gWRITE_RTC_ADDR 和 gDS1302_TIME。 gREAD_RTC_ADDR和 gWRITE_RTC_ADDR 数组内存储的是 DS1302 写入和读取时分秒的地址命令 这个可以对照前面介绍的寄存器看。 TIME 数组是用来存储初始化时间 每个数据对应含义在代码内已做注释。 在使用中主要调用 ds1302_init()函数和ds1302_read_time()函数来初始化 DS1302 时钟数据以及读取 DS1302 时钟数据。在初始化时钟数据时 首先要禁止写保护即关闭写保护功能 然后将所需设置的时钟数据写入到对应的时钟寄存器地址内 最后打开写保护功能 以防止意外修改 DS1302 内部寄存器。 对于读取时钟数据其实很简单 只要从对应的时钟寄存器地址内读取数据即可 然后将读取的数据存储到一个缓存数组中 方便数据的处理与显示 这个操作在后面 main.c 文件内会有。25.3.2 主函数打开 main.c 代码如下/************************************************************************************** 深圳市普中科技有限公司PRECHIN 普中 技术支持www.prechin.net PRECHIN 普中 实验名称DS1302时钟实验 接线说明 实验现象下载程序后数码管上显示电子时钟时分秒格式为“XX-XX-XX” 注意事项 ***************************************************************************************/ #include public.h #include smg.h #include ds1302.h /******************************************************************************* * 函 数 名 : main * 函数功能 : 主函数 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void main() { u8 time_buf[8]; ds1302_init();//初始化DS1302 while(1) { ds1302_read_time(); time_buf[0]gsmg_code[gDS1302_TIME[2]/16]; time_buf[1]gsmg_code[gDS1302_TIME[2]0x0f]; time_buf[2]0x40; time_buf[3]gsmg_code[gDS1302_TIME[1]/16]; time_buf[4]gsmg_code[gDS1302_TIME[1]0x0f]; time_buf[5]0x40; time_buf[6]gsmg_code[gDS1302_TIME[0]/16]; time_buf[7]gsmg_code[gDS1302_TIME[0]0x0f]; smg_display(time_buf,1); } }主函数代码非常简单 首先调用外设头文件 然后初始化 DS1302 并设定好初始时间 进入 while 循环 读取 DS1302 时钟数据存储至全局变量数组gDS1302_TIME 中 最后将读取的数据转换为数码管可显示的段码数据并调用数码管显示函数显示时间。细心的朋友可能发现 在处理 DS1302 读取的数据时 取高低位是使用除 16和取余 16 并非之前的除 10 和取余 10。 这是因为写入进 DS1302 时是 BCD 码读取出的数据也是 BCD 码 而 BCD 码即是 4 位表示一个十进制数 类似于一个字节的十六进制数据的高 4 位和低 4 位一样 所以这里是除 16 和取余 16。25.4 实验现象使用 USB 线将开发板和电脑连接成功后电脑能识别开发板上 CH340 串口 把编译后产生的.hex 文件烧入到芯片内 实现现象如下 数码管上显示电子时钟时分秒 格式为“XX-XX-XX” 。