文章目录

  • SPI总线的概念
  • 什么是实时时钟
  • DS1302介绍
  • DS1302寄存器
  • Ds1302附加31字节静态RAM
  • 时序图和控制指令
  • 参考例程

SPI总线的概念

SPI接口全称“serial peripheral Interface”,意为串行外围接口
SPI接口是在CPU外围低速之间进行数据传输,在主器件的移位脉冲下,数据按位传输,高位在前,低位在后,为全双工通信
SPI以主从方式工作,这种模式通常有一个主器件和一个或多个器件,一般包含4根线。

MOSI——主器件数据输出,从器件数据输入
MISO——主器件数据输入,从器件数据输出
SCLK——时钟信号,由主器件产生
CS/SS——从器件使能信号,由主器件控制

在SPI应用中也有三线制的SPI,实现半双工通信

SPI总线接口连接

什么是实时时钟

RTC:Real Time Clock

我们知道单片机内部有定时器,但定时器只能表示一个时间段,这不是唯一的时间。比如我们应用单片机写一个交通灯;当我们应用单片机来表示一个时间点,这是唯一的,表示单片机需要做一些必须到某一个时间才能做的事情,所以需要用到RTC,如应用单片机写一个定时炸弹,这时我们就需要实时的时钟计时。使用实时的实时计时还有一个好处就是能够减少时间的误差。
关于RTC,在钟表、电子日历、手表、智能手环等都有实际应用。
在STM32F103系列的MCU中,已集成有RTC外设,是一个掉电后还能继续运行的定时器,从定时器角度来说,相当于定时器外设。它十分简单,只有很纯粹的中断和触发功能。

DS1302介绍

用一句话总结DS1302:内部存着一个时间点信息(年月日时分星期几)可以读写
DS1302内部还有31*8RAM用于临时存储数据;
工作电压范围在2.0V-5.5V之间。当工作在低功耗模式下(2.0V)时,消耗不少于300nA。;
DS1302传输时钟和内存数据有单字节或多字节(突发模式);
有8-pin DIP或8-pin SOIC封装可选;3线SPI通信接口,兼容TTL(5V)电平,兼容DS1202。

管脚说明:
Vcc2:双电源配置中的主电源
X1、X2:与标准的32.768KHZ晶振相连
GND:电源地
CE:使能,CE信号在读写必须保持高电平
I/O:数据
SCLK:时钟
Vcc1:低功率工作单电源和低功率备用电源



DS1302和单片机的IO连接只需3根线:CE数据传输使能、SCLK串行时钟输入端、I/O串行数据端,同时3个引脚分别接4.7K上拉电阻。

关于钟表里的晶振为什么是32.768KHZ的晶振?
钟表运行需要需要一个精准的节拍器,机械钟表依靠的是机械摆,电阻钟表依靠的就是晶振了。晶振能够提供精准稳定的节拍,常用的晶振是32.768KHZ晶振,也就是每秒跳动32768次,对于二进制运行的电子表、计算机来说,32768是一个整数。
对于二进制运行的电子钟表里,有一个16位的计数器,十进制的32768刚好是16位二进制的“1000 0000 0000 0000”。钟表里的晶振每秒跳动32768次就是每秒加32768个1,这样在16位加1速度就被减慢到秒1次。
用32768晶振还有一个好处,晶振的误差体现到秒是上面只有1/32768。
那么为什么不选择更加高频或者低频的晶振呢?
综合成本考虑,32.768KHZ晶振已经是属于低频产品,再低体积会增大,和它搭配的负载电容也会增大,不适合小型化的钟表;如果选择更高频率的晶振对于数字电路来说,工作频率越高,就意味着更高的电力消耗,32768这个频率已经能满足精度和成本要求,也能满足低功耗要求,所有没必要使用到更高的频率。
在数字电路中,晶振决定电路的生与死、好与坏,也会影响到系统 稳定性。

DS1302寄存器


秒寄存器(81h、80h):bit7定义为时钟暂停标志(CH),当该位置为1时,时钟震荡停止,DS1302处于低功耗状态;当置0时,时钟开始运行。
小时寄存器(85h、84h):bit7定义是运行于12小时模式/24小时模式,当为1时选择12小时模式,此时bit5为AM/PM位,在24小时模式时为小时数据位。
控制寄存器(8Fh、8Eh):bit7是写保护位(WP)其他7位均为0.在任何对时钟或者RAM读写操作之前,WP必须为0.当WP为1时,不能对任何时钟日历寄存器或RAM进行读写操作。
突发模式:突发模式是指一次传输多个字节的时钟信号或RAM数据。

Ds1302附加31字节静态RAM

时序图和控制指令


命令字是启动数据传输的控制指令
bit7必须使逻辑1,如果是0则禁止对DS1302写入
bit6在逻辑0时规定为时钟/日历日历数据,为1时规定为RAM数据
bit1-bit5表示输入/输出指定的寄存器
bit0在逻辑0时为写操作,逻辑1时为读操作

参考例程

/***********************************************************功能:STC12C5A60S2单片机在LCD1602液晶显示DS1302时钟日历*备注:按照DS1302接口定义用杜邦线连接*版本:V1.0开源***作者:小途*编写时间:2022年9月16日***********************************************************/#include <STC12C5A60S2.h>
#include <intrins.h>#define uchar unsigned char
#define uint unsigned int//宏定义
#define MAIN_Fosc       11059200UL  //宏定义主时钟HZ
#define LCD1602_DB P0   //LCD1602数据总线
#define DS1302_W_ADDR 0x80  //写时钟日历寄存器起始地址
#define DS1302_R_ADDR 0x81  //读时钟日历寄存器起始地址//时钟日历暂存数组,秒、分、时、日、月、周、年 初值为= 22年9月15日 周四 23:59:00
uchar TimeData[7]={00, 59, 23, 15, 9, 4, 22};//LCD1602端口定义
sbit LCD1602_RS = P3^5;     //RS端
sbit LCD1602_RW = P3^6;     //RW端
sbit LCD1602_EN = P3^4;     //EN端//DS1302端口定义
sbit TSCLK = P1^0; //时钟
sbit TIO = P1^1;   //数据
sbit TRST = P1^2;  //使能/*=================================================
*函数名称:Delay_Ms
*函数功能:STC12自适应主时钟毫秒级延时函数
*说明:需定义MAIN_Fosc(晶振主频单位HZ)
*输入:ms:要延时的毫秒
=================================================*/
void Delay_Ms(uint ms)
{uint i;do{i = MAIN_Fosc / 96000; while(--i);   //96T per loop}while(--ms);
}/*=================================================
*函数名称:DS1302_W_Byte
*函数功能:DS1302写一字节数据
*输入:dat:要写入的数据
=================================================*/
void DS1302_W_Byte(uchar dat)
{uchar i;for(i = 0; i < 8; i++) //每次写1bit,写8次{TSCLK = 0;         //拉低时钟总线TIO = dat & 0x01;  //从一字节最低位开始写TSCLK = 1;         //拉高时钟总线,DS1302把数据读走dat >>= 1;        //数据右移一位 }
}
/*=================================================
*函数名称:DS1302_R_Byte
*函数功能:DS1302读一字节
*输出:dat:读取的数据
=================================================*/
uchar DS1302_R_Byte()
{uchar i, dat;for(i = 0; i < 8; i++)  //每次写1bit,写8次{TSCLK = 0;            //拉低时钟总线,DS1302把数据放到数据总线上dat >>= 1;           //数据右移一位,数据从最低位开始读 if(TIO)   dat |= 0x80;//读取数据TSCLK = 1;          //拉高时钟总线}return dat;                //返回读取的数据
}
/*=================================================
*函数名称:DS1302_W_DAT
*函数功能:写DS1302数据一次写2个字节
*说明:先写命令后写数据
*调用:DS1302_W_Byte()
*输入:cmd:需要写的命令 ,dat:需要些的数据
=================================================*/
void DS1302_W_DAT(uchar cmd, uchar dat)
{TRST = 0;          //拉低使能端TSCLK = 0;          //拉低数据总线TRST = 1;          //拉高使能端,开始写数据DS1302_W_Byte(cmd);     //写命令DS1302_W_Byte(dat);    //写数据
}
/*=================================================
*函数名称:DS1302_R_DAT
*函数功能:读DS1302数据
*说明:先写入命令字节后读出对应数据
*调用: DS1302_W_Byte();DS1302_R_Byte();
*输入: cmd:需要写的命令
*输出: dat:读出的数据
=================================================*/
uchar DS1302_R_DAT(uchar cmd)
{uchar dat;TRST = 0;               //拉低使能端TSCLK = 0;              //拉低数据总线TRST = 1;              //拉高使能端,开始写数据DS1302_W_Byte(cmd);     //写命令dat = DS1302_R_Byte();    //读出数据return dat;               //返回读出数据
}/*=================================================
*函数名称:DS1302_Clear_WP
*函数功能:清除DS1302写保护
*说明:先写入命令0x8e(写控制寄存器)接着向该寄存器写0
*调用:DS1302_W_DAT()
=================================================*/
void DS1302_Clear_WP()
{DS1302_W_DAT(0x8e,0x00);  //把控制寄存器WP位置0
}
/*=================================================
*函数名称:DS1302_Clear_WP
*函数功能:设置DS1302写保护
*说明:先写入命令0x8e(写控制寄存器)接着向该寄存器写0x80
*调用:DS1302_W_DAT()
=================================================*/
void DS1302_Set_WP()
{   DS1302_W_DAT(0x8e,0x80); //把控制寄存器WP位置1TRST = 0;                 //拉低使能端TSCLK = 0;              //拉低数据总线
}
/*=================================================
*函数名称:Set_DS1302_Time
*函数功能:设置DS1302时钟日历数据
*说明:把时钟日历暂存数组TimeData数据转换为BCD码并写入到DS1302时钟日历寄存器中
*调用:DS1302_Clear_WP();DS1302_W_DAT();DS1302_Set_WP();
*输入:addr:需要写入寄存器的地址 ,TimeData数组:时钟日历初始值
=================================================*/
void Set_DS1302_Time(uchar addr)
{uchar i, j;DS1302_Clear_WP();      //清除写保护for(i = 0; i < 7; i++) //写入7个字节的时钟初始值{j = TimeData[i]/10;  //BCD码转换TimeData[i] %= 10;     //BCD码转换TimeData[i] += j*16; //BCD码转换DS1302_W_DAT(addr, TimeData[i]); //先写DS1302时钟日历起始地址,再写数据addr += 2;  //时钟日历寄存器地址+2转向下一个寄存器}DS1302_Set_WP(); //开起写保护
}
/*=================================================
*函数名称:Read_DS1302_Time
*函数功能:读取DS1302时钟数据
*说明: 读取DS1302时钟数据 返回数据存入时钟日历暂存数组TimeData(数据格式BCD码)
*调用:DS1302_Clear_WP();DS1302_R_DAT();DS1302_Set_WP();
*输入: addr:需要读取时钟日历寄存器的起始地址
=================================================*/
void Read_DS1302_Time(uchar addr)
{uchar i;DS1302_Clear_WP();     //清楚些保护for(i = 0; i < 7; i++) //从DS1302读取7个字节的时钟日历数据{TimeData[i] = DS1302_R_DAT(addr);//先写入要读取数据的寄存器起始地址,再读出数据存入TimeData数组addr += 2;                         //时钟日历寄存器地址+2转向下一个寄存器}DS1302_Set_WP();   //开起写保护
} /*=================================================
*函数名称:Read_Busy
*函数功能:判断1602液晶忙,并等待
=================================================*/
void Read_Busy()
{uchar busy;LCD1602_DB = 0xff;//复位数据总线LCD1602_RS = 0;   //拉低RSLCD1602_RW = 1;      //拉高RW读do{LCD1602_EN = 1;//使能ENbusy = LCD1602_DB;//读回数据LCD1602_EN = 0;  //拉低使能以便于下一次产生上升沿}while(busy & 0x80); //判断状态字BIT7位是否为1,为1则表示忙,程序等待
}
/*=================================================
*函数名称:LCD1602_Write_Cmd
*函数功能:写LCD1602命令
*调用:Read_Busy();
*输入:cmd:要写的命令
=================================================*/
void LCD1602_Write_Cmd(uchar cmd)
{Read_Busy();    //判断忙,忙则等待LCD1602_RS = 0;LCD1602_RW = 0;  //拉低RS、RW操作时序情况1602课件下中文使用说明基本操作时序章节LCD1602_DB = cmd;//写入命令LCD1602_EN = 1;     //拉高使能端 数据被传输到LCD1602内LCD1602_EN = 0;  //拉低使能以便于下一次产生上升沿
}
/*=================================================
*函数名称:LCD1602_Write_Dat
*函数功能:写LCD1602数据
*调用:Read_Busy();
*输入:dat:需要写入的数据
=================================================*/
void LCD1602_Write_Dat(uchar dat)
{Read_Busy();LCD1602_RS = 1;LCD1602_RW = 0;LCD1602_DB = dat;LCD1602_EN = 1;LCD1602_EN = 0;
}
/*=================================================
*函数名称:LCD1602_Dis_OneChar
*函数功能:在指定位置显示一个字符
*调用:LCD1602_Write_Cmd(); LCD1602_Write_Dat();
*输入:x:要显示的横坐标取值0-40,y:要显示的行坐标取值0-1(0为第一行,1为第二行)dat:需要显示的数据以ASCLL形式显示
=================================================*/
void LCD1602_Dis_OneChar(uchar x, uchar y,uchar dat)
{if(y)  x |= 0x40;x |= 0x80;LCD1602_Write_Cmd(x);LCD1602_Write_Dat(dat);
}//显示一个字节字符
void DisplayOneStr(uchar X,uchar Y,uchar DData)
{LCD1602_Dis_OneChar (X++,Y,DData/16 + '0');LCD1602_Dis_OneChar (X,Y,DData%16 + '0');
}/*=================================================
*函数名称:LCD1602_Dis_Str
*函数功能:在指定位置显示字符串
*调用:LCD1602_Write_Cmd(); LCD1602_Write_Dat();
*输入:x:要显示的横坐标取值0-40,y:要显示的行坐标取值0-1(0为第一行,1为第二行)*str:需要显示的字符串
=================================================*/
void LCD1602_Dis_Str(uchar x, uchar y, uchar *str)
{if(y) x |= 0x40;x |= 0x80;LCD1602_Write_Cmd(x);while(*str != '\0'){LCD1602_Write_Dat(*str++);}
}
/*=================================================
*函数名称:Init_LCD1602
*函数功能:1602初始化
*调用: LCD1602_Write_Cmd();
=================================================*/
void Init_LCD1602()
{LCD1602_Write_Cmd(0x38); //    设置16*2显示,5*7点阵,8位数据接口LCD1602_Write_Cmd(0x0c); //开显示LCD1602_Write_Cmd(0x06); //读写一字节后地址指针加1LCD1602_Write_Cmd(0x01); //清除显示
}void main()
{uchar TestStr[] = {"Date:"};uchar str[] = {"Time:"};Init_LCD1602();                         //1602初始化Set_DS1302_Time(DS1302_W_ADDR);         //写入时钟日历寄存器起始地址再设置时钟日历初始值LCD1602_Dis_Str(0, 0, &TestStr[0]);        //显示字符串LCD1602_Dis_Str(0, 1, &str[0]);          //显示字符串while(1){Read_DS1302_Time(DS1302_R_ADDR);        //先写入时钟日历寄存器起始地址再读出时钟日历写入到TimeData数组中DisplayOneStr (5,0,TimeData[6]);       //年LCD1602_Dis_OneChar (7,0,'-');         //-DisplayOneStr (8,0,TimeData[4]);         //月LCD1602_Dis_OneChar (10,0,'-');            //-DisplayOneStr (11,0,TimeData[3]);        //日LCD1602_Dis_OneChar (13,0,'-');            //-DisplayOneStr (14,0,TimeData[5]);        //星期DisplayOneStr (6,1,TimeData[2]);        //时LCD1602_Dis_OneChar (8,1,':');         //:DisplayOneStr (9,1,TimeData[1]);      //分LCD1602_Dis_OneChar (11,1,':');            //:DisplayOneStr (12,1,TimeData[0]);     //秒Delay_Ms(1000);                          //延时1秒}
}

STC12C5A60S2软件模式SPI读取DS1302时钟实时显示在1602相关推荐

  1. 读取海康威视摄像头实时显示视频流

    提示:文章用于学习记录 文章目录 前言 一.设置同一网段 二.密码重置 三.VLC 读取视频流 四.opencv 读取视频流 总结 前言 摄像头一般有网线和电源线两个接口,如下图所示, 用网线将摄像头 ...

  2. 【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片

    目录 硬知识 DS1302 简介 DS1302 使用 控制寄存器 日历/时钟寄存器 DS1302 的读写时序 电路设计 示例程序 DS1302.c DS1302.h 测试程序 main.c 实验现象 ...

  3. 51单片机DS18B20+DS1302+LCD12864实时显示时间日期温度

    文章目录 介绍 Proteus仿真运行效果 源程序 主函数 DS1302时钟函数 DS18B20函数 LCD12864(不带字库) sharing函数 mine头文件 介绍 DS18B20采集温度 D ...

  4. javascript实现 时钟实时显示及幻灯片自动播放

    动态时钟的实现--实时显示时间 <!DOCTYPE html> <html><head><meta http-equiv="Content-Type ...

  5. 51单片机DS1302时钟LCD1602显示(可以按键设置时钟)

    DS1302实时时钟具有能计算2100年之前的秒.分.时.日.日期.星期.月.年的能力,还有闰年调整的能力. 图1:DS1302引脚示意图 其中: X1.X2:32.768KHz晶振接入引脚. GND ...

  6. DS1302时钟(显示时间,不可调)

    DS1302.H```c 在这里插入代码片 #define _DS1302_H__extern unsigned char DS1302_Time[];void DS1302_Init(void);/ ...

  7. 七段数码管数字时钟实时显示显示(年月日时分秒)

    用数码管显示系统实时时间需要用到turtle.datetime以及time这三个函数,调出系统时间进行运用并控制数码管绘制过程实现这一程序! 最后呈现出来的结果会是一个动态的数码管,每秒钟刷新一次,来 ...

  8. 使用51单片机和DS1302时钟芯片做一个简易的电子时钟

    简易的电子时钟实验 一.前言 二.DS1302模块介绍 三.驱动DS1302的代码 3.1 初始化DS1302时钟芯片 3.2 读取DS1302时钟芯片的时间 3.3 设置DS1302时钟芯片的时间 ...

  9. STM32软硬件SPI读取MAX31865 PT100温度支持shell功能

    PT100的温度读取硬件是利用TB的MAX31865现成模块,也可以自己做相应的PCB.原理图可以查看美信官方文档作为参考.传送门:https://www.maximintegrated.com/en ...

最新文章

  1. Java解决递归栈溢出_方法递归调用中java栈溢出的问题 及 解答 | 学步园
  2. c语言考试经典编程题目及答案,经典练习C语言编程的题目及答案整理
  3. python 易支付sdk
  4. appium定位WebView页面元素
  5. 纪念第一个正式的java程序
  6. html 后# 号的作用,及html 如何传参
  7. MongoDB---之---可视化客户端
  8. php--字符串常用函数
  9. 云主机挂载硬盘 - 开机自动挂载
  10. VS Code远程连接矩池云GPU主机
  11. 给已经做好的GHO文件添加密码
  12. CentOS+postfix+ExtMail+amavisd-new+Spam_Locker+DSpam配置指南:七、配置Webmail-ExtMail
  13. 仿微信小程序小空投(头)iApp源码+PHP后端
  14. 给Java程序猿们推荐一些值得一看的好书
  15. matlab神经网络训练图解释,matlab实现神经网络算法
  16. R语言入门(第一篇)--R软件基本操作
  17. 法语语法学习笔记——代词(2)
  18. 并购支付牌照中金支付90.01%股权该注意哪些风险
  19. dataframe删除原来索引,使新索引从0开始
  20. 程序员的四个等级:菜鸟、普通、大牛、大神

热门文章

  1. OpenCV:vector subscript out of range
  2. 全国 省市区 经纬度 (XML格式)
  3. 图片加水印怎么加,快速图片加水印?
  4. python弹出框多一个空白框_python – 自定义/删除Django选择框空白选项
  5. Informix 12.10版本新特性-2
  6. 极简风格的演讲型幻灯片设计
  7. linux系统安装绿色版mysql
  8. 使用oracle.jdbc.OracleDriver
  9. 盛姓取名女孩儒雅大气
  10. 镜子法则--看得人泪流满面!