//---庫函數(shù)聲明及相關(guān)定義---// #include <reg52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int sbit SDA=P3^1; //數(shù)據(jù) sbit SCL=P3^0; //時(shí)鐘 #define LCDIO P1 //1602數(shù)據(jù)口 sbit rs=P2^0; //1602數(shù)據(jù)命令選擇引腳 sbit rw=P2^1; //讀寫選擇抖? sbit en=P2^2; //1602選通引腳 uchar code table[]={" 2010-11-29 MON"}; uchar code table1[]={" 15:45:00 "}; uchar code table2[]= "SUNMONTUEWESTHUFRISAT"; uchar g8563_Store[8]; /*時(shí)間交換區(qū),全局變量聲明*/ uchar code c8563_Store[8]={0x50,0x59,0x23,0x31,0x05,0x07,0x88,0x20}; /*寫入時(shí)間初值:世紀(jì),08年 7月 星期一 13日 07:59:00*/ //****** sbit menu=P0^0;//菜單 sbit add=P0^1;//加一 sbit dec=P0^2;//減一 uchar second,minute,hour,day,month,year,week,count=0; void delay1602(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void write_com(uchar com)//1602寫命令子程序 { rs=0;//RS是數(shù)據(jù)命令選擇短,高電平寫數(shù)據(jù),低電平寫命令 rw=0;//RD是讀寫選擇短,高電平讀,低電平寫 en=0;//1602選通端,高電平選通,低電平禁止 P1=com; delay1602(5); en=1; delay1602(5); en=0; } void write_date(uchar date)//1602寫數(shù)據(jù)子程序 { rs=1; //RS是數(shù)據(jù)命令選擇短,高電平寫數(shù)據(jù),低電平寫命令 rw=0; //RD是讀寫選擇短,高電平讀,低電平寫 en=0; //1602選通端,高電平選通,低電平禁止 P1=date; delay1602(5); en=1; delay1602(5); en=0; } void init() { uchar num; en=0; write_com(0x38); //0011 1000B,功能模式設(shè)置,設(shè)置為8為數(shù)據(jù)口,兩行顯示,5*7點(diǎn)陣 write_com(0x0c); //0000 1011B,顯示開及光標(biāo)設(shè)置,關(guān)顯示,顯示光標(biāo),光標(biāo)閃爍 write_com(0x06); //0000 0110B,顯示光標(biāo)移動(dòng)設(shè)置,讀或?qū)懸粋(gè)字符,地址指針減一且光標(biāo)減一,寫一個(gè)字符屏幕顯示不移動(dòng) write_com(0x01); //0000 0001B,顯示清屏,數(shù)據(jù)指針和所有顯示清屏 write_com(0x80); //1000 000B,關(guān)閉顯示 delay1602(5); write_com(0x80); //1000 000B,設(shè)置為2行顯示,寫入第一行字符的地址,第一行地址是00-2F for(num=0;num<15;num++) { write_date(table[num]); //寫入第一行數(shù)據(jù) ****** delay1602(5); } write_com(0x80+0x40); //1100 0000B,設(shè)置為2行顯示,寫入第二行字符的地址,第二行地址是40-67 for(num=0;num<15;num++) //寫入第二行數(shù)據(jù) { write_date(table1[num]);//寫入第二行數(shù)據(jù) delay1602(5); } } /******************************************** 內(nèi)部函數(shù),延時(shí)1 ********************************************/ void Delay() { // {P00=1;_nop_();P00=0;} ***** _nop_(); _nop_(); /*根據(jù)晶振頻率制定延時(shí)時(shí)間*/ } void Start() { EA=0; SDA=1; SCL=1; Delay(); SDA=0; Delay(); SCL=0; } void Stop() { SDA=0; SCL=0; Delay(); SCL=1; Delay(); SDA=1; Delay(); EA=1; } /******************************************** 內(nèi)部函數(shù),輸出ACK ,每個(gè)字節(jié)傳輸完成,輸出ack=0,結(jié)束讀書據(jù),ack=1; ********************************************/ void WriteACK(uchar ack) { SDA=ack; //****** Delay(); SCL=1; Delay(); SCL=0; } /******************************************** 內(nèi)部函數(shù),等待ACK ********************************************/ void WaitACK() { uchar errtime=20; SDA=1; Delay(); /*讀ACK*/ //****** SCL=1; Delay(); while(!SDA) //+!? { errtime--; if(!errtime) Stop(); } SCL=0; Delay(); } /******************************************** 內(nèi)部函數(shù).輸出數(shù)據(jù)字節(jié) 入口:B=數(shù)據(jù) ********************************************/ void writebyte(uchar wdata) { uchar i; for(i=0;i<8;i++) { if(wdata&0x80) SDA=1; else SDA=0; wdata<<=1; SCL=1; Delay(); SCL=0; } WaitACK(); //I2C器件或通訊出錯(cuò),將會(huì)退出I2C通訊 } /******************************************** 內(nèi)部函數(shù).輸入數(shù)據(jù) 出口:B ********************************************/ uchar Readbyte() { uchar i,bytedata; SDA=1; for(i=0;i<8;i++) { //****** SCL=1; bytedata<<=1; bytedata|=SDA; SCL=0; Delay(); } return(bytedata); } /******************************************** 輸出數(shù)據(jù)->pcf8563 ********************************************/ void writeData(uchar address,uchar mdata) { Start(); writebyte(0xa2); /*寫命令*/ writebyte(address); /*寫地址*/ writebyte(mdata); /*寫數(shù)據(jù)*/ Stop(); } /******************************************** 輸入數(shù)據(jù)<-pcf8563 ********************************************/ uchar ReadData(uchar address) /*單字節(jié)*/ { uchar rdata; Start(); writebyte(0xa2); /*寫命令*/ //****** writebyte(address); /*寫地址*/ Start(); writebyte(0xa3); /*讀命令*/ //****** rdata=Readbyte(); WriteACK(1); Stop(); return(rdata); } void ReadData1(uchar address,uchar count,uchar * buff) /*多字節(jié)*/ { uchar i; Start(); writebyte(0xa2); /*寫命令*/ writebyte(address); /*寫地址*/ Start(); writebyte(0xa3); /*讀命令*/ for(i=0;i<count;i++) { buff[i]=Readbyte(); if(i<count-1) WriteACK(0); } WriteACK(1); Stop(); } /******************************************** 內(nèi)部函數(shù),讀入時(shí)間到內(nèi)部緩沖區(qū) ********************************************/ void P8563_Read() { uchar time[7],century; ReadData1(0x02,0x07,time); century=time[5]; g8563_Store[0]=time[0]&0x7f; /*秒*/ g8563_Store[1]=time[1]&0x7f; /*分*/ g8563_Store[2]=time[2]&0x3f; /*小時(shí)*/ g8563_Store[3]=time[3]&0x3f; /*日*/ g8563_Store[4]=time[4]&0x07; /*星期*/ g8563_Store[5]=time[5]&0x1f; /*月*/ g8563_Store[6]=time[6]&0xff; /*年*/ g8563_Store[7]=century&0x80; /*去世紀(jì),00為2000,80為1900*/ if(g8563_Store[7]==0x00)g8563_Store[7]=20; if(g8563_Store[7]==0x80)g8563_Store[7]=19; } /******************************************** 讀入時(shí)間到內(nèi)部緩沖區(qū)----外部調(diào)用 ********************************************/ void P8563_gettime() { P8563_Read(); if(g8563_Store[0]==0) P8563_Read(); /*如果為秒=0,為防止時(shí)間變化,再讀一次*/ } /******************************************** 寫時(shí)間修改值 ********************************************/ void P8563_settime() { writeData(2,g8563_Store[0]);//秒 writeData(3,g8563_Store[1]);//分 writeData(4,g8563_Store[2]);//時(shí) writeData(5,g8563_Store[3]);//日 writeData(6,g8563_Store[4]);//星期 if(g8563_Store[7]==0x20)g8563_Store[5]=(g8563_Store[5]&0x3F);//判斷世紀(jì) if(g8563_Store[7]==0x19)g8563_Store[5]=(g8563_Store[5]|0x80);//判斷世紀(jì) writeData(7,g8563_Store[5]);//月 writeData(8,g8563_Store[6]);//年 } /******************************************** P8563的初始化 ********************************************/ void P8563_init() { uchar i; if((ReadData(0xa)&0x3f)!=0x8) /*檢查是否第一次啟動(dòng),是則初始化時(shí)間*/ //****** { for(i=0;i<8;i++) g8563_Store[i]=c8563_Store[i]; /*初始化時(shí)間*/ P8563_settime(); writeData(0x0,0x00); writeData(0xa,0x8); /*8:00報(bào)警*/ writeData(0x1,0x12); /*報(bào)警有效*/ writeData(0xd,0xf0); //****/*32.768*/ } } void DisplaySecond(uchar x) //寫入1602秒 { uchar i,j; i=x/10; j=x%10; write_com(0xc7); //寫1602的命令字,設(shè)置秒的數(shù)據(jù)地址為47H write_date(0x30+i); //寫入秒的低位 write_date(0x30+j); //寫入秒的高位 } void DisplayMinute(uchar x) //寫入1602分 { uchar i,j; i=x/10; j=x%10; write_com(0xc4); write_date(0x30+i); write_date(0x30+j); } void DisplayHour(uchar x) //寫入1602小時(shí) { uchar i,j; i=x/10; j=x%10; write_com(0xc1); write_date(0x30+i); write_date(0x30+j); } void DisplayDay(uchar x) //寫入1602天 { uchar i,j; i=x/10; j=x%10; write_com(0x89); write_date(0x30+i); write_date(0x30+j); } void DisplayMonth(uchar x) //寫入1602月 { uchar i,j; i=x/10; j=x%10; write_com(0x86); write_date(0x30+i); write_date(0x30+j); } void DisplayYear(uchar x) //寫入1602年 { uchar i,j; i=x/10; j=x%10; write_com(0x83); write_date(0x30+i); write_date(0x30+j); } void DisplayWeek(uchar x) //寫入星期 { uchar i; x=(x)*3; write_com(0x8c); for(i=0;i<3;i++) { write_date(table2[x]); x++; } } void DisplayCentury(uchar x) //寫入世紀(jì) { uchar i,j; i=x/10; j=x%10; write_com(0x81); write_date(0x30+i); write_date(0x30+j); } //---BCD轉(zhuǎn)換16函數(shù)---// void BCD_16( ) { uchar i,ucData1,ucData2; for(i=0;i<7;i++) { ucData1=g8563_Store[i]/16; //BCD碼轉(zhuǎn)十六進(jìn)制 ucData2=g8563_Store[i]%16; g8563_Store[i]=ucData1*10+ucData2; } } void display(void) { DisplaySecond(g8563_Store[0]); DisplayMinute(g8563_Store[1]); DisplayHour(g8563_Store[2]); DisplayDay(g8563_Store[3]); DisplayMonth(g8563_Store[5]); DisplayYear(g8563_Store[6]); DisplayWeek(g8563_Store[4]); DisplayCentury(g8563_Store[7]); } void turn_val(uchar newval,uchar flag,uchar newaddr,uchar s1num) //newval是時(shí)間日期值,flag是時(shí)間日期增減標(biāo)識(shí),newaddr是讀取數(shù)據(jù)的地址,s1num是年月日時(shí)分秒星期的數(shù)字標(biāo)識(shí) { uchar ucData1,ucData2; newval=ReadData(newaddr); // century=newval; switch(newaddr) { case 0x02:newval=(newval&0x7f); /*秒*/ break; case 0x03:newval=(newval&0x7f); /*秒*/ break; case 0x04:newval=(newval&0x3f);/*小時(shí)*/ break; case 0x05:newval=(newval&0x3f); /*日*/ break; case 0x06:newval=(newval&0x07); /*星期*/ break; case 0x07:newval=(newval&0x1f);/*月*/ break; case 0x08:newval=(newval&0xff);/*年*/ } ucData1=newval/16; //BCD碼轉(zhuǎn)十六進(jìn)制 ucData2=newval%16; newval=ucData1*10+ucData2; if(flag) //判斷是加一還是減一 { newval++; switch(s1num) { case 1: if(newval>99) newval=0; DisplayYear(newval); break; case 2: if(newval>12) newval=1; DisplayMonth(newval); break; case 3: if(newval>31) newval=1; DisplayDay(newval); break; case 4: if(newval>6) newval=0; DisplayWeek(newval); break; case 5: if(newval>23) newval=0; DisplayHour(newval); break; case 6: if(newval>59) newval=0; DisplayMinute(newval); break; case 7: if(newval>59) newval=0; DisplaySecond(newval); break; default:break; } } else { newval--; switch(s1num) { case 1: if(newval==0xff) newval=99; DisplayYear(newval); break; case 2: if(newval==0) newval=12; DisplayMonth(newval); break; case 3: if(newval==0) newval=31; DisplayDay(newval); break; case 4: if(newval==0xff) newval=6; DisplayWeek(newval); break; case 5: if(newval==0xff) newval=23; DisplayHour(newval); break; case 6: if(newval==0xff) newval=59; DisplayMinute(newval); break; case 7: if(newval==0xff) newval=59; DisplaySecond(newval); break; default:break; } } ucData1=newval/16; //BCD碼轉(zhuǎn)十六進(jìn)制 ucData2=newval%16; newval=ucData1*10+ucData2; writeData(newaddr,newval); } void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } //鍵盤掃描程序 void key_scan(void) { uchar s1num=0; //s1num記錄光標(biāo)的位置的編號(hào) if(menu==0) { delay(5); if(menu==0) { while(!menu); //menum測試到由0到1的變化,也就是按下松開的變化,s1num加1 s1num++; while(1) { if(menu==0) { delay(5); if(menu==0) { while(!menu); s1num++; //menum測試到由0到1的變化,也就是按下松開的變化,s1num再加1 } } writeData(0x0,0x20);;//停止計(jì)時(shí),開始相關(guān)設(shè)置。 write_com(0x0f);//光標(biāo)閃射,0X0F是1602的命令字,顯示開,光標(biāo)開,光標(biāo)閃爍 if(s1num==1) { year=ReadData(0x08); //讀取年的數(shù)據(jù)。 write_com(0x80+4); //年光標(biāo),0X80+地址碼,設(shè)置數(shù)據(jù)地址指針 if(add==0) { delay(3); if(add==0) { while(!add); turn_val(year,1,0x08,1); } } if(dec==0) { delay(3); if(dec==0) { while(!dec); turn_val(year,0,0x08,1);//讀取當(dāng)前年值,根據(jù)減小年值,并寫入1302 } } } if(s1num==2) { month=ReadData(0x07); write_com(0x80+7); //月光標(biāo) if(add==0) { delay(3); if(add==0) { while(!add); turn_val(month,1,0x07,2); } } if(dec==0) { delay(3); if(dec==0) { while(!dec); turn_val(month,0,0x07,2); } } } if(s1num==3) { day=ReadData(0x05); write_com(0x80+10);//日光標(biāo) if(add==0) { delay(3); if(add==0) { while(!add); turn_val(day,1,0x05,3); } } if(dec==0) { delay(3); if(dec==0) { while(!dec); turn_val(day,0,0x05,3); //寫入日寄存器 } } } if(s1num==4) { week=ReadData(0x06); write_com(0x80+14); //星期光標(biāo) if(add==0) { delay(3); if(add==0) { while(!add); turn_val(week,1,0x06,4); } } if(dec==0) { delay(3); if(dec==0) { while(!dec); turn_val(week,0,0x06,4); } } } if(s1num==5) { hour=ReadData(0x04); write_com(0x80+0x40+2); //時(shí)光標(biāo),因?yàn)槭堑诙械牡刂窂?X40開始,所以加0X40。 if(add==0) { delay(3); if(add==0) { while(!add); turn_val(hour,1,0x04,5); } } if(dec==0) { delay(3); if(dec==0) { while(!dec); turn_val(hour,0,0x04,5); } } } if(s1num==6)//調(diào)時(shí)間分 { minute=ReadData(0x03); write_com(0x80+0x40+5); if(add==0) { delay(5); if(add==0) { while(!add); turn_val(minute,1,0x03,6); //寫入分寄存器 } } if(dec==0) { delay(3); if(dec==0) { while(!dec); turn_val(minute,0,0x03,6); //寫入分寄存器 } } } if(s1num==7)//調(diào)時(shí)間秒 { second=ReadData(0x02); write_com(0x80+0x40+8);//秒光標(biāo) if(add==0) { delay(3); if(add==0) { while(!add); if(second==0x60) second=0x00; turn_val(second,1,0x02,7); } } if(dec==0) { delay(3); if(dec==0) { while(!dec); turn_val(second,0,0x02,7); } } } if(s1num==8) { writeData(0x0,0x00);//設(shè)置結(jié)束,開始計(jì)時(shí) s1num=0;//s1num清零// write_com(0x0c);//光標(biāo)不閃爍// break; } } } } } //---主函數(shù)---// void main() { P8563_init(); init(); while(1) { P8563_gettime(); BCD_16( ); display(); key_scan(); } } |