如何读出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时钟芯片哪个精度比较高