親測可以用,Proteus7.8打開
51單片機源程序:
- //---庫函數聲明及相關定義---//
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit SDA=P3^1; //數據
- sbit SCL=P3^0; //時鐘
- #define LCDIO P1 //1602數據口
- sbit rs=P2^0; //1602數據命令選擇引腳
- sbit rd=P2^1; //讀寫選擇抖?
- sbit lcden=P2^2; //1602選通引腳
- uchar code table[]={" 2010-11-29 MON"};
- uchar code table1[]={" 15:45:00 "};
- uchar code table2[]= "SUNMONTUEWESTHUFRISAT";
- uchar g8563_Store[8]; /*時間交換區,全局變量聲明*/
- uchar code c8563_Store[8]={0x50,0x59,0x23,0x31,0x05,0x07,0x88,0x20}; /*寫入時間初值:世紀,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是數據命令選擇短,高電平寫數據,低電平寫命令
- rd=0;//RD是讀寫選擇短,高電平讀,低電平寫
- lcden=0;//1602選通端,高電平選通,低電平禁止
- P1=com;
- delay1602(5);
- lcden=1;
- delay1602(5);
- lcden=0;
- }
- void write_date(uchar date)//1602寫數據子程序
- {
- rs=1; //RS是數據命令選擇短,高電平寫數據,低電平寫命令
- rd=0; //RD是讀寫選擇短,高電平讀,低電平寫
- lcden=0; //1602選通端,高電平選通,低電平禁止
- P1=date;
- delay1602(5);
- lcden=1;
- delay1602(5);
- lcden=0;
- }
- void init()
- {
- uchar num;
- lcden=0;
- write_com(0x38); //0011 1000B,功能模式設置,設置為8為數據口,兩行顯示,5*7點陣
- write_com(0x0c); //0000 1011B,顯示開及光標設置,關顯示,顯示光標,光標閃爍
- write_com(0x06); //0000 0110B,顯示光標移動設置,讀或寫一個字符,地址指針減一且光標減一,寫一個字符屏幕顯示不移動
- write_com(0x01); //0000 0001B,顯示清屏,數據指針和所有顯示清屏
- write_com(0x80); //1000 000B,關閉顯示
- delay1602(5);
- write_com(0x80); //1000 000B,設置為2行顯示,寫入第一行字符的地址,第一行地址是00-2F
- for(num=0;num<15;num++)
- {
- write_date(table[num]); //寫入第一行數據
- delay1602(5);
- }
- write_com(0x80+0x40); //1100 0000B,設置為2行顯示,寫入第二行字符的地址,第而行地址是40-67
- for(num=0;num<15;num++) //寫入第二行數據
- {
- write_date(table1[num]);//寫入第二行數據
- delay1602(5);
- }
- }
- /********************************************
- 內部函數,延時1
- ********************************************/
- void Delay()
- {
- // {P10=1;_nop_();P10=0;}
- _nop_();
- _nop_(); /*根據晶振頻率制定延時時間*/
- }
- /********************************************
- 內部函數,I2C開始
- ********************************************/
- void Start()
- { EA=0;
- SDA=1;
- SCL=1;
- Delay();
- SDA=0;
- Delay();
- SCL=0;
- }
- /********************************************
- 內部函數,I2C結束
- ********************************************/
- void Stop()
- {
- SDA=0;
- SCL=0;
- Delay();
- SCL=1;
- Delay();
- SDA=1;
- Delay();
- EA=1;
- }
- /********************************************
- 內部函數,輸出ACK ,每個字節傳輸完成,輸出ack=0,結束讀書據,ack=1;
- ********************************************/
- void WriteACK(uchar ack)
- {
- SDA=ack;
- Delay();
- SCL=1;
- Delay();
- SCL=0;
- }
- /********************************************
- 內部函數,等待ACK
- ********************************************/
- void WaitACK()
- { uchar errtime=20;
- SDA=1;
- Delay(); /*讀ACK*/
- SCL=1;
- Delay();
- while(SDA)
- { errtime--;
- if(!errtime) Stop();
- }
- SCL=0;
- Delay();
- }
- /********************************************
- 內部函數.輸出數據字節
- 入口:B=數據
- ********************************************/
- 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器件或通訊出錯,將會退出I2C通訊
- }
- /********************************************
- 內部函數.輸入數據
- 出口: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);
- }
- /********************************************
- 輸出數據->pcf8563
- ********************************************/
- void writeData(uchar address,uchar mdata)
- {
- Start();
- writebyte(0xa2); /*寫命令*/
- writebyte(address); /*寫地址*/
- writebyte(mdata); /*寫數據*/
- Stop();
- }
- /********************************************
- 輸入數據<-pcf8563
- ********************************************/
- uchar ReadData(uchar address) /*單字節*/
- { 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) /*多字節*/
- { 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();
- }
- /********************************************
- 內部函數,讀入時間到內部緩沖區
- ********************************************/
- 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; /*小時*/
- 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; /*去世紀,00為2000,80為1900*/
- if(g8563_Store[7]==0x00)g8563_Store[7]=20;
- if(g8563_Store[7]==0x80)g8563_Store[7]=19;
- }
- /********************************************
- 讀入時間到內部緩沖區----外部調用
- ********************************************/
- void P8563_gettime()
- {
- P8563_Read();
- if(g8563_Store[0]==0)
- P8563_Read(); /*如果為秒=0,為防止時間變化,再讀一次*/
- }
- /********************************************
- 寫時間修改值
- ********************************************/
- void P8563_settime()
- {
-
- writeData(2,g8563_Store[0]);//秒
- writeData(3,g8563_Store[1]);//分
- writeData(4,g8563_Store[2]);//時
- writeData(5,g8563_Store[3]);//日
- writeData(6,g8563_Store[4]);//星期
- if(g8563_Store[7]==0x20)g8563_Store[5]=(g8563_Store[5]&0x3F);//判斷世紀
- if(g8563_Store[7]==0x19)g8563_Store[5]=(g8563_Store[5]|0x80);//判斷世紀
- writeData(7,g8563_Store[5]);//月
- writeData(8,g8563_Store[6]);//年
- }
- /********************************************
- P8563的初始化
- ********************************************/
- void P8563_init()
- {
- uchar i;
- if((ReadData(0xa)&0x3f)!=0x8) /*檢查是否第一次啟動,是則初始化時間*/
- {
- for(i=0;i<8;i++) g8563_Store[i]=c8563_Store[i]; /*初始化時間*/
- P8563_settime();
- writeData(0x0,0x00);
- writeData(0xa,0x8); /*8:00報警*/
- writeData(0x1,0x12); /*報警有效*/
- writeData(0xd,0xf0);
- }
- }
- void DisplaySecond(uchar x) //寫入1602秒
- {
- uchar i,j;
- i=x/10;
- j=x%10;
- write_com(0xc7); //寫1602的命令字,設置秒的數據地址為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小時
- {
- 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) //寫入世紀
- {
- uchar i,j;
- i=x/10;
- j=x%10;
- write_com(0x81);
- write_date(0x30+i);
- write_date(0x30+j);
- }
-
- //---BCD轉換16函數---//
- void BCD_16( )
- {
- uchar i,ucData1,ucData2;
- for(i=0;i<7;i++)
- {
- ucData1=g8563_Store[i]/16; //BCD碼轉十六進制
- 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是時間日期值,flag是時間日期增減標識,newaddr是讀取數據的地址,s1num是年月日時分秒星期的數字標識
- {
- 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);/*小時*/
- 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碼轉十六進制
- 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/10; //BCD碼轉十六進制
- ucData2=newval%10;
- newval=ucData1*16+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記錄光標的位置的編號
- 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);;//停止計時,開始相關設置。
- write_com(0x0f);//光標閃射,0X0F是1602的命令字,顯示開,光標開,光標閃爍
-
- if(s1num==1)
- {
- year=ReadData(0x08); //讀取年的數據。
- write_com(0x80+4); //年光標,0X80+地址碼,設置數據地址指針
- 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);//讀取當前年值,根據減小年值,并寫入1302
- }
- }
- }
-
- if(s1num==2)
- {
- month=ReadData(0x07);
- write_com(0x80+7); //月光標
- 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);//日光標
- 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); //星期光標
- 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); //時光標,因為是第二行的地址從0X40開始,所以加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)//調時間分
- {
- 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)//調時間秒
- {
- second=ReadData(0x02);
- write_com(0x80+0x40+8);//秒光標
- 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);//設置結束,開始計時
- s1num=0;//s1num清零//
- write_com(0x0c);//光標不閃爍//
- break;
- }
- }
- }
- }
- }
- //---主函數---//
- void main()
- {
- P8563_init();
- init();
-
- while(1)
- {
- P8563_gettime();
- BCD_16( );
- …………限于本文篇幅 余下代碼請從51hei電子下載附件…………
復制代碼
下載(Proteus7.8打開,其他版本都不行):
PCF8563.rar
(64.6 KB, 下載次數: 297)
2017-4-25 13:24 上傳
點擊文件名下載附件
|