單片機實現電子鐘主要有兩種方案。一種是利用單片機內部的定時/計數器產生標準秒信號,并根據時間系統的進位原則進行加1調整。另一種方法是為單片機配置一片可獨立走時的實時鐘(RTC)芯片,單片機通過串行信號線與該芯片進行通信,讀取或設置其當前時間。第一種方案結構簡單、成本低,精度可滿足多數場合的需要,因此,本設計采用第一種方案。
捕獲.PNG (71.09 KB, 下載次數: 29)
下載附件
2020-5-9 09:56 上傳
C語言源程序如下: #include <reg51.h> #include <string.h> //*****************************特殊功能寄存器聲明******************** sfr P4SW = 0xBB; sfr P4 = 0xC0; //*******************************數據類型定義************************ typedef unsigned char uint8; typedef unsigned int uint16; typedef struct { char Hour; char Minute; char Second; } tsRTClock; //**********************************口線聲明************************* #define LCD1602_DATA P0 sbit LCD1602_RS=P4^6; sbit LCD1602_EN=P4^5; sbit LCD1602_BL=P1^5; sbit KX0 =P3^2; sbit KX1 =P3^4; sbit KX2 =P3^5; sbit KX3 =P3^7; sbit BUZZ=P1^0; //******************************全局變量聲明************************* tsRTClock RTClock; uint8 Timer50ms=0; //******************************函數原型聲明************************* void SystemInit(); void LCD1602BLCtrl(uint8 OnOff); void LCD1602CmdWrite(uint8 cmdByte); void LCD1602DataWrite(uint8 DataByte); void LCD1602Init(); void LCD1602ClrScr(); void LCD1602DispChar(uint8 Row, uint8 Col, char Char); void LCD1602DispStr(uint8 Row, uint8 Col, char *Str); void RTClockInit(); void RTClockAdj(); void RTClockDisp(); uint8 key(); void Delay(uint16 ms); void AA(); void ZD (void); //*******************************中斷服務函數************************ void T0ISR(void) interrupt 1 { TH0=(65536-45*1024)>>8; //設置50ms定時初值(對應晶振11.0592MHz) TL0=(65536-45*1024)&0xFF; if(++Timer50ms<20 ) return; Timer50ms=0; //已滿1s,Timer50ms清0 RTClockAdj(); //時間調整 } //*********************************主函數**************************** void main() { SystemInit(); //系統初始化 RTClockInit(); //時鐘初始化 LCD1602ClrScr(); LCD1602DispStr(0, 0, "What time is it ?"); //首行顯示提示信息 while(1) { Delay(100); key(); ZD (); RTClockDisp(); //顯示當前時間 } } //******************************系統初始化函數*********************** void SystemInit() { P4SW |= 0x70; //將P44-P46設為I/O口 TMOD=0x01; //T0用作定時器(方式1) TH0=(65536-45*1024)>>8; //設置50ms定時初值(對應晶振11.0592MHz) TL0=(65536-45*1024)&0xFF; TR0=1; //啟動T0 ET0=1; //允許T0中斷 EA=1; LCD1602BLCtrl(0); //背光點亮 LCD1602Init(); //LCD1602初始化 } //****************************LCD1602背光控制函數******************** void LCD1602BLCtrl(uint8 OnOff) //0:背光點亮,1:背光熄滅 { LCD1602_BL=OnOff; } //*****************************LCD1602寫命令函數********************* void LCD1602CmdWrite(uint8 cmdByte) { uint16 i; for(i=100;i;i--); //適當延時(取代忙狀態檢測) LCD1602_RS=0 ; LCD1602_EN=1; LCD1602_DATA=cmdByte; //發送命令字節 LCD1602_EN=0; } //*****************************LCD1602寫數據函數********************* void LCD1602DataWrite(uint8 DataByte) { uint16 i; for(i=100;i;i--); //適當延時(取代忙狀態檢測) LCD1602_RS=1; LCD1602_EN=1; LCD1602_DATA=DataByte; //發送數據字節 LCD1602_EN=0; } //*****************************LCD1602初始化函數********************* void LCD1602Init() { LCD1602_EN=0; LCD1602CmdWrite(0x38); //8位總線方式,兩行顯示,5*7點陣 LCD1602CmdWrite(0x0C); //LCD顯示開,無光標 LCD1602CmdWrite(0x06); //寫入一個數據字節后地址計數器自動加1 } //******************************LCD1602清屏函數********************** void LCD1602ClrScr() { LCD1602CmdWrite(0x01); //發送清屏命令 Delay(8); } //****************************LCD1602字符顯示函數******************** void LCD1602DispChar(uint8 Row, uint8 Col, char Char) { if(Row) Col |= 0x40; //顯示第二行時DDRAM地址從40H開始 Col |= 0x80; //拼為DDRAM地址設置命令 LCD1602CmdWrite(Col); //發送DDRAM地址 LCD1602DataWrite(Char); //發送ASCII碼 } //***************************LCD1602字符串顯示函數******************* void LCD1602DispStr(uint8 Row, uint8 Col, char *Str) { if(Row) Col |= 0x40; //顯示第二行時DDRAM地址從40H開始 Col |= 0x80; //拼為DDRAM地址設置命令 LCD1602CmdWrite(Col); //發送DDRAM地址 while(*Str ) LCD1602DataWrite(*Str++); //連續發送每個字符的ASCII碼 } //******************************電子鐘初始化函數********************* void RTClockInit() { RTClock.Hour=23; RTClock.Minute=59; RTClock.Second=50; } //*****************************電子鐘時間調整函數******************** void RTClockAdj() { if(++RTClock.Second<60 ) return; RTClock.Second=0; if(++RTClock.Minute<60 ) return; RTClock.Minute=0; if(++RTClock.Hour<24 ) return; RTClock.Hour=0; } //*****************************電子鐘顯示更新函數******************** void RTClockDisp() { if(RTClock.Hour>=10) LCD1602DispChar(1,4,0x30+RTClock.Hour/10); //顯示Hour的十位 else LCD1602DispChar(1,4,' '); //Hour的十位為0則隱去 LCD1602DispChar(1,5,0x30+RTClock.Hour%10); //顯示Hour的個位 LCD1602DispChar(1,6,':'); LCD1602DispChar(1,7,0x30+RTClock.Minute/10); //顯示Minute的十位 LCD1602DispChar(1,8,0x30+RTClock.Minute%10); //顯示Minute的個位 LCD1602DispChar(1,9,':'); LCD1602DispChar(1,10,0x30+RTClock.Second/10); //顯示Second的十位 LCD1602DispChar(1,11,0x30+RTClock.Second%10); //顯示Second的個位 } uint8 key() { if(KX0==0) { Delay(2); if(KX0==0) { EA=0; TH0=0; TL0=0; RTClock.Hour++; RTClock.Second=0; if(RTClock.Hour>=24) RTClock.Hour=0; while(!KX0); } EA=1; return RTClock.Hour; } if(KX1==0) { Delay(2); if(KX1==0) { EA=0; TH0=0; TL0=0; RTClock.Hour--; RTClock.Second=0; if(RTClock.Hour<0) RTClock.Hour=23; while(!KX1); } EA=1; return RTClock.Hour; } if(KX2==0) { Delay(2); if(KX2==0) { EA=0; TH0=0; TL0=0; RTClock.Minute++; RTClock.Second=0; if(RTClock.Minute>=60) RTClock.Minute=0; while(!KX2); } EA=1; return RTClock.Minute; } if(KX3==0) { Delay(2); if(KX3==0) { EA=0; TH0=0; TL0=0; RTClock.Minute--; RTClock.Second=0; if(RTClock.Minute<0) RTClock.Minute=59; while(!KX3); } EA=1; return RTClock.Hour; } } void AA() { int i=0; for(i=0;i<=RTClock.Hour;i++) { BUZZ=0; Delay(100); BUZZ=1; } } void ZD (void) { if(RTClock.Second==0&&RTClock.Minute==0) { { AA(); } } } //******************************軟件延時函數************************* void Delay(uint16 ms) { uint16 i; do{ for(i=700;i;i--); //以1ms為延時單位 } while(--ms); }
|