• 1
  • 新人请关照

c51 1602显示ds1302时间不正常?

定时器定时,每秒读取一次ds1302时间。
第一次能够成功读取预设时间,之后就不正常。
1.ds1302头文件

#ifndef _DS1302_H_
#define _DS1302_H_
#include <reg52.h>

sbit DS1302_IO = P3^4;            //ds1302串行数据引脚
sbit DS1302_CE = P3^5;            //ds1302使能引脚、复位引脚
sbit DS1302_CK = P3^6;            //ds1302串行时钟引脚

void DS1302BurstInit();                                //ds1302突发模式初始化
void ds1302BurstRead(unsigned char *dat);            //ds1302突发模式连续读

#endif

2.ds1302文件

#include "ds1302.h"

//ds1302写字节操作(低位->高位),上升沿写
void ds1302ByteWrite(unsigned char dat) {
    unsigned char i=0;
    
    for(i=0; i<8; i++) {
        DS1302_IO = dat & 0x01;
        dat >>= 1;
        DS1302_CK = 1;
        DS1302_CK = 0;
    }
}

//ds1302读字节操作(低位->高位),下降沿读
unsigned char ds1302ByteRead() {
    unsigned char i=0, dat=0;
    
    for(i=0; i<8; i++) {
        dat >>= 1;
        dat |= (unsigned char)DS1302_IO << 7;
        
        DS1302_CK = 1;
        DS1302_CK = 0;
    }
    
    return dat;
}

//ds1302单次写操作(向某一寄存器写入一个字节)
void ds1302SingleWrite(unsigned char addr, unsigned char dat) {
    DS1302_CE = 1;
    ds1302ByteWrite(addr);
    ds1302ByteWrite(dat);
    DS1302_CE = 0;
}

//ds1302单次读操作(从某一寄存器读出一个字节)
unsigned char ds1302SingleRead(unsigned char addr) {
    unsigned char dat = 0;
    
    DS1302_CE = 1;
    ds1302ByteWrite(addr);
    dat = ds1302ByteRead();
    DS1302_CE = 0;
    
    DS1302_CK = 1;
    DS1302_IO = 1;
    DS1302_IO = 0;
    
    return dat;
}

//ds1302突发模式写操作(连续写入8个字节)
void ds1302BurstWrite(unsigned char *dat) {
    unsigned char i=0;
    
    DS1302_CE = 1;
    ds1302ByteWrite(0xBE);                    //发送突发写寄存器指令
    //连续写入8个字节
    for(i=0; i<8; i++) {
        ds1302ByteWrite(dat[i]);
    }
    DS1302_CE = 0;
}

//ds1302突发模式读操作(连续读取8个字节)
void ds1302BurstRead(unsigned char *dat) {
    unsigned char i=0;
    
    DS1302_CE = 1;
    ds1302ByteWrite(0xBF);                    //发送突发读寄存器指令
    //连续读取8个字节
    for(i=0; i<8; i++) {
        *dat++ = ds1302ByteRead();
        
    }
    DS1302_CE = 0;
}

//ds1302突发模式初始化
void DS1302BurstInit() {
    unsigned char ch=0;                        //时钟停止标志位
    
    //初始化时间(秒、分、时、日、月、星期、年、写保护位)(2000年1月1日星期六 00:00:00)
    unsigned char code InitTime[] = {
        0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00, 0x00
    }; 
    
    //初始化ds1302通信引脚
    DS1302_CE = 0;
    DS1302_CK = 0;
    
    ch = ds1302SingleRead(0x81);            //读取秒寄存器
    //由秒寄存器最高位CH的值判断DS1302是否停止工作(已停止工作则初始化时钟)
    if((ch & 0x80) != 0) {
        ds1302SingleWrite(0x8E, 0x00);        //撤销写保护功能,允许写入数据
        ds1302BurstWrite(InitTime);
    }
    
    ds1302SingleWrite(0x8E, 0x80);            //打开写保护功能,禁止写入数据
}

3.主文件

#include <reg52.h>
#include "ds1302.h"
#include "lcd1602.h"

bit flag200ms;

void timeProcessDisplay(unsigned char *dat);
void ConfigInterrupt();
void Time0();

void main() {
    unsigned char time[8] = {0};
    
    ConfigInterrupt();    
    DS1302BurstInit();
    lcdInit();
    lcdFullclear();
    flag200ms = 1;
    while(1) {
        if(flag200ms) {
            flag200ms = 0;
            
            ds1302BurstRead(time);
            timeProcessDisplay(time);
        }
    }
}

//时间处理及显示
void timeProcessDisplay(unsigned char *dat) {
    static unsigned char secBackup = 0x60;    //秒备份值(判断是否需要刷新显示,确保首次刷新显示)
    unsigned char str[12] = {0};
     
    if(secBackup != dat[0]) {
        lcdFullclear();
        
        str[0]  = '2';
        str[1]  = '0';
        str[2]  = (dat[6] >> 4) + '0';
        str[3]  = (dat[6]&0x0f) + '0';
        str[4]  = '-';
        str[5]  = (dat[4] >> 4) + '0';
        str[6]  = (dat[4]&0x0f) + '0';
        str[7]  = '-';
        str[8]  = (dat[3] >> 4) + '0';
        str[9]  = (dat[3]&0x0f) + '0';
        str[10] = '\0';
        lcdShowStr(0, 2, str);
        
        str[0]  = (dat[5]&0x0f) + '0';
        str[1]  = '\0';
        lcdShowStr(0, 13, str);
        
        str[0]  = (dat[2] >> 4) + '0';
        str[1]  = (dat[2]&0x0f) + '0';
        str[2]  = ':';
        str[3]  = (dat[1] >> 4) + '0';
        str[4]  = (dat[1]&0x0f) + '0';
        str[5]  = ':';
        str[6]  = (dat[0] >> 4) + '0';
        str[7]  = (dat[0]&0x0f) + '0';
        str[8] = '\0';
        lcdShowStr(1, 4, str);
        
        secBackup = dat[0];
    }
}

//中断配置
void ConfigInterrupt() {
    TMOD &= 0xf0;
    TMOD |= 0x01;
    
    //1ms
    TH0 = 0xfc;
    TL0 = 0x82;
    
    ET0 = 1;
    EA  = 1;
    
    TR0 = 0;
}

//定时器0中断
void Time0() interrupt 1 {
    static unsigned char time200ms = 0;
    
    //1ms
    TH0 = 0xfc;
    TL0 = 0x82;
    
    time200ms++;
    if(time200ms >= 200) {
        time200ms = 0;
        flag200ms = 1;
    }
}

lcd1602程序文件应该没问题,就不贴出来占地方了。时间数据处理函数测试过应该也没问题。用的是普中的板子。
烦请网友帮忙看一下哪里出问题了,自己检查好久都没找出来问题。

阅读 108
评论
    0 个回答
    撰写回答

    登录后参与交流、获取后续更新提醒

    相似问题
    社区建设
    合作问答

    欢迎来到 SegmentFault 0x 社区建设。这里可以讨论有关 SegmentFault 的一切,帮助我们改进产品、完善社...

    推荐文章