STC89C52RC嵌入式DS1302实时时钟实验及数码管显示
- STC89C52RC嵌入式DS1302实时时钟实验及数码管显示
- 1 概述
- 1.1 DS1302简介
- 1.2 DS1302功能和特点
- 1.3 DS1302工作原理
- 1.4 DS1302应用领域
- 2 DS1302设计原理
- 2.1 引脚说明
- 2.2 寄存器说明及使用
- (1)命令cmd字节说明
- (2)命令汇总
- 3 DS1302读写软件设计
- 3.1 读程序
- 3.2 写程序
- 4 软件工程代码
- 5 总结
- 5.1 注意事项
- 5.2 应用总结
STC89C52RC嵌入式DS1302实时时钟实验及数码管显示
1 概述
1.1 DS1302简介
DS1302是一种经典的实时时钟芯片,由Dallas Semiconductor(现在是Maxim Integrated)生产。它是一款低成本、低功耗的实时时钟模块,适用于许多嵌入式系统和电子设备中,用于提供实时时钟和日期功能。
DS1302 可慢速充电实时时钟芯片包含实时时钟/日历和 31 字节的非易失性静态 RAM。它经过一 个简单的串行接口与微处理器通信。实时时钟/日历可对秒,分,时,日,周,月,和年进行计数,对 于小 于 31 天的月,月末的日期自动进行调整,还具有闰年校正的功能。时钟可以采用 24 小时格式 或带 AM(上午)/PM(下午)的 12 小时格式。31 字节的 RAM 可以用来临时保存一些重要数据。 使用同步串行通信, 简化了 DS1302 与微处理器的通信。与时钟/RAM 通信仅需 3 根线:(1)RST (复位),(2)I/O(数据线)和(3)SCLK(串行时钟)。数据可以以每次一个字节的单字节形式或多 达 31 字节的多字节形式传输。DS1302 能在非常低的功耗下工作,消耗小于 1µW 的功率便能保存 数据和时钟信息。
1.2 DS1302功能和特点
实时时钟功能: DS1302提供了秒、分、时、日、月、年等实时时钟信息,并能够自动处理闰年。
低功耗: DS1302具有低功耗特性,通常可以通过外部电池来提供备用电源,以保持时钟的持续运行。
SPI接口: DS1302通过简单的3线SPI接口与微控制器或其他设备进行通信。
32字节RAM: DS1302集成了32字节的RAM,可以用于存储临时数据或者配置信息。
电压范围: DS1302能够在较宽的电压范围内工作,通常在2V至5.5V之间。
精度: DS1302的时钟误差非常小,通常在几秒内每月。
1.3 DS1302工作原理
DS1302通过与微控制器的SPI通信来读取和设置时间信息。它通常连接到微控制器的GPIO引脚,并通过特定的协议(如时钟脉冲和数据线)来进行通信。通过读取和写入特定的寄存器,可以控制DS1302的各种功能。
1.4 DS1302应用领域
嵌入式系统: DS1302常被用于嵌入式系统中,为设备提供实时时钟功能。
时钟模块: DS1302可以用于制作各种时钟模块,如数字时钟、温度计时钟等。
计时器和提醒器: DS1302可以用于创建计时器、闹钟和提醒功能。
数据记录: 由于具有RAM存储功能,DS1302还可用于数据记录应用,如温度记录器等。
总的来说,DS1302是一个功能丰富、易于使用的实时时钟芯片,适用于许多需要时间记录和计时功能的应用场景。
2 DS1302设计原理
2.1 引脚说明
电路连接示意图:
2.2 寄存器说明及使用
(1)命令cmd字节说明
通常我们将第六位为0,不作为RAM使用,将其作为实时时钟的专用芯片。
(2)命令汇总
将寄存器地址看成命令即可:
3 DS1302读写软件设计
DS1302通过与微控制器的SPI通信来读取和设置时间信息。所以基本的通讯方式是以SPI半双工主从方式获取和操作DS1302内部时间数据。
3.1 读程序
根据手册读流程:
数据读代码设计如下:
// 从DS1302读取一个字节
unsigned char DS1302_ReadByte(void)
{unsigned char i, dat = 0;for (i = 0; i < 8; i++){dat >>= 1; // 右移一位,准备接收下一位数据if (DS1302_IO) // 读取数据位dat |= 0x80; // 如果数据位为1,将最高位置1DS1302_SCLK = 1; // 拉高时钟线,传输数据DS1302_SCLK = 0; // 将时钟线拉低,准备传输下一位}return dat; // 返回读取到的数据
}
// 从DS1302读取一个字节的数据
unsigned char DS1302_Read(unsigned char addr)
{unsigned char temp,i;DS1302_RST=0; //停止工作DS1302_SCLK=0; DS1302_RST=1; for (i = 0; i < 8; i++){DS1302_IO = addr & 0x01; // 传输地址的最低位addr >>= 1; // 右移一位,准备传输下一位DS1302_SCLK = 1; // 拉高时钟线,传输数据DS1302_SCLK = 0; // 将时钟线拉低,准备传输下一位}temp = DS1302_ReadByte();DS1302_RST=0;DS1302_SCLK=1; //停止工作return temp; // 读取地址和数据,地址最高位置0表示读操作
}
3.2 写程序
根据手册写流程:
软件代码设计如下:
// 向DS1302写入一个字节
void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{unsigned char i;for (i = 0; i < 8; i++){DS1302_IO = addr & 0x01; // 传输地址的最低位addr >>= 1; // 右移一位,准备传输下一位DS1302_SCLK = 1; // 拉高时钟线,传输数据DS1302_SCLK = 0; // 将时钟线拉低,准备传输下一位}for (i = 0; i < 8; i++){DS1302_IO = dat & 0x01; // 传输数据的最低位dat >>= 1; // 右移一位,准备传输下一位DS1302_SCLK = 1; // 拉高时钟线,传输数据DS1302_SCLK = 0; // 将时钟线拉低,准备传输下一位}
}
// 向DS1302写入一个字节的数据
void DS1302_Write(unsigned char addr, unsigned char dat)
{DS1302_RST=0; //停止工作DS1302_SCLK=0; DS1302_RST=1; //重新工作DS1302_WriteByte(addr | 0x80, dat); // 写入地址和数据,地址最高位置1表示写操作DS1302_RST=0;DS1302_SCLK=1;
}
4 软件工程代码
工程示意图:
//main.c文件
#include "includes.h"/******************************************************************/
/* 微秒延时函数 //10us */
/******************************************************************/
void delay_us(unsigned int us)//delay us
{while(us--){}
}/******************************************************************/
/* 微秒延时函数 */
/******************************************************************/
void delay_ms(unsigned int Ms)//delay us
{while(Ms--){delay_us(100);}
}/*------------------------------------------------主函数
------------------------------------------------*/
void main (void)
{
// unsigned char sec, min, hour;
//
// DS1302_Write(0x80, 0x00); // // 设置时间DS1302_Write(0x80, 0); // 秒DS1302_Write(0x82, 0x25); // 分钟DS1302_Write(0x84, 0x19); // 小时while (1){// 读取时间sec = DS1302_Read(0x81); // 秒min = DS1302_Read(0x83); // 分钟hour = DS1302_Read(0x85); // 小时// 在这里可以进行对时间的处理或其他操作delay_ms(1);sys_keynum_ledon(sec/16,6);delay_ms(1);sys_keynum_ledon(sec%16,7);delay_ms(1);sys_keynum_ledon(10,5);delay_ms(1);sys_keynum_ledon(min/16,3);delay_ms(1);sys_keynum_ledon(min%16,4);delay_ms(1);sys_keynum_ledon(10,2);delay_ms(1);sys_keynum_ledon(hour/16,0);delay_ms(1);sys_keynum_ledon(hour%16,1);}
}
//includes.h文件
#ifndef __INCLUDES_H__
#define __INCLUDES_H__//#include<reg52.h> #include<intrins.h> //汇编指令_nop_
#include<stdio.h> //标准输入输出//_nop_(); 产生一条NOP指令
//作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
//NOP指令为单周期指令,可由晶振频率算出延时时间。//8051 为每个机器周期 12 时钟
//对于12M晶振,延时1uS。
//11.0592M晶振,延时1.0851uS。//对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "STC89C5xRC_RDP.h"//应用层头文件
//#include "c51_gpio.h"
#include "c51_ledtube.h"
//#include "c51_key.h"
//#include "c51_timer.h"
//#include "c51_exit.h"
//#include "c51_lcd1602.h"
//#include "c51_iic.h"
//#include "c51_tx1838.h"
//#include "c51_uart.h"
//#include "c51_28byj48.h"
#include "c51_ds1302.h"//extern void delay(unsigned int cnt);
extern void delay_us(unsigned int us);//delay us;
extern void delay_ms(unsigned int Ms);//delay Ms;///******************************************************************/
///* 微秒延时函数 //10us */
///******************************************************************/
//void delay_us(unsigned int us)//delay us
//{
// while(us--)
// {
// }
//}///******************************************************************/
///* 微秒延时函数 */
///******************************************************************/
//void delay_ms(unsigned int Ms)//delay us
//{
// while(Ms--)
// {
// delay_us(100);
// }
//}///*------------------------------------------------
// 延时子程序
//------------------------------------------------*/
//void delay(unsigned int cnt)
//{
// while(--cnt);
//}#endif
//c51_ledtube.c文件
#include "includes.h"// 显示段码值01234567,可对应原理图查看显示不同图形对应的引脚高点电平配置状态
unsigned char const EL[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,\0x77,0x7c,0x39,0x5e,0x79,0x71};//0-Fcode unsigned char ledmap[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};///********************************************************
//函数名称:sys_ledtube_on1
//函数功能:点亮一个数码管全为亮起来
//入口参数:
//出口参数:
//修 改:
//内 容:
//********************************************************/
//void sys_ledtube_on1(void)
//{
// //根据原理图,将P0口全部输出高电平,P2选择0号数码管
// P0=0xFF;//取显示数据,段码
// P2=0; //取位码
//}///********************************************************
//函数名称:sys_ledtube_on2
//函数功能:显示一组数据
//入口参数:
//出口参数:
//修 改:
//内 容:
//********************************************************/
//static unsigned char ledtube_cnt = 0;//void sys_ledtube_on2(void)
//{
// ledtube_cnt++;
// if(ledtube_cnt>7)
// {
// ledtube_cnt = 0;
// }
// P0 = 0x00; //防止切换数码管瞬间有虚影出现
// P2 = 0x00;
// P0 = ledmap[ledtube_cnt]; //取显示数据,段码
// P2 = ledtube_cnt; //取位码
//
// //根据人眼适应虚影缓冲时间为50ms左右
// //我们调整delay在500以下可以看到明显的看起来是一串数据一起显示
// delay(100);
//}///********************************************************
//函数名称:sys_keynum_ledon
//函数功能:显示按键数值
//入口参数:按键数值
//出口参数:
//修 改:
//内 容:
//********************************************************/
void sys_keynum_ledon(unsigned char num,unsigned char pn)
{//根据原理图,将P0口全部输出高电平,P2选择0号数码管P0 = 0x00; //防止切换数码管瞬间有虚影出现P2 = pn; //取位码P0 = ledmap[num]; //取显示数据,段码
}
//c51_ledtube.h文件
#ifndef __C51_LEDTUBE_H__
#define __C51_LEDTUBE_H__extern unsigned char const EL[];//extern void sys_ledtube_on1(void);
//extern void sys_ledtube_on2(void);extern void sys_keynum_ledon(unsigned char num,unsigned char pn);#endif
//c51_ds1302.c文件
#include "includes.h"unsigned char sec, min, hour;// 向DS1302写入一个字节
void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{unsigned char i;for (i = 0; i < 8; i++){DS1302_IO = addr & 0x01; // 传输地址的最低位addr >>= 1; // 右移一位,准备传输下一位DS1302_SCLK = 1; // 拉高时钟线,传输数据DS1302_SCLK = 0; // 将时钟线拉低,准备传输下一位}for (i = 0; i < 8; i++){DS1302_IO = dat & 0x01; // 传输数据的最低位dat >>= 1; // 右移一位,准备传输下一位DS1302_SCLK = 1; // 拉高时钟线,传输数据DS1302_SCLK = 0; // 将时钟线拉低,准备传输下一位}
}// 从DS1302读取一个字节
unsigned char DS1302_ReadByte(void)
{unsigned char i, dat = 0;for (i = 0; i < 8; i++){dat >>= 1; // 右移一位,准备接收下一位数据if (DS1302_IO) // 读取数据位dat |= 0x80; // 如果数据位为1,将最高位置1DS1302_SCLK = 1; // 拉高时钟线,传输数据DS1302_SCLK = 0; // 将时钟线拉低,准备传输下一位}return dat; // 返回读取到的数据
}// 向DS1302写入一个字节的数据
void DS1302_Write(unsigned char addr, unsigned char dat)
{DS1302_RST=0; //停止工作DS1302_SCLK=0; DS1302_RST=1; //重新工作DS1302_WriteByte(addr | 0x80, dat); // 写入地址和数据,地址最高位置1表示写操作DS1302_RST=0;DS1302_SCLK=1;
}// 从DS1302读取一个字节的数据
unsigned char DS1302_Read(unsigned char addr)
{unsigned char temp,i;DS1302_RST=0; //停止工作DS1302_SCLK=0; DS1302_RST=1; for (i = 0; i < 8; i++){DS1302_IO = addr & 0x01; // 传输地址的最低位addr >>= 1; // 右移一位,准备传输下一位DS1302_SCLK = 1; // 拉高时钟线,传输数据DS1302_SCLK = 0; // 将时钟线拉低,准备传输下一位}temp = DS1302_ReadByte();DS1302_RST=0;DS1302_SCLK=1; //停止工作return temp; // 读取地址和数据,地址最高位置0表示读操作
}
//c51_ds1302.h文件
#ifndef __C51_DS1302_H__
#define __C51_DS1302_H__sbit DS1302_SCLK = P3^6; // DS1302的时钟引脚sbit DS1302_IO = P3^4; // DS1302的数据引脚sbit DS1302_RST = P3^5; // DS1302的复位引脚extern unsigned char sec, min, hour;// 函数声明
extern void DS1302_WriteByte(unsigned char addr, unsigned char dat);extern unsigned char DS1302_ReadByte(void);extern void DS1302_Write(unsigned char addr, unsigned char dat);extern unsigned char DS1302_Read(unsigned char addr);#endif
5 总结
5.1 注意事项
(1)DS1302获取和设置的时间数值采用BCD吗方式,形式上10进制的16进制数据,比如获取数值为0x16,则其数值就是十进制的16。在解析和设置时注意发送接收数据格式。
(2)DS1302有一个停止,当芯片断电后,DS1302会停止不再计时 ,“秒”寄存器第7位为1,当DS1302停止时,读出来的秒为一直是0x80,则此时需要对秒寄存器最高位设置为0,重新启动。
DS1302_Write(0x80, 0x00);
5.2 应用总结
DS1302实时时钟芯片在许多电子设备和嵌入式系统中具有广泛的应用价值。以下是DS1302实时时钟在各种应用中的重要作用和价值:
- 实时时钟功能:
DS1302提供了秒、分、时、日、月、年等实时时钟信息,可以用于跟踪时间并记录时间戳。在需要时间记录、数据同步或定时操作的应用中,DS1302可以提供准确的时间基准。 - 定时器和闹钟功能:
通过DS1302,您可以实现定时器、闹钟和提醒功能,使设备能够在特定时间点执行预定的任务或发出提醒。 - 数据记录和时间戳:
DS1302内置的32字节RAM可以用于存储临时数据或配置信息,适用于数据记录应用(如温度记录器),同时可以为数据添加时间戳。 - 电源失效保护:
DS1302通常可以通过外部电池提供备用电源,以保持实时时钟在主电源中断时的持续运行。这种功能对于需要持续时间记录和时间跟踪的应用非常重要。 - 低功耗设计:
DS1302具有低功耗特性,适用于要求节能设计的电子设备,同时可以延长电池寿命。 - 嵌入式系统应用:
DS1302广泛应用于嵌入式系统、智能家居设备、温控器、时钟模块等各类电子产品中,为这些设备提供时间管理和实时时钟功能。 - 开发教学和实验:
由于DS1302易于使用和集成,它也经常被用于教学和实验项目中,帮助学生学习嵌入式系统和时钟控制的基础知识。
综上所述,DS1302实时时钟芯片在各种应用中扮演着关键角色,为设备提供准确的时间记录、定时功能和数据管理,同时具备低功耗设计和备用电源支持,使其在电子领域中具有重要的应用和价值。