手工做了個萬年歷放在工作臺前,仔細揀選ds1302模塊,竟然挺準,大約快一年不要校準。其中四個按鍵:1增鍵,2減鍵,3移位鍵,4設置鍵。長按4鍵進入設置,從年開始,設置位閃爍,1和2鍵點按增減,長按連續增減。短按4鍵切換到鬧鈴設置,時分位閃爍1,2鍵修改。再點按4鍵正常顯示并保存。在正常顯示時,短按4鍵,鬧鈴靜音,不按延時靜音。此按鍵只一個函數就完成四個鍵的長短和連發,以狀態機編寫,來源于網上大咖,妙極。
電路原理圖如下:
萬年歷.PNG (60.13 KB, 下載次數: 47)
下載附件
2022-1-12 16:33 上傳
單片機源程序如下:
- #include "REG52.H"
- #include<intrins.h>
- #include "key.h"
- extern struct sTime pdata CurTime; //ds1302定義 當前日期時間
- extern struct sTime pdata CurTimeDec; //ds1302定義
- struct sTime pdata SetTimeBcd; //ds1302定義 日期時間設置緩沖區
- struct sTime pdata SetTimeDec; //本定義 轉換成十進制日期時間設置緩沖區
- extern enum eStaSystem staSystem ; //定義枚舉并賦予初值系統運行狀態
- extern code uchar SEGweek[];
- extern code uchar SEG[];
- extern uchar SetIndex=0 ; //main.c定義 設置位索引
- extern uchar pdata DigShow[16]; //main.c定義 顯示中間變量
- extern uchar pdata DisplayData[16]; //main.c定義 顯示緩沖區
- uchar FlashLock=0; //設置閃爍原子鎖
- uint FlashCnt=0; //設置閃爍計數器
- #define Flash_half 100 //閃爍計數的半值
- #define Flash_all 200 //閃爍計數的全值 一定要比 半值大
- bit staMute = 0; //靜音標志位
- uint8 AlarmHour = 7; //鬧鐘時間的小時數
- uint8 AlarmMin = 30; //鬧鐘時間的分鐘數
- uint8 pdata SetAlarmHour; //鬧鐘小時數設置緩沖
- uint8 pdata SetAlarmMin; //鬧鐘分鐘數設置緩沖
- bit staBuzzer = 0; //蜂鳴器狀態控制位,1-鳴叫、0-關閉
- void DS1302SingleWrite(uchar reg, uchar dat);//ds1302.c定義的函數
- void WritinTime(struct sTime *time);
- void RefreshTime();
- sbit key1 = P3^0 ;
- sbit key2 = P3^1 ;
- sbit key3 = P3^2 ;
- sbit key4 = P3^3 ;
- #define key_value1 0x0e //1110
- #define key_value2 0x0d //1101
- #define key_value3 0x0b //1011
- #define key_value4 0x07 //0111
- #define key_null 0x0f
- #define key_long_period 10
- #define key_continue_period 1
- #define key_down 0x80 //定義按鍵返回值狀態(按下,長按,連發,釋放)
- #define key_long 0x40
- #define key_continue 0x20
- #define key_up 0x10
- enum key_state
- {
- key_state_init ,
- key_state_wobble ,
- key_state_press ,
- key_state_long ,
- key_state_continue ,
- key_state_release
- };
-
- enum key_state KeyState = key_state_init ;
-
- uchar KeyScan(void) //執行按鍵掃描
- {
- if(key1 == 0)
- return key_value1 ;
- if(key2 == 0)
- return key_value2 ;
- if(key3 == 0)
- return key_value3 ;
- if(key4 == 0)
- return key_value4 ;
- return key_null ; //無效
- }
- void KeyInit(void)
- {
- key1 = 1 ;
- key2 = 1 ;
- key3 = 1 ;
- key4 = 1 ;
- }
- void GetKey(uint8 *pKeyValue)
- {
- static uint8 KeyTimeCount = 0 ;
- static uint8 LastKey = key_null ; //保存按鍵釋放時候的鍵值
- uint8 KeyTemp = key_null ; //鍵值變量賦初值 無效鍵值
- KeyTemp = KeyScan() ; //獲取鍵值
- switch(KeyState)
- {
- case key_state_init : //初始態S1
- {
- if( key_null != (KeyTemp)) //鍵值不為無效 有鍵按下
- {
- KeyState = key_state_wobble ; //進入消抖態 state_init,
- }
- }
- break ;
- case key_state_wobble : //在消抖態S2
- {
- KeyState = key_state_press ; // 依舊按下態
- }
- break ;
- case key_state_press : //在按下態S3
- {
- if( key_null != (KeyTemp)) //鍵按下
- {
- LastKey = KeyTemp ; //保存鍵值,以便在釋放按鍵狀態返回鍵值
- KeyTemp |= key_down ; //////////////////0x80
- KeyState = key_state_long ;//長按態 S4
- }
- else
- {
- KeyState = key_state_init ; //初始態
- }
- }
- break ;
- case key_state_long : ////長按態
- {
- if( key_null != (KeyTemp)) //
- {
- if(++KeyTimeCount > key_long_period )//時間計數大于閥值300 3s
- {
- KeyTimeCount = 0 ; //計數清零
- KeyTemp |= key_long ; ////////////////////// //長按鍵事件發生0x40
- KeyState = key_state_continue ; //連發
- }
- }
-
- else
- {
- KeyState = key_state_release ; //釋放態
- }
- }
-
- break ;
- case key_state_continue : // //連動態S5
- {
- if( key_null != (KeyTemp)) ///
- {
-
- if(++KeyTimeCount >key_continue_period ) //連發態25階段一段時間
- {
- KeyTimeCount = 0 ; //
- KeyTemp |= key_continue ; /////////////////////////連發事件發生0x20
- }
- }
-
-
- else
- {
- KeyState = key_state_release ; ////釋放態
- }
- }
- break ;
- case key_state_release : ////釋放態S6
- {
- LastKey |= key_up ; /////////////////////////鍵彈起
- KeyTemp = LastKey ; //
- KeyState = key_state_init ; //初始化
- }
- break ;
- default : break ;
- }
- *pKeyValue = KeyTemp ; //返回鍵值
- }
-
-
- void RefreshTime()
- {
- DigShow[0] =SEG[ CurTimeDec.year/10 ]; //年份
- DigShow[1] = SEG[CurTimeDec.year %10];
- DisplayData[0] =DigShow[0] ;
- DisplayData[1]=DigShow[1];
-
- DigShow[2] = SEG[CurTimeDec.mon/10] ; //月份
- DigShow[3] = SEG[CurTimeDec.mon %10];
- if(CurTimeDec.mon/10==0) DisplayData[2]=0xff;
- DisplayData[2] =DigShow[2] ;
- DisplayData[3]=DigShow[3];
-
- DigShow[4] = SEG[CurTimeDec.day /10] ; //日期
- DigShow[5] = SEG[CurTimeDec.day %10];
- if(CurTimeDec.day /10==0) DisplayData[4]=0xff;
- DisplayData[4] =DigShow[4] ;
- DisplayData[5]=DigShow[5];
-
- DigShow[10]=SEGweek[CurTimeDec.week%10];
- DisplayData[10]=DigShow[10];
-
- DigShow[6]=SEG[CurTimeDec.hour/10 ]; //時
- DigShow[7]=SEG[CurTimeDec.hour%10];
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
Keil代碼下載(不含仿真和原理圖):
Keil代碼.7z
(38.71 KB, 下載次數: 45)
2022-1-13 00:08 上傳
點擊文件名下載附件
keil文件 下載積分: 黑幣 -5
|