DS1302的一个问题
本帖最后由 fjlonng 于 2011-12-19 10:59:54 编辑 以下代码在串口调试助手上显示:
(省略一部分)
11-12-17 00:35:57
11-12-17 00:35:57
11-12-17 00:35:58
11-12-17 00:35:58
11-12-17 00:35:58
(省略一部分)
以上是正确的读出数据
但是,假如下面那行红色的代码去掉,就会变成:
(省略一部分)
11-12-?? 00:??:02
11-12-?? 00:??:02
11-12-?? 00:??:02
11-12-?? 00:??:02
11-12-?? 00:??:02
11-12-?? 00:??:02
11-12-?? 00:??:02
11-12-?? 00:??:02
11-12-17 ??:00:03
11-12-17 ??:00:03
11-12-17 ??:00:03
11-12-17 ??:00:03
11-12-17 ??:00:03
(省略)
该显示部分居然出现问号
请大神帮帮忙解决下,就一句代码不理解,3Q,代码如下:
# include <reg52.h>
# define WRITE_ADDRESS 0x80
# define READ_ADDRESS 0x81
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit SDA = P3^4;
sbit SCK = P3^5;
sbit RST = P1^7;
uint8 Time[] = {0,0,0,17,12,7,11}; //设置DS1302的初始值,分别为:秒,分,时,日,月,周,年
void delay(uint16 counter)
{
while(--counter);
}
void DS1302_Initial()
{
RST = 0;
SCK = 0;
RST = 1;
}
void DS1302_InputByte(uint8 BYTE) //写一个字节
{
uint8 i;
for(i = 0;i < 8;i++)
{
BYTE >>= 1;
SDA = CY;
SCK = 1;
SCK = 0;
}
}
void Write_DS1302(uint8 ADDRESS,uint8 BYTE)
{
DS1302_Initial();
DS1302_InputByte(ADDRESS);
DS1302_InputByte(BYTE);
RST = 0; //该句前面不用对SDA进行处理,不懂!!
}
uint8 DS1302_OutputByte() //读一个字节
{
uint8 i;
for(i = 0;i < 8;i++)
{
ACC >>= 1;
if(SDA)
ACC |= 0x80;
SCK = 1;
SCK = 0;
}
return ACC;
}
uint8 Read_DS1302(ADDRESS) //读时间子函数
{
DS1302_Initial();
DS1302_InputByte(ADDRESS);
ACC = DS1302_OutputByte();
SDA = 0; //罪魁祸首,就这句如果删了就出现错误了,大大们看看为什么?
RST = 0;
return ACC;
}
void Read_Time() //读时间
{
uint8 i,addr;
addr = READ_ADDRESS;
for(i = 0;i < 7;i++) //读7次,存入Time数组
{
Time = Read_DS1302(addr);
addr += 2;
}
}
void DS1302_If_Protece(bit Flag) //设置写保护或者清写保护
{
if(Flag)
{
Write_DS1302(0x8e,0x80);
}
else
{
Write_DS1302(0x8e,0);
}
}
void DS1302_SetTime() //设置初始时间
{
uint8 i,temp;
for(i = 0;i < 7;i++) //转换成BCD码
{
temp = Time/10;
Time = Time%10;
Time = Time + temp * 16;
}
temp = WRITE_ADDRESS;
DS1302_If_Protece(0);
for(i = 0;i < 7;i++) //写入DS1302
{
Write_DS1302(temp,Time);
temp += 2;
}
DS1302_If_Protece(1);
}
void Serial_Initial() //串口初始化
{
TMOD = 0x20;
SCON = 0x40;
TH1 = 0xfd;
TL1 = TH1;
TR1 = 1;
}
void Serial_OutputByte(uint8 Byte)
{
SBUF = Byte;
while(!TI);
TI = 0;
}
void Serial_OutputTime(uint8 Data)
{
Serial_OutputByte(Data/16+'0'); //读回来的数据转换成字符送调试助手显示
Serial_OutputByte(Data%16+'0');
}
void main()
{
Serial_Initial();
DS1302_SetTime();
while(1)
{
Read_Time();
Serial_OutputTime(Time[6]);
Serial_OutputByte('-');
Serial_OutputTime(Time[4]);
Serial_OutputByte('-');
Serial_OutputTime(Time[3]);
Serial_OutputByte(' ');
Serial_OutputTime(Time[2]);
Serial_OutputByte(':');
Serial_OutputTime(Time[1]);
Serial_OutputByte(':');
Serial_OutputTime(Time[0]);
Serial_OutputByte('\r');
Serial_OutputByte('\n');
delay(10000);
}
}
[最优解释]
= 0x80;
SCK = 1;
SCK = 0;
}
return ACC;
}
这个我认为有问题,首先读取数据是下降沿有效,然而你读取第一位时候没有给出一个下降沿 导致的错误,而红色那个SDA=0纯属侥幸 刚好正确。
建议改成
uint8 DS1302_OutputByte() //读一个字节
{
uint8 i;
for(i = 0;i < 8;i++)
{
ACC >>= 1;
SCK = 1;
SCK = 0;
if(SDA)
ACC
[其他解释]
高手都去吃饭了。- -
[其他解释]
这个具体什么原因,偶也不清楚
印象中在用DS1302的时候,读完全部数据后,总线还要求拉高
否则,之后读出来的数据会出错
当时,是为什么我也不知道。。。
不知道能不能归到硬件特性上
[其他解释]
SDA就是那个IO接口,那句红色的SDA = 0;改成SDA = 1,也会出现这个?号,闷
[其他解释]
用其它的串口调试软件观察一下到底?号是什么字符。我记得以前做点阵LED显示时钟的时候出现过BCD码大于9的情况,后来确认是因为手摸到了IC的引脚,导致寄存器数值发生改变,启用写保护就能消除此现象。但我看你的情况应该不同。这程序我时间不够,没法看完,不知道你是在学习改动别人的代码,还是自己写的代码不工作。如果别人的代码原本很可靠就不要改了,直接用吧。
[其他解释]
uint8 DS1302_OutputByte() //读一个字节
{
uint8 i;
for(i = 0;i < 8;i++)
{
ACC >>= 1;
if(SDA)
ACC
[其他解释]
= 0x80;
}
return ACC;
}
参考建议 呵呵不知道对不
[其他解释]
不好意思 上面那个改进方法 错误 见谅啊
给个写入读取数据的方法
在SCLK为高电平时,DATA线是不能变化的;在SCLK为低电平时,DATA线是可以变化的;所以,写数据的时候,先关数据,再给SCLK上升沿;读数据时,在SCLK下降沿之前读
莫怪~~