手工做了个万年历放在工作台前,仔细拣选ds1302模块,竟然挺准,大约快一年不要校准。其中四个按键:1增键,2减键,3移位键,4设置键。长按4键进入设置,从年开始,设置位闪烁,1和2键点按增减,长按连续增减。短按4键切换到闹铃设置,时分位闪烁1,2键修改。再点按4键正常显示并保存。在正常显示时,短按4键,闹铃静音,不按延时静音。此按键只一个函数就完成四个键的长短和连发,以状态机编写,来源于网上大咖,妙极。
电路原理图如下:
单片机源程序如下:
- #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, 下载次数: 34)
|