51微控制器實時時鐘 PCF8563時鐘晶片
實現實時時鐘,電源拔插時間不重置(內建電池供電維持時間變化)。功能有檢視日期,檢視星期,檢視鬧鐘和分別的調整時間,調整日期,調整鬧鐘,調整星期。且預設情況下不可以調整,當按下可調控鍵之後才可以調整、再次按可調控鍵關閉變為不可調整狀態。還有整點報時功能(有個小瑕疵就是鬧鐘正好是整點的時候和這個整點報時同時間的時候不會報時和鬧鐘,這個很容易改好,因為下午3點要答辯了,懶得改了機子老是寫不進去,學校窮便宜機子沒辦法)。然後這個鬧鐘可以設定星期幾幾點鬧也可以設定為普通的每天的這個時間點鬧鈴,這些都是可以調控的。時鐘所有的功能都有,只差一個秒錶,,這個很簡單,,,外部中斷來一個或者定時器T1中斷來一個都可以,我沒弄,因為我這個已經程式碼很長了,頭疼、加中斷還得加顯示函式和秒錶變化函式if分大於60 時++啥的,但因為這個採用的顯示是低四位高四位控制的,我強行加一個也比較麻煩所有就沒加了。歡迎下載乾貨,難看懂的都有備註,寫了斷斷續續一週+時間左右(恕在下才疏學淺,因為書上上課的時候沒學過I2C匯流排和pcf8563所以寫的比較久。)部分程式碼如下:
#define MAIN_Fosc 22118400L //定義主時鐘 頻率也是計數計時週期一秒的計數值
#include "STC15Fxxxx.H"
/***********************************************************/
#define DIS_DOT 0x20
#define DIS_BLACK 0x10
#define DIS_ 0x11
/****************************** 使用者定義巨集***********************************/
#define Timer0_Reload (65536UL -(MAIN_Fosc / 1000)) //Timer 0 中斷頻率,1000次/秒 頻率倍數計數即週期 週期為1秒 除以一千就是1000次每秒
/*****************************************************************************/
/************* 本地常量宣告 **************/
u8 code t_display[]={ //標準字型檔
// 0 1 2 3 4 5 6 7 8 9 A B C D E F //共陰
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
u8code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位碼 取反就是書上213面 0從低位到高位
/************* IO口定義 **************/
sbit P_HC595_SER = P4^0; //pin 14 SER datainput
sbit P_HC595_RCLK = P5^4; //pin 12 RCLk store(latch) clock
sbit P_HC595_SRCLK = P4^3; //pin 11 SRCLK Shift data clock
sbit led=P1^7;
sbit led1=P4^7;
sbit key=P3^2;
/************* 本地變數宣告 **************/
u8 LED8[8]; //顯示緩衝
u8 display_index; //顯示位索引
bit B_1ms; //1ms標誌
u8IO_KeyState, IO_KeyState1, IO_KeyHoldCnt; //行列鍵盤變數
u8 KeyHoldCnt; //鍵按下計時
u8 KeyCode; //給使用者使用的鍵碼, 1~16有效
u8 cnt50ms;
u8hello;
u8nao;
u8minute2;
u8KeyCode0;
u8 hour,hour1,minute,minute1,second,day,week,week1,month,year; //RTC變數
u16 msecond;
u16msecond1;
u8hello;
u8naofu;
u8zhuangtai;
u8xunhuan;
u8tuinao; //鬧鐘控制開啟退出
u8xinqinao;//星期·鬧鐘
/************* 本地函式宣告 **************/
void CalculateAdcKey(u16 adc);
void IO_KeyScan(void); //50ms call
void WriteNbyte(u8 addr, u8 *p, u8 number);
void ReadNbyte( u8 addr, u8 *p, u8 number);
void DisplayRTC(void);
void DisplayRTC1(void);
void DisplayRTC2(void);
void ReadRTC(void);//讀取時鐘
void ReadRTC1(void);
void ReadRTC2(void);
void ReadRTC3(void);
void WriteRTC(void);
void WriteRTC1(void);
void WriteRTC2(void);
void WriteRTC3(void);
void DisplayRTC3(void);
void DisplayRTC4(void);
void DisplayRTC5(void);
/**************** 外部函式宣告和外部變數宣告*****************/
/**********************************************/
voidmain(void)
{
u8 i;
P0M1= 0; P0M0 = 0; //設定為準雙向口
P1M1= 0; P1M0 = 0; //設定為準雙向口
P2M1= 0; P2M0 = 0; //設定為準雙向口
P3M1= 0; P3M0 = 0; //設定為準雙向口
P4M1= 0; P4M0 = 0; //設定為準雙向口
P5M1= 0; P5M0 = 0; //設定為準雙向口
P6M1= 0; P6M0 = 0; //設定為準雙向口
P7M1= 0; P7M0 = 0; //設定為準雙向口
display_index= 0;
AUXR= 0x80;//T0時鐘無分頻
TMOD=0x00; //Timer0 set as 1T, 16 bits timer auto-reload,T0時鐘無分頻,16位自動重灌
TH0= (u8)(Timer0_Reload / 256); //定時器取其高低8位為狀態值
TL0= (u8)(Timer0_Reload % 256);
ET0= 1; //Timer0 interrupt enable T0中斷允許
TR0= 1; //Tiner0 run T0啟動
EA= 1; //開啟總中斷 ,總中斷允許
hello=0;
if(nao==1){}//斷電重置
elseif(nao==2){}
else
{
nao=0;
}
for(i=0;i<8; i++) LED8[i] = 0x10; //上電消隱 dp高位 防止極短時間內出現兩個數字的重疊
ReadRTC();//讀取時鐘
ReadRTC1();
F0= 0;
if(second>= 60) F0 = 1; //錯誤
if(minute>= 60) F0 = 1; //錯誤
if(hour >= 24) F0= 1; //錯誤
if(F0==1) //有錯誤, 預設12:00:00
{
second= 0;
minute= 0;
hour = 12;
WriteRTC();
}
if(day>=32) F0=2;
if(week>=8) F0=2;
if(month>=13)F0=2;
if(year>=100)F0=2;
if(F0==2) //有錯誤, 預設12:00:00
{
day=6;
week=3;
month=6;
year=18;
WriteRTC1();
}
if(minute1>= 60) F0 = 3; //錯誤
if(hour1 >= 24) F0= 3; //錯誤
if(F0==3)
{
minute1=30;
hour1=7;
WriteRTC2();
}
if(week1>=8)
{
WriteRTC3();
}
DisplayRTC();
KeyHoldCnt= 0; //鍵按下計時
KeyCode= 0; //給使用者使用的鍵碼,1~16有效
IO_KeyState= 0;
IO_KeyState1= 0;
IO_KeyHoldCnt= 0;
cnt50ms= 0;
zhuangtai=0;
KeyCode0=0;
tuinao=0;
minute2=61;
naofu=0;//控制鬧鐘加1加5與分鐘同步
xunhuan=0;//控制迴圈鬧鐘
xinqinao=0;//星期鬧鐘控制
if(msecond1==0){}
else
{
msecond1=0;
}
while(1)
{
if(B_1ms) //1ms到
{
B_1ms= 0;
if(++msecond>= 500) //1秒到 重新整理時鐘
{
if(hello==0)
{
ReadRTC();
DisplayRTC();
if(minute==0) //整點報時
{
if(hour==hour1)
{
if(minute==minute1)
{}else{
led1=0;
}
}else
{
led1=0;
}
}
else{
led1=1;
}
if(hour==hour1) //鬧鐘實現塊
{
if(second==0)//保證和時鐘分鐘同步++乘其下一分鐘前進行+5 +1操作
{
msecond1=0;
naofu=1;
}
else
{
if(naofu==1)
{
if(++msecond1>=60)
{msecond1=0;
naofu=0;
}
}
}
if(minute==minute1-1)//取出鬧鐘分鐘值
{ ReadRTC2();
minute2=minute1;
}