C51实时时钟SD24XX读写演示程序

感情迁移 提交于 2020-01-12 06:44:42


//************************************************************
// 实时时钟SD24XX读写C51演示程序
// MCU: STC15W1K16S   @11.0592MHz
// E-mail:   FAE@whwave.com.cn
// TEL:         0755-83114387
// Last update:                   2016/11/8
//************************************************************

#include <reg51.h>
#include <intrins.h>

/******************** RTC Device address ********************/
#define        RTC_Address            0x64

/******************** EEPROM/NVSRAM存储器地址宏定义 ********************/
#define        EE_FirstPage_Address        0xA0//第一页(尾缀B、C、D、E、F型)
#define        EE_SecondPage_Address        0xA2//第二页(尾缀B、C型)
#define        EE_ThirdPage_Address        0xA4//第三页(尾缀C型)
#define        EE_FourthPage_Address        0xA6//第四页(尾缀C型)
#define        EE_FifthPage_Address        0xA8//第五页(尾缀C型)
#define        EE_SixthPage_Address        0xAA//第六页(尾缀C型)
#define        EE_SeventhPage_Address    0xAC//第七页(尾缀C型)
#define        EE_EighthPage_Address        0xAE//第八页(尾缀C型)

/******************** Alarm register ********************/
#define        Alarm_SC    0x07
#define        Alarm_MN    0x08
#define        Alarm_HR    0x09
#define        Alarm_WK    0x0A
#define        Alarm_DY    0x0B
#define        Alarm_MO    0x0C
#define        Alarm_YR    0x0D
#define        Alarm_EN    0x0E

/******************** Control Register ********************/
#define        CTR1                        0x0F
#define        CTR2                        0x10
#define        CTR3                        0x11

/***************** Time Trimming Register ***********************/
#define        TTF                            0x12

/***************** Timer Counter Register ***********************/
#define        Timer_Counter        0x13

/******************** User Ram Register ***********************/
#define        User_ram14H            0x14
#define        User_ram15H            0x15
#define        User_ram16H            0x16
#define        User_ram17H            0x17
#define        User_ram18H            0x18
#define        User_ram19H            0x19
#define        User_ram1AH            0x1A
#define        User_ram1BH            0x1B
#define        User_ram1CH            0x1C
#define        User_ram1DH            0x1D
#define        User_ram1EH            0x1E
#define        User_ram1FH            0x1F

/***********************************************************/
#define        NULL                      0

#define        TRUE                      1
#define     FALSE                     0

//*********变量及IO口定义*********
typedef unsigned char uchar;
typedef unsigned int uint;

sfr AUXR  = 0x8e;               //辅助寄存器
sfr T2H   = 0xd6;               //定时器2高8位
sfr T2L   = 0xd7;               //定时器2低8位

sbit SDA    =    P1^5;//EEPROM和RTC共总线
sbit SCL    =    P1^6;//EEPROM和RTC共总线

uchar   E_data[8];    // EEPROM数据缓存器
uchar    Sram[8] = {"01234567"};        //通用数据缓存器
typedef    struct
{
    uchar second;
    uchar    minute;
    uchar    hour;
    uchar    week;
    uchar    day;
    uchar    month;
    uchar    year;
}S_Time;    

S_Time  RTC={0x55,0x59,0x14,0x02,0x26,0x01,0x16};    //初始化时间结构体变量(设置时间:2016年1月26日 14:59:55  星期二)
//           55秒 59分 14时 周二 26日 1月 16年

/********SD24XX函数名********/
uchar I2CReadOneByte(uchar DeviceAddress, uchar add);//读一字节
bit   I2CWriteOneByte(uchar DeviceAddress,uchar add, uchar date);//写一字节
uchar I2CReadSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps);//连续读
uchar I2CWriteSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps);//连续写
bit   I2CWriteDate(S_Time    *SetRTC);//写时间    
bit   I2CReadDate(S_Time    *psRTC);//读时间
bit   WriteRTC_Enable(void);//写允许
bit   WriteRTC_Disable(void);//写禁止

/*********I2C延时4us***********/
void I2CWait(void)//4us  @11.0592MHz
{    
    unsigned char i;

    _nop_();
    _nop_();
    i = 8;
    while (--i);
}

/********开启SD24XX的I2C总线********/
bit I2CStart(void)
{
    SDA = 1;
    I2CWait();
    SCL = 1;
    I2CWait();
    if(!SDA)return FALSE;    //SDA线为低电平则总线忙,退出
    SDA = 0;
    I2CWait();
    SCL = 0;
    I2CWait();
    return TRUE;
}

/********关闭SD24XX的I2C总线*******/
void I2CStop(void)
{
    SDA = 0;
    I2CWait();
    SCL = 0;
    I2CWait();
    SCL = 1;
    I2CWait();
    SDA = 1;
}

/*********发送 ACK*********/
void I2CAck(void)
{    
    SDA = 0;
    SCL = 0;
    I2CWait();
    SCL = 1;
    I2CWait();
    SCL = 0;
}

/*********发送NO ACK*********/
void I2CNoAck(void)
{    
    SDA = 1;
    SCL = 0;
    I2CWait();
    SCL = 1;
    I2CWait();
    SCL = 0;
}

/*********读取ACK信号*********/
bit I2CWaitAck(void)      //返回为:1=有ACK,0=无ACK
{
    SCL = 0;
    SDA = 1;    //设置SDA为输入(其它类型的单片机需要配置IO输入输出寄存器)
    I2CWait();
    SCL = 1;
    I2CWait();
    while(SDA)
    {
        SCL = 0;
        return FALSE;
    }
    SCL = 0;
    return TRUE;
}

/************MCU向SD24XX发送一个字节*************/
void I2CSendByte(uchar demand) //数据从高位到低位//
{
    uchar i = 8;                                                    
    
    while(i--)
    {
        SCL = 0;
        _nop_();
        SDA=(bit)(demand&0x80);
        demand <<= 1;
        I2CWait();
        SCL = 1;
        I2CWait();
    }
    SCL = 0;
}

/*********MCU从SD24XX读入一字节*********/
uchar I2CReceiveByte(void)      //数据从高位到低位//
{
    uchar i = 8;
    uchar ddata = 0;
    SDA = 1;        //设置SDA为输入(其它类型的单片机需要配置IO输入输出寄存器)
    while(i--)
    {
        ddata <<= 1;    //数据从高位开始读取
        SCL = 0;
        I2CWait();
        SCL = 1;
        I2CWait();    //从高位开始 ddata|=SDA;ddata<<=1
        if(SDA)
        {
            ddata |= 0x01;
        }
    }
    SCL = 0;
    return ddata;
}

/******I2C写一个字节******/
bit I2CWriteOneByte(uchar DeviceAddress,uchar add, uchar date)
{        
    if(!I2CStart())return FALSE;
    I2CSendByte(DeviceAddress);      
    if(!I2CWaitAck()){I2CStop(); return FALSE;}
    I2CSendByte(add);        //设置写地址      
    I2CWaitAck();    
    I2CSendByte(date);        //写数据
    I2CWaitAck();    
    I2CStop();
    return    TRUE;
}

/******I2C读一个字节程序******/
uchar I2CReadOneByte(uchar DeviceAddress,uchar add)
{        
    uchar dat;
    if(!I2CStart())return FALSE;
    I2CSendByte(DeviceAddress);      
    if(!I2CWaitAck()){I2CStop(); return FALSE;}
  I2CSendByte(add);                //设置要读的地址
    I2CWaitAck();
    I2CStart();    
     I2CSendByte(DeviceAddress+1);    
    I2CWaitAck();    
    dat = I2CReceiveByte();        //读数据
    I2CNoAck();
    I2CStop();
    return  dat;
}

/******写SD24XX允许程序******/
bit WriteRTC_Enable(void)
{        
    if(!I2CWriteOneByte(RTC_Address,CTR2,0x80))return FALSE;
    I2CWriteOneByte(RTC_Address,CTR1,0x84);
    return    TRUE;
}

/******写SD24XX禁止程序******/
bit WriteRTC_Disable(void)
{        
    if(!I2CWriteOneByte(RTC_Address,CTR1,0))return FALSE;
    I2CWriteOneByte(RTC_Address,CTR2,0);
    return    TRUE;
}

/******读SD24XX实时数据寄存器******/
bit I2CReadDate(S_Time    *psRTC)
{
    
    if(!I2CStart())return FALSE;
    I2CSendByte(RTC_Address+1);
  if(!I2CWaitAck()){I2CStop(); return FALSE;}
    psRTC->second = I2CReceiveByte();
    I2CAck();
    psRTC->minute = I2CReceiveByte();
    I2CAck();
    psRTC->hour = I2CReceiveByte() & 0x3f;
    I2CAck();
    psRTC->week = I2CReceiveByte();
    I2CAck();
    psRTC->day = I2CReceiveByte();
    I2CAck();
    psRTC->month = I2CReceiveByte();
    I2CAck();
    psRTC->year = I2CReceiveByte();
    I2CNoAck();        //读时间完成,发送NoAck
    I2CStop();
    return    TRUE;
}

/******写SD24XX实时数据寄存器******/
bit I2CWriteDate(S_Time    *psRTC)    //写时间操作要求一次对实时时间寄存器(00H~06H)依次写入,
{                               //不可以单独对7个时间数据中的某一位进行写操作,否则可能会引起时间数据的错误进位.
                                //要修改其中某一个数据 , 应一次性写入全部 7 个实时时钟数据.

    WriteRTC_Enable();            //使能,开锁
    if(!I2CStart())return FALSE;
    I2CSendByte(RTC_Address);
    if(!I2CWaitAck()){I2CStop(); return FALSE;}
    I2CSendByte(0x00);            //设置写起始地址      
    I2CWaitAck();    
    I2CSendByte(psRTC->second);        //second     
    I2CWaitAck();    
    I2CSendByte(psRTC->minute);        //minute      
    I2CWaitAck();    
    I2CSendByte(psRTC->hour|0x80);        //hour ,同时设置小时寄存器最高位(0:为12小时制,1:为24小时制)
    I2CWaitAck();    
    I2CSendByte(psRTC->week);        //week      
    I2CWaitAck();    
    I2CSendByte(psRTC->day);        //day      
    I2CWaitAck();    
    I2CSendByte(psRTC->month);            //month      
    I2CWaitAck();    
    I2CSendByte(psRTC->year);        //year      
    I2CWaitAck();    
    I2CStop();
    
    I2CWriteOneByte(RTC_Address,TTF,NULL);  //如果不需要调整时间快慢,请给TTF调整寄存器清零
    
    WriteRTC_Disable();                //上锁
    return    TRUE;
}


/******设置SD24XX报警中断演示程序演示******/
void WriteALARM(void)                //设置报警时间:2016年2月14日 8:00
{                        
    WriteRTC_Enable();
    I2CWriteOneByte(RTC_Address,Alarm_HR,0x08);    //8时
    I2CWriteOneByte(RTC_Address,Alarm_DY,0x14);    //14日
    I2CWriteOneByte(RTC_Address,Alarm_MO,0x02);    //02月
    I2CWriteOneByte(RTC_Address,Alarm_YR,0x16);    //16年
    I2CWriteOneByte(RTC_Address,Alarm_EN,0x74);    //设置报警允许(使能年、月、日、小时报警)
    I2CWriteOneByte(RTC_Address,CTR2,0x92);            //设置INT中断选通(INTS1,INTS0),及报警中断总允许位(INTAE)
    WriteRTC_Disable();
}

/******设置SD24XX倒计时中断演示******/
void SetDjs(void)                        //设置倒计时中断
{
    WriteRTC_Enable();
    I2CWriteOneByte(RTC_Address,CTR2,0xF0);//先清倒计时中断总允许位(INTDE)
    I2CWriteOneByte(RTC_Address,CTR2,0xF4);//设置周期性中断(IM=1)INT中断选通(INTS1,INTS0),配置倒计时中断总允许位(INTDE)
    I2CWriteOneByte(RTC_Address,CTR3,0x20);//选择定时器频率源(TDS1、TDS0)为1HZ
    I2CWriteOneByte(RTC_Address,Timer_Counter,5);//倒计时初值寄存器,设置8位倒计时计数初值(5s)
    WriteRTC_Disable();
}

/******设置SD24XX频率中断演示******/
void SetFrq_2Hz(void)                    
{
    WriteRTC_Enable();
    I2CWriteOneByte(RTC_Address,CTR2,0xA1);    //选通频率中断(INTS1,INTS0),设置频率中断总允许位(INTFE)
    I2CWriteOneByte(RTC_Address,CTR3,0x09);    //设置2Hz频率中断
    WriteRTC_Disable();
}
/******禁止SD24XX中断******/
void ClrINT(void)         
{
    WriteRTC_Enable();
    I2CWriteOneByte(RTC_Address,CTR2,0x80);
    WriteRTC_Disable();
}
//|************I2C连续读多个字节************|
//|***尾缀B、C、F型读EEPROM程序(连续读)***|
uchar I2CReadSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps)
{
    uchar    i;
    if(!I2CStart())return FALSE;
    I2CSendByte(DeviceAddress);      
    if(!I2CWaitAck()){I2CStop(); return FALSE;}
    I2CSendByte(Address);            //设置要读的地址
    I2CWaitAck();
    I2CStart();    
     I2CSendByte(DeviceAddress+1);
    I2CWaitAck();
    for(i = 0;i<length-1;i++,ps++)
    {
        *ps = I2CReceiveByte();        //读数据
        I2CAck();
    }
    *ps = I2CReceiveByte();    
    I2CNoAck();
    I2CStop();
    return    TRUE;
}

//|******************I2C连续写多个字节******************|
//|******尾缀B、C型和F型写EEPROM程序(连续写)演示******|
uchar I2CWriteSerial(uchar DeviceAddress, uchar Address, uchar length,uchar *ps)
{
    uchar    i;
    if(!I2CStart())return FALSE;
    I2CSendByte(DeviceAddress);          //器件地址(或EEPROM页地址)
    if(!I2CWaitAck()){I2CStop(); return FALSE;}
    I2CSendByte(Address);            //设置起始地址
    I2CWaitAck();
    for(i = 0;i<length;i++)
    {     
        I2CSendByte(*(ps++));        //B、C型最多连续发送16个字节数据,F型最多连续发送8个字节数据,若使
        I2CAck();            //用的是NVSRAM则无此限制,可连续写任意多个数据直到存储器的末地址。
    }
    I2CStop();
    return    TRUE;
}

/******尾缀D、E型写EEPROM程序(连续写)******/
void WriteEE_DE(uchar sramadd, uchar sramdata)
{
    uchar n;
    I2CStart();
    I2CSendByte(EE_FirstPage_Address);        //发送页地址
    I2CWaitAck();
    I2CSendByte(sramadd >> 8);            //先发送高8位地址
    I2CWaitAck();
    I2CSendByte(sramadd & 0xFF);            //再发送低8位地址
    I2CWaitAck();  
    for(n = 0;n<8;n++)
    {
        I2CSendByte(sramdata++);        //D型最多连续发送32个字节数据,E型最多连续发送64个字节数据,若使用
        I2CWaitAck();                //的是NVSRAM则无此限制,可连续写任意多个数据直到存储器的末地址。
    }
    I2CStop();
            
}

/******D、E型读EEPROM程序******/
void ReadEE_DE(uchar sramadd, uchar length)
{
    uchar n;
    I2CStart();
    I2CSendByte(EE_FirstPage_Address);        //发送页地址
    I2CWaitAck();
    I2CSendByte(sramadd >> 8);            //先发送高8位地址
    I2CWaitAck();    
    I2CSendByte(sramadd & 0xFF);            //再发送低8位地址
    I2CWaitAck();
    I2CStart();                    //重发起始信号
    I2CSendByte(EE_FirstPage_Address+1);//发送读EEPROM命令
  I2CWaitAck();
    for(n = 0;n<length;n++)                //可读任意多个数据,直到存储器的末地址
    {
        E_data[n]=I2CReceiveByte();
        if (n!=length-1)            //最后一个数据不应答
        {
            I2CAck();
        }
    }
    I2CNoAck();
    I2CStop();
}

void UartInit(void)        //115200bps@11.0592MHz
{
    SCON = 0x50;        //8位数据,可变波特率
    AUXR |= 0x01;        //串口1选择定时器2为波特率发生器
    AUXR |= 0x04;        //定时器2时钟为Fosc,即1T
    T2L = 0xE8;        //设定定时初值
    T2H = 0xFF;        //设定定时初值
    AUXR |= 0x10;        //启动定时器2
}

void UartSend(uchar dat)
{
        SBUF = dat;
        while(!TI);
        TI = 0;    
}

void TxString(uchar *puts)        //串口发送字符串
{
  for (; *puts != 0;    puts++)       
    {
        SBUF = *puts;
        while(!TI);
        TI = 0;
    }
}

void RTC_display(void)
{
        TxString("\r\n\r\n");
        UartSend((RTC.hour >> 4) + '0');
        UartSend((RTC.hour & 0x0f) + '0');
        TxString("时");
        UartSend((RTC.minute >> 4) + '0');
        UartSend((RTC.minute & 0x0f) + '0');
        TxString("分");
        UartSend((RTC.second >> 4) + '0');
        UartSend((RTC.second & 0x0f) + '0');
        TxString("秒  ");

        UartSend((RTC.year >> 4) + '0');
        UartSend((RTC.year & 0x0f) + '0');
        TxString("年");
        UartSend((RTC.month >> 4) + '0');
        UartSend((RTC.month & 0x0f) + '0');
        TxString("月");
        UartSend((RTC.day >> 4) + '0');
        UartSend((RTC.day & 0x0f) + '0');
        TxString("日  星期");
        UartSend(RTC.week + '0');
}

/*********延时子程序*********/
void Delay1ms()        //@11.0592MHz
{
    unsigned char i, j;

    _nop_();
    _nop_();
    _nop_();
    i = 11;
    j = 190;
    do
    {
        while (--j);
    } while (--i);
}

void Delayms(uint n)
{
    while(n--)
        Delay1ms();
}
//////*****主程序演示*****//////
void main()
{
    UartInit();//115200bps@11.0592MHz
    I2CWriteDate(&RTC);    //设置时间演示,16年1月26日......
//    WriteALARM();        //设置报警中断时间演示
//    SetDjs();        //设置倒计时中断演示
    SetFrq_2Hz();        //设置频率中断(从INT脚输出方波)演示
    
//    I2CWriteSerial(EE_FirstPage_Address,0,8,&Sram); //把Sram数据写入SD2400CLPI EEPROM的00-07地址
//    Delayms(10);                    //写完EEPROM以后需要延时10ms
//    I2CReadSerial(EE_FirstPage_Address,0,8,&E_data);//读从SD2400CLPI EEPROM第一页的00地址开始读8字节数据(00-07地址)演示

    while(1)
    {
        I2CReadDate(&RTC);        //读时间演示
        RTC_display();    //把时间数据从串口打出来显示
        Delayms(1000);            //延时1000ms,1s读1次
    }

}
//特别提醒:当写实时时间数据时 (00H~06H), 不可以单独 对 7 个时间数据中的某一位进行写操作 ,
//否则可能会引起时间数据的错误进位 , 所以要修改其中某一个数据 , 应一次性写入全部 7 个实时时钟数据 .

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!