如何读出DS1302里面的时钟数据?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何读出DS1302里面的时钟数据?相关的知识,希望对你有一定的参考价值。

将年月日时分秒分别读出,请给出C51语句!

#include <REG51.H>
#include <intrins.h>
//#include "LCD1602.h"
//#include "DS1302.h"
#define uint unsigned int
#define uchar unsigned char
sbit DS1302_CLK = P1^7; //实时时钟时钟线引脚
sbit DS1302_IO = P1^6; //实时时钟数据线引脚
sbit DS1302_RST = P1^5; //实时时钟复位线引脚
sbit wireless_1 = P3^0;
sbit wireless_2 = P3^1;
sbit wireless_3 = P3^2;
sbit wireless_4 = P3^3;
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year; //秒,分,时到日,月,年位闪的计数
sbit Set = P2^0; //模式切换键
sbit Up = P2^1; //加法按钮
sbit Down = P2^2; //减法按钮
sbit out = P2^3; //立刻跳出调整模式按钮
char done,count,temp,flag,up_flag,down_flag;
uchar TempBuffer[5],week_value[2];

/***********DS1302时钟部分子程序******************/
typedef struct __SYSTEMTIME__

unsigned char Second;
unsigned char Minute;
unsigned char Hour;
unsigned char Week;
unsigned char Day;
unsigned char Month;
unsigned char Year;
unsigned char DateString[11];
unsigned char TimeString[9];
SYSTEMTIME; //定义的时间类型
SYSTEMTIME CurrentTime;

#define AM(X) X
#define PM(X) (X+12) // 转成24小时制
#define DS1302_SECOND 0x80 //时钟芯片的寄存器位置,存放时间
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_WEEK 0x8A
#define DS1302_DAY 0x86
#define DS1302_MONTH 0x88
#define DS1302_YEAR 0x8C

void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数)

unsigned char i;
ACC = d;
for(i=8; i>0; i--)

DS1302_IO = ACC0; //相当于汇编中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0;
ACC = ACC >> 1;



unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数)

unsigned char i;
for(i=8; i>0; i--)

ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0;

return(ACC);


void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要写的数据

DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 写1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;


unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据

unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 读1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;
return(ucData);


void DS1302_GetTime(SYSTEMTIME *Time) //获取时钟芯片的时钟数据到自定义的结构型数组

unsigned char ReadValue;
ReadValue = Read1302(DS1302_SECOND);
Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MINUTE);
Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_HOUR);
Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_DAY);
Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_WEEK);
Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MONTH);
Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_YEAR);
Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);


void DateToStr(SYSTEMTIME *Time) //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]
if(hide_year<2) //这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为 2007/07/22

Time->DateString[0] = '2';
Time->DateString[1] = '0';
Time->DateString[2] = Time->Year/10 + '0';
Time->DateString[3] = Time->Year%10 + '0';

else

Time->DateString[0] = ' ';
Time->DateString[1] = ' ';
Time->DateString[2] = ' ';
Time->DateString[3] = ' ';

Time->DateString[4] = '/';
if(hide_month<2)

Time->DateString[5] = Time->Month/10 + '0';
Time->DateString[6] = Time->Month%10 + '0';

else

Time->DateString[5] = ' ';
Time->DateString[6] = ' ';

Time->DateString[7] = '/';
if(hide_day<2)

Time->DateString[8] = Time->Day/10 + '0';
Time->DateString[9] = Time->Day%10 + '0';

else

Time->DateString[8] = ' ';
Time->DateString[9] = ' ';

if(hide_week<2)

week_value[0] = Time->Week%10 + '0'; //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示

else

week_value[0] = ' ';

week_value[1] = '\0';

Time->DateString[10] = '\0'; //字符串末尾加 '\0' ,判断结束字符


void TimeToStr(SYSTEMTIME *Time) //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[];
if(hide_hour<2)

Time->TimeString[0] = Time->Hour/10 + '0';
Time->TimeString[1] = Time->Hour%10 + '0';

else

Time->TimeString[0] = ' ';
Time->TimeString[1] = ' ';

Time->TimeString[2] = ':';
if(hide_min<2)

Time->TimeString[3] = Time->Minute/10 + '0';
Time->TimeString[4] = Time->Minute%10 + '0';

else

Time->TimeString[3] = ' ';
Time->TimeString[4] = ' ';

Time->TimeString[5] = ':';
if(hide_sec<2)

Time->TimeString[6] = Time->Second/10 + '0';
Time->TimeString[7] = Time->Second%10 + '0';

else

Time->TimeString[6] = ' ';
Time->TimeString[7] = ' ';

Time->DateString[8] = '\0';


void Initial_DS1302(void) //时钟芯片初始化

unsigned char Second="Read1302"(DS1302_SECOND);
if(Second&0x80) //判断时钟芯片是否关闭

Write1302(0x8e,0x00); //写入允许
Write1302(0x8c,0x07); //以下写入初始化时间 日期:07/07/25.星期: 3. 时间: 23:59:55
Write1302(0x88,0x07);
Write1302(0x86,0x25);
Write1302(0x8a,0x07);
Write1302(0x84,0x23);
Write1302(0x82,0x59);
Write1302(0x80,0x55);
Write1302(0x8e,0x80); //禁止写入




void Upkey()//升序按键

Up=1;
if(Up==0||wireless_2==1)

mdelay(8);
switch(count)
case 1:
temp="Read1302"(DS1302_SECOND); //读取秒数
temp="temp"+1; //秒数加1
up_flag=1; //数据调整后更新标志
if((temp&0x7f)>0x59) //超过59秒,清零
temp="0";
break;
case 2:
temp="Read1302"(DS1302_MINUTE); //读取分数
temp="temp"+1; //分数加1
up_flag=1;
if(temp>0x59) //超过59分,清零
temp="0";
break;
case 3:
temp="Read1302"(DS1302_HOUR); //读取小时数
temp="temp"+1; //小时数加1
up_flag=1;
if(temp>0x23) //超过23小时,清零
temp="0";
break;
case 4:
temp="Read1302"(DS1302_WEEK); //读取星期数
temp="temp"+1; //星期数加1
up_flag=1;
if(temp>0x7)
temp="1";
break;
case 5:
temp="Read1302"(DS1302_DAY); //读取日数
temp="temp"+1; //日数加1
up_flag=1;
if(temp>0x31)
temp="1";
break;
case 6:
temp="Read1302"(DS1302_MONTH); //读取月数
temp="temp"+1; //月数加1
up_flag=1;
if(temp>0x12)
temp="1";
break;
case 7:
temp="Read1302"(DS1302_YEAR); //读取年数
temp="temp"+1; //年数加1
up_flag=1;
if(temp>0x85)
temp="0";
break;
default:break;


while(Up==0);
while(wireless_2==1);



////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Downkey()//降序按键

Down=1;
if(Down==0||wireless_3==1)

mdelay(8);
switch(count)
case 1:
temp="Read1302"(DS1302_SECOND); //读取秒数
temp="temp-1"; //秒数减1
down_flag=1; //数据调整后更新标志
if(temp==0x7f) //小于0秒,返回59秒
temp="0x59";
break;
case 2:
temp="Read1302"(DS1302_MINUTE); //读取分数
temp="temp-1"; //分数减1
down_flag=1;
if(temp==-1)
temp="0x59"; //小于0秒,返回59秒
break;
case 3:
temp="Read1302"(DS1302_HOUR); //读取小时数
temp="temp-1"; //小时数减1
down_flag=1;
if(temp==-1)
temp="0x23";
break;
case 4:
temp="Read1302"(DS1302_WEEK); //读取星期数
temp="temp-1"; //星期数减1
down_flag=1;
if(temp==0)
temp="0x7";;
break;
case 5:
temp="Read1302"(DS1302_DAY); //读取日数
temp="temp-1"; //日数减1
down_flag=1;
if(temp==0)
temp="31";
break;
case 6:
temp="Read1302"(DS1302_MONTH); //读取月数
temp="temp-1"; //月数减1
down_flag=1;
if(temp==0)
temp="12";
break;
case 7:
temp="Read1302"(DS1302_YEAR); //读取年数
temp="temp-1"; //年数减1
down_flag=1;
if(temp==-1)
temp="0x85";
break;
default:break;


while(Down==0);
while(wireless_3==1);



void Setkey()//模式选择按键

Set=1;
if(Set==0||wireless_4==1)

mdelay(8);
count="count"+1; //Setkey按一次,count就加1
done="1"; //进入调整模式
while(Set==0);
while(wireless_4==1);




void keydone()//按键功能执行
uchar Second;
if(flag==0) //关闭时钟,停止计时
Write1302(0x8e,0x00); //写入允许
temp="Read1302"(0x80);
Write1302(0x80,temp|0x80);
Write1302(0x8e,0x80); //禁止写入
flag="1";

Setkey(); //扫描模式切换按键
switch(count)
case 1:do //count=1,调整秒

outkey(); //扫描跳出按钮
Upkey(); //扫描加按钮
Downkey(); //扫描减按钮
if(up_flag==1||down_flag==1) //数据更新,重新写入新的数据

Write1302(0x8e,0x00); //写入允许
Write1302(0x80,temp|0x80); //写入新的秒数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;


hide_sec++; //位闪计数
if(hide_sec>3)
hide_sec=0;
show_time(); //液晶显示数据
while(count==2);break;
case 2:do //count=2,调整分

hide_sec=0;
outkey();
Upkey();
Downkey();
if(temp>0x60)
temp="0";
if(up_flag==1||down_flag==1)

Write1302(0x8e,0x00); //写入允许
Write1302(0x82,temp); //写入新的分数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;

hide_min++;
if(hide_min>3)
hide_min=0;
show_time();
while(count==3);break;
case 3:do //count=3,调整小时

hide_min=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)

Write1302(0x8e,0x00); //写入允许
Write1302(0x84,temp); //写入新的小时数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;

hide_hour++;
if(hide_hour>3)
hide_hour=0;
show_time();
while(count==4);break;
case 4:do //count=4,调整星期

hide_hour=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)

Write1302(0x8e,0x00); //写入允许
Write1302(0x8a,temp); //写入新的星期数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;

hide_week++;
if(hide_week>3)
hide_week=0;
show_time();
while(count==5);break;
case 5:do //count=5,调整日

hide_week=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)

Write1302(0x8e,0x00); //写入允许
Write1302(0x86,temp); //写入新的日数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;

hide_day++;
if(hide_day>3)
hide_day=0;
show_time();
while(count==6);break;
case 6:do //count=6,调整月

hide_day=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)

Write1302(0x8e,0x00); //写入允许
Write1302(0x88,temp); //写入新的月数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;

hide_month++;
if(hide_month>3)
hide_month=0;
show_time();
while(count==7);break;
case 7:do //count=7,调整年

hide_month=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)

Write1302(0x8e,0x00); //写入允许
Write1302(0x8c,temp); //写入新的年数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;

hide_year++;
if(hide_year>3)
hide_year=0;
show_time();
while(count==8);break;
case 8: count="0";hide_year=0; //count8, 跳出调整模式,返回默认显示状态
Second="Read1302"(DS1302_SECOND);
Write1302(0x8e,0x00); //写入允许
Write1302(0x80,Second&0x7f);
Write1302(0x8E,0x80); //禁止写入
done="0";
break; //count=7,开启中断,标志位置0并退出
default:break;



参考技术A 一个例子 重点看DS1302_Read()

#include <reg51.h>
#include<intrins.h>

#define uchar unsigned char
#define uint unsigned int
#define SECOND 0x81
#define MINUTE 0x83
#define HOUR 0x85
sbit rs=P2^0;
sbit rw=P2^1;
sbit ep=P2^2;
sbit DS1302_SCLK = P1^0;
sbit DS1302_IO= P1^1;
sbit DS1302_RST = P1^2;
sbit M=P3^2;
sbit U=P3^3;
sbit D=P3^4;
unsigned char sel=0;
uchar code DIS1[]=“abcdef";
uchar code DIS2[]="abcdef";
/////////////////////////延时////////////////////////////////
void delay(uint ms)

unsigned int a,b;
for(a=0;a<ms;a++)
for(b=0;b<120;b++);

////////////////////////////////////////////////////////////
/***************DS1302驱动************************/
////////////////////////////////////////////////////////////
void DS1302_Write(uchar D)

uchar i;
for(i=0;i<8;i++)

DS1302_IO=D&0x01;
DS1302_SCLK=1;
DS1302_SCLK=0;
D=D>>1;


////////////////////////////////////////////////////////////
uchar DS1302_Read()

uchar TempDat=0,i;
for(i=0;i<8;i++)

TempDat>>=1;
if(DS1302_IO) TempDat=TempDat|0x80;
DS1302_SCLK=1;
DS1302_SCLK=0;


return TempDat;

////////////////////////////////////////////////////////////
void WDS1302(uchar ucAddr, uchar ucDat)

DS1302_RST = 0;
DS1302_SCLK = 0;
DS1302_RST = 1;
DS1302_Write(ucAddr);
DS1302_Write(ucDat);
DS1302_SCLK = 1;
DS1302_RST = 0;

////////////////////////////////////////////////////////////
uchar RDS1302(uchar ucAddr)

uchar ucDat;
DS1302_RST = 0;
DS1302_SCLK = 0;
DS1302_RST = 1;
DS1302_Write(ucAddr);
ucDat=DS1302_Read();
DS1302_SCLK = 1;
DS1302_RST = 0;
return ucDat;

//////////////////////////////////////////////////////////
void init_1302()

WDS1302(0x8e,0x00);//开保护寄存器
WDS1302(0x80,0x55);//秒
WDS1302(0x82,0x59);//分
WDS1302(0x84,0x23);//时
WDS1302(0x8A,0x07);//星期
WDS1302(0x86,0x02);//日
WDS1302(0x88,0x08);//月
WDS1302(0x8C,0x09);//年
WDS1302(0x90,0xab);//卷电流充电
WDS1302(0x8e,0x80);//关保护寄存器


//////////////////////////////////////////////////////////
/************************1602驱动************************/
//////////////////////////////////////////////////////////

bit lcd_bz()

bit result;
rs = 0;
rw = 1;
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result = (bit)(P0 & 0x80);
ep = 0;
return result;

////////////////////////////////////////////////////////
void lcd_wcmd(unsigned char cmd)

while(lcd_bz());
rs = 0;
rw = 0;
ep = 0;
_nop_();
_nop_();
P0 = cmd;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep= 0;

/////////////////////////////////////////////////////////
void lcd_pos(unsigned char pos)

lcd_wcmd(pos | 0x80);

/////////////////////////////////////////////////////////
void lcd_wdat(unsigned char dat)

while(lcd_bz());
rs = 1;
rw = 0;
ep = 0;
P0 = dat;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;

//////////////////////////////////////////////////////////
void lcd_init()

lcd_wcmd(0x38);
delay(1);
lcd_wcmd(0x0c);
delay(1);
lcd_wcmd(0x06);
delay(1);
lcd_wcmd(0x01);
delay(1);


/////////////////////////////////////////////////////////
/*********************调时函数*************************/
/////////////////////////////////////////////////////////
void set_time()


signed char address,item;
signed char max,mini;
if(M==0)

sel++;
delay(300);
if(sel==6) sel=0;
if(sel==2) address=0x82; max=59;mini=0;
if(sel==1) address=0x84; max=23;mini=0;
if(sel==3) address=0x8c; max=99;mini=9;
if(sel==4) address=0x88; max=12;mini=1;
if(sel==5) address=0x86; max=31;mini=1;
M=1;

item=((RDS1302(address+1))/16)*10 + (RDS1302(address+1))%16;
if(U == 0)

delay(200);
U=1;
item++;

if(D == 0)

delay(200);
D=1;
item--;

if(item>max) item=mini;
if(item<mini) item=max;
WDS1302(0x8e,0x00);//允许写操作
WDS1302(address,(item/10)*16+item%10);
WDS1302(0x8e,0x80);//写保护,禁止写操作

/////////////////////////////////////////////////////////
/*********************显示子函数************************/
/////////////////////////////////////////////////////////
uchar lcdshow_u(uchar i,uchar y)


lcd_wcmd(0x80+0x00+i);
lcd_wdat(y);



uchar lcdshow_d(uchar i,uchar y)

lcd_wcmd(0x80+0x40+i);
lcd_wdat(y);

/////////////////////////////////////////////////////////
/*******************显示函数****************************/
/////////////////////////////////////////////////////////
void display(void)


uchar x,y;

x=RDS1302(HOUR);
y=x;
x=x>>4; lcdshow_u(6,0x30+x);
y=y&0x0f; lcdshow_u(7,0x30+y);
lcdshow_u(8,':');

x=RDS1302(MINUTE);
y=x;
x=x>>4; lcdshow_u(9,0x30+x);
y=y&0x0f; lcdshow_u(0x0a,0x30+y);
lcdshow_u(0x0b,':');
x=RDS1302(SECOND);
y=x;
x=x>>4; lcdshow_u(0x0c,0x30+x);
y=y&0x0f; lcdshow_u(0x0d,0x30+y);

x=RDS1302(0x8d);
y=x;
x=x>>4; lcdshow_d(8,0x30+x);
y=y&0x0f; lcdshow_d(9,0x30+y);
lcdshow_d(0x0a,'-');
x=RDS1302(0x89);
y=x;
x=x>>4; lcdshow_d(0x0b,0x30+x);
y=y&0x0f; lcdshow_d(0x0c,0x30+y);
lcdshow_d(0x0d,'-');
x=RDS1302(0x87);
y=x;
x=x>>4; lcdshow_d(0x0e,0x30+x);
y=y&0x0f; lcdshow_d(0x0f,0x30+y);
for(x=45;x>0;x--)

set_time();
delay(10);


////////////////////////////////////////////////////////////////
/**************************主函数******************************/
////////////////////////////////////////////////////////////////
void main()

uchar i;
lcd_init();
delay(10);
lcd_pos(0x03);
i = 0;
while(DIS1[i] != '\0')

lcd_wdat(DIS1[i]);
i++;

lcd_pos(0x42);
i = 0;
while(DIS2[i] != '\0')

lcd_wdat(DIS2[i]);
i++;


//init_1302();
delay(1000);
for(i=0;i<17;i++)

lcdshow_u(i,'>');
delay(90) ;

for(i=0;i<17;i++)

lcdshow_d(i,'>');
delay(90) ;

lcd_init();
delay(10);
lcdshow_u(0,'T');
lcdshow_u(1,'i');
lcdshow_u(2,'m');
lcdshow_u(3,'e');

lcdshow_d(0,'D');
lcdshow_d(1,'a');
lcdshow_d(2,'t');
lcdshow_d(3,'a');

lcdshow_d(6,'2');
lcdshow_d(7,'0'); //LCD框架描绘

while(1)

set_time();
if(sel==2) lcdshow_u(9,' ');lcdshow_u(0x0a,' ');delay(500);
if(sel==1) lcdshow_u(6,' ');lcdshow_u(7,' ');delay(500);
if(sel==4) lcdshow_d(0x0b,' ');lcdshow_d(0x0c,' ');delay(500);
if(sel==5) lcdshow_d(0x0e,' ');lcdshow_d(0x0f,' ');delay(500); //调时LCD闪烁显示
display();


本回答被提问者采纳
参考技术B P1.2;令=0

DS_READ�SETBP1.2;令=0。

CLRP1.1;令SCLK=0。

CLRP1.2;令=1,启动芯片。

LCALLDS_WSUB;写8位地址。

LCALLDS_RSUB;读出8位数据。

RET

DS_WSUB�MOVR7,#08H

WL00P�RRCA;A为地址字节。

MOVP1.0,C

SETBP1.1;在时钟上升沿

NOP;输入地址字节。

CLRP1.1

DJNZR7�WL00P

RET

DS_RSUB�SETBP1.0;为读数据作准备。

MOVR7�#08H

RL00P:SETBP1.1

NOP

CLRP1.1;在第9个正脉冲的下

MOVC,P1.0;降沿开始输出数据。

RRCA;A中为读出的数据。

DJNZR7,RL00P

RET

若使用如下程序对DSl302的RAM1�其内容为5AH 进行读操作

READ:MOVA�#11000101B;RAM1单元的读地址。

LCAllDS_READ;调用读子程序。

则程序执行后A中的数据为2DH,显然读出的数据不正确。若再使用一条RLA指令调整后,则A中为5AH,结果才正确。由此说明:使用上述程序读出的RAM1单元中的第0位数据实为第1位数据,读出的第7位数据实为第0位数据。

经笔者仔细研究时序图和多次试验得知,问题的原因在于:对于读操作时序,在SCLK出现第8个正脉冲时,上升沿输入地址字节的最后一位数据,而在此正脉冲的下降沿就要输出数据字节的第0位数据。然而笔者的程序中是在第9个正脉冲的下降沿才误认为输出了数据字节的第0位数据,此位数据事实上是第二个下降沿输出的,故实为数据字节的第1位数据。经笔者实验:只要RST保持为高电平,如果超过8个下降沿,它们将重新从第0位输出数据位,因程序中输出的最后一位数据位,是9个下降沿输出的数据位,故实为数据字节的第0位数据位。

由此可见,单字节读操作的时序图如改为图2所示时序图,则读者较容易理解可避免发生上述编程错误。

只要将上述的DS_RSUB子程序改为如下的子程序即可解决上述问题:

DS_RSUBl:SETBP1.0;为读数据作准备

MOVR7,#08H

RL00P:CLRP1.1;SCLK第8个正脉冲的

MOVC,P1.0;下降沿开始输出数据。

RAC

SETBP1.1

DJNZR7,RL00P

RET

FIFO IP核仿真

FIFO IP核仿真

1.FIFO IP核配置

 

 2.FIFO测试逻辑代码

    首先往FIFO里面写入512个数据(FIFO深度的一半),然后再开始同时往FIFO里面写入,读出数据。FIFO读和写的时钟域不同,对于不同时钟域的信号应该进行区分,状态机也应该分开来写。

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: chensimin
// 
// Create Date: 2017/10/23 16:11:32
// Design Name: 
// Module Name: top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module top(
    rst,
    wr_clk,
    rd_clk,
    dout,
    full,
    empty,
    rd_data_count,
    wr_data_count
    );

//input
input rst;
input wr_clk;
input rd_clk;

//output
output [7:0]dout;
output full;
output empty;
output [9:0]rd_data_count;
output [9:0]wr_data_count;

//write state
reg [2:0]i;
reg read_start;
reg [7:0]din_r;
reg clear_fifo_full;
reg wr_en_r;
wire wr_en;
wire [7:0]din;
wire [9:0]wr_data_count;
wire full;
always@(posedge wr_clk)
begin
    if(rst)
        begin
            wr_en_r <= 1\'b0;
            i <= 3\'d0;
            read_start <= 1\'b0;
            clear_fifo_full <= 1\'b0;
            din_r <= 8\'d0;
        end
    else 
        begin
            case(i)
                0:
                begin 
                    if(!full) begin wr_en_r <= 1\'b1; i<=i+1\'b1; end
                    else wr_en_r <= 1\'b0;
                end
                1:
                begin
                    if(wr_data_count ==10\'d512) begin read_start <=1\'b1; din_r <= din_r +1\'b1; i<=i+1\'b1; end
                    else din_r <= din_r +1\'b1;
                end
                2:
                begin
                    if(full) begin clear_fifo_full <= 1\'b1;  wr_en_r <= 1\'b0;  i<=3\'d0; end
                    else din_r <= din_r +1\'b1;
                end
            endcase
        end
end

assign wr_en = wr_en_r;
assign din = din_r;

//read state
reg rd_en_r;
reg [2:0]j;
reg clear_fifo_empty;
wire rd_en;
always@(posedge rd_clk) 
begin
    if(rst) 
        begin
            rd_en_r <= 1\'b0;
            j <= 3\'d0;
            clear_fifo_empty <= 1\'b0;
        end
    else 
        begin
            case(j)
                0:
                begin
                    if(read_start & !empty) begin rd_en_r <= 1\'b1; j<=j+1\'b1; end
                    else rd_en_r <= 1\'b0;
                end
                1:
                begin
                    if(empty) begin  clear_fifo_empty <= 1\'b1; rd_en_r <= 1\'b0; j<=3\'d0; end
                    else rd_en_r <= 1\'b1;
                end
            endcase
        end
end

assign rd_en = rd_en_r;

fifo_generator_0 U1 (
  .rst(rst),                      // input wire rst
  .wr_clk(wr_clk),                // input wire wr_clk
  .rd_clk(rd_clk),                // input wire rd_clk
  .din(din),                      // input wire [7 : 0] din
  .wr_en(wr_en),                  // input wire wr_en
  .rd_en(rd_en),                  // input wire rd_en
  .dout(dout),                    // output wire [7 : 0] dout
  .full(full),                    // output wire full
  .empty(empty),                  // output wire empty
  .rd_data_count(rd_data_count),  // output wire [9 : 0] rd_data_count
  .wr_data_count(wr_data_count)  // output wire [9 : 0] wr_data_count
);

endmodule

 

3.测试脚本

add_force {/top/rst} -radix hex {1 0ns} {0 150000ps} 
add_force {/top/wr_clk} -radix hex {0 0ns} {1 50000ps} -repeat_every 100000ps
add_force {/top/rd_clk} -radix hex {0 0ns} {1 49500ps} -repeat_every 99000ps

4.仿真波形分析

仿真波形图

FIFO进行复位操作,开始full,empty都会拉高一段时间,然后才会恢复正常。

与写状态有关的信号分析

full恢复正常后,写使能,同时状态机跳转。

 当写入512个数据后(wr_data_count == 512),read_start信号开始拉高,FIFO开始读出数据,同时状态机也在此刻跳转,下一个状态再写数据的同时,也在监测FIFO是否已经被写满。

 下面来看FIFO读数据端的仿真波形

read_start信号拉高时,re_en信号开始拉高,FIFO才开始从dout端口读出数据,可以看到,刚开读出的数据为FIFO din端口最先写入的数据。从rd_data_count端口可以看到,此时FIFO里面已经有500多个数据可以读。

结论:仿真结果与预期相符。

以上是关于如何读出DS1302里面的时钟数据?的主要内容,如果未能解决你的问题,请参考以下文章

DS12C887,DS1302,DS3231时钟芯片那个精度比较高?

DS12C887,DS1302,DS3231时钟芯片哪个精度比较高

遇到问题 DS1302读取数据有问题

DS1302芯片怎么用

ds1302时钟芯片。。。谁给我看下这个程序?液晶可以显示,但是时钟不会走显示的也不是我初始化的时间。

可编程 USB 转串口适配器开发板 DS1302 时钟芯片参数读取与修改