目录
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();}
}