|
这个系统可以近似的看成是按键并发操作,单击、双击等一系列的动作都已经定义过。以下是头文件:
#define BaseTime 10 //时基,由单片机时钟中断精准产生
#define number_init 0xfffffffd //对任何时间变量需要初始化的地方预设的初始化值
typedef unsigned char uchar ;
typedef unsigned int uint ;
typedef unsigned long ulong ;
typedef unsigned long utime ;
enum ButtonModel{noneClick=0,singalClick,doubleClick,repeatClick,longPress};
enum ButtonStaus{nonePress=1,pressDown,pressUp,pressDownHold};
struct button
{
uchar outPutEn:1; //发送数据使能
uchar lastButton:1; //缓存按键上次变动后的状态
uchar init_leavel:1; //设置默认按键电平
uchar longPressFlag:1; //长按释放标志 默认0,一旦开始长按则置1
uchar Gpio_level :3; //读取IO口电平
uchar applyUseOpenAPI:1; //在关机状态下,若本按键按下启动了系统,则需要申请全局变量标明,禁止其他按键关闭被本按键打开的系统(自己打开自己负责关闭)
uchar ticks; //按键按下次数
enum ButtonStaus lastButtonStaus; //缓存按键上个循环的状态
enum ButtonStaus thisButtonStaus; //缓存按键本循环的状态
enum ButtonModel lastButtonModel; //缓存按键上个循环所处的模式
enum ButtonModel thisButtonModel; //缓存按键本循环应该所处的模式
uint changeModelTime; //10ms基准 多击时间定义
uint pressLongTime; //10ms基准 长按时间定义
utime lastPressDownMoment; //上次按键按下所处的时刻
utime thisPressDownMoment; //本次按键按下所处的时刻
uint tempTime; //缓存按键两次按下之间的时长
utime buttonConfir; //按键防抖时长
utime getTimer; //获取时钟精准时刻,用于设定按键扫描周期
utime acquisitionMoment; //获取时钟精准时刻,用于记录相同按键状态持续时长
uchar (*read_gpio)(void); //获取按键状态方法
};
void Button_init(struct button *Key,uchar(*get_leavel)(),bit init_button_leavel,uint LongPressTimes,uint changeModelTime); //按键初始化
void Scan_key(struct button *Key,utime timer ,uint enOutTime ,uint noiseProofTime); //按键扫描函数
以下是DEMO:
#include"button.h"
struct button button1,button2;
uchar keyCounter=0;
uint Pwm=0;
utime COLCK=0;
inline uchar Get_gpio_level1(void)//获取开关的电平,特别注意:如果一个IO口下有三四十个按钮,用ADC扫描不同的电压值来判断是哪个按钮动作时,要注意程序嵌套层数,层数太多会有栈溢出的问题,暂时无解
{
return P10; //P10是单片机接开关的IO口
}
inline uchar Get_gpio_level2(void)
{
return P11; //P11是单片机接开关的IO口
}
uchar Pwm_excute(uchar pwmDuty); //pwm示例程序,不填充
void Get_button_model(struct button* ); //对扫描到的单击,双击,长按动作响应
main()
{
Button_init(&button1,Get_gpio_level1,1,300,100);// 默认开关不动作时是高电平,定义长按时长为300个10ms,定义多击时长为100个10ms
Button_init(&button2,Get_gpio_level2,1,300,100);
/*记得开COLCK所在的中断!这个时间中断程序就不填充了*/
while(1)
{
Scan_key(&button1,COLCK,50,20); //定义50ms 扫描一次,定义按键防抖时间20ms
Scan_key(&button2,COLCK,50,20);
Get_button_model(&button1); //对按键动作响应
Get_button_model(&button2);
}
}
void Get_button_model(struct button* Key )
/*注意啦!多按键会存在资源竞争的风险,比如按键1打开了某个操作只能由按键1关闭,
如果不仔细设计会存在按键2执行某个动作时关闭掉按键1打开的操作,遇到这个问题记得applyUseOpenAPI这个玩意来申请权限,然后用全局变量标识这个操作已经被占用,
目前在本DEMO例程中没有用到这么复杂的设计
*/
{
if(Key->outPutEn)
{
switch(Key->thisButtonModel)
{
switch noneClick:
{
/*
最精华的部分,在按键无动作的时候该处理那些数据,
*/
break;
}
switch singalClick:
{
Pwm++;
if(Pwm>255)
Pwm=255;
Pwm_excute(Pwm); //这个函数没有填充,每个单片机的PWM定义不一样,甚至不是PWM的动作,单击执行什么动作,自己发挥
break;
}
switch doubleClick:
{
/*
*/
break;
}
switch repeatClick:
{
/*
*/
break;
}
switch longPress:
{
/*
*/
break;
}
}
Key->outPutEn=0; //单片机运行的速度太快,但是按键扫描又设置的固定多长时间扫描一次,为了解决矛盾,才有的这么个参数
}
}
EXN interrupt N //定时器中断
{
/*
*/
COLCK++; //每10ms加1
}
PS:公司的项目非常复杂,用的是多按键并发,等过段时间我整一张原理图上来。当然,公司项目的源程序有5千行,处于保密需求是不可能上传的。
|
-
-
按键驱动.zip
5.07 KB, 下载次数: 34, 下载积分: 黑币 -5
程序
评分
-
查看全部评分
|