目录
DS1302
引脚图
典型连接电路
原理图:
时钟寄存器编辑
地址/命令字
读写指令具有以下特点:
SPI协议
SPI总线概念
1. 读时序
2.写时序编辑
写代码实现:
读代码实现:
Ds1302电子时钟代码实现(模块化设计)
ds1302.h
ds1302.c
Display_SMG.h
Display_SMG.c
InitSystem.h
InitSystem.c
main.c
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不会通过日期计算出星期,所以在设置日期的时候,需要将日期计算出确切的星期后一并写入
前面我们讲过,在写入或读出数据之前,都需要提前发送对应的读写地址(指令),读写地址的指令如图:
SPI,是英语Serial Peripheral interface的缩写,意思为:串行外围设备接口。
在DS1302中采用的是3线制的SPI通信协议,分别是SCLK时钟线、I/O数据线、CE复位线
SPI接口的全称是“Serial Peripheral Interface”,意为串行外围接口
SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI接口是在CPU和外围低速器件之间进行同步串行数据传输,在主器件的移位脉冲下,数据按位传输,高位在前,低位在后,为全双工通信,数据传输速度总体来说比I2C总线要快,速度可达到几Mbps。
SPI接口是以主从方式工作的,这种模式通常有一个主器件和一个或多个从器件,其接口包括以下四种信号:
MOSI – 主器件数据输出,从器件数据输入
MISO – 主器件数据输入,从器件数据输出
SCLK – 时钟信号,由主器件产生
/CS – 从器件使能信号,由主器件控制
下面是SPI的具体操作:
要点:在时钟的上升沿,单片机往时钟芯片写入数据;在时钟的下降沿,时钟芯片往单片机输出数据
在时序图中,只有红色方框框住的是时钟芯片控制的,其余绿色圆形圈住的都是单片机控制的
不管是读还是写都要给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);
}
#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
#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);
}
#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
#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]);
}
#ifndef _InitSystem_H
#define _InitSystem_H
void InitSystem();
#endif
#include "reg52.h"
#include "InitSystem.h"
void InitSystem()
{
P2 = P2&0x1f|0x80;
P0 = 0xff;//初始化led
P2 = P2&0x1f|0xa0;
P0 = 0x00;//初始化蜂鸣器
}
#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();
}
}