bbxyliyang08 发表于 2012-11-11 17:15:47

ds1302 电子时钟

#include<reg51.h>
#define uint8 unsigned char
#define uint16 unsigned int
sbit RST=P1^7;
sbit SDA=P3^5;
sbit SCK=P1^6;
uint8 LedBitCnt; //LedBitCnt控制数码管的位选
uint8 ms2_flag; //2ms数码管动态扫描时标消息
uint8 ms10_flag,ms500_flag;
uint8 ms2_cnt,ms10_cnt,count,s1num;
uint8 dis_buff={0};
uint8 shi=12,fen=23,miao=56;
uint8 code SegTab[]={0x3f,0x06,0x5b,0x4f,
                                        0x66,0x6d,0x7d,0x07,
                                        0x7f,0x6f,0x40,0x00};
sbit ADDR0 = P2^0;//74hc138的输入控制端A
sbit ADDR1 = P2^1;//74hc138的输入控制端B
sbit ADDR2 = P2^2;//74hc138的输入控制端C
sbit adjust=P3^2;
sbit add=P3^3;
sbit sub=P3^4;

//常数宏
#define DS1302_SECOND_WRITE 0x80//写时钟芯片的寄存器位置
#define DS1302_MINUTE_WRITE 0x82
#define DS1302_HOUR_WRITE   0x84
#define DS1302_SECOND_READ0x81//读时钟芯片的寄存器位置
#define DS1302_MINUTE_READ0x83
#define DS1302_HOUR_READ0x85


void reset_ds1302(void)
{
        RST=0;
        SCK=0;
        RST=1;
}

/****************************
*名称:write_ds1302_byte
*说明:无
*功能: 写入8bit数据
*调用: 无
*输入:dat:要写入的数据
*输出:无
*****************************/
void write_ds1302_byte(uint8 dat)
{
        uint8i;
        SCK=0;//初始化时钟线置为0
        for(i=0;i<8;i++)//开始传输8个字节的数据
        {
                SDA=dat&0x01;//取最低位,注意DS1302的数据
                     //和地址都是从最低位开始传输的
                SCK=1;//时钟线拉高,制造上升沿,SDA数据被传输
                SCK=0;//时钟线拉低,为下个上升沿做准备
                dat>>=1;//数据右移一位,准备传输的下一位
        }
}
/****************************
*名称:read_ds1302_byte
*说明:无
*功能: 读取8bit数据
*调用: 无
*输入:dat:读取的数据
*输出:无
*****************************/
uint8 read_ds1302_byte(void)
{
        uint8i ,dat=0;
    for (i=0;i<8;i++)
        {
                dat >>=1;
                if(SDA)
      dat|=0x80;
                SCK=1;
                SCK=0;//制造下降沿
    }
                return dat;
}

/****************************
*名称:write_ds1302
*说明:先写地址,后写数据
*功能:向addr相应地址中写一个字节的数据
*调用: write_ds1302_byte()
*输入:addr:要写入的控制字,dat:要写入的数据
*输出:无
*****************************/
void write_ds1302(uint8 addr,uint8 dat)
{
                reset_ds1302();
          write_ds1302_byte(addr);
                write_ds1302_byte((dat/10)<<4|(dat%10));
       //将10进制转化为压缩的BCD码,传输时为BCD码
      SCK=1;//时钟线拉高
                RST=0;//读取结束,CE置0,结束数据的传输

}
/****************************
*名称:uint8 read_ds1302
*说明:先写地址,后读数据
*功能: 从addr相应地址中读取一个字节的数据
*调用: write_ds1302_byte(),read_ds1302_byte()
*输入:addr:要写入的控制字
*输出:dat:要写入的数据
*****************************/
uint8 read_ds1302(uint8 addr)
{
                uint8 dat,datH,datL,temp=0;
                reset_ds1302();
          write_ds1302_byte(addr);
      dat=read_ds1302_byte();
               
      SCK=1;
                RST=0;
                datH=dat/16;//将压缩的BCD码转换为十进制相当于左移4位
      datL=dat%16;                           
      temp=datH*10+datL;
                return temp;//返回得到的时间/日期

}
/****************************
*名称:void Init_DS1302
*说明:给1302写一个初始值
*功能:
*调用: write_ds1302()
*输入:无
*输出:无
*****************************/
void Init_DS1302(void)
{
        write_ds1302(0x8e,0x00);//写保护关
        write_ds1302(DS1302_SECOND_WRITE,40);
        write_ds1302(DS1302_MINUTE_WRITE,59);
        write_ds1302(DS1302_HOUR_WRITE,23);//初始24小时模式
    write_ds1302(0x8e,0x80);//写保护开
}

void init()
{
        TMOD=0x01;
        TH1=0xf8;
        TL1=0xcd;
    ET0=1;
        TR1=1;
        ET1=1;                       
}
void time_to_disbuff(void)
{
       
                dis_buff=miao%10;
                dis_buff=miao/10;
          dis_buff=10;
      dis_buff=fen%10;
                dis_buff=fen/10;
      dis_buff=10;
      dis_buff=shi%10;
                dis_buff=shi/10;

}
void disp()
{
        P0=SegTab];
        switch(LedBitCnt)
        {
                case 0:
                ADDR0=0;ADDR1=0;ADDR2=0;
                break;
                case 1:
                ADDR0=1;ADDR1=0;ADDR2=0;
                break;
                case 2:
                ADDR0=0;ADDR1=1;ADDR2=0;
                break;
                case 3:
                ADDR0=1;ADDR1=1;ADDR2=0;
                break;
                case 4:
                ADDR0=0;ADDR1=0;ADDR2=1;
                break;
                case 5:
                ADDR0=1;ADDR1=0;ADDR2=1;
                break;
                case 6:
                ADDR0=0;ADDR1=1;ADDR2=1;
                break;
                case 7:
                ADDR0=1;ADDR1=1;ADDR2=1;
                break;
        }

}

void main()
{
        Init_DS1302();
        init();
        EA=1;

        while(1)
        {
               
                        miao=read_ds1302(DS1302_SECOND_READ);
                        fen=read_ds1302(DS1302_MINUTE_READ);
                        shi=read_ds1302(DS1302_HOUR_READ);
                        if(ms2_flag)
              {
                     ms2_flag=0;
                     LedBitCnt++;
                  if(LedBitCnt>7)
                  {
                        LedBitCnt=0;
                  }
                  time_to_disbuff();
                  disp();
                  }       
        }

}
void timer1() interrupt 3//定时1ms
{
        TH1=0xf8;
        TL1=0xcd;
        ms2_flag=1;   //用于数码管显示
        ms2_cnt++;
        if(ms2_cnt>=5)
        {
                ms2_cnt=0;
                ms10_flag=1;//用于键扫描
                if(++ms10_cnt>=50)
                        {
                                ms10_cnt=0;
                                ms500_flag=~ms500_flag;
                        }
        }
}

bbxyliyang08 发表于 2012-11-11 17:25:21

成功读取DS1302的时间,现在在添加按键调时遇到了问题,在第一次按下调整键时候,停止走时,显示秒的两位数码管以1 Hz 频率闪烁;如果第二次按下调整键,则分开始闪烁,秒恢复正常显示;如果第三次按下调整键,则时开始闪烁,分恢复正常显示;如果第四次按下调整键,时恢复正常显示,开始走时。在数码管闪烁的时候,按下加或者减键可以调整相应的显示内容,按下加减时要把调整后的数据送到时钟寄存器中后,在读出来,还是直接显示?

sf49ers 发表于 2012-11-11 21:33:00

一般是在进调整状态时,把当前时钟读到一个缓存中,调整时钟其实是在调整缓存中的数据,当调整完一起写入1302,并开始走时。调整期间,1302会按原时钟继续走时。
另外,你这个帖子放这个版不合适

bbxyliyang08 发表于 2012-11-11 23:17:06

sf49ers 发表于 2012-11-11 21:33 static/image/common/back.gif
一般是在进调整状态时,把当前时钟读到一个缓存中,调整时钟其实是在调整缓存中的数据,当调整完一起写入13 ...

一般的时钟不是进入调时状态,都停止走时,我的功能键第一次按下,调整秒的,我要把秒从0x80中读出来,当按加时,秒++,在把这个值写进0x80,最后在送到数码管显示?

sf49ers 发表于 2012-11-11 23:41:41

bbxyliyang08 发表于 2012-11-11 23:17 static/image/common/back.gif
一般的时钟不是进入调时状态,都停止走时,我的功能键第一次按下,调整秒的,我要把秒从0x80中读出来,当 ...

干吗做这么麻烦,反正时钟不走了,中间往1302写有什么意义。
如果象pc界面那样,专门有个取消键,本次调整无效,按原时间走,你怎么办

bbxyliyang08 发表于 2012-11-12 00:02:16

void keyscan()
{
        if(adjust==0)
                {
                        delayms(10);
                        if(adjust==0)
                                {
                                        s1num++;
                                        while(!adjust);
                                        if(s1num==1)
                                        {
                                                flagm=1;
                                                TR0=0;
                                        }
                                }
                }
               
                        if(s1num==2)
                {
                        flagm=0;
                        flagf=1;
                }

       if(s1num==3)
                {
                        flagm=0;
                        flagf=0;
                        flags=1;
                }
        if(s1num==4)
        {
                TR0=1;
                flags=0;
                s1num=0;
        }
        if(adjust!=0)
                {
                        if(add==0)
                        {
                                delayms(10);
                                if(add==0)
                                {
                                        while(!add);
                                        if(s1num==1)
                                        {
                                                miao++;
                                                if(miao==60)
                                                        miao=0;
                                       
                                               
                                               
                                        }
                                        if(s1num==2)
                                        {
                                                fen++;
                                                if(fen==60)
                                                        fen=0;
                                               
                                       
                                        }
                                        if(s1num==3)
                                        {
                                                shi++;
                                                if(shi==24)
                                                        shi=0;
                                               
                                        }
                                }
                        }
                        if(sub==0)
                        {
                                delayms(10);
                                if(sub==0)
                                {
                                        while(!sub);
                                        if(s1num==1)
                                        {
                                       
                                                miao--;
                                                if(miao==-1)
                                                        miao=59;
                                               
                                        }
                                        if(s1num==2)
                                        {
                                                fen--;
                                                if(fen==-1)
                                                        fen=59;
                                       
                                        }
                                        if(s1num==3)
                                        {
                                                shi--;
                                                if(shi==-1)
                                                        shi=23;
                                               
                                        }
                                }
                        }
                }
       
             write_ds1302(DS1302_SECOND_WRITE,miao);
         write_ds1302(DS1302_MINUTE_WRITE,fen);
      write_ds1302(DS1302_HOUR_WRITE,shi);
}

bbxyliyang08 发表于 2012-11-12 00:03:13

这样写对吗?
页: [1]
查看完整版本: ds1302 电子时钟