DS1307 C語言程序
//********************************************************************
//***************************DS1307調試 *****************************
//********************************************************************
//**DS1307實時時鐘芯片地址0xD0 讀0xD1 寫0xD0 *********************
//********************************************************************
#include《reg51.h》 //單片機80C51
sbit SCL=P1^1; //串口時鐘信號
sbit SDA=P1^0; //串口數據信號
sbit clock=P1^2; //調試用脈沖輸出信號**************
unsigned char error; //通訊正常error=0x10;超時error=0x11
void delay(int i); //延時子函數
void TimeInitial(); //時鐘初始化子函數
void Start_I2C(); //打開串口子函數
void Stop_I2C (); //關閉串口子函數
void Ack_I2C(); //接受應答信號并判斷是否正常子函數
void SendAck(); //發送應答信號子函數
void SendNotAck(); //發送非應答信號子函數
void Send_I2C (int ch); //向總線上發送一個字節
unsigned int Receive_I2C(); //在總線上接受一個字節
int read_time(int address); //從芯片D1307讀出10為字節 地址1:秒 2:分 3:時 4:星期 5:號 6:月7:年 8 控制字
void write_time(int address,int date); //向芯片D1307 之中地址為address的寄存器寫入數據date 僅為八位字節
void main() //主程序************************************************************
{
TimeInitial(); //時鐘初始化
write_time(0x07,0x10); //向芯片D1307寫入控制字(芯片地址0X07)0x10 控制字:1晶振使能(0有效)4:SOUT方波輸出 7、8:方波頻率編碼
while(1)
{
}
}
void TimeInitial() //時鐘初始化
{
TMOD=0x10; //時鐘選擇方式2 T1時鐘
TH1=0x15;
TL1=0xA0; //定時60ms
EA=1; //中斷準許
ET1=1; //時鐘T1 溢出中斷準許
TR1=1; //啟動時鐘T1
}
//**********************************延時
void delay(int i)
{
int j,h;
for(j=1;j《99;j++)
{
for(h=0;h《i;h++)
;
}
}
//**********************************傳送啟動
void Start_I2C()
{
EA=0; //關閉中斷
SCL=0; //總線放空,以便更改總線數據
delay(1); //延時
SDA=1; //發送I2C總線起始條件的數據信號1以便總線使能時產生下降沿
delay(1); //延時
SCL=1; //發送I2C總線起始條件的時鐘信號
delay(1); //延時
SDA=0; //產生下降沿 總線傳輸開始
delay(1); //延時
SCL=0; //時鐘線從高到低一次跳變,總線放空 準備傳輸數據
}
//**********************************傳送關閉
void Stop_I2C ()
{
SCL=0; //發送I2C總線時鐘信號放空
SDA=0; //發送I2C總線停止條件的數據信號0以便產生上升沿
delay(1); //延時
SCL=1; //時鐘線從低到高一次跳變 總線 使能
delay(1); //延時
SDA=1; //發送I2C總線數據信號產生上升沿 終止傳送
delay(1); //延時
SCL=0; //發送I2C總線時鐘信號放空
delay(1);
SDA=0; //發送I2C總線放空 準備下次動作
EA=1; //傳輸結束開啟中斷
}
//**********************************傳送響應
void Ack_I2C()
{
unsigned char errtime=255; //因故障接收方無ACK,超時值為255。
SDA=1; //數據線升高,以便捕捉相應信號,(相應信號:拉低數據線)
SCL=1; // 主機放出一脈沖,等待捕捉相應信號
error=0x10; //通訊正常(即:接受到了相應信號)為0X10;
while(SDA) //等待捕捉相應信號,信號沒有到來前一直保持循環,信號到來后迅速跳出循環
{
errtime--; //每循環一次,倒計時減一
if(!errtime) //判斷倒計時是否減到了0,即循環了255次,如果減到了0,判定此次通訊未接受到響應信號,傳送失敗
{
Stop_I2C (); //傳送失敗,停止傳送
error=0x11; //傳送結果未傳送失敗0x11
return; //跳出循環
}
}
SCL=0; //無論傳送是否正確,都需放空總線,以備后用
}
//**********************************向總線傳送響應
void SendAck()
{
SDA=0; //數據線保持拉低,時鐘線發生一次從高低的跳變 發送一個應答信號
delay(1);
SCL=1;
delay(1);
SCL=0;
}
//**********************************向總線傳送非響應
void SendNotAck()
{
SDA=1; //數據線保持高,時鐘線發生一次從高低的跳變 沒有應答
delay(1);
SCL=1;
delay(1);
SCL=0;
}
//**********************************向總線傳送字節
void Send_I2C (int ch)
{
int i;
for (i=1;i《=8;i++) //發送八位
{
SCL=0; //總線放空
delay(1); //延時
SDA=(ch&0x80); //根據給定數據,又高位到低位逐步提出字節位,發送到總線上
ch《《=1; //左循環以便輸出下一位
delay(1); //延時
SCL=1; //總線使能,發送總線數據
delay(1); //延時
}
SCL=0; //總線8位傳送完成,總線放空
}
//**********************************向總線讀入字節
unsigned int Receive_I2C()
{
unsigned char i,a;
SDA=1; //不知道為啥,1的時候讀入正確 0的時候讀入全部為0;
for (i=1;i《=8;i++) //讀入八個位
{
a《《=1; // 讀入數據左循環
SCL=0; //總線放空
delay(1);
SCL=1; //時鐘做一次從低到高的跳變 可以接收一位數據
delay(1);
a|=SDA; // 將數據編入變量a
}
SCL=0; //總線放空
return a; //反饋接收到的信息
}
//**********************************向芯片D1307 之中地址為address的寄存器寫入數據date 僅為八位字節
void write_time(int address,int date)
{
Start_I2C(); //啟動總線
Send_I2C (0xD0); //呼叫芯片D1307,并定義為 寫 動作
Ack_I2C(); //等待響應信號
Send_I2C (address); //發送地址
Ack_I2C(); //等待響應信號
Send_I2C (date); //發送數據
Ack_I2C(); //等待響應信號
Stop_I2C (); //停止總線
}
//****************從芯片D1307讀出10為字節 地址1:秒 2:分 3:時 4:星期 5:號 6:月7:年 8 控制字
int read_time(int address)
{
int a[10]; //定義一個數組以便接受數據
int i=1;
Start_I2C(); //啟動傳送
Send_I2C (0xD0); //呼叫芯片D1307,并定義為 寫 動作
Ack_I2C(); //等待響應信號
Send_I2C (0x00); //發送起始地址
Ack_I2C(); //等待響應信號
Stop_I2C (); //關閉總線
Start_I2C(); //啟動總線
Send_I2C (0xD1); //呼叫芯片D1307,并定義為 讀 動作
SendAck(); //發送應答就位,準備接受數據
for(i;i《10;i++)
{
a[i]=Receive_I2C(); //接受自初始地址開始的10個字節 地址1:秒 2:分 3:時 4:星期 5:號 6:月7:年 8 控制字
SendAck(); //每成功接受一位發送一個響應信號 以便接受下一位
}
Stop_I2C (); //接受完成停止
return a[address]; //反饋所需數據
}
void t1(void) interrupt 3 using 0 //T1溢出中斷
{
TH1=0x15;
TL1=0xa0; //重新載入60ms
clock=~clock; //調試用脈沖
P0=read_time(1); //將實時時鐘 秒 送入P0口
}