首先附上DS1302的时序图和它的寄存器图,程序中写的不好的地方希望大家多多谅解,谢谢~
#include<reg52.h> //头文件预编译
#define uchar unsigned char //宏定义
#define uint unsigned int //宏定义
uint DisplayData[8]; //无符号整型数码管显示的总位数
uint code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴极数码管0-9的全数组
uint code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; //读寄存器的秒分钟日月周年
uint code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c}; //写寄存器的秒分钟日月周年
uint TIME[7] = {0x50, 0x43, 0x21, 0x25, 0x07, 0x06, 0x20}; //数码管显示的时间2020年7月25日星期六21点43分50秒
sbit SCLK=P3^6; //位选时钟线
sbit IO=P3^4; //位选输出输出
sbit CE=P3^5; //位选复位
sbit LSA=P2^2; //数码管端口A
sbit LSB=P2^3; //数码管端口B
sbit LSC=P2^4; //数码管端口C
void write1302(uchar add,uchar dat) //DS1302的写操作(写地址,写数据)
{
uchar i;
CE=0; //一开始CE为0
SCLK=0; //时钟线为0
CE=1; //过段时间CE为1开始工作
for(i=0;i<8;i++) //FOR循环八次,写八次地址
{
IO=add&0x01; //从最低位开始接收
add>>=1; //右移一位,执行8次
SCLK=1; //时钟线升高,上升沿
SCLK=0; //时钟线降低,为下一次for循环的上升沿做准备
}
for(i=0;i<8;i++) //与上同理
{
IO=dat&0x01;
dat>>=1;
SCLK=1;
SCLK=0;
}
CE=0; //CE为0,停止工作
}
uint read1302(uchar add) //DS1302的读操作,注意因为是读操作,所以有返回值,不能为void而是需要unsigned,形参为之前的地址
{
uchar i,dat,dat1;
SCLK=0;
CE=0;
CE=1;
for(i=0;i<8;i++)
{
IO=add&0x01; //与上同理
add>>=1;
SCLK=1; //读操作时,时钟线做下降沿
SCLK=0;
}
for(i=0;i<8;i++)
{
dat1 = IO;
dat = (dat>>1) | (dat1<<7); //dat1左移7位变成最高位,dat1右移一位变成次高位,循环操作就能够将数据完整的读出
SCLK = 1;
SCLK = 0;
}
CE = 0;
return dat; //返回dat值
}
void init1302() //初始化ds1302
{
uchar i;
write1302(0x8e,0); //去除写保护
for(i=0;i<7;i++)
{
write1302(WRITE_RTC_ADDR[i],TIME[i]);//循环七次的目的就是为了能够将秒分钟日月周年输入,括号内就是为之前的写地址和写数据
}
write1302(0x8e,0x80); //重新赋予写保护
}
void read1302time() //读取ds1302的数据
{
uchar i;
for(i=0;i<7;i++)
{
TIME[i]=read1302(READ_RTC_ADDR[i]) ;//读七次,依次输出秒分钟日月周年,但是要注意的是,由于八段数码管数量有限,只能显示出时分秒
}
}
void delay(uint i) //延时函数,当i为1时,延时大概10ms
{
while(i--);
}
void datapros() //数据处理函数
{
read1302time();
DisplayData[0] = smgduan[TIME[2]/16]; //显示小时的整数位
DisplayData[1] = smgduan[TIME[2]&0x0f]; //显示小时的低位
DisplayData[2] = 0x40; //显示“-”
DisplayData[3] = smgduan[TIME[1]/16]; //同理
DisplayData[4] = smgduan[TIME[1]&0x0f];
DisplayData[5] = 0x40;
DisplayData[6] = smgduan[TIME[0]/16]; //同理
DisplayData[7] = smgduan[TIME[0]&0x0f];
}
void DigDisplay() //八段数码管的位选显示
{
uchar i;
for(i=0;i<8;i++)
{
switch(i)
{
case(0):
LSA=1;LSB=1;LSC=1; break;//显示第0位
case(1):
LSA=0;LSB=1;LSC=1; break;//显示第1位
case(2):
LSA=1;LSB=0;LSC=1; break;//显示第2位
case(3):
LSA=0;LSB=0;LSC=1; break;//显示第3位
case(4):
LSA=1;LSB=1;LSC=0; break;//显示第4位
case(5):
LSA=0;LSB=1;LSC=0; break;//显示第5位
case(6):
LSA=1;LSB=0;LSC=0; break;//显示第6位
case(7):
LSA=0;LSB=0;LSC=0; break;//显示第7位
}
P0=DisplayData[i]; //发送数据
delay(100); //间隔一段时间扫描
P0=0x00; //消隐
}
}
void main()
{
init1302();
while(1)
{
datapros(); //数据处理函数
DigDisplay(); //数码管显示函数
}
}