打印

有关DS1302的应用问题

[复制链接]
2168|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lzfact|  楼主 | 2007-2-5 10:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
ov, TE, hm, mt, RS

 请各位前辈帮忙 

我设计DS1302进行计时,晶振是正常的,可它就是不计时,请个位分析一下有那些原因,先谢谢了!程序如下:

BitCnt data 20h ; 数据位计数器
ByteCnt data 21h ; 数据字节计数器
Command data 22h ; 命令字节地址
RcvDat DATA 40H ; 接收数据缓冲区
XmtDat DATA 10H ; 发送数据缓冲区
;端口位定义
IO_DATA bit P1.5 ; 数据传送总线
SCLK bit P1.4; 时钟控制总线
RST bit P1.6 ; 复位总线
ORG   0000H

START:
;------------------------------------初始化1302-------------------------

SET1302:
clr sclk
  CLR     RST
MOV  SP,#50H

LCALL Write_Enable;写允许
LCALL Osc_Enable
LCALL Write_Multiplebyte;初始化1302,将我们要设定的数据写入
LCALL Write_Disable

START:LCALL Read_Multiplebyte;将我们设定的数据读出来


lcall exchange
lcall disp

AJMP START
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;********************************************************************************************
;发送数据程序
;名称:Send_Byte
;描述:发送ByteCnt 个字节给被控器DS1302
;命令字节地址在Command 中
;所发送数据的字节数在ByteCnt 中发送的数据在XmtDat 缓冲区中
;********************************************************************************************
Send_Byte:
CLR RST ;复位引脚为低电平所有数据传送终止
NOP
CLR SCLK; 清时钟总线
NOP
SETB RST ;复位引脚为高电平逻辑控制有效
NOP
MOV A,Command; 准备发送命令字节
MOV BitCnt,#08h ;传送位数为8
S_Byte0:
RRC A ;将最低位传送给进位位C
MOV IO_DATA,C ;位传送至数据总线
NOP
SETB SCLK ;时钟上升沿发送数据有效
NOP
CLR SCLK ;清时钟总线
DJNZ BitCnt,S_Byte0 ;位传送未完毕则继续
NOP
S_Byte1: ;准备发送数据
MOV A,@R0 ;传送数据过程与传送命令相同
MOV BitCnt,#08h
S_Byte2:
RRC A
MOV IO_DATA,C
NOP
SETB SCLK
NOP
CLR SCLK
DJNZ BitCnt,S_Byte2
INC R0 ;发送数据的内存地址加1
DJNZ ByteCnt,S_Byte1 ;字节传送未完毕则继续
NOP
CLR RST ;逻辑操作完毕清RST
RET
;***************************************************************************************
;接收数据程序;
;名称:Receive_Byte
;描述:从被控器DS1302 接收ByteCnt 个字节数据
;命令字节地址在Command 中
;所接收数据的字节数在ByteCnt 中接收的数据在RcvDat 缓冲区中
;***********************************************************************************
Receive_Byte:
CLR RST ;复位引脚为低电平所有数据传送终止
NOP
CLR SCLK ;清时钟总线
NOP
SETB RST ;复位引脚为高电平逻辑控制有效
MOV A,Command ;准备发送命令字节
MOV BitCnt,#08h ;传送位数为8
R_Byte0:
RRC A ;将最低位传送给进位位C
MOV IO_DATA,C ;位传送至数据总线
NOP
SETB SCLK ;时钟上升沿发送数据有效
NOP
CLR SCLK ;清时钟总线
DJNZ BitCnt,R_Byte0 ;位传送未完毕则继续
NOP
R_Byte1: ;准备接收数据
CLR A ;清类加器
CLR C ;清进位位C
MOV BitCnt,#08h ;接收位数为8
R_Byte2:
NOP
MOV C,IO_DATA ;数据总线上的数据传送给C
RRC A ;从最低位接收数据
SETB SCLK ;时钟总线置高
NOP
CLR SCLK ;时钟下降沿接收数据有效
DJNZ BitCnt,R_Byte2 ;位接收未完毕则继续
MOV @R1,A ;接收到的完整数据字节放入接收内存缓冲区
INC R1 ;接收数据的内存地址加1
DJNZ ByteCnt,R_Byte1 ;字节接收未完毕则继续
NOP
CLR RST ;逻辑操作完毕清RST
RET

;--写保护寄存器操作------------------------------------------
Write_Enable:
MOV Command,#8Eh ;命令字节为8E
MOV ByteCnt,#1 ;单字节传送模式
MOV R0,#XmtDat ;数据地址覆给R0
MOV XmtDat,#00h ;数据内容为0 写入允许
ACALL Send_Byte ;调用写入数据子程序
RET

;当写保护寄存器的最高位为1 时禁止数据写入寄存器---------------
Write_Disable:
MOV Command,#8Eh ;命令字节为8E
MOV ByteCnt,#1 ;单字节传送模式
MOV R0,#XmtDat ;数据地址覆给R0
MOV XmtDat,#80h ;数据内容为80h 禁止写入
ACALL Send_Byte ;调用写入数据子程序
RET ;返回调用本子程序处


;当把秒寄存器的第7 位时钟停止位设置为0 时起动时钟开始---------
Osc_Enable:
MOV Command,#80h ; 命令字节为80
MOV ByteCnt,#1 ; 单字节传送模式
MOV R0,#XmtDat ;数据地址覆给R0
MOV XmtDat,#00h ;数据内容为0 振荡器工作允许
ACALL Send_Byte ;调用写入数据子程序
RET ;返回调用本子程序处


;当把秒寄存器的第7 位时钟停止位设置为1 时时钟振荡器停止HT1380 进入低功耗方式---------------
Osc_Disable:
MOV Command,#80h ;命令字节为80
MOV ByteCnt,#1 ;单字节传送模式
MOV R0,#XmtDat ;数据地址覆给R0
MOV XmtDat,#80h ;数据内容为80h 振荡器停止
ACALL Send_Byte ;调用写入数据子程序
RET ;返回调用本子程序处


;写入00 年6 月21 日星期三13 时59 分59---------------------
Write_Multiplebyte:
MOV Command,#0BEh ;命令字节为BEh
MOV ByteCnt,#8 ;多字节写入模式此模块为8 个
MOV R0,XmtDat;数据地址覆给R0
MOV XmtDat,#55h ;秒单元内容为59h
MOV XmtDat+1 ,#55h ;分单元内容为59h
MOV XmtDat+2,#55h ;时单元内容为13h
MOV XmtDat+3,#55h ;日期单元内容为21h
MOV XmtDat+4,#55h ;月单元内容为06h
MOV XmtDat+5,#55h ;星期单元内容为03h
;MOV 46h,#0 ;年单元内容为00h
MOV XmtDat+6,#55h ;写保护单元内容为00h
ACALL Send_Byte ;调用写入数据子程序
RET ;返回调用本子程序处


;读出寄存器0-7 的内容程序设置如下
Read_Multiplebyte:
MOV Command,#0BFh ;命令字节为BFh
MOV ByteCnt,#8 ;多字节读出模式此模块为8 个
MOV R1,#RcvDat ;数据地址覆给R1
ACALL Receive_Byte; 调用读出数据子程序
RET; 返回调用本子程序处


;写入8 时12 小时模式程序设置如下
Write_Singlebyte:
MOV Command,#84h ; 命令字节为84h
MOV ByteCnt,#1 ; 单字节传送模式
MOV R0,#XmtDat ;数据地址覆给R0
MOV XmtDat,#88h ;数据内容为88h
ACALL Send_Byte ;调用写入数据子程序
RET ;返回调用本子程序处

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

exchange:

mov a,46h
mov b,#10H
div ab ;把40H高低4位分开
mov 3Dh,a ;高4位存入31H单元
mov a,b
mov 3Ch,a ;低4位存入30H单元

mov a,45h
mov b,#10H
div ab ;把40H高低4位分开
mov 3Bh,a ;高4位存入31H单元
mov a,b
mov 3Ah,a ;低4位存入30H单元

mov a,44h
mov b,#10H
div ab ;把40H高低4位分开
mov 39h,a ;高4位存入31H单元
mov a,b
mov 38h,a ;低4位存入30H单元

mov a,43h
mov b,#10H
div ab ;把40H高低4位分开
mov 37h,a ;高4位存入31H单元
mov a,b
mov 36h,a ;低4位存入30H单元
                        ;;;;;;;
mov a,42h
mov b,#10H
div ab ;把41H高低4位分开
mov 35h,a ;高4位存入33H单元
mov a,b
mov 34h,a ;低4位存入32H单元

mov a,41h
mov b,#10H
div ab ;把41H高低4位分开
mov 33h,a ;高4位存入33H单元
mov a,b
mov 32h,a ;低4位存入32H单元

mov a,40h
mov b,#10H
div ab ;把40H高低4位分开
mov 31h,a ;高4位存入31H单元
mov a,b
mov 30h,a ;低4位存入30H单元
;ajmp exchange
ret
NOP
NOP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  DISP:

     MOV  p2,#12h
     MOV A,30H
     MOV DPTR,#TAB2
     MOVC A,@A+DPTR
     MOV P0,A
     ACALL  delay1

    MOV  p2,#52h
     MOV A,31H
     MOV DPTR,#TAB2
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1


    MOV  p2,#22h
     MOV A,32H
     MOV DPTR,#TAB1
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1


    MOV  p2,#0a2h
     MOV A,33H
     MOV DPTR,#TAB1
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1

    MOV  p2,#62h
     MOV A,34H
     MOV DPTR,#TAB1
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1

    MOV  p2,#0E2h
     MOV A,35H
     MOV DPTR,#TAB1
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1


    MOV  p2,#02h
     MOV A,36H
     MOV DPTR,#TAB1
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1

    MOV  p2,#82h
     MOV A,37H
     MOV DPTR,#TAB1
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1

    MOV  p2,#42h
     MOV A,38H
     MOV DPTR,#TAB1
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1


    MOV  p2,#0C2h
     MOV A,39H
     MOV DPTR,#TAB1
     MOVC A,@A+DPTR
     MOV P0,A
    ACALL  delay1


  AJMP DISP

delay1: MOV r2,#2
      D11: MOV r3,#50
        D12:MOV r4,#10

          D13:DJNZ r4,D13
              DJNZ r3,D12
               DJNZ r2,D11
               RET


TAB1: DB 14H ,77H, 4CH ,45H, 27H  ,85H  ,84H ,57H ,04H ,05H
TAB2: DB 03H, 3FH, 4AH, 2AH ,36H, 0A2H,82H ,3BH, 02H ,22H
end


 
 

相关帖子

沙发
szzhengjin| | 2007-2-5 15:04 | 只看该作者

#看不懂你那#55H是做什么的

现在我都用C,很少用汇编,我给你段你自己看吧,看你那些我也说不出为什么,没细看

#define RTC_OK                1        //操作成功
#define RTC_FAIL            0        //操作失败
#define SECOND_INVALID        40        //秒值无效
#define MINUTE_INVALID        41        //分钟值无效
#define HOUR_INVALID        42        //小时值无效
#define WEEK_INVALID        43        //星期值无效
#define DAY_INVALID            44        //日期值无效
#define MONTH_INVALID        45        //月份值无效
#define YEAR_INVALID        46        //年份值无效
#define CENTURY_INVALID        47        //世纪值无效

//时钟制式参数定义(暂没开启,全用24小时制)
#define MODE_12_HOUR    0x80    //12小时制,即有AM/PM
#define MODE_24_HOUR    0x00    //24小时制

//充电参数定义
#define CHARGE_ENABLE    0xA0    //开启充电,此时,若限流电阻选择SELECT_NONE,还是不能充电
#define CHARGE_DISABLE    0x00    //关闭充电
//充电二极管参数
#define SELECT_ONE_DIODE    0x04    //选择一个二极管
#define SELECT_TWO_DIODE    0x08    //选择二个二极管
//充电限流电阻参数
#define SELECT_NONE        0x00    //不用连,即断开充电电路
#define SELECT_R1_2k    0x01    //选择电阻1,2K
#define SELECT_R2_4k    0x02    //选择电阻2,4K
#define SELECT_R3_8k    0x03    //选择电阻3,8K


#define RAM_MAXSIZE        31    //时钟内部用户可自定义的RAM最大空间

typedef struct _DATETIME
{
    unsigned char Century;
    unsigned char Year;
    unsigned char Month;
    unsigned char Day;
    unsigned char Hour;
    unsigned char Min;
    unsigned char Sec;
    unsigned char Week;
}sttDateTime;

sbit    RST        =    P1^5;
sbit    SCL        =    P1^6;
sbit    SDA        =    P1^7;

#define SEC_ADDR        0x80    //1000 0000
#define MIN_ADDR        0x82    //1000 0010
#define HOUR_ADDR        0x84    //1000 0100
#define DAY_ADDR        0x86    //1000 0110
#define MOM_ADDR        0x88    //1000 1000
#define WEEK_ADDR        0x8A    //1000 1010
#define YEAR_ADDR        0x8C    //1000 1100    
#define CENTURY_ADDR    0xC0    //1100 0000        用其RTC内存一字节作为年世纪字节
#define CONTROL_ADDR    0x8E    //1000 1110
#define TRCH_ADDR        0x90    //1001 0000    

#define RAM_BASE_ADDR    0xC0

#define READ            1
#define WRITE            0

void DS1302_SendByte(unsigned char Data)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        SCL = 0;
        SDA = (bit)(Data & 0x01);
        SCL = 1;
        Data >>= 1;
    }
    return;
}


unsigned char DS1302_ReadByte(void)
{
    unsigned char i,Data;
    SDA = 1;
    for(i=0;i<8;i++) 
    {
        Data >>= 1;
        SCL = 0;
        if(SDA==1) Data |= 0x80;
        SCL = 1;
    }
    return(Data);
}

void  DS1302WriteByte(unsigned char Addr, unsigned char Data)
{
    SCL = 0;
    RST = 1;
    DS1302_SendByte(Addr);
    DS1302_SendByte(Data);
    RST = 0;
    return ;
}

unsigned char DS1302ReadByte(unsigned char Addr)
{
    unsigned char Data;
    SCL = 0;
    RST = 1;
    DS1302_SendByte(Addr | READ);
    Data = DS1302_ReadByte();
    RST = 0;
    return Data;
}

//初始化时钟
void InitDS1302(unsigned char ChargeMode)
{
    unsigned char i;
    SCL = 0;
    RST = 0;
    DS1302WriteByte(CONTROL_ADDR,0x00);    //WP=0;
    i = DS1302ReadByte(SEC_ADDR);
    if((i & 0x80) == 0x80) 
    {    //若时钟丢失,即锂电池没电时,自动复位为2005-1-1 00:00:00 星期六
        DS1302WriteByte(CENTURY_ADDR,0x20);
        DS1302WriteByte(YEAR_ADDR,0x06);
        DS1302WriteByte(MOM_ADDR,0x01);
        DS1302WriteByte(DAY_ADDR,0x01);
        DS1302WriteByte(HOUR_ADDR,0x00);
        DS1302WriteByte(MIN_ADDR,0x00);
        DS1302WriteByte(SEC_ADDR,0x00);
        DS1302WriteByte(WEEK_ADDR,0x00);
    }
    DS1302WriteByte(TRCH_ADDR,ChargeMode);//设置充电模式
    DS1302WriteByte(CONTROL_ADDR,0x80);    //WP=1;
}

//读时钟
void ReadClock(sttDateTime *pstDateTime)
{
    //pstDateTime->Century = DS1302ReadByte(CENTURY_ADDR);
    pstDateTime->Year   = DS1302ReadByte(YEAR_ADDR);
    if(pstDateTime->Year < 0x80)
        pstDateTime->Century = 0x20;
    else
        pstDateTime->Century = 0x19;
    pstDateTime->Month  = DS1302ReadByte(MOM_ADDR);
    pstDateTime->Day    = DS1302ReadByte(DAY_ADDR);
    pstDateTime->Hour   = DS1302ReadByte(HOUR_ADDR);
    pstDateTime->Min    = DS1302ReadByte(MIN_ADDR);
    pstDateTime->Sec    = DS1302ReadByte(SEC_ADDR);
    pstDateTime->Week   = DS1302ReadByte(WEEK_ADDR);
}


//写时钟
void WriteClock(sttDateTime *pstDateTime)
{
    DS1302WriteByte(CONTROL_ADDR,0x00);    //WP=0;
    DS1302WriteByte(CENTURY_ADDR,pstDateTime->Century);
    DS1302WriteByte(YEAR_ADDR,pstDateTime->Year);
    DS1302WriteByte(MOM_ADDR,pstDateTime->Month);
    DS1302WriteByte(DAY_ADDR,pstDateTime->Day);
    DS1302WriteByte(HOUR_ADDR,pstDateTime->Hour);
    DS1302WriteByte(MIN_ADDR,pstDateTime->Min);
    DS1302WriteByte(SEC_ADDR,pstDateTime->Sec);
    DS1302WriteByte(WEEK_ADDR,pstDateTime->Week);
    DS1302WriteByte(CONTROL_ADDR,0x80);    //WP=1;
}

使用特权

评论回复
板凳
lzfact|  楼主 | 2007-2-5 21:08 | 只看该作者

谢谢这位仁兄

#55H是我任意输入的一个初始数值,下面的程序不是DS1302内部已经定义了吗?
还要定义一次?
我先试试,谢谢!




//时钟制式参数定义(暂没开启,全用24小时制)
#define MODE_12_HOUR    0x80    //12小时制,即有AM/PM
#define MODE_24_HOUR    0x00    //24小时制

//充电参数定义
#define CHARGE_ENABLE    0xA0    //开启充电,此时,若限流电阻选择SELECT_NONE,还是不能充电
#define CHARGE_DISABLE    0x00    //关闭充电
//充电二极管参数
#define SELECT_ONE_DIODE    0x04    //选择一个二极管
#define SELECT_TWO_DIODE    0x08    //选择二个二极管
//充电限流电阻参数
#define SELECT_NONE        0x00    //不用连,即断开充电电路
#define SELECT_R1_2k    0x01    //选择电阻1,2K
#define SELECT_R2_4k    0x02    //选择电阻2,4K
#define SELECT_R3_8k    0x03    //选择电阻3,8K


#define RAM_MAXSIZE        31    //时钟内部用户可自定义的RAM最大空间

使用特权

评论回复
地板
lzfact|  楼主 | 2007-2-6 10:13 | 只看该作者

RE;

使用特权

评论回复
5
szzhengjin| | 2007-2-6 10:19 | 只看该作者

那些是定义好的,只是我定义成宏,方便调用

要使程序灵活,多定义些宏,以后调用就可以了,那些宏都是头文件里的
这样做方便以后调用时就不用再去查datasheet了,看一下头文件便知道怎么用了

使用特权

评论回复
6
lzfact|  楼主 | 2007-2-6 10:23 | 只看该作者

RE

请问:DS1302的程序流程是怎么样的,我只要求能够设置初始值,并让其计时读出显示。我现在的流程是这样的,看行不行
1、写允许;2、启动时钟开始;3、写入初试时钟值;4、禁止写允许;5、读出数据显示。不断的循环第5步;
仅仅是这样可以吗?写初始和读数据都是用多字节方式,其它设置为单字节。
请指教

使用特权

评论回复
7
szzhengjin| | 2007-2-6 14:27 | 只看该作者

运用中不用每次那样

我给你的函数,启动后,执行初始化一次

初始化时判断秒钟最高位是否为1,若为1则表示时钟已停止,时钟数据已无效,需重新设置(即校对时钟,这里没办法知道当前时钟,只能恢复成一个默认值)

初始化完成后,就是一直取时钟就可以了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

6

帖子

0

粉丝