I2C實(shí)時(shí)時(shí)鐘/日歷芯片在8051系統(tǒng)中的應(yīng)用
掃描二維碼
隨時(shí)隨地手機(jī)看文章
1 PCF8563簡(jiǎn)介
PCF8563是PHILIPS公司生產(chǎn)的低功耗CMOS實(shí)時(shí)時(shí)鐘/日歷芯片,芯片最大總線速度為400kbits/s,每次讀寫(xiě)數(shù)據(jù)后,其內(nèi)嵌的字地址寄存器器會(huì)自動(dòng)產(chǎn)生增量。PCF8563可廣泛應(yīng)用于移動(dòng)電話(huà)、便攜儀器、傳真機(jī)、電池電源等產(chǎn)品中。
PCF8563的引腳排列如圖1所示,各引腳功能說(shuō)明如表1所列。
PCF8563有16個(gè)8位寄存器,其中包括:可自動(dòng)增量的地址寄存器、內(nèi)置32.768kHz的振蕩器(帶有一個(gè)內(nèi)部集成電容)、分頻器(用于給實(shí)時(shí)時(shí)鐘RTC提供源時(shí)鐘)、可編程時(shí)鐘輸出、定時(shí)器、報(bào)警器、掉電檢測(cè)器和400kHz的I2C總線接口。
所有16個(gè)寄存器設(shè)計(jì)成可尋址的8位并行寄存器,但不是所有位都有用。當(dāng)一個(gè)RTC寄存器被讀時(shí),所有計(jì)數(shù)器的內(nèi)容將被鎖存,因此,在傳送條件下,可以禁止對(duì)時(shí)鐘/日歷芯片的錯(cuò)讀。
表2、表3所列為各寄存器概況及對(duì)應(yīng)的內(nèi)存地址和功能,同時(shí)列出了它們的BCD格式編碼。表中“——”表示無(wú)效位,“0”表示此位應(yīng)置邏輯。表3中的世紀(jì)位C=0指定世紀(jì)數(shù)為20XX,C=1指定世紀(jì)數(shù)為19XX。當(dāng)年寄存器中的99變00時(shí),世紀(jì)位才會(huì)改變。
2 I2C總線
2.1 I2C總線特性
I2C 總線用兩條線(SDA和SCL)在芯片和模塊間傳遞信息。SDA為串行數(shù)據(jù)線,SCL為串行時(shí)鐘線,這兩條線必須用一個(gè)上拉電阻與正電源相連,其數(shù)據(jù)只有在總線不忙時(shí)才可傳送。I2C總線的系統(tǒng)配置參見(jiàn)圖2,產(chǎn)生信號(hào)的設(shè)備是傳送器,接收信號(hào)的設(shè)備是接收器,控制信號(hào)的設(shè)備是主設(shè)備,受控制信號(hào)的設(shè)備是從設(shè)備。
2.2 啟動(dòng)和停止條件
總線不忙時(shí),數(shù)據(jù)線和時(shí)鐘線保持在高電平。數(shù)據(jù)線(SDA)在下降沿而時(shí)鐘線(SCL)為高電平時(shí),為起動(dòng)條件(S);數(shù)據(jù)線在上升沿而時(shí)鐘線為高電平時(shí)為停止條件(P),參見(jiàn)圖3。
2.3 位傳送
每個(gè)時(shí)鐘脈沖傳送一個(gè)數(shù)據(jù)位,SDA線上的數(shù)據(jù)在時(shí)鐘脈沖高電平時(shí)應(yīng)保持穩(wěn)定,否則將成為控制信號(hào),參見(jiàn)圖4。
2.4 標(biāo)志位
在起動(dòng)條件和停止條件之間,傳送器傳送給接收器的數(shù)據(jù)數(shù)量沒(méi)有限制。在每個(gè)8位字節(jié)后加一個(gè)標(biāo)志位,傳送器便產(chǎn)生一個(gè)高電平的標(biāo)志位,這時(shí)主設(shè)備產(chǎn)生一個(gè)附加標(biāo)志位時(shí)鐘脈沖。
從接受器必須在接收到每個(gè)字節(jié)后產(chǎn)生一個(gè)標(biāo)志位,主接收器也必須在接收從傳送器傳送的每個(gè)字節(jié)后產(chǎn)生一個(gè)標(biāo)志位。在標(biāo)志位時(shí)鐘脈沖出現(xiàn)時(shí),SDA線應(yīng)保持低電平(應(yīng)考慮起動(dòng)和保持時(shí)間)。傳送器應(yīng)在從設(shè)備接收到最后一個(gè)字節(jié)時(shí)變?yōu)榈碗娖剑菇邮掌鳟a(chǎn)生標(biāo)志位,這時(shí)主設(shè)備即可產(chǎn)生停止條件。參見(jiàn)圖5。
2.5 I2C總線協(xié)議
用I2C 總線傳遞數(shù)據(jù)前,接收的設(shè)備應(yīng)先標(biāo)明地址,在I2C總線起動(dòng)后,這個(gè)地址與第一個(gè)傳送字節(jié)一起被傳送出去。PCF8563可以作為一個(gè)從接收器或從傳送器,此時(shí)的時(shí)鐘信號(hào)線SCL只能輸入信號(hào)線,數(shù)據(jù)信號(hào)線SDA則為一條雙向信號(hào)線。PCF8563的從地址參見(jiàn)圖6。
3 應(yīng)用概述
圖7所示為PCF8563的具體應(yīng)用電路圖,對(duì)圖中石英晶片頻率的調(diào)整,筆者給出3種可行性方法,供參考:
方法1:定值OSCI電容。計(jì)算所需的電容平均值,用此值的定值電容,通電后在CLKOUT管腳上測(cè)出的頻率應(yīng)為32.768kHz,測(cè)出的頻率值偏差取決于石英晶片本身,電容偏差和器件之間的偏差平均為±5×10 -6。平均偏差可達(dá)5分鐘/年。
方法2:OSCI微調(diào)電容??赏ㄟ^(guò)調(diào)整OSCI管腳的微調(diào)電容式振蕩器的頻率來(lái)獲得更高的精度,此時(shí)可測(cè)出通電時(shí)管腳CLKOUT上的信號(hào)頻率為32.768kHz。
方法3:OSCI輸出。直接測(cè)量管腳OSCI的輸出。
4 程序范例
以下的C語(yǔ)言源程序是用8051單片機(jī)的普通I/O口(如P0.0/P0.4)模擬實(shí)現(xiàn) PCF8563的I2C時(shí)鐘/日歷芯片的操作,有字節(jié)寫(xiě)/讀兩種狀態(tài)。程序中從地址的讀地址為0A3H,寫(xiě)地址為0A2H.所發(fā)送的數(shù)據(jù)字節(jié)為9個(gè),發(fā)送的初始數(shù)據(jù)在rom_sed[9]中,rom_sed[9]定義了寄存器中當(dāng)前發(fā)送的值:控制/狀態(tài)寄存器1為0,控制/狀態(tài)寄存器2為0,秒寄存器為 0,分鐘寄存器55,小時(shí)寄存器為23,日寄存器為31,星期寄存器為6,月/世紀(jì)寄存器為0x12,年寄存器為0x99(即1999年12月31日23 點(diǎn)55分0秒),當(dāng)程序運(yùn)行一段時(shí)間(5分鐘)后,從地址寄存器 02H開(kāi)始讀數(shù)據(jù),數(shù)據(jù)存放在rom_rec7中,發(fā)現(xiàn)變量rom_rec7變?yōu)?000年1月1日0點(diǎn)0分。若外轉(zhuǎn)帳電路有顯示,則時(shí)間可以顯示在面板上。
#include<d:.h>
#define byte unsigned char
sbit scl=0x81; //定義串行I/O口
sbit sda=0x80;
idata byte rom_sed[9];
idata byte rom_rec[7];
idata byte j,k;
bit flag,flag1;
void delay(void) //延時(shí)子程序
{data byte i;
for(i=0;i<6;i++);
}
void I_start(void) //發(fā)送I2C總線起始條件子程序
{sda=1;
;
scl=1;
delay();
sda=0;
delay();
scl=0;
;
}
void I_stop(void) //I2C總線停止條件子程序
{sda=0;
;
scl=1;
delay();
sda=1;
delay();
}
bit I_send(byte I_data) //字節(jié)數(shù)據(jù)傳送子程序
{data byte i;
for(i=0,i<8;i++)
{sda-(bit)(I_data&0x80);
I_data=I_data<<1;
;
scl=1;
delay();
scl=0;
}
;;
sda=1; ;; //ready for receiving ACK bit
scl=1; ;; //start receiving ack bit
flag=0;
if(sda= =0)flag=0;
else flag=1; //return(~I(xiàn)_clock());
scl=0;
return(flag);
}
byte I_receive(void) //字節(jié)數(shù)據(jù)接收子程序
{ data byte i;
byte I_data=0;
sda=1;
for(i=0;I<8;i++)
{ I_data*=2;
;
scl=0;
delay();
scl=1; ;;
if(sda= =1)I_data++;
;;
}
scl=0; ;;;
sda=0;
if(flag1= =0){;;scl=1;delay();scl=0;} //not last receic_byte ACK
else{sda=1; ;;scl=1;delay();scl=0;flag1=0;} //the last receive_byte ~ACK
return(I_data);
}
main() //主程序
{data byte i;
rom_sed[0]=0x00; rom_sed[1]=0x00;
rom_sed[2]=0x00; rom_sed[3]=0x55;
rom_sed[4]=0x23; rom_sed[5]=0x31;
rom_sed[6]=0x06; rom_sed[7]=0x92;
rom_sed[8]=0x99;
for(i=0;i<255;i++)delay();
I_start();
if(~I(xiàn)_send(rom_sed[i]));
else;
}
I_stop();
}
else;
}
else;
start: I_start();
if(~I(xiàn)_send(0xa2)) //pcf_write address
{if(~I(xiàn)_send(0x02)) //pcf_status register address
{I_start();
if(~I(xiàn)_send(0xa3)) //write status register
{for(i=0;i<7;i++)
{if(i= =6)flag1=1;
else flag1=0;
rom_rec[i]=I_receive();
switch(i)
{case 1:rom_rec[i]=rom_rec[i]&0x7f;break;
ease2:
case3:rom_rec[i]=rom_rec[i]&0x3f;break;
case4:rom_rec[i]=rom_rec[i]&0x07;break;
case5:rom_rec[i]=rom_rec[i]&0x9f;brealk;default:break;
}
}
I_stop()
}
}
}
goto start;
}