afeiyang 发表于 2011-5-1 16:33:02

STC12C5A60S2单片机与DS1302时序问题

大家用过STC12C5A60S2这块芯片驱动DS1302吗?小弟最近这块芯片无法正常驱动DS1302,时序始终没控制好,参考了很多资料人无法解决,求帮助……


以下是我的部分程序,完整程序在附件中,那位仁兄指点指点,不胜感激…………


完整程序ourdev_635738DIDJ0V.zip(文件大小:59K) (原文件名:DS1302.zip)


main.c文件


#include "STC12C5A60S2.h"
#include <DS1302.h>
#include <LCD1602.h>

void main()
{
DS1302_Init();
LCD1602_Init();
while(1)
{
DS1302_GetTime();
LCD1602_Put_Num2(0,0,year);
LCD1602_Put_Num2(2,0,week);
LCD1602_Put_Num2(4,0,month);
LCD1602_Put_Num2(6,0,day);
LCD1602_Put_Num2(8,0,hour);
LCD1602_Put_Num2(10,0,minute);
LCD1602_Put_Num2(12,0,second);
}
}


DS1302.h文件


#ifndef        __DS1302_H__
#define        __DS1302_H__

#include"STC12C5A60S2.h"

//时间变量定义
extern volatile unsigned char second;
extern volatile unsigned char minute ;
extern volatile unsigned char hour;
extern volatile unsigned char day;
extern volatile unsigned char month;
extern volatile unsigned char year;
extern volatile unsigned char week;

//端口定义
sbit        DS1302_IO         = P3^4;          
sbit        DS1302_CLK        = P3^6;          
sbit        DS1302_RST        = P3^5;          

//全局函数声明
void DS1302_Init();
unsigned char DS1302_Read_Date(unsigned char cmd);
void DS1302_Write_Date(unsigned char cmd,unsigned char date);
void DS1302_SetTime();
void DS1302_GetTime();

#endif




DS1302.c文件

/*******************************************************
* 程序名称:DS1302.c                                                                  
* 功能描述:DS1302时钟芯片                                                  
* 修改日期:2011-4-24                                                                  
* 编程环境:Kile uVision4                                                          
* 程序说明:晶振频率为12.000M                                                        
*******************************************************/

#include"DS1302.h"
#include<intrins.h>

//时间变量定义
volatile unsigned char second =0x30;
volatile unsigned char minute =0x30;
volatile unsigned char hour =0x20;
volatile unsigned char day =0x28;
volatile unsigned char month =0x04;
volatile unsigned char year =0x11;
volatile unsigned char week =0x04;

//短暂延时函数
void nop()
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}

/*******************************************************
* 功能描述:向DS1302相应的地址写数据
* 隶属模块:DS1302模块
* 函数属性:外部,用户可调用
* 参数说明:cmd: 控制字 date:要写入的数据         
* 返回说明:无
* 注:无
*******************************************************/
void DS1302_Write_Date(unsigned char cmd,unsigned char date)
{
unsigned char i=0;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
for(i=0;i<8;i++)
{
nop();
DS1302_IO = cmd & 0x01;
nop();
DS1302_CLK = 0;
nop();
DS1302_CLK = 1;
nop();
cmd >>= 1;
}
for(i=0;i<8;i++)
{
nop();
DS1302_IO = date & 0x01;
nop();
DS1302_CLK = 0;
nop();
DS1302_CLK = 1;
nop();
date >>= 1;
}
DS1302_RST = 0;       
}

/*******************************************************
* 功能描述:从相应的地址读数据
* 隶属模块:DS1302模块
* 函数属性:外部,用户可调用
* 参数说明:cmd:控制字         
* 返回说明:无
* 注:无
*******************************************************/
unsigned char DS1302_Read_Date(unsigned char cmd)
{
unsigned char i=0;
unsigned char temp = 0;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
for(i=0;i<8;i++)
{
nop();
DS1302_IO = cmd & 0x01;
nop();
DS1302_CLK = 0;
nop();
DS1302_CLK = 1;
nop();
cmd >>= 1;
}
for(i=0;i<8;i++)
{
nop();
DS1302_CLK = 1;
nop();
DS1302_CLK = 0;
nop();
if(DS1302_IO)
{
   nop();
   temp |= 0x01 << i;
}
}
DS1302_RST = 0;

temp = (temp/16*10)+temp%16;
return temp;
}

/*******************************************************
* 功能描述:设置DS1302时间
* 隶属模块:DS1302模块
* 函数属性:外部,用户可调用
* 参数说明:*time:时间数组time[]首地址         
* 返回说明:无
* 注:将时间数组中的数据写到DS1302
*******************************************************/

void DS1302_SetTime()
{                  
DS1302_Write_Date(0x8E,0x00);           //允许写操作

DS1302_Write_Date(0x80,second);        //写秒数据
DS1302_Write_Date(0x82,minute);        //写分数据
DS1302_Write_Date(0x84,hour);                //写时数据
DS1302_Write_Date(0x86,day);                //写天数据
DS1302_Write_Date(0x88,month);                //写月数据
DS1302_Write_Date(0x8A,week);                //写周数据
DS1302_Write_Date(0x8C,year);                //写年数据

DS1302_Write_Date(0x8E,0x80);           //写保护
}                                                  
                               
/*******************************************************
* 功能描述:读取DS1302时间信息
* 隶属模块:DS1302模块
* 函数属性:外部,用户可调用
* 参数说明:*time:时间数组         
* 返回说明:无
* 注:将DS1302中时间信息放到时间数组time[]中
*   存放顺序为: 秒 分 时 日 月 星期 年
*******************************************************/

void DS1302_GetTime()
{       
DS1302_Write_Date(0x8E,0x00);                //允许写操作

second=DS1302_Read_Date(0x81);               //读秒数据
minute=DS1302_Read_Date(0x83);               //读分数据
hour=DS1302_Read_Date(0x85);               //读时数据
day=DS1302_Read_Date(0x87);               //读天数据
month=DS1302_Read_Date(0x89);               //读月数据
week=DS1302_Read_Date(0x8B);               //读周数据
year=DS1302_Read_Date(0x8D);               //读年数据

DS1302_Write_Date(0x8E,0x80);           //写保护
}

/*******************************************************
* 功能描述:DS1302初始化
* 隶属模块:DS1302模块
* 函数属性:外部,用户可调用
* 参数说明:无         
* 返回说明:无
* 注:无
*******************************************************/
void DS1302_Init()
{
DS1302_Write_Date(0x8E,0x00);//允许写操作
DS1302_Write_Date(0x84,0x00);        //设置24小时制
DS1302_SetTime();                        //设置初始时间
DS1302_Write_Date(0x80,0x00);        //启动时钟
// DS1302_Write_Date(0x90,0xA6);        //启动充电功能 一个二极管+4K电阻充电
DS1302_Write_Date(0x8E,0x80);        //写保护
}

zqy517 发表于 2011-5-1 19:03:18

记得需要上拉

d-link 发表于 2011-5-1 19:08:23

STC 只要设定 Px_M1 =1

liucw99 发表于 2011-5-1 22:09:32

你是用IO口来模拟I2C协议的,所以要延时正确。

STC12C5A60是1T的单片机,所以你用的软件延时要比12T的要长一些。具体长多少,你要去看指令的时间了。

如果找不到合适的文档资料,你就延时是12T单片机的6倍左右吧,试试看。

gdzhong 发表于 2011-5-1 22:34:44

加上拉电阻或者开内部的上拉及强推挽输出!

millwood0 发表于 2011-5-2 00:04:53

"你是用IO口来模拟I2C协议的"

ds1302 is an i2c device?

millwood0 发表于 2011-5-2 00:10:14

"小弟最近这块芯片无法正常驱动DS1302"

you have to isolate the problem to either ds1302 modules or the lcd modules.

as to ds1302, you need to figure construct a routine that sends a byte to the slave and another routine that reads a byte from the slave.

from that, you construct a routine that writes a command + a byte to the slave, and another that writes a command + reads a byte from the slave.

from there, you can write routines that reads / writes time.

this approach makes sure that your hardware interface is consistent and you maximize the reusability of your code.

millwood0 发表于 2011-5-2 00:13:03

"for(i=0;i<8;i++)
{
nop();
DS1302_IO = cmd & 0x01;
nop();
DS1302_CLK = 0;
nop();
DS1302_CLK = 1;
nop();
cmd >>= 1;
}
for(i=0;i<8;i++)
{
nop();
DS1302_IO = date & 0x01;
nop();
DS1302_CLK = 0;
nop();
DS1302_CLK = 1;
nop();
date >>= 1;
} "

that's a piece of shit code: the two sections are almost identical and there is NO reason that you cannot write a little routine that does one of the two sections and all you need to do is then to call that new piece of code twice to send cmd and date.

that kind of code will get you fired in most respectable companies.

afeiyang 发表于 2011-5-2 09:57:38

回复【7楼】millwood0
-----------------------------------------------------------------------

很感谢millwood0的提醒,以后会注意的……

liucw99 发表于 2011-5-2 11:04:21

回复【5楼】millwood0
-----------------------------------------------------------------------

严格说来,它既不是I2C,也不是SPI的。我只是借用LZ的程序说他是用IO来模拟类似这种协议的时候要注意延迟时间的问题而已。
页: [1]
查看完整版本: STC12C5A60S2单片机与DS1302时序问题