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

目录

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】 具有两个电源引脚,可以可以通过涓细电流对后备电源充电

引脚图

[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第1张图片

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

典型连接电路

[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第2张图片

原理图: 

[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第3张图片

时钟寄存器[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第4张图片

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

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

值得一提的是:

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

地址/命令字

前面我们讲过,在写入或读出数据之前,都需要提前发送对应的读写地址(指令),读写地址的指令如图:[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第5张图片

读写指令具有以下特点:

  • 最高位必须为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. 读时序

[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第6张图片

2.写时序[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第7张图片 

[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第8张图片

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

[IAP15F2K61S2]基于SPI三线协议Ds1302电子时钟_第9张图片

以写入操作为例:

单片机首先要将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 
#include 

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;//初始化led
	P2 = 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();
	}
}

你可能感兴趣的:(单片机,嵌入式硬件)