| 
 
| 一、DS1302简介 1. 功能特性
 DS1302是一款由Maxim Integrated公司生产的实时时钟(RTC)芯片。
 RTC芯片用于计算机和其他电子设备中的时间和日期的集成电路,通常被用于电子时钟、计时器、温度记录器等应用中。
 
 DS1302部分功能特性:
 
 实时时钟功能:提供年、月、日、时、分、秒等时间数据。
 串行接口:通过串行接口(如SPI)与微控制器进行通信。
 低功耗设计:具有低功耗特性,在电池供电情况下能够长时间稳定运行。
 内置晶体振荡器:集成了晶体振荡器,不需要外部晶振。
 电池备份:支持电池备份以保持时钟运行,即使主电源断电时也能保持时间数据。
 温度补偿:具有温度补偿功能,可以提高时钟的准确性。
 DS1302通常与微控制器或单片机配合使用,通过串行接口进行通信,并通过读写寄存器来配置和读取时间数据。
 
 DS1302工作电压2.0~5.5V。
 
 2. 涓流充电
 涓流充电是一种低功率充电方式,它通过限制充电电流的大小来防止电池过度充电和损坏。
 
 DS1302内部集成了涓流充电电路,它会在主电源供电时通过合适的电阻限制充电电流,以适当的速率充电芯片内部的备用电池。一旦电池被充满,充电电路会自动停止充电,以防止过度充电。
 
 当主电源断电时,DS1302会自动从备用电池供电,保持时钟和日期功能正常运行。备用电池通常是一个较小的锂电池,它能够提供足够的电力维持DS1302的基本功能长达数年。
 
 3. 接口介绍
 DS1302实时时钟芯片具有串行接口,通常使用3线或4线SPI(Serial Peripheral Interface)进行通信。以下是DS1302的主要接口:
 
 时钟数据和控制线:
 CE(Chip Enable):芯片使能线,用于启用DS1302的通信。
 IO(Data I/O):数据输入/输出线,用于与微控制器进行数据交换。
 SCLK(Serial Clock):串行时钟线,用于同步数据传输。
 电源线:
 VCC:芯片供电正极。
 GND:芯片地线。
 备用电池连接:
 VBAT:备用电池正极,用于备份时钟数据。
 GND(BAT):备用电池地线。
 
 
 
 二、寄存器介绍
 1. 控制寄存器
 
 
 
 BIT7 MSB,1时定稿,0时禁止对DS1302写入
 BIT6 0:时钟/日历;1RAM数据
 BIT5~BIT1:输入输出的寄存器
 BIT0 LSB,0时写操作,1时读操作。
 2. 时间寄存器
 
 
 
 3. 日历/时钟寄存器
 BCD码格式存入。
 
 
 
 三、BCD码介绍
 BCD(Binary-Coded Decimal)码是一种数字编码方式,用于表示十进制数字的二进制形式。在BCD编码中,每个十进制数字(0到9)都用4位二进制数表示。这种编码方式可以使计算机更方便地处理十进制数字。
 
 BCD码的基本原理是将一个十进制数的每一位分别用二进制数表示,例如将十进制数 45 分别用BCD编码表示:
 
 数字 4 的BCD编码为 0100
 数字 5 的BCD编码为 0101
 因此,数字 45 的BCD编码为 0100 0101。
 
 BCD码有几种常见的表示方法:
 
 8421码:每个十进制数字用4位二进制数表示,范围从 0000 到 1001。这种编码方式的名称来自每个位上的权重,分别是8、4、2和1。例如,十进制数 7 的BCD编码为 0111。
 
 2421码:类似于8421码,但在前四个数字中,9表示为 1001,而不是 1000。这种编码方式的目的是为了简化BCD加法的实现。
 
 Excess-3码:在8421码的基础上,每个数字都加上了3。例如,数字 0 的8421码是 0000,加上3后变为 0011。
 
 DS1302实时时钟芯片使用的是8421码(也称为8421BCD码)
 
 四、DS1302时序
 1. 读时序
 单字节读:
 
 
 
 CE:高电平使能
 
 SCLK:时钟
 
 IO:数据读
 
 I/O设置为输入
 
 在时钟上升沿写入,从低向高写入;
 第一个字节是写入指令
 
 I/O设置为输出
 
 后一个字节是读操作
 
 写入完成后,在下一个时钟下降沿读;
 
 2. 写时序
 单字节写:
 
 
 
 五、实现
 1. 硬件原理图
 
 
 
 下面代码在数码管显示时间。
 
 2. ds1302.h
 //
 // 时钟芯片
 //
 
 #ifndef LESSON11_DS1302_H
 #define LESSON11_DS1302_H
 #include <reg52.h>
 #include "types.h"
 
 sbit DS1302_CE = P3^5;
 // 时钟口
 sbit DS1302_CLK = P3^6;
 // IO 口
 sbit DS1302_IO = P3^4;
 
 /**
 * 写入一个字节
 */
 void ds1302_write_byte(u8 addr, u8 dat);
 /**
 * 读取一个字节
 */
 u8 ds1302_read_byte(u8 addr);
 
 //变量声明
 extern u8 gDS1302_TIME[7];//存储时间
 
 void ds1302_init(void);
 void ds1302_read_time(void);
 #endif //LESSON11_DS1302_H
 
 
 
 
 3. ds1302.c
 //
 // 时钟芯片
 //
 #include "ds1302.h"
 #include "intrins.h"
 
 // DS1302写入和读取的地址命令
 u8 gREAD_RTC_ADDR[7] = {
 0x81,   // 二进制  1000 0001 , 表示: 1000 0000 读取秒
 0x83,   // 1000 0011 读取分
 0x85,   // 1000 0101 读取时
 0x87,   // 1000 0111 读取日
 0x89,   // 1000 1001 读取月
 0x8b,   // 1000 1011 读取星期
 0x8d    // 1000 1101 读取年
 };
 u8 gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
 // DS1302 初始化要写入的时间
 u8 gDS1302_TIME[7] = {
 0x47,   // 秒
 0x56,   // 分
 0x15,   // 时
 0x20,   // 日
 0x03,   // 月
 0x05,   // 星期
 0x24    // 年
 };
 
 /**
 * 写入一个字节
 */
 void ds1302_write_byte(u8 addr, u8 dat){
 u8 i;
 
 // 使能脚复位
 DS1302_CE = 0;
 _nop_();
 // 时钟脚复位
 DS1302_CLK = 0;
 _nop_();
 // 使能脚置高
 DS1302_CE = 1;
 _nop_();
 // 从低位开始写入
 for(i=0; i<8; i++){
 // 先发送地址
 DS1302_IO = addr & 0x01;
 // 右移一位
 addr >>= 1;
 
 // SLK 上升沿写入
 DS1302_CLK = 1;
 _nop_();
 DS1302_CLK = 0;
 _nop_();
 }
 // 写入数据
 for(i=0; i<8; i++){
 // 先发送数据
 DS1302_IO = dat & 0x01;
 // 右移一位
 dat >>= 1;
 // SLK 上升沿写入
 DS1302_CLK = 1;
 _nop_();
 DS1302_CLK = 0;
 _nop_();
 }
 // 复位
 DS1302_CE = 0;
 _nop_();
 }
 /**
 * 读取一个字节
 */
 u8 ds1302_read_byte(u8 addr){
 u8 i;
 u8 temp = 0;
 u8 value = 0;
 // 使能脚复位
 DS1302_CE = 0;
 _nop_();
 // 时钟脚复位
 DS1302_CLK = 0;
 _nop_();
 // 使能脚置高
 DS1302_CE = 1;
 _nop_();
 // 从低位开始写入
 for(i=0; i<8; i++){
 // 先发送地址
 DS1302_IO = addr & 0x01;
 // 右移一位
 addr >>= 1;
 // SLK 上升沿写入
 DS1302_CLK = 1;
 _nop_();
 DS1302_CLK = 0;
 _nop_();
 }
 // 读取数据
 for(i=0; i<8; i++){
 temp = DS1302_IO;
 value = (temp << 7) | (value >> 1);
 // SLK 下降沿读取
 DS1302_CLK = 1;
 _nop_();
 DS1302_CLK = 0;
 _nop_();
 }
 // 复位
 DS1302_CE = 0;
 _nop_();
 
 // 释放时钟
 DS1302_CLK = 1;
 
 _nop_();
 DS1302_IO = 0;
 _nop_();
 DS1302_IO = 1;
 _nop_();
 return value;
 }
 /**
 * ds1302初始化
 */
 void ds1302_init(void){
 u8 i = 0;
 // 写入禁止写保护
 ds1302_write_byte(0x8e, 0x00);
 // 写数据
 for(i=0; i<7; i++){
 ds1302_write_byte(gWRITE_RTC_ADDR, gDS1302_TIME);
 }
 // 写入启用写保护
 ds1302_write_byte(0x8e, 0x80);
 }
 /**
 * 写入时间
 */
 void ds1302_read_time(void){
 u8 i=0;
 for(i=0;i<7;i++)
 {
 gDS1302_TIME=ds1302_read_byte(gREAD_RTC_ADDR);
 }
 }
 
 
 
 
 4. main.c
 #include <reg52.h>
 #include "led_utils.h"
 #include "common_utils.h"
 #include "timer_utils.h"
 #include "uart_utils.h"
 #include "key_utils.h"
 #include "eeprom_utils.h"
 #include "segment_display_utils.h"
 #include "ds1302.h"
 
 
 /**
 * @brief 主函数
 */
 main()
 {
 u8 time_buf[8];
 // 关闭所有led
 led_all_off();
 uart_init(0xFA);
 ds1302_init();
 
 while(1)
 {
 ds1302_read_time();
 uart_send(u8_to_hex(gDS1302_TIME[2]));
 time_buf[0]=gDS1302_TIME[2]/16;
 time_buf[1]=gDS1302_TIME[2]&0x0f;
 time_buf[2]=0x10;
 time_buf[3]=gDS1302_TIME[1]/16;
 time_buf[4]=gDS1302_TIME[1]&0x0f;
 time_buf[5]=0x10;
 time_buf[6]=gDS1302_TIME[0]/16;
 time_buf[7]=gDS1302_TIME[0]&0x0f;
 
 segment_show_u8_array(time_buf);
 }
 }
 
 
 
 ————————————————
 
 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
 
 原文链接:https://blog.csdn.net/xundh/article/details/137163027
 
 
 | 
 
×本帖子中包含更多资源您需要 登录 才可以下载或查看,没有账号?注册 
  |