蓝桥杯单片机学习计划之DS1302时钟
前言
上一节介绍了DS18B20温度传感器的通讯方式以及使用方法,编写程序实现数码管显示环境温度,这一节我们来学习DS1302时钟模块。
一、DS1302介绍
1.芯片介绍
DS1302是一款涓流充电计时芯片,其内部包含一个实时时钟和31字节的静态RAM。实时时钟可以提供秒、分、时、日、日期、月和年的信息,并且小时具有24小时和12小时两种格式。其掉电时保持数据和时钟走时的功耗能够小于1uw。下面来看下它的引脚分布和介绍:
1脚和8脚是两个双电源供电的引脚,1脚Vcc2是主电源引脚,8脚Vcc1是备用电源引脚用于在没有主电源的情况下保持时间和日期,当Vcc2引脚上的电压大于Vcc1 +0.2V时,Vcc2为DS1302供电,当Vcc2小于Vcc1电压是,Vcc1为DS1302供电。即Vcc2用于连接电源电压,Vcc1可连接一个纽扣电池,如果断开电源电压,纽扣电池可以为DS1302提供电源,保持其内部的数据和时钟。
X1和X2是外接晶振的引脚,连接32.768KHZ晶振。
SCLK、I/O、CE是三个用于数据通信的引脚,SCLK是时钟引脚,I/O是数据传输引脚,CE是芯片使能引脚。
来看下竞赛板原理图:
从上面原理图中我们可以看到,三个通信引脚分别连接到了P17、P23、P13三个引脚上。
2.通信方式介绍
1.命令字节
对于DS1302来说,不管是写数据还是读数据,主机都要先发送一个命令字节告诉DS1302要读写那个寄存器,这个命令字节如下图所示:
第七位固定为1;第6位选择RAM和时钟,"0"选择时钟,"1"选择RAM;第5位到第1位是各个寄存器的地址;第0位选择读写操作方式,"0"选择写数据,"1"选择读数据。
各个寄存器定义如下图所示:
每个寄存器的读写地址表里都给出来了,写代码时直接查表即可。下面来分别解析一下这几个时间的寄存器:
第一个为秒寄存器,第七位是时钟运行标志位,如果这一位为1,则时钟振荡器停止工作,DS1302进入低功耗待机模式,如果为0则时钟启动。第6位——第4位是秒的十位,第3位——第0位是秒的个位。
第二个为分寄存器,第七位选择24小时模式或者12小时模式,如果为0则表示24小时模式,第5位是24小时模式下的十位。
其他的寄存器都是前四个位为十位,后四位为个位。
2.写数据
向DS1302写入数据时,首先主机需要将使能引脚CE拉高,并且在整个通信过程中都需要保持高电平不变;然后在SCLK时钟的作用下通过I/O引脚将数据按位发送出去,即每来一个SCLK时钟,发送一位数据。发送数据时,第一个字节发送命令字节,然后发送数据字节。从下图中可以看到,数据需要在SCLK上升沿之前准备好,到达上升沿时会发送出去。(注意数据从低位先开始发)
3.读数据
读数据过程和写数据相同,只不过发送命令字节后是主机从DS1302读取数据。
三、代码
#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);
}
void Write_Ds1302_InitTime()
{
Write_Ds1302_Byte(0x8E,0x00);
Write_Ds1302_Byte(0x84,0x19);
Write_Ds1302_Byte(0x82,0x20);
Write_Ds1302_Byte(0x80,0x00);
}
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "ds1302.h"
unsigned char SEG_Code[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//0-9段码
unsigned char SEG_Buf[8];//显示数据缓冲区
bit timer_flag_1ms;
void Seg_Display()//数码管扫描函数
{
static unsigned char seg_index=0;//显示数据索引
static unsigned char seg_temp=0x01;//位索引
P2 = (P2&0x1f) | 0xC0; //消隐
P0= 0x00;
P2=0x00;
P2 = (P2&0x1f) | 0xE0;//选通段锁存器
P0=SEG_Buf[seg_index++]; //送入段码
P2=0x00;
P2 = (P2&0x1f) | 0xC0;//选通位锁存器
P0= seg_temp;//送入位码
P2=0x00;
seg_temp<<=1;
if(seg_index>7)
{
seg_index=0;
seg_temp=0x01;
}
}
void main()
{
unsigned char Hr,sec,min;
unsigned int cnt;
Write_Ds1302_InitTime();
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;//开启定时器0中断
EA=1;//开启总中断
while(1)
{
if(timer_flag_1ms)
{
timer_flag_1ms=0;
if(++cnt>=500)
{
cnt=0;
Hr=Read_Ds1302_Byte(0x85);
min=Read_Ds1302_Byte(0x83);
sec=Read_Ds1302_Byte(0x81);
SEG_Buf[0]=SEG_Code[Hr>>4];
SEG_Buf[1]=SEG_Code[Hr&0x0f];
SEG_Buf[2]=0xBF;
SEG_Buf[3]=SEG_Code[min>>4];
SEG_Buf[4]=SEG_Code[min&0x0f];
SEG_Buf[5]=0xBF;
SEG_Buf[6]=SEG_Code[sec>>4];
SEG_Buf[7]=SEG_Code[sec&0x0f];
}
}
}
}
void Timer0_Rountine(void) interrupt 1 //定时器0中断,1ms
{
timer_flag_1ms=1;
Seg_Display();//使用定时器进行数码管扫描
}