|
|
智能電子時鐘仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
0.png (14.64 KB, 下載次數(shù): 12)
下載附件
2018-12-22 00:40 上傳
0.png (12.58 KB, 下載次數(shù): 14)
下載附件
2018-12-22 00:40 上傳
單片機(jī)源程序如下:
- #include <reg51.h>
- #include <string.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit SDA=P1^0; //DS1302數(shù)據(jù)線
- sbit CLK=P1^1; //DS1302時鐘線
- sbit RST=P1^2; // DS1302 復(fù)位線
- sbit k1=P3^4; // 選擇按鍵
- sbit k2=P3^5; // 加
- sbit k3=P3^6; // 減
- sbit k4=P3^7; // 確定
- sbit RS=P2^0; // LCD寄存器選擇
- sbit RW=P2^1; // LCD讀寫控制
- sbit EN=P2^2; // LCD啟動
- uchar tcount=0;
- uchar MonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31}; // 一年中每個月的天數(shù),二月的天數(shù)由年份決定
- uchar *Week[]={"SUN","MON","TUS","WEN","THU","FRI","SAT"}; //周日,周一到周六
- // LCD顯示緩沖
- uchar LCD_DSY_BUFFER1[]={"DATE 00-00-00 "} ;
- uchar LCD_DSY_BUFFER2[]={"TIME 00:00:00 "} ;
- uchar DateTime[7]; //所讀取的日期時間
- char Adjust_Index=-1; //當(dāng)前調(diào)節(jié)的時間對象:秒,分,時,日,月,年(0,1,2,3,4,6)
- uchar Change_Flag[]="-MHDM-Y"; //(分,時,日,月,年)不調(diào)節(jié)秒和周
- //函數(shù)聲明
- void Initialize_LCD1602(); //液晶初始化函數(shù)
- void LCD_Display(uchar p,uchar *str);
- void Write_Byte_TO_DS1302(uchar X); // 向DS1302寫入一個字節(jié)
- uchar Read_Byte_FROM_DS1302(); //從DS1302中讀取一個字節(jié)
- uchar Read_Data_FROM_DS1302(uchar addr); //從DS1302指定位置讀取數(shù)據(jù), 讀數(shù)據(jù)
- void Write_Data_TO_DS1302(uchar addr,uchar dat); // 向DS1302指定位置寫入數(shù)據(jù), 寫數(shù)據(jù)
- void SET_DS1302(); // 設(shè)置時間
- void GetTime(); // 讀取當(dāng)前時間
- void Initialization(); //初始化函數(shù)
- void main()
- {
- Initialization();
- while(1)
- {
- if(Adjust_Index==-1)
- GetTime();
- }
- }
- /*********************************************************************************************************************/
- void DelayMS(uint K)
- {
- uchar i;
- while(K--)
- {
- for(i=0;i<120;i++);
- }
- }
- //----------讀取LCD的狀態(tài)-------*/
- uchar Read_LCD_State()
- {
- uchar state;
- RS=0;
- RW=1;
- EN=1;
- DelayMS(2);
- state=P0;
- EN=0;
- DelayMS(2);
- return state;
- }
- void LCD_Busy_Wait()
- {
- while((Read_LCD_State()&0x80)==0x80);
- DelayMS(5);
- }
- void Write_LCD_Command(uchar cmd)
- {
- LCD_Busy_Wait();
- RS=0;
- RW=0;
- EN=0;
- P0=cmd;
- EN=1;
- DelayMS(2);
- EN=0;
- }
- void Write_LCD_Data(uchar dat)
- {
- LCD_Busy_Wait();
- RS=1;
- RW=0;
- EN=0;
- P0=dat;
- EN=1;
- DelayMS(2);
- EN=0;
- }
- void Initialize_LCD1602() //液晶初始化函數(shù)
- {
- Write_LCD_Command(0x38);DelayMS(2); //功能設(shè)置,數(shù)據(jù)長度為8位,雙行顯示,5×7點(diǎn)陣字體
- Write_LCD_Command(0x01);DelayMS(2); //清屏
- Write_LCD_Command(0x06);DelayMS(2); //字符進(jìn)入模式:屏幕不動,字符后移
- Write_LCD_Command(0x0c);DelayMS(2); // 顯示開,關(guān)光標(biāo)
- }
- void Set_LCD_Position(uchar pos)
- {
- Write_LCD_Command(pos|0x80); //設(shè)置7位的DDRAM地址值
- }
- void LCD_Display(uchar p,uchar *str)
- {
- uchar i;
- Set_LCD_Position(p);
- for(i=0;i<16;i++)
- {
- Write_LCD_Data(str[i]);
- DelayMS(2);
- }
- }
- /****************************************************************************************************************/
- void Initialization()
- {
- Initialize_LCD1602(); //調(diào)用液晶初始化函數(shù)
- IE=0x83; //允許中斷 外部0中斷和T0中斷
- IP=0x01; //設(shè)置中斷優(yōu)先級
- IT0=0x01; //設(shè)置外部中斷的脈沖觸發(fā)方式
- TMOD=0x01; //設(shè)置定時器的工作方式,為方式1
- TH0=-50000/256; //寫入初值
- TL0=-50000%256; //寫入初值
- TR0=1; //啟動定時器
- }
- void Write_Byte_TO_DS1302(uchar X) // 向DS1302寫入一個字節(jié)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- SDA=X&1;
- CLK=1;
- CLK=0;
- X>>=1;
- }
- }
- uchar Read_Byte_FROM_DS1302() //從DS1302中讀取一個字節(jié)
- {
- uchar i,byte,t;
- for(i=0;i<8;i++)
- {
- byte>>=1;
- t=SDA;
- byte|=t<<7;
- CLK=1;
- CLK=0;
- }
- //BCD碼轉(zhuǎn)換
- return byte/16*10+byte%16;
- }
- uchar Read_Data_FROM_DS1302(uchar addr) //從DS1302指定位置讀取數(shù)據(jù) , 讀數(shù)據(jù)
- {
- uchar dat;
- RST=0;
- CLK=0;
- RST=1;
- Write_Byte_TO_DS1302(addr); //向DS1302寫入一個地址
- dat=Read_Byte_FROM_DS1302(); //在上面寫入的地址中讀取數(shù)據(jù)
- CLK=1;
- RST=0;
- return dat;
- }
- void Write_Data_TO_DS1302(uchar addr,uchar dat) //向DS1302指定位置寫入數(shù)據(jù), 寫數(shù)據(jù)
- {
- CLK=0;
- RST=1;
- Write_Byte_TO_DS1302(addr);
- Write_Byte_TO_DS1302(dat);
- CLK=1;
- RST=0;
- }
- void SET_DS1302() //設(shè)置時間
- {
- uchar i;
- Write_Data_TO_DS1302(0x8E,0x00); //寫控制字,取消寫保護(hù)
- // 分,時,日,月,年依次寫入
- for(i=1;i<7;i++)
- {
- // 分的起始地址是10000010(0x82),后面依次是時,日,月,周,年,寫入地址每次遞增2
- Write_Data_TO_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10));
- }
- Write_Data_TO_DS1302(0x8E,0x80); //寫控制字,加寫保護(hù)
- }
- //--------------------------------------------------------
- // 讀取當(dāng)前時間
- //-------------------------------------------------------
- void GetTime() // 讀取當(dāng)前時間
- {
- uchar i;
- for(i=0;i<7;i++)
- {
- DateTime[i]=Read_Data_FROM_DS1302(0x81+2*i);
- }
- }
- void Format_DateTime(uchar d,uchar *a)
- {
- a[0]=d/10+'0';
- a[1]=d%10+'0';
- }
- uchar Is_Leapyear(uint year)
- {
- return (year%4==0&&year%100!=0)||(year%400==0) ;
- }
- void Refresh_Week_Day()
- {
- uint i,d,w=5; //已知1999年12.31是星期五
- for(i=2000;i<2000+DateTime[6];i++)
- {
- d=Is_Leapyear(i)?366:365;
- w=(w+d)%7;
- }
- d=0;
- for (i=1;i<DateTime[4];i++)
- {d+=MonthsDays[i];}
- d+=DateTime[3];
- //保存星期,0-6表示星期日,星期一至星期六,為了與DS1302的星期格式匹配,返回值需要加1
- DateTime[5]=(w+d)%7+1;
- }
- void Datetime_Adjust(char X)
- {
- switch(Adjust_Index)
- {
- case 6: //年調(diào)整,00-99
- if(X==1&&DateTime[6]<99)
- {
- DateTime[6]++;
- }
- if(X==-1&&DateTime[6]>0)
- {
- DateTime[6]--;
- }
- //獲取2月天數(shù)
- MonthsDays[2]=Is_Leapyear(2000+DateTime[6])?29:28;
- //如果年份變化后當(dāng)前月份的天數(shù)大于上限則設(shè)為上限
- if(DateTime[3]>MonthsDays[DateTime[4]])
- {
- DateTime[3]=MonthsDays[DateTime[4]];
- }
- Refresh_Week_Day(); //刷新星期
- break;
-
-
- case 4: //月調(diào)整 01-12
- if(X==1&&DateTime[4]<12)
- {
- DateTime[4]++;
- }
- if(X==-1&&DateTime[4]>1)
- {
- DateTime[4]--;
- }
- //獲取2月天數(shù)
- MonthsDays[2]=Is_Leapyear(2000+DateTime[6])?29:28;
- //如果年份變化后當(dāng)前月份的天數(shù)大于上限則設(shè)為上限
- if(DateTime[3]>MonthsDays[DateTime[4]])
- {
- DateTime[3]=MonthsDays[DateTime[4]];
- }
- Refresh_Week_Day(); //刷新星期
- break;
-
-
- case 3: //日調(diào)整00-28或00-29或00-30或00-31
- //調(diào)節(jié)之前首先根據(jù)當(dāng)前年份得出該年中2月的天數(shù)
- MonthsDays[2]=Is_Leapyear(2000+DateTime[6])?29:28;
- //根據(jù)當(dāng)前月份決定調(diào)節(jié)日期的上限
- if(X==1&&DateTime[3]<MonthsDays[DateTime[4]])
- {
- DateTime[3]++;
- }
- if(X==-1&&DateTime[3]>0)
- {
- DateTime[3]--;
- }
- Refresh_Week_Day(); //刷新星期
- break;
-
-
- case 2: // 時調(diào)整
- if(X==1&&DateTime[2]<23)
- {
- DateTime[2]++;
- }
- if(X==-1&&DateTime[4]>0)
- {
- DateTime[2]--;
- }
- break;
-
-
- case 1: // 分調(diào)整
- if(X==1&&DateTime[1]<59)
- {
- DateTime[1]++;
- }
- if(X==-1&&DateTime[4]>0)
- {
- DateTime[1]--;
- }
- break;
- }
- }
- void T0_INT()interrupt 1
- {
- TH0=-50000/256; // 寫入初值
- TL0=-50000%256; // 寫入初值
- if(++tcount!=2) return;
- tcount=0;
- //按指定格式生成待顯示的日期時鐘
- Format_DateTime(DateTime[6],LCD_DSY_BUFFER1+5);
- Format_DateTime(DateTime[4],LCD_DSY_BUFFER1+8);
- Format_DateTime(DateTime[3],LCD_DSY_BUFFER1+11);
- //星期
- strcpy(LCD_DSY_BUFFER1+13,Week[DateTime[5]-1]);
- //時,分。秒
- Format_DateTime(DateTime[2],LCD_DSY_BUFFER2+5);
- Format_DateTime(DateTime[1],LCD_DSY_BUFFER2+8);
- Format_DateTime(DateTime[0],LCD_DSY_BUFFER2+11);
- // 顯示年、月、日、星期、時、分、秒
- LCD_Display(0x00,LCD_DSY_BUFFER1);
- LCD_Display(0x40,LCD_DSY_BUFFER2);
- }
- void EX_INT0()interrupt 0
- {
- if(k1==0)
- {
- while (k1==0);
- if(Adjust_Index==-1||Adjust_Index==-1)
- {Adjust_Index=7;}
- Adjust_Index--;
- if(Adjust_Index==5)
- {Adjust_Index=4;} //跳過對星期的調(diào)節(jié)
- LCD_DSY_BUFFER2[13]='[';
- LCD_DSY_BUFFER2[14]=Change_Flag[Adjust_Index];
- LCD_DSY_BUFFER2[15]=']';
- }
- else if(k2==0) // 加
- {
- while(k2==0);
- Datetime_Adjust(1);
- }
- else if(k3==0) // 減
- {
- while(k3==0);
- Datetime_Adjust(-1);
- }
- else if(k4==0)
- {
- while(k4==0);
- SET_DS1302();
- LCD_DSY_BUFFER2[13]=' ';
- LCD_DSY_BUFFER2[14]=' ';
- LCD_DSY_BUFFER2[15]=' ';
- Adjust_Index=-1; //操作索引重設(shè)為-1,時間繼續(xù)正常顯示
- }
- }
復(fù)制代碼
所有資料51hei提供下載:
智能電子時鐘2.zip
(79.1 KB, 下載次數(shù): 34)
2018-12-21 11:37 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|
|