[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟

news/2024/12/15 10:02:55/

目录

DS1302

引脚图

典型连接电路

原理图: 

时钟寄存器​编辑

地址/命令字

读写指令具有以下特点:

SPI协议

        SPI总线概念

        1. 读时序

        2.写时序​编辑 

        写代码实现: 

         读代码实现:

Ds1302电子时钟代码实现(模块化设计)

ds1302.h

ds1302.c

Display_SMG.h

Display_SMG.c 

InitSystem.h

InitSystem.c

main.c


DS1302

DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,具有以下特点:
【1】 可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能。
【2】 31字节大小的RAM
【3】 工作电压:2.0~5.5V
【4】 采用三线接口的SPI通信协议
【5】 支持单字节和多字节(突发模式)传输
【6】 兼容TTL电平标准
【7】 具有两个电源引脚,可以可以通过涓细电流对后备电源充电

引脚图

其中:
X1、X2连接外部晶振,频率为32.768kHz不需要外界起振电容或者并联电阻
Vcc2:主电源引脚
Vcc1:后备电源引脚
SCLK::时钟线,用于提供时钟信号,内部接有40KΩ的下拉电阻(默认是低电平)
I/O:数据线,用于输入/输出逻辑0/1,内部接有40KΩ的下拉电阻 (默认是低电平)
CE:相当于复位引脚,在整个通信期间处于高电平,为低电平时不允许通信,内部接有40KΩ的下拉电阻 (默认是低电平)
 

典型连接电路

原理图: 

时钟寄存器

        图上左边两列分别是时钟寄存器的读地址(指令)、写地址(指令),当需要对寄存器进行读写操作时,需要先发送对应的读写地址(指令),方可对时钟寄存器的数据进行操作;
        从上往下对应的寄存器存储的分别是秒值、分钟值、小时值、日期、月份、星期、年份;
最右边一列是对应值的范围
其中:

CH:时钟暂停标志,当他的值为1是,时钟停止,当为0时,时钟正常工作
WP:写保护标志位,当位0时,允许对时钟寄存器进行写入操作,当为1时,不允许对时钟进行写入操作

值得一提的是:

        在时钟寄存器中,数据的存储方式是BCD码的格式,即高四位表示十进制数字的十位,第四位表示十进制数码的个位,再写入和读出的时候,需要对数据进行提前处理。
DS1302不会通过日期计算出星期,所以在设置日期的时候,需要将日期计算出确切的星期后一并写入

地址/命令字

前面我们讲过,在写入或读出数据之前,都需要提前发送对应的读写地址(指令),读写地址的指令如图:

读写指令具有以下特点:

  • 最高位必须为1,为0则无法进行通信
  • 第六位控制写入/读出的对象,为1则表示需要对RAM区域进行操作,为0则表示对时钟寄存器操作
  • 第一位到第五位用于选择需要操作的对象(时钟寄存器的标号)
  • 最低位控制数据是读出还是写入,为1是读出,为0是写入。

SPI协议

        SPI,是英语Serial Peripheral interface的缩写,意思为:串行外围设备接口。
在DS1302中采用的是3线制的SPI通信协议,分别是SCLK时钟线、I/O数据线、CE复位线

SPI总线概念

SPI接口的全称是“Serial Peripheral Interface”,意为串行外围接口

SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

SPI接口是在CPU和外围低速器件之间进行同步串行数据传输,在主器件的移位脉冲下,数据按位传输,高位在前,低位在后,为全双工通信,数据传输速度总体来说比I2C总线要快,速度可达到几Mbps。

SPI接口是以主从方式工作的,这种模式通常有一个主器件和一个或多个从器件,其接口包括以下四种信号:

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

下面是SPI的具体操作:

要点:在时钟的上升沿,单片机往时钟芯片写入数据;在时钟的下降沿,时钟芯片往单片机输出数据

在时序图中,只有红色方框框住的是时钟芯片控制的,其余绿色圆形圈住的都是单片机控制

1. 读时序

2.写时序 

 不管是读还是写都要给Ds1302写一个命令进去让1302知道下一个操作是什么 

以写入操作为例:

单片机首先要将CE置高电平,IO口的第一位是命令字的最低位,就是规定本次操作是读还是写,然后SCLK给个上升沿,第一位就被发送出去了,SCLK变回低电平,接着就是下一位A0,同样是上升沿就发送出去,待第一个字节(8位)全部发送出去后,此时便确定了要操作的地址以及操作的模式,是读还是写;

第二个字节便是数据,低地址在前,同样上升沿发送,发送完后,将CE置为低电平,整个写入时序完成

写代码实现: 

sbit SCK=P1^7;		//时钟线(SCLK)
sbit SDA=P2^3;		//数据线(I/O)
sbit RST=P1^3;    //复位线(CE)		// 写入读写地址(指令)
void Write_Ds1302(unsigned  char temp) 
{unsigned char i =0;for(i=0;i<8;i++){//循环八次写入地址(指令)  SCK = 0;SDA = temp & 0x01;//单片机通过 I/O写入数据位temp >>= 1;SCK = 1;    //DS302在每一个上升沿读取一次I/O的电平信号}
}//写入一个字节的数据函数,address为读写地址(指令),dat为写入的数据
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )    
{RST = 0;_nop_();SCK = 1;_nop_();RST = 1;_nop_();Write_Ds1302(address);// 写入读写地址(指令)Write_Ds1302(data);//写入读写数据(指令)RST = 0;//结束本次通讯
}

 读代码实现:

sbit SCK=P1^7;		//时钟线(SCLK)
sbit SDA=P2^3;		//数据线(I/O)
sbit RST=P1^3;    //复位线(CE)unsigned char Read_Ds1302_Byte ( unsigned char address )
{unsigned char i =0;unsigned char tmp = 0x00;RST = 0;_nop_();SCK = 1;_nop_();RST = 1;_nop_();Write_Ds1302(address);//不管是读还是写都要给Ds1302写一个命令进去让1302直到下一个操作是什么 for(i=0;i<8;i++){SCK = 0;tmp >>= 1;if(SDA){tmp = tmp | 0x80;}else{tmp = tmp | 0x00;}SCK = 1;}RST = 0;//通信结束SCK=0;	_nop_();SCK=1;	_nop_();SDA=0;	_nop_();SDA=1;	_nop_();return (tmp);			}

Ds1302电子时钟代码实现(模块化设计)

ds1302.h

#ifndef __DS1302_H
#define __DS1302_H#include <reg52.h>
#include <intrins.h>sbit SCK = P1^7;		
sbit SDA = P2^3;		
sbit RST = P1^3; void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );#endif

ds1302.c

#include "reg52.h"								
#include "ds1302.h"//写字节
void Write_Ds1302(unsigned  char temp) 
{unsigned char i;for (i=0;i<8;i++)     	{ SCK = 0;SDA = temp&0x01;temp>>=1; SCK=1;}
}   //向DS1302寄存器写入数据
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{RST=0;	_nop_();SCK=0;	_nop_();RST=1; 	_nop_();  Write_Ds1302(address);	Write_Ds1302(dat);		RST=0; 
}//从DS1302寄存器读出数据
unsigned char Read_Ds1302_Byte ( unsigned char address )
{unsigned char i,temp=0x00;RST=0;	_nop_();SCK=0;	_nop_();RST=1;	_nop_();Write_Ds1302(address);for (i=0;i<8;i++) 	{		SCK=0;temp>>=1;	if(SDA)temp|=0x80;	SCK=1;} RST=0;	_nop_();SCK=0;	_nop_();SCK=1;	_nop_();SDA=0;	_nop_();SDA=1;	_nop_();return (temp);			
}

Display_SMG.h

#ifndef _Display_SMG_H
#define _Display_SMG_H
unsigned  char code  NixieTube1[];
unsigned char Timer[];//数组声明不用在[]写数组个数
void Display_SMG();
void Delay(unsigned char t);//函数声明如果有形参必须要写上
void Display_Bit(unsigned char pos,unsigned char dat);									 
#endif

Display_SMG.c 

#include "reg52.h"
#include "Display_SMG.h"unsigned  char code  NixieTube1[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,       //数码管段码表/* A   B     C    D    E    F    H    L    N    P */0x88,0x83,0xC6,0xA1,0x86,0x8E,0x89,0xC7,0xC8,0x8C,/* U    -   ' ' */0xC1,0xBF,0xFF};//23年2月6日周一20:03:30s
unsigned char Timer[7] = {0x30,0x03,0x20,0x06,0x02,0x01,0x23};void Delay(unsigned char t)
{while(t--);
}void Display_Bit(unsigned char pos,unsigned char dat)
{P2 = (P2&0x1f)|0xc0;P0 = 0x01 << pos;P2 = (P2&0x1f)|0xe0;P0 = dat;
}
void Display_SMG()
{Display_Bit(0,NixieTube1[Timer[2]/16]);Delay(100);Display_Bit(1,NixieTube1[Timer[2]%16]);Delay(100);Display_Bit(2,0xbf);Delay(100);Display_Bit(3,NixieTube1[Timer[1]/16]);Delay(100);	Display_Bit(4,NixieTube1[Timer[1]%16]);Delay(100);	Display_Bit(5,0xbf);Delay(100);	Display_Bit(6,NixieTube1[Timer[0]/16]);Delay(100);	Display_Bit(7,NixieTube1[Timer[0]%16]);
}

InitSystem.h

#ifndef _InitSystem_H
#define	_InitSystem_H
void InitSystem();#endif

InitSystem.c

#include "reg52.h"
#include "InitSystem.h"void InitSystem()
{P2 = P2&0x1f|0x80;P0 = 0xff;//初始化ledP2 = P2&0x1f|0xa0;P0 = 0x00;//初始化蜂鸣器
}

main.c

#include "reg52.h"
#include "ds1302.h"  		
#include "Display_SMG.h"
#include "InitSystem.h"code unsigned char Write_Ds1302_addr[7] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
code unsigned char Read_Ds1302_addr[7] 	= {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
code unsigned char DS1302_Timer[7] 			= {0x56,0x59,0x23,0x12,0x01,0x04,0x23};  void Config_Time()
{unsigned char i;Write_Ds1302_Byte(0x8E,0x00);for(i=0;i<7;i++){Write_Ds1302_Byte(Write_Ds1302_addr[i],Timer[i]);}Write_Ds1302_Byte(0x8E,0x80);
}void Read_Time()
{unsigned char i;for(i=0;i<7;i++){Timer[i] = Read_Ds1302_Byte(Read_Ds1302_addr[i]);}
}void main()
{InitSystem();Config_Time();while(1){Read_Time();Display_SMG();}
}


http://www.ppmy.cn/news/461733.html

相关文章

USB TYPE -A -B -C 接口

1. USB TYEP -A 普通电脑上那个USB口&#xff0c;称为A口母座&#xff0c;对应的插头&#xff0c;称为A口公头&#xff0c;A口主要的作用是作为数据及电源的下行端口&#xff0c;即拥有A口母座的设备&#xff0c;在电源上来说&#xff0c;属于供电设备**(TYPE-C中称为SRC即SOU…

51单片机P0/P1/P2/P3端口的区别

传统的以MCS-51为基础的8051内核单片机通常有4个双向8位I/O接口&#xff0c;它们是P0、P1、P2、P3。在无外接存储器时&#xff0c;这4个I/O接口均可以作为通用I/O接口使用&#xff0c;CPU既可以对它们进行字节操作也可以进行位操作。 1.P0口 一个双向IO口&#xff0c;可作为低8…

Type-C接口简单介绍-面向单片机应用

Type-C接口简单介绍-面向单片机应用 1、绪论 用单片机做一些东西时&#xff0c;Type-C接口逐渐替代了MicroUSB接口。但不像MicroUSB那样只有5V、GND、D、D-、ID五个接口&#xff0c;Type-C接口有24个引脚&#xff0c;比较复杂。大多时候我们用TypeC也用不到USB3.0协议&#x…

2PC与Seata简介

在大多数场景下&#xff0c;应用只需要操作单一的数据库&#xff0c;这种情况下的事务称之为本地事务&#xff0c;本地事务的ACID特性&#xff0c;数据库直接提供支持。 在微服务架构下&#xff0c;如果应用操作的资源位于多个资源服务器&#xff0c;需要操作多个数据库时&…

epcis 之OPI接口工具cs-studio安装与使用指南

epcis 之OPI接口工具css 安装与使用指南 linux版本安装请参考链接&#xff1a; https://blog.csdn.net/weixin_42066185/article/details/106530508 本文介绍的是windows系统安装 一、 CSS的安装 安装之前需要建立java环境&#xff0c;java版本要和CSS需要的java环境对应。…

SAI接口

https://www.nxpic.org.cn/document/id-17022 https://doc.embedfire.com/linux/imx6/base/zh/latest/linux_basis/audio_video.html 在所有 i.MX 串行 SoC 中&#xff0c;i.MX28/i.MX6UL/i.MX7D/S 使用同步音频接口&#xff08;SAI&#xff09;来支持音频应用。SAI 支持 I2S…

激活window10专业版的方法。

以管理员身份打开window10终端&#xff0c;输入以下三条命令即可激活window10专业版 slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX slmgr /skms zh.us.to slmgr /ato

【C数据结构】带头双向循环链表_HDList

目录 带头双向循环链表_HDList 【1】链表概念 【2】链表分类 【3】带头双向循环链表 【3.1】带头双向循环链表数据结构与接口定义 【3.2】带头双向循环链表初始化 【3.3】带头双向循环链表开辟节点空间 【3.4】带头双向循环链表销毁 【3.5】带头双向循环链表头插 【3…