单片机学习 15-ds1302时钟实验

news/2024/5/9 13:55:19/文章来源:https://blog.csdn.net/qq_25218501/article/details/131459796

DS1302 时钟实验

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

DS1302时钟芯片介绍

DS1302简介

​ DS1302是DALLAS公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31字节静态RAM,通过简单的串行接口与单片机进行通信。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。时钟操作可通过AM/PM指示决定采用24或12小时格式。DS1302与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三根通信线:①RES复位②I/O数据线③SCLK串行时钟。时钟/RAM的读/写数据以一个字节或多达31个字节的字符组方式通信。DS1302工作时功耗很低保持数据和时钟信息时功率小于1mW。

​ DS1302由DS1202改进而来增加了以下的特性:双电源管脚用于主电源VCC2和备份电源VCC2供应,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;
下面来看下DS1302芯片的管脚及功能。

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。
(1)控制寄存器
​ 控制寄存器用于存放DS1302的控制命令字,DS1302的RST引脚回到高电平后写入的第一个字节就为控制命令。它用于对DS1302读写过程进行控制,格式如下:

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

1、第7位永远都是1;

2、第6位,1表示RAM,寻址内部存储器地址;0表示CK,寻址内部寄存器;

3、第5到第1位,为RAM或者寄存器的地址;

4、最低位,高电平表示RD,即下一步操作将要“读”;低电平表示W,即下一步操作将要“写”。(与AT24C02寄存器类似,这点要理解好)。

​ 比如要读秒寄存器则命令为 1000 0001,反之写为 1000 0000,要注意其含义。
(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 内部电路有关。

​ 前面我们提到在日历/时钟寄存器中都是以 BCD 码存放数据,那么 BCD 码是什么呢?BCD 码是通过 4 位二进制码来表示 1 位十进制中的 0~9 这 10 个数码。如下所示:

​ 所以从 DS1302 中读取出来的时钟数据均为 BCD 码格式,需转换为我们习惯的10进制,转换方法在源程序里,后面我们会介绍。
(3)DS1302的读写时序
​ 在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位(位0)开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。其时序图如下所示:

​ 上图就是DS1302的三个时序:复位时序,单字节写时序,单字节读时序;

​ CE(RST):复位时序,即在RST引脚产生一个正脉冲,在整个读写器件,RST要保持高电平,一次字节读写完毕之后,要注意把RST返回低电平准备下次读写周期;

​ 单字节读时序:注意读之前还是要先对寄存器写命令,从最低位开始写;可以看到,写数据是在SCLK的上升沿实现,而读数据在SCLK的下降沿实现。所以,在单字节读时序中,写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了!这个就是DS1302操作中最特别的地方。当然读出来的数据也是最低位开始。

​ 单字节写时序:两个字节的数据配合16个上升沿将数据写入即可。写命令的第八个上升沿结束后接着的第九个上升沿继续将要读寄存器的第一位数据写入。

​ 程序注意事项:
★要记得在操作DS1302之前关闭写保护(将wp设置为0,下次开启再设置为1);

★注意用延时来降低单片机的速度以配合器件时序;

★DS1302读出来的数据是BCD码形式,要转换成我们习惯的10进制,转换方法在源程序里;

★读取字节之前,将IO设置为输入口,读取完之后,要将其改回输出口;

★在写程序的时候,建议实现开辟数组(内存空间)来集中放置DS1302的一系列数据,方便以后扩展键盘输入。

硬件设计

本实验使用到硬件资源如下:
(1)动态数码管
(2)DS1302
动态数码管电路在前面章节都介绍过,这里就不再重复。下面我们来看下开发板上DS1302时钟模块电路,如下图所示:

​ 从上图中可以看出,该电路是独立的,DS1302芯片的控制管脚接至J3端子上,芯片的VCC1脚外接了一个纽扣电池BT1,以保证系统断电后时钟仍然可以运行,在芯片的X1、X2管脚处外接了一个32.768KHZ晶振,为时钟运行提供一个稳定的时钟频率,C2和C3为旁路电容,目的是消除晶振起振时产生的电感干扰。

​ 由于该模块电路是独立的,所以DS1302芯片的控制管脚J3端子可以使用任意单片机管脚连接,为了与我们例程程序配套,这里使用单片机的P3.4管脚与时钟芯片的I/O脚连接,使用单片机的P3.5管脚与时钟芯片的CE脚连接,使用单片机的P3.6管脚与时钟芯片的SCLK脚连接。

软件设计

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l5y5H5wq-1688028515642)(C:\Users\10789\AppData\Roaming\Typora\typora-user-images\image-20220711214631846.png)]

本章所要实现的功能是:数码管上显示电子时钟时分秒,格式为“XX-XX-XX”。
程序框架如下:
(1)编写数码管显示功能
(2)编写 DS1302 时钟读写功能
(3)编写主函数

ds1302.h:

#ifndef _ds1302_H
#define _ds1302_H#include"public.h"sbit DS1302_RST=P3^5;
sbit DS1302_IO=P3^4;
sbit DS1302_CLK=P3^6;extern u8 gDS1302_TIME[7];void ds1302_write_byte(u8 addr,u8 dat);
u8 ds1302_read_byte(u8 addr);
void ds1302_init(void);
void ds1302_read_time(void);
#endif

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 i=0;
DS1302_RST=0;
_nop_();
DS1302_CLK=0;//CLK 低电平
_nop_();
DS1302_RST=1;//RST 由低到高变化
_nop_();
for(i=0;i<8;i++)//循环 8 次,每次写 1 位,先写低位再写高位
{
DS1302_IO=addr&0x01;
addr>>=1;
DS1302_CLK=1;
_nop_();
DS1302_CLK=0;//CLK 由低到高产生一个上升沿,从而写入数据
_nop_();
}
for(i=0;i<8;i++)//循环 8 次,每次写 1 位,先写低位再写高位
{
DS1302_IO=dat&0x01;
dat>>=1;
DS1302_CLK=1;
_nop_();
DS1302_CLK=0;
_nop_();
}
DS1302_RST=0;//RST 拉低
_nop_();
}
/********************************************************************
***********
* 函 数 名 : ds1302_read_byte
* 函数功能 : DS1302 读单字节
* 输 入 : addr:地址/命令
* 输 出 : 读取的数据
*********************************************************************
**********/
u8 ds1302_read_byte(u8 addr)
{
u8 i=0;
u8 temp=0;
u8 value=0;
DS1302_RST=0;
_nop_();
DS1302_CLK=0;//CLK 低电平
_nop_();
DS1302_RST=1;//RST 由低到高变化
_nop_();
for(i=0;i<8;i++)//循环 8 次,每次写 1 位,先写低位再写高位
{
DS1302_IO=addr&0x01;
addr>>=1;
DS1302_CLK=1;
_nop_();
DS1302_CLK=0;//CLK 由低到高产生一个上升沿,从而写入数据
_nop_();
}
for(i=0;i<8;i++)//循环 8 次,每次读 1 位,先读低位再读高位
{
temp=DS1302_IO;
value=(temp<<7)|(value>>1);//先将 value 右移 1 位,然后 temp 左移 7 位,
最后或运算
DS1302_CLK=1;
_nop_();
DS1302_CLK=0;
_nop_();
}
DS1302_RST=0;//RST 拉低
_nop_();
DS1302_CLK=1;//对于实物中,P3.4 口没有外接上拉电阻的,此处代码需要添加,使数
据口有一个上升沿脉冲。
_nop_();
DS1302_IO = 0;
_nop_();
DS1302_IO = 1;
_nop_();
return value;
}
/********************************************************************
***********
* 函 数 名 : ds1302_init
* 函数功能 : 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[i],gDS1302_TIME[i]);
}
ds1302_write_byte(0x8E,0X80);
}
/********************************************************************
***********
* 函 数 名 : ds1302_read_time
* 函数功能 : DS1302 读取时间
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void ds1302_read_time(void)
{
u8 i=0;
for(i=0;i<7;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数组是用来存储初始化时间,每个数据对应含义在代码内已做注释。在使用中主要调用ds1302init()函数和ds1302readtime()函数来初始化DS1302时钟数据以及读取DS1302时钟数据。

​ 在初始化时钟数据时,首先要禁止写保护即关闭写保护功能,然后将所需设置的时钟数据写入到对应的时钟寄存器地址内,最后打开写保护功能,以防止意外修改DS1302内部寄存器。对于读取时钟数据其实很简单,只要从对应的时钟寄存器地址内读取数据即可,然后将读取的数据存储到一个缓存数组中,方便数据的处理与显示,这个操作在后面main.c文件内会有。

main.c:

/********************************************************************
******************
实验名称: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。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TP6在composer包里写控制器

前提&#xff1a;首先要了解下如何自建composer包。 1.先建一个空包&#xff0c;加一个文件&#xff1a;composer.json {"name": "test/ctrs","type": "library","license": "MIT","autoload": {&quo…

亚马逊测评:如何有效使用IP和养号设备环境

随着网络科技的崛起&#xff0c;越来越多的本土企业入驻亚马逊电子商务平台上&#xff0c;这导致了对产品评价需求的激增。然而&#xff0c;评价并非随意进行&#xff0c;它需要多方面的资源&#xff0c;并需要密切注意一些重要环节。以下是我分享给大家一些宝贵的知识&#xf…

Modbus协议在TCP/IP上的运用

文章目录 1 Modbus规约2 Modbus TCP/IP2.1 概要2.2 0x01读线圈2.3 0x03读保持寄存器2.4 0x05写单个寄存器2.5 0x06写单个寄存器2.6 0x10写多个寄存器 3 实例&#xff08;ADU&#xff09; 1 Modbus规约 Modbus规约是典型的一问一答的通信规约&#xff0c;支持多种电气接口&#…

数据结构--顺序栈的实现

数据结构–顺序栈的实现 顺序栈的定义 顺序栈的定义代码实现 #define MaxSize 10 typedef struct {ElemType data[MaxSize]; //静态数组存放栈中元素int top; //栈顶指针 } SqStack;int main() {SqStack S; //声明一个顺序栈(分配空间)//... ...return 0; }一些常见操作 初始…

hyperf 学习 一、搭建

docker中ubuntu容器php语言hyperf框架开发环境搭建。 docker地址&#xff1a;Docker tag:20.04 docker pull ubuntu:20.04docker run --name hyperf -v D:\workspace\docker\hyperf:/wj/hyperf -p 9501:9501 -it --privileged -u root --entrypoint /bin/sh ubuntu:20.04步骤…

事务不同的隔离级别产生的脏读、不可重复读、幻读是什么

目录 1.什么是事务的隔离级别 2.脏读 3.不可重复读 4.幻读 1.什么是事务的隔离级别 1.声明式事务属性---事务隔离级别 2.设置隔离级别为默认级别&#xff08;在mysql中为可重复读&#xff09; Transactional(isolation Isolation.DEFAULT ) 3.什么是隔离级别&#xff…

SpringBoot - 在IDEA中经常发现:Could not autowire. No beans of ‘xxx‘ type found的错误

错误描述 在SPRINGBOOT的项目中&#xff0c;使用IDEA时经常会遇到Could not autowire. No beans of ‘xxxx’ type found的错误提示&#xff0c;但是程序的编译和运行都没有问题&#xff0c;这个错误提示并不影响项目的生产。 解决方案

【保姆级】Redis安装教程(Windows版)

Redis安装教程&#xff08;Windows版&#xff09; 文章目录 Redis安装教程&#xff08;Windows版&#xff09;1.下载安装包2. 安装注意事项3. 注意事项4. 登录Redis客户端5. 停止Redis服务附&#xff1a;详细安装步骤附&#xff1a;RESP&#xff08;Redis桌面管理&#xff09;使…

leetcode 145. 二叉树的后序遍历

2023.6.24 继上一题前序遍历&#xff0c;这道后序遍历就很容易了&#xff0c;把递归的顺序稍微改一下就行。 递归法&#xff1a; class Solution { public:void travelsal(TreeNode* cur , vector<int>& ans){if(cur nullptr) return;travelsal(cur->left , an…

【静态单元格 Objective-C语言】

一、预习QQ动态 1.我们今天,是三、到四个任务,第一个任务,就是这个,预习QQ动态 OK,看到这个效果了吗 这是咱们第一个任务,第一个任务,是实现这么一个效果, 一看这个,就肯定是个啥,UITableView吧, 是不是肯定是一个TableView啊 又能滚动,又能显示一行一行的数据…

解密:Prompt、Token、和completions是什么?

Prompt、Token、和completions 本文是科普向&#xff0c;大家放心阅读 在ChatGPT越来越火的时候&#xff0c;很多开发者都想大展拳脚&#xff0c;但在这之前&#xff0c;我们需要了解一些基础知识&#xff0c;比如你知道什么是token、什么是prompt、什么是Complemention Pro…

Windows 引导启动流程详述(BIOS-UEFI)

Windows 启动流程详述 BIOS 和 UEFI 的由来BIOS 存在哪里BIOS 程序的功能BIOS 和 UEFI 的发展由来如何查看当前计算机是什么方式引导启动呢&#xff1f;Linux 下如何查看 BIOS 大小&#xff1f; 启动流程详述使用 BIOS 进行系统启动流程使用 UEFI 进行系统启动流程SEC阶段PEI阶…

广州华锐互动:机电专业VR模拟实操教学平台提供沉浸式的实践操作和训练机会

虚拟现实(VR)技术是一种先进的技术&#xff0c;可以应用于机电专业的培训中。以下是VR技术应用到机电专业培训的一些好处&#xff1a; 模拟实际操作环境&#xff1a;VR技术可以创建一个虚拟的环境&#xff0c;模拟真实的机械和电气设备的操作环境。这使得学生可以在安全的环境…

自定义MVC

目录 一、MVC概念描述 1、什么是MVC&#xff1f; 2、什么是自定义MVC&#xff1f; 3、自定义MVC有什么用&#xff08;主要用途&#xff09;&#xff1f; 二、MVC三层架构 第一种版本 JSP页面 servlet 结果 第二种版本 JSP代码 servlet 结果 第三种版本 jsp页面 s…

Ubuntu18.04 系统设置修改物理内存-迅为RK3568开发板

打开虚拟机&#xff0c;如下图。单击红色框中的“虚拟机”。如下图所示&#xff1a; 然后点击“设置”弹出虚拟机的设置界面&#xff0c;如下图所示&#xff1a; 更多教程B站搜&#xff1a;迅为3568开发板

云原生运维实战 | 快速解决高可用K8s集群证书到期问题

欢迎关注「全栈工程师修炼指南」公众号 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; 专注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章 等知识分享 “ 花开堪折直须折&#xff0c;莫待无花空折枝。 ” 作者主页&#xff1…

(小程序)uniapp调接口完整流程

(小程序)uniapp调接口完整流程 代码&#xff1a; <script lang"ts" setup>import { ref } from "vue"; const form ref({searchVal: "", });//搜索const searchClick () > {console.log(form.value.searchVal)let data {text: form…

Redis高并发分布式锁

文章目录 高并发场景秒杀抢购超卖Bug高并发场景秒杀抢购Demo测试结果 JVM级别锁使用nginx对本地服务进行负载均衡 Redis实现分布式锁Redis分布式锁实现DemoRedis分布式锁有关问题 分布式锁性能的提升减少锁的粒度使用异步处理 高并发场景秒杀抢购超卖Bug 在今天的数字化世界中&…

Python操作SQLite数据库

文章目录 这篇博客很简单&#xff0c;简单记录下SQLite基础使用。有些数据文件是.db为扩展名的&#xff0c;要用到SQLite进行读写和增删改查操作。SQLite数据库是一种轻量级的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;以单个文件的形式存储&#xff0c;整…

【数据挖掘】时间序列教程【二】

2.4 示例&#xff1a;颗粒物浓度 在本章中&#xff0c;我们将使用美国环境保护署的一些空气污染数据作为运行样本。该数据集由 2 年和 5 年空气动力学直径小于或等于 3.2017 \&#xff08;mu\&#xff09;g/m\&#xff08;^2018\&#xff09; 的颗粒物组成。 我们将特别关注来自…