好東東啊 下面是樓主的主程序:
- /*******************************************************
- 功能:LED數碼管電子鐘
- *******************************************************/
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- //函數定義
- void DelayMS(uint x); //延時 xms(晶振:11.0592MHz,)
- uchar Get_A_Byte_FROM_DS1302(); //從DS1302讀取一個字節
- uchar Read_Data( uchar addr ); //從DS1302指定位置讀數據
- void Write_A_Byte_TO_DS1302( uchar x ); //向DS1302寫入一個字節
- void Write_DS1302( uchar addr, uchar dat ); //向DS1302某地址寫數據
- void SET_DS1302(); //設置日期時間
- void GetTime(); //讀取當前時間日期
- void LedDisplay(); //顯示數據
- void Scan_Key(); //掃描鍵盤
- void Init(); //系統初始化
- void Play(); //蜂鳴器發音
- void Format_DS1302(); //日期格式化
- sbit RST = P3^5; //DS1302復位線
- sbit SDA = P3^6; //DS1302數據線
- sbit CLK = P3^7; //DS1302時鐘線
- sbit NOT = P3^4; //日期分隔小數點和時間分隔冒號(1-冒號亮、0-小數點亮)
- sbit BEEP = P1^7; //蜂鳴器輸出端口
- uchar Current_Time[7]; //保存所讀取的日期時間(秒分時日月周年)
- uchar Display_Buffer[12]; //處理過的日期時間,用于數碼管顯示
- uchar DelayTwinkle = 5; //閃爍延時長度,原200
- uchar TimeTwinkle = 4; //閃爍顯示時間,原30
- uchar WeiTwinkle = 0; //閃爍的位
- uchar TimeShake = 100; //去抖動延時時間長度
- uint BeepTime = 0; //蜂鳴器響一次的間隔時間
- uint Set_State = 0; //0:走時狀態、1:設置狀態。
- bit DateTime_State = 0; //0:顯示時間、1:顯示日期。
- uint Count = 0; //記錄“K_Setup”的狀態
- //按鍵定義
- sbit K_Setup = P1^2; //設置/移動/退出
- sbit K_Add = P1^3; //加1
- sbit K_Sub = P1^0; //減1
- sbit K_OK = P1^1; //保存并退出/翻頁
- sbit K_GND = P1^4; //由于薄膜開關的原因,此腳定義為地。
- sbit K_FORMAT = P1^5; //格式化(使日期時間內容為:2019-06-17 12:00:00)
- //共陽LED數碼管位碼(從左到右:1、2、3、4、5、6)
- //用PNP管驅動
- code uchar WEI_CODE [] =
- {
- 0xFE, //1 11111110
- 0xFD, //2 11111101
- 0xFB, //3 11111011
- 0xF7, //4 11110111
- 0xEF, //5 11101111
- 0xDF //6 11011111
- };
- //共陽LED數碼管段碼
- code uchar DSY_CODE [] =
- {
- 0x40, //0
- 0x79, //1
- 0x24, //2
- 0x30, //3
- 0x19, //4
- 0x12, //5
- 0x02, //6
- 0x78, //7
- 0x00, //8
- 0x10 //9
- };
- // 延時 xms(晶振:11.0592MHz,)
- void DelayMS(uint x)
- {
- uchar i;
- while( x-- )
- {
- for( i=0; i<111; i++ );
- }
- }
- //蜂鳴器發音
- void Play()
- {
- uchar i, j;
- for( i = 0; i < 250; i++ )
- {
- BEEP = ~BEEP;
- for (j = 0; j < 30; j++ )
- {
- _nop_(); //延時時間長短決定發音頻率
- }
- }
- BEEP = 0;
- }
- //從DS1302讀取一個字節
- uchar Get_A_Byte_FROM_DS1302()
- {
- uchar i,b,t;
- for ( i = 0; i < 8; i++ )
- {
- b >>= 1;
- t = SDA;
- b |= t << 7;
- CLK = 1;
- CLK = 0;
- }
- //BCD碼轉換
- return b / 16 * 10 + b % 16;
- }
- //從DS1302指定位置讀數據
- uchar Read_Data( uchar addr )
- {
- uchar dat;
- RST = 0;
- CLK = 0;
- RST = 1;
- Write_A_Byte_TO_DS1302( addr );
- dat = Get_A_Byte_FROM_DS1302();
- CLK = 1;
- RST = 0;
- return dat;
- }
- //向DS1302寫入一個字節
- void Write_A_Byte_TO_DS1302( uchar x )
- {
- uchar i;
- for ( i = 0; i < 8; i++ )
- {
- SDA = x & 1;
- CLK = 1;
- CLK = 0;
- x >>= 1;
- }
- }
- //向DS1302某地址寫數據
- void Write_DS1302( uchar addr, uchar dat )
- {
- CLK = 0;
- RST = 1;
- Write_A_Byte_TO_DS1302( addr );
- Write_A_Byte_TO_DS1302( dat );
- CLK = 0;
- RST = 0;
- }
- //設置日期時間,括號里面是地址
- //秒(0x80)分(0x82)時(0x84)日(0x86)月(0x88)周(0x8a)年(0x8c)
- void SET_DS1302()
- {
- uchar i;
- Write_DS1302( 0x8E, 0x00 ); //寫控制字,取消寫保護
- for ( i = 0; i < 7; i++ )
- {
- Write_DS1302( 0x80 + 2 * i, ( Current_Time[i] / 10 << 4 ) | ( Current_Time[i] % 10 ) );
- }
- Write_DS1302( 0x8E, 0x80 ); //加保護
- }
- //日期格式化,使日期時間值為合法數據(使日期時間內容為:2019-06-20 12:00:00)
- void Format_DS1302()
- {
- Current_Time[0] = 0x00; //秒
- Current_Time[1] = 0x00; //分
- Current_Time[2] = 0x0C; //12小時
- Current_Time[3] = 0x14; //20日
- Current_Time[4] = 0x06; //06月
- Current_Time[5] = 0x05; //周5(星期日是一周的開始)
- Current_Time[6] = 0x13; //19年
-
- SET_DS1302();
- }
- //讀取當前時間日期(秒、分、時、日、月、周、年)
- //將讀取到的日期時間保存到顯示緩沖區中。
- //運行時間約 2.4ms
- void GetTime()
- {
- uchar i;
- for ( i = 0; i < 7; i++ )
- {
- Current_Time[i] = Read_Data( 0x81 + 2 * i );
- }
- Display_Buffer[0] = DSY_CODE[ Current_Time[2] / 10 ]; //小時的十位
- Display_Buffer[1] = DSY_CODE[ Current_Time[2] % 10 ]; //小時的個位
- Display_Buffer[2] = DSY_CODE[ Current_Time[1] / 10 ]; //分的十位
- Display_Buffer[3] = DSY_CODE[ Current_Time[1] % 10 ]; //分的個位
- Display_Buffer[4] = DSY_CODE[ Current_Time[0] / 10 ]; //秒的十位
- Display_Buffer[5] = DSY_CODE[ Current_Time[0] % 10 ]; //秒的個位
- Display_Buffer[6] = DSY_CODE[ Current_Time[6] / 10 ]; //年的十位
- Display_Buffer[7] = DSY_CODE[ Current_Time[6] % 10 ]; //年的個位
- Display_Buffer[8] = DSY_CODE[ Current_Time[4] / 10 ]; //月的十位
- Display_Buffer[9] = DSY_CODE[ Current_Time[4] % 10 ]; //月的個位
- Display_Buffer[10] = DSY_CODE[ Current_Time[3] / 10 ]; //日的十位
- Display_Buffer[11] = DSY_CODE[ Current_Time[3] % 10 ]; //日的個位
- Display_Buffer[12] = DSY_CODE[ Current_Time[5] - 1 ]; //周的個位(星期日是一周的開始)
- }
- //顯示數據(運行時間約 12ms)
- void LedDisplay()
- {
- uchar i;
- if ( Set_State == 0 ) //走時狀態
- {
- WeiTwinkle = 0;
- if ( DateTime_State == 0 ) //顯示時間
- {
- NOT = 1;
- for ( i = 0; i < 6; i++ )
- {
- P2 = WEI_CODE[ i ];
- P0 = Display_Buffer[ i ];
- DelayMS(1);
- P2 = 0xFF;
- P0 = 0xFF;
- DelayMS(1);
- }
- }
- else //顯示日期
- {
- NOT = 0;
- for ( i = 0; i < 6; i++ )
- {
- P2 = WEI_CODE[ i ];
- P0 = Display_Buffer[ i + 6 ];
- DelayMS(1);
- P2 = 0xFF;
- P0 = 0xFF;
- DelayMS(1);
- }
- }
- }
- else //設置狀態
- {
- uchar j,k;
- if ( DateTime_State == 0 ) //顯示時間
- {
- NOT = 1;
- for ( i = 0; i < 6; i++ )
- {
- if ( i != WeiTwinkle && i != WeiTwinkle + 1 ) //不閃爍的位
- {
- P2 = WEI_CODE[ i ];
- P0 = Display_Buffer[ i ];
- DelayMS(1);
- }
- else if ( j > DelayTwinkle ) //閃爍的位(2位)
- {
- for ( k = 0; k < TimeTwinkle; k++ )
- {
- P2 = WEI_CODE[ i ];
- P0 = Display_Buffer[ i ];
- DelayMS( 1 );
- P2 = WEI_CODE[ i + 1 ];
- P0 = Display_Buffer[ i + 1 ];
- DelayMS( 1 );
- }
- j = 0;
- }
- P2 = 0xFF;
- P0 = 0xFF;
- DelayMS(1);
- j++;
- }
- }
- else //顯示日期
- {
- NOT = 0;
- for ( i = 0; i < 6; i++ )
- {
- if ( i != WeiTwinkle && i != WeiTwinkle + 1 ) //不閃爍的位
- {
- P2 = WEI_CODE[ i ];
- P0 = Display_Buffer[ i + 6 ];
- DelayMS(2);
- }
- else if ( j > DelayTwinkle ) //閃爍的位(2位)
- {
- for ( k = 0; k < TimeTwinkle; k++ )
- {
- P2 = WEI_CODE[ i ];
- P0 = Display_Buffer[ i + 6 ];
- DelayMS( 1 );
- P2 = WEI_CODE[ i+1 ];
- P0 = Display_Buffer[ i + 7 ];
- DelayMS( 1 );
- }
- j = 0;
- }
- P2 = 0xFF;
- P0 = 0xFF;
- DelayMS(1);
- j++;
- }
- }
- }
- }
- //掃描鍵盤
- void Scan_Key()
- {
- //設置
- if ( K_Setup == 0 )
- {
- DelayMS( TimeShake ); //去抖動
- if ( K_Setup == 0 )
- {
- Set_State ++;
- if ( Set_State > 6 )
- {
- Set_State = 0;
- DateTime_State = 0;
- WeiTwinkle = 0;
- }
- else
- {
- switch ( Set_State )
- {
- case 0:
- WeiTwinkle = 0;
- break;
- case 1:
- WeiTwinkle = 0;
- break;
- case 2:
- WeiTwinkle = 2;
- break;
- case 3:
- WeiTwinkle = 4;
- break;
- case 4:
- WeiTwinkle = 0;
- break;
- case 5:
- WeiTwinkle = 2;
- break;
- case 6:
- WeiTwinkle = 4;
- break;
- }
- if ( Set_State < 4 )
- {
- DateTime_State = 0; //第一頁,顯示時間
- }
- else
- {
- DateTime_State = 1; //第二頁,顯示日期
- }
- }
- DelayMS(1);
- Play();
- }
- }
-
- //在設置時才能操作的按鍵
- if ( Set_State != 0 )
- {
- //調時:增加(設置狀態有效)
- if ( K_Add == 0 )
- {
- DelayMS( TimeShake ); //去抖動
- if ( K_Add == 0 )
- {
- switch( WeiTwinkle )
- {
- case 0: //時/年
- if ( DateTime_State == 0 )
- { //小時
- Current_Time[2]++;
- if ( Current_Time[2] > 23 )
- {
- Current_Time[2] = 0;
- }
- Display_Buffer[0] = DSY_CODE[ Current_Time[2] / 10 ];
- Display_Buffer[1] = DSY_CODE[ Current_Time[2] % 10 ];
- }
- else
- { //年
- Current_Time[6]++;
- Display_Buffer[6] = DSY_CODE[ Current_Time[6] / 10 ];
- Display_Buffer[7] = DSY_CODE[ Current_Time[6] % 10 ];
- }
- break;
- case 2: //分/月
- if ( DateTime_State == 0 )
- { //分
- Current_Time[1]++;
- if ( Current_Time[1] > 59 )
- {
- Current_Time[1] = 0;
- }
- Display_Buffer[2] = DSY_CODE[ Current_Time[1] / 10 ];
- Display_Buffer[3] = DSY_CODE[ Current_Time[1] % 10 ];
- }
- else
- { //月
- Current_Time[4]++;
- if ( Current_Time[4] > 12 )
- {
- Current_Time[4] = 1;
- }
- Display_Buffer[8] = DSY_CODE[ Current_Time[4] / 10 ];
- Display_Buffer[9] = DSY_CODE[ Current_Time[4] % 10 ];
- }
- break;
- case 4: //秒/日
- if ( DateTime_State == 0 )
- { //秒
- Current_Time[0]++;
- if ( Current_Time[0] > 59 )
- {
- Current_Time[0] = 0;
- }
- Display_Buffer[4] = DSY_CODE[ Current_Time[0] / 10 ];
- Display_Buffer[5] = DSY_CODE[ Current_Time[0] % 10 ];
- }
- else
- { //日
- Current_Time[3]++;
- if ( Current_Time[3] > 31 )
- {
- Current_Time[3] = 1;
- }
- Display_Buffer[10] = DSY_CODE[ Current_Time[3] / 10 ];
- Display_Buffer[11] = DSY_CODE[ Current_Time[3] % 10 ];
- }
- break;
- }
- Play();
- }
- }
- //調時:減小(設置狀態有效)
- if ( K_Sub == 0 )
- {
- DelayMS( TimeShake ); //去抖動
- if ( K_Sub == 0 )
- {
- switch( WeiTwinkle )
- {
- case 0: //時/年
- if ( DateTime_State == 0 )
- { //小時
- Current_Time[2]--;
- if ( Current_Time[2] < 0 )
- {
- Current_Time[2] = 23;
- }
- Display_Buffer[0] = DSY_CODE[ Current_Time[2] / 10 ];
- Display_Buffer[1] = DSY_CODE[ Current_Time[2] % 10 ];
- }
- else
- { //年
- Current_Time[6]--;
- if ( Current_Time[6] < 0 )
- {
- Current_Time[6] = 0;
- }
- Display_Buffer[6] = DSY_CODE[ Current_Time[6] / 10 ];
- Display_Buffer[7] = DSY_CODE[ Current_Time[6] % 10 ];
- }
- break;
- case 2: //分/月
- if ( DateTime_State == 0 )
- { //分
- Current_Time[1]--;
- if ( Current_Time[1] < 0 )
- {
- Current_Time[1] = 59;
- }
- Display_Buffer[2] = DSY_CODE[ Current_Time[1] / 10 ];
- Display_Buffer[3] = DSY_CODE[ Current_Time[1] % 10 ];
- }
- else
- { //月
- Current_Time[4]--;
- if ( Current_Time[4] <= 0 )
- {
- Current_Time[4] = 12;
- }
- Display_Buffer[8] = DSY_CODE[ Current_Time[4] / 10 ];
- Display_Buffer[9] = DSY_CODE[ Current_Time[4] % 10 ];
- }
- break;
- case 4: //秒/日
- if ( DateTime_State == 0 )
- { //秒
- Current_Time[0]--;
- if ( Current_Time[0] < 0 )
- {
- Current_Time[0] = 59;
- }
- Display_Buffer[4] = DSY_CODE[ Current_Time[0] / 10 ];
- Display_Buffer[5] = DSY_CODE[ Current_Time[0] % 10 ];
- }
- else
- { //日
- Current_Time[3]--;
- if ( Current_Time[3] <= 0 )
- {
- Current_Time[3] = 31;
- }
- Display_Buffer[10] = DSY_CODE[ Current_Time[3] / 10 ];
- Display_Buffer[11] = DSY_CODE[ Current_Time[3] % 10 ];
- }
- break;
- }
- Play();
- }
- }
-
- //保存數據并退回到走時狀態(設置狀態有效)
- if ( K_OK == 0 )
- {
- DelayMS( TimeShake ); //去抖動
- if ( K_OK == 0 )
- {
- SET_DS1302();
- Set_State = 0;
- Play();
- }
- }
- //日期格式化,使日期時間值為合法數據(這個按鍵不安裝在機殼上,如要操作,直接用杜邦線短接既可。)
- if ( K_FORMAT == 0 )
- {
- DelayMS( TimeShake );
- if ( K_FORMAT == 0 )
- {
- Format_DS1302();
- Set_State = 0;
- }
- }
- }
- else
- {
- //走時狀態(切換日期與時間)
- if ( K_OK == 0 )
- {
- DelayMS( TimeShake ); //去抖動
- if ( K_OK == 0 )
- {
- DateTime_State = ~DateTime_State;
- DelayMS(1);
- Play();
- }
- }
- }
- }
- //判斷是否是閏年
- //uchar isLeapYear(uint y)
- //{
- // return ( y % 4 == 0 && y % 100 != 0 ) || ( y % 400 == 0 );
- //}
- //系統初始化
- //T0 用于鍵盤掃描,每50ms一次。
- void Init()
- {
- K_GND = 0; //薄膜開關的地。
- TMOD = 0x01; //設置定時器0、1為工作方式1
- TH0 = 0; //65.536ms
- TL0 = 0;
- ET0 = 1; //允許定時器0
- TR0 = 1; //啟動定時器0
- EA = 1; //全局中斷開
- }
- //主函數
- void main()
- {
- Init();
- while(1)
- {
- if ( Set_State == 0 ) //走時狀態
- {
- GetTime(); //讀取時間數據(運行時間約 2.4ms)
- }
- LedDisplay();
- }
- }
- //定時器0中斷
- void Time0() interrupt 1
- {
- TR0 = 0; //關閉定時器0
- Scan_Key(); //掃描鍵盤
- TH0 = 0; //65.536ms產生一次中斷
- TL0 = 0;
- TR0 = 1; //啟動定時器0
- }
- //定時器1中斷
- //控制蜂鳴器2秒響一聲
- //void Time1() interrupt 3
- //{
- // TR1 = 0;
- // if ( BeepTime >= 40 )
- // {
- //// Play();
- // BeepTime = 0;
- // }
- // BeepTime++;
- // TH1 = ( 65536 - 50000 ) / 256;
- // TL1 = ( 65536 - 50000 ) % 256;
- // TR1 = 1;
- //}
復制代碼 |