单片机第一季:零基础11——实时时钟DS1302

news2024/11/25 4:37:23

目录

1,DS1302 时钟芯片介绍 

2,BCD码介绍 

3,涉及到的寄存器 

3.1,控制寄存器

3.2,日历/时钟寄存器 

3.3,DS1302 的读写时序 

4,相关代码 


这一章我们来学习DS1302 时钟芯片,该芯片是3 线SPI 接口,所以需要使用51单片机的3 个IO 口模拟SPI 时序与DS1302 时钟芯片通信,将时钟日历数据读取出来。开发板上集成了1 个DS1302 时钟模块,可使用它设计一个多功能电子时钟。本章要实现的功能是:系统运行时,数码管上显示电子时钟时分秒,格式为“XX-XX-XX”。

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 兼容Vcc=5V;
★ 可选工业级温度范围-40~+85; 

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

51单片机和DS1302芯片之间的通讯是SPI,SPI的主要特点:3线or4线、同步、主从、串行;

3线or4线: CE、I/O、SCLK,3线I/O是一根线,4线I/O是两根线;

同步:与UART的异步通讯相比,需要SCLK同步信息的发送和接收;

主从:谁来发出SCLK同步信号; 

串行:在数据线上按位传输数据; 

DS1302是变种SPI,通过SCLK和I/O相互配合,发送和接收信息。SCLK在上升沿前,主机通过I/O口发送数据,DS1302在上升沿是接收;SCLK在下降沿后,DS1302通过I/O口发送数据,主机接收。

 SPI:SPI = Serial Peripheral Interface,是串行外围设备接口,是一种高速,全双工,同步的通信总线。

DS1302参考: 

DS1302介绍

2,BCD码介绍 

为什么要介绍BCD码?因为从DS1302芯片读出来的数据是BCD 码形式,当使用串口助手查看数据时看到的是十进制形式,但其本质上是十六进制数据。

BCD码是一种数字编码,这种计数编码有个特点:很像10进制和16进制的结合。看起来很像10进制(29下来是30而不是2A),BCD码实际是用十六进制来表示的(BCD码的21其实在计算机中就是0x21)。BCD码中只有0-9,而没有ABCDEF等字目。 

综合来讲:BCD码其实就是看起来很像十进制数的十六进制数。意思就是:BCD码本质上是十六进制数,但是因为他没有ABCDEF,所以看起来很像十进制数。 

DS1302使用BCD码来处理时间信息,对单片机来说是16进制方便单片机处理,对人来说可以认为是10进制,同时方便单片机和人来识别信息。

例如:

如果把一个数21分成两个数,对于十进制的21,需要通过21/10得到2,通过21%10得到1; 

对于十六进制的21,分成两个数,通过0x21>>4的得到2 ,通过0x21&0x0F得到1;

对于计算机来说,移位和与操作的复杂度优于除和取余。 

3,涉及到的寄存器 

操作DS1302 的大致过程,就是将各种数据写入DS1302 的寄存器,以设置它当前的时间的格式。然后使DS1302 开始运作,DS1302 时钟会按照设置情况运转,再用单片机将其寄存器内的数据读出。 

3.1,控制寄存器

控制寄存器用于存放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,要注意其含义。 

3.2,日历/时钟寄存器 

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 内部电路有关。

思考:日历/时钟寄存器中还存储了除了时间数据之外的其它数据,这些数据在读写时是如何操作的? 

3.3,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 的
一系列数据,方便以后扩展键盘输入。 

4,相关代码 

ds1302底层时序代码,分为ds1320.c和ds1302.h两个文件:

 ds1302.h

#ifndef  __DS1302_H__
#define  __DS1302_H__

//从ds1302的内部寄存器addr写入一个值value
void ds1302_write_reg(unsigned char addr, unsigned char value);
//从ds1302的内部寄存器addr读出一个值,作为返回值
unsigned char ds1302_read_reg(unsigned char addr);



#endif

ds1320.c

#include "ds1302.h"

#include <reg51.h>


sbit DSIO	= P3^4;
sbit RST	= P3^5;
sbit SCLK	= P3^6;


void delay(void)
{
	unsigned char i;
	for (i=0; i<3; i++);
}

//从ds1302的内部寄存器addr写入一个值value
void ds1302_write_reg(unsigned char addr, unsigned char value)
{
	unsigned char i,dat;
	//第一部分:时序初始化
	RST = 0;
	delay();
	SCLK = 0;
	delay();
	RST = 1;
	delay();

	//第二部分:写入地址
	for(i=0; i<8; i++)
	{
	   dat = addr & 0x01; //取地址的低位
	   DSIO = dat;
	   addr >>=1;
	   SCLK = 1;		  //创造一个上升沿,让ds1302将信号线上的值读走
	   delay();
	   SCLK = 0;
	}

    //第三步:写入数据
	for(i=0; i<8;i++)
	{
	   dat = value & 0x01; //取数据的低位
	   DSIO = dat;
	   value >>=1;
	   SCLK = 1;		  //创造一个上升沿,让ds1302将信号线上的值读走
	   delay();
	   SCLK = 0;		
	}

	//第四部分:时序结束
	RST = 0;
	delay();
	SCLK = 0;
	delay();


}


// 从ds1302的内部寄存器addr读出一个值,作为返回值
unsigned char ds1302_read_reg(unsigned char addr)
{
	unsigned char i = 0;
	unsigned char dat = 0; 		// 用来存储读取到的一字节数据的
	unsigned char tmp = 0;

	// 第1部分: 时序起始
	SCLK = 0;
	delay();
	RST = 0;
	delay();
	RST = 1;  		// SCLK为低时,RST由低变高,意味着一个大的周期的开始
	delay();
	// 第2部分: 写入要读取的寄存器地址,addr
	for (i=0; i<8; i++)
	{
		dat = addr & 0x01;	 	// SPI是从低位开始传输的
		DSIO = dat;	 			// 把要发送的bit数据丢到IO引脚上去准备好
		SCLK = 1;		 		// 制造上升沿,让DS1302把IO上的值读走
		delay();				// 读走之后,一个小周期就完了
		SCLK = 0;				// 把SCLK拉低,是为了给下一个小周期做准备
		delay();
		addr >>= 1;	   			// 把addr右移一位
	}
	// 第3部分: 读出一字节DS1302返回给我们的值
	dat = 0;
	for (i=0; i<8; i++)
	{
	// 在前面向ds1302写入addr的最后一个bit后,ds1302就会将读取到的寄存器值
	// 的第一个bit放入到IO引脚上,所以我们应该先读取IO再制造下降沿然后继续
	// 读取下一个bit
		tmp = DSIO;
		dat |= (tmp << i);		// 读出来的数值是低位在前的
		SCLK = 1;  				// 由于上面SCLK是低,所以要先拉到高
		delay();
		SCLK = 0;				// 拉低SCLK制造一个下降沿
		delay();
	}
	// 第4部分: 时序结束
	SCLK = 0;				  	// SCLK拉低为了后面的周期时初始状态是对的
	delay();
	RST = 0;					// RST拉低意味着一个大周期的结束
	delay();

	// 第5部分:解决读取时间是ff的问题
	DSIO = 0;

	return dat;
}


通过串口接收时钟数据,分为uart.c和uart.h两个文件:

 uart.h

#ifndef __UART_H__
#define __UART_H__


//串口初始化
void uart_init();
//串口发送数据
void uart_send_byte(unsigned char c);


#endif

uart.c

#include "uart.h"
#include <reg51.h>


void uart_init()
{
	TMOD|=0X20; //设置计数器工作方式2
	SCON=0X50; //设置为工作方式1
	PCON=0X80; //波特率加倍
	TH1=0xFA; //计数器初始值设置
	TL1=0xFA;
	ES=1; //打开接收中断
	EA=1; //打开总中断
	TR1=1; //打开计数器
}

void uart_send_byte(unsigned char c)
{
   // 第1步,发送一个字节
   SBUF = c;

   // 第2步,先确认串口发送部分没有在忙
   while (!TI);

   // 第3步,软件复位TI标志位
   TI = 0;
}

main函数:

包括ds1302的上层时序,读出时钟数据和写入时钟数据,以及调用uart函数。

#include <reg51.h>
#include <intrins.h>

#include "ds1302.h"
#include "uart.h"

unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
unsigned char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
unsigned char time[7]={0};


void delay1s(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=167;c>0;c--)
        for(b=171;b>0;b--)
            for(a=16;a>0;a--);
    _nop_();  //if Keil,require use intrins.h
}


void ds1302_read_time(void)
{
	unsigned char i = 0;
	for (i=0; i<7; i++)
	{
		time[i] = ds1302_read_reg(READ_RTC_ADDR[i]);
	}
}

void ds1302_write_time(void)
{
	unsigned char i = 0;

	// 准备好要写入的时间
	time[0] = 0x24;				// 对应 24s
	time[1] = 0x39;				// 对应 39m
	time[2] = 0x11;				// 对应 11h
	time[3] = 0x06;				// 对应 6日
	time[4] = 0x12;				// 对应 12月
	time[5] = 0x02;				// 对应 星期2
	time[6] = 0x16;				// 对应 2016年

	ds1302_write_reg(0x8E, 0x00);	// 去掉写保护
	for (i=0; i<7; i++)
	{
		ds1302_write_reg(WRITE_RTC_ADDR[i], time[i]);
	}
	ds1302_write_reg(0x8E, 0x80);	// 打开写保护
}


void main()
{


	uart_init();

	ds1302_write_time();



	while(1)
	{
	   int i = 0;
	   ds1302_read_time();
	   for(i=0;i<7;i++) 
	   {
	   	  uart_send_byte(time[i]);
	   }

	   delay1s();
	}

}



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/785361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构栈和队列

3.栈和队列 3.1栈和队列的定义和特点 栈和队列是两种常用的、重要的数据结构栈和队列是限定插入和删除只能在表的 “ 端点 ”进行的线性表栈和队列是线性表的子集&#xff08;是插入和删除位置受限的线性表&#xff09; 栈的应用&#xff1a; ​ 由于栈的操作具有后进先出的…

国内疫情地图和省级疫情地图

基础地图演示 from pyecharts.charts import Mapfrom pyecharts.options import VisualMapOpts map Map() data [ ("北京", 99), ("上海", 199), ("湖南", 299), ("台湾", 199), ("安徽", 299), ("广州", 399…

干货满满-运营校园跑腿小程序

校园跑腿是指在校园内提供代办、送餐、购物等服务的一种形式。学生可以通过跑腿服务解决一些日常生活中的繁琐事务&#xff0c;节省时间和精力。在校园跑腿小程序运营中&#xff0c;你可以尝试以下方法进行运营管理&#xff1a; &#xff08;1&#xff09;注册或加入相关的校园…

fdbus和proto编译

1. 下载protobuf和FDBUS 1.下载 FDBUS需要用到protobuf&#xff0c;所以需要提前安装好protobuf。 protobuf下载地址 https://gitee.com/it-monkey/protocolbuffers/ fdbus下载地址 https://gitee.com/jeremyczhen/fdbus 2. Windows编译 生成vs工程 打开CMake&#xff…

(vue)vue项目中引入外部字体

(vue)vue项目中引入外部字体 效果&#xff1a; 第一步 放置字体包&#xff0c;在assets下创建一个fonts文件夹&#xff0c;放入下载的字体文件 第二步 创建一个font.css文件用于定义这个字体包的名字 第三步 在App.vue的css中将这个css文件引入 第四步 页面使用 font-famil…

NumPy 专业人士应该掌握的 45 个技能

一、说明 NumPy&#xff08;或Numeric Python&#xff09;是每个数据科学和机器学习项目的核心。 整个数据驱动的生态系统在某种程度上依赖于NumPy及其核心功能。这使它成为 Python 有史以来最重要和改变游戏规则的库之一。 鉴于NumPy由于其无与伦比的潜力而在工业界和学术界具…

java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法

文章目录 一、记录文件相关操作方法二、代码1.读取路径返回List\<File>2.读取路径返回List\<String>3.删除文件夹4.删除文件 一、记录文件相关操作方法 二、代码 1.读取路径返回List<File> import org.slf4j.LoggerFactory; import org.slf4j.Logger;impo…

【学会动态规划】按摩师(11)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…

es通过rest接口_search、_delete_by_query查询与删除数据

1、rest接口查询数据 rest查询: http://localhost:9200/index_name/_search 查询表达式&#xff1a; {"query": {"wildcard": {"accountID": {"value": "v*"}}} }postman请求截图&#xff1a; 2、使用Rest接口删除数据 …

基于Lucene实现校园搜索引擎——太强搜索

完整资料进入【数字空间】查看——搜索"writebug" 实验环境 win10 一、实验内容 综合运用搜索引擎体系结构和核心算法方面的知识&#xff0c;基于开源资源搭建搜索引擎&#xff0c;具体包括如下几点&#xff1a; 抓取清华校园网内绝大部分资源&#xff0c;并且进行…

【NLP】温和解读:transformer的核心思想

变压器模型及其关键组件的概述。 一、介绍 在这篇博文中&#xff0c;我将讨论本世纪最具革命性的论文“注意力是你所需要的一切”&#xff08;Vaswani et al.&#xff09;。首先&#xff0c;我将介绍自我注意机制&#xff0c;然后介绍变形金刚的架构细节。在之前的博客文章《从…

【数据分析 最火 全集干货】Anaconda的安装及使用

关于我的专栏&#xff1a; 接下来会有许多关于“数据分析”的文章哦&#xff0c;记得看哦&#xff01;&#xff01;&#xff01; Python最详细最全面基础合集_adaptation_T_C的博客-CSDN博客 有兴趣&#xff0c;需要 的小伙伴可以免费订阅哦&#xff01;&#xff01;&#x…

阿里 P8 架构师 20 年经验!总结成微服务设计企业架构转型之道

前言 本文涉及两个方面的知识体系&#xff0c;即企业架构知识体系和软件架构知识体系。 企业架构和软件架构虽然都与 IT 相关&#xff0c;但其知识体系是完全不同的两个领域。一般而言&#xff0c;搞企业架构的人士不明白软件架构的细节和实现&#xff0c;而从事软件架构的架…

如何恢复损坏/删除的 Word 文件

有关如何修复不可读的 Microsoft Word 文件或 Rich Text 文件中的文本的分步说明。这些说明有助于从损坏的*.doc、*.docx、*.dot、*.dotx、*.rtf文件&#xff08;任何版本和大小&#xff09;中提取文本&#xff0c;只需单击几下&#xff1a; 从此处下载奇客数据恢复 &#xff…

React AntDesign写一个导出数据的提示语 上面有跳转的路径,或者点击知道了,关闭该弹层

效果如下&#xff1a; 代码如下&#xff1a; ForwardDataCenterModal(_blank);export const ForwardDataCenterModal (target?: string) > {let contentBefore React.createElement(span, null, 数据正在处理中&#xff0c;请稍后前往);let contentAfter React.creat…

【如何训练一个中译英翻译器】LSTM机器翻译模型训练与保存(二)

系列文章 【如何训练一个中译英翻译器】LSTM机器翻译seq2seq字符编码&#xff08;一&#xff09; 目录 系列文章1、加载训练集2、训练集数据处理3、网络搭建4、启动训练5、模型保存6、模型加载与推理 基于LSTM训练一个翻译器&#xff0c;要怎么做呢&#xff1f;其实很简单&am…

大厂案例 - 实时分析引擎

文章目录 概述内容收获思路建议 概述 网络安全态势越来越复杂&#xff0c;传统的基于单点的防护和攻击检测系统在应对现代网络攻击方面有着很大的局限性。 基于大数据平台&#xff0c;通过流式实时分析技术可以对全局网络空间进行实时的分析和异常检测&#xff0c;解决单点很…

2023年7月杭州/武汉/深圳制造业产品经理NPDP认证招生

产品经理国际资格认证NPDP是新产品开发方面的认证&#xff0c;集理论、方法与实践为一体的全方位的知识体系&#xff0c;为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会&#xff08;PDMA&#xff09;成立于1979年&#xff0c;是…

独立开发者必备的29个开源React后台管理模板

React Web应用程序开发管理后台可能非常耗时&#xff0c;这和设计所有前端页面一样重要。 以下是收集的近几年顶级React.js管理模板列表。 这些模板确实很有价值&#xff0c;使开发人员更容易构建应用程序后端的用户界面。 此外&#xff0c;它们将帮助您完善网站的管理后台&…

Clion开发STM32之W5500系列(综合实验)

说明 此为w5500模块的综合实验测试模块,包含dhcp、dns、ntp以上三个模块的驱动参考之前的文章&#xff0c;本篇不做说明.使用的开发芯片 stm32f103vet6系列,外设接口使用的spi2 实验内容: 通过dhcp动态获取ip,通过dns解析NTP服务域名的ip通过NTP服务ip获取时间 w5500配置驱…