精华内容
下载资源
问答
  • 按键单击与双击
    2021-05-23 06:51:24

    按键的单击与双击与长按短按实现方式相近,以下代码仅供参考,写得不是很好

    适用于蓝桥杯开发板

    程序扩展性不强,更重要的是思路

    io.h

    #ifndef _IO_H

    #define _IO_H

    #include "stm32f10x.h"

    #define SingleClick 1

    #define DoubleClick 2

    #define KEY_B1 1

    #define KEY_B2 2

    #define KEY_B3 3

    #define KEY_B4 4

    #define TimeInterval 300 //判断双击与单击时间

    #define keyState1 1

    #define keyState2 2

    #define keyState3 3

    #define keyState4 4

    //enum ss{keyState1,keyState2,keyState3,keyState4}keyState;

    #define KEY0 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)

    #define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)

    #define KEY2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)

    #define KEY3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)

    enum k{key0,key1,key2,key3};

    extern void Delay_Ms(u32 nTime);

    void RCC_Init(void);

    void IO_Init(void);

    void LED_Control(u16 nled , u8 flag);

    u8 KEY_Scan(void);

    void Key_Double(void);

    #endif

    io.c

    u8 KEY_Scan(void)//按键扫描函数,查找键值

    {

    static u8 flag = 1;

    if(flag&&(KEY0==0||KEY1==0||KEY2==0||KEY3==0))

    {

    Delay_Ms(10);

    flag = 0;

    if(KEY0==0)return key0;

    else if(KEY1==0)return key1;

    else if(KEY2==0)return key2;

    else if(KEY3==0)return key3;

    }

    else if(KEY0==1&&KEY1==1&&KEY2==1&&KEY3==1)flag = 1;

    return 0xff;

    }

    //单击双击

    /*

    1、两次间隔10ms - 300ms以内是双击, 按下第一次开始计时

    2、300ms 之后没有按下第二次就是单击

    3、思路与我按键单击双击的思维在方向上不太一样,这里是直接状态中判断按键

    */

    void Key_Double(void)

    {

    static u8 key_value = 0xff;

    // static u16 keynum1 = 0,keynum2 = 0;

    static u8 key = 0; //记录第一次按键是谁按下

    switch(keyState)//keyState见宏定义,是按键第一次按下

    {

    case keyState1: key_value = KEY_Scan();

    if(key_value != 0xff){

    // keynum1 = keyTime;

    flag_1 = 1;

    keyState = keyState2;

    if(key_value==key0)key = 1;

    else if(key_value==key1)key = 2;

    else if(key_value==key2)key = 3;

    else if(key_value==key3)key = 4;

    }

    else

    {

    flag_1 = 0;

    keyState = keyState1;

    }

    break;

    case keyState2: key_value = KEY_Scan();

    if(keyTime<300)

    {

    switch(key)

    {

    case 1:if(key_value==key0){

    keyDouble = KEY_B1;flag_1 = 0;

    keyTime = 0;

    keyState = keyState1;

    } break;

    case 2:if(key_value==key1){

    keyDouble = KEY_B2;flag_1 = 0;

    keyTime = 0;

    keyState = keyState1;

    } break;

    case 3:if(key_value==key2){

    keyDouble = KEY_B3;flag_1 = 0;

    keyTime = 0;

    keyState = keyState1;

    }

    break;

    case 4:if(key_value==key3){

    keyDouble = KEY_B4;flag_1 = 0;

    keyTime = 0;

    keyState = keyState1;

    }

    break;

    }

    }

    else

    {

    switch(key)

    {

    case 1:keySingle = KEY_B1; break;

    case 2:keySingle = KEY_B2; break;

    case 3:keySingle = KEY_B3; break;

    case 4:keySingle = KEY_B4; break;

    }

    flag_1 = 0;

    keyTime = 0;

    keyState = keyState1;

    key = 0;

    }

    break;

    case keyState3:

    break;

    case keyState4:

    break;

    default: break;

    }

    }

    更多相关内容
  • 单击后,马上返回按键值单击后,释放之后,返回按键值单击后,按住不放,多次返回按键值但是在其上面扩展双击和三击以及多击程序时,遇到了麻烦(其实就是不会啦),于是在网上看了某个老师的经典按键程序,...

    下面这段是引言,和按键程序实质内容没有任何关系,可以当P话,可直接跳到分割线的地方。

    最近自己在琢磨按键程序,之前弄了,按键单击程序,程序可以实现读取按键的几个状态,然后根据需求使用。单击按键的几个状态如下:

    单击后,马上返回按键值

    单击后,释放之后,返回按键值

    单击后,按住不放,多次返回按键值

    但是在其上面扩展双击和三击以及多击程序时,遇到了麻烦(其实就是不会啦),于是在网上看了某个老师的经典按键程序,里面讲了单击和双击,拿着源程序理解了半天,终于一知半解了(一知半解的状态就是能读懂思想,但是闭卷完全自己写,写不出)。但是个人觉得其中的消抖部分还有按键释放的部分还可以改善,还有根据其思路扩展了三击以及N击,于是写了这篇博客供自己以后遗忘时参考以及跟大家分享。

    正文:

    此按键程序的实现的功能是单个独立按键的[单击],[长按],[双击],[三击]以及[多击]。本文分为三个部分,

    第一个部分是说[单击],[长按]的程序;

    第二部分是讲[双击];

    第三部分是讲[三击],[多击];

    一、[单击]、[长按]程序

    1. 简单介绍本按键程序的单击和长按

    首先说一下单击,长按的响应情况,就是按多久算单击或者长按,按下按键马上返回有效键值,还是释放之后返回有效键值等等,下面说下它在什么情况下返回有效的【单击】和【长按】。

    首先看一张时序图:

    0818b9ca8b590ca3270a3433284dd417.png

    注:

    T1:是单击的按键消抖时长,这里预设的是30ms,也可以根据需求自行定义;

    T2:是单击时,按键释放的有效时间段,提前或者超过这个时间段释放的按键都再是单击了。提前释放则是无效键值,超过后释放则是长按。

    T3:是长按时长,按键超过此时长,则为长按。这里的预设值是3s,同样可根据需求自行更改。

    【单击】:按键按下超过消抖时长T1(30ms),并且在T2时间段内释放按键,按键一释放,马上返回有效按键值—【单击】。

    注意:单击是释放后,才返回有效按键值,不释放时,是无效按键值。

    【长按】:按键按下的时间超过预设的长按时长T3(3s) ,马上返回有效按键值—【长按】;

    注意:双击是只要按下的时间超过预设的长按时长,马上返回有效键值。但是,如果按键一直按着不释放,则只返回一次有效按键值,不重复返回,直到释放之后,才开始重新读取键值。

    2. 按键程序的架构

    按键程序可以分为四个部分,第一部分:判断有无按键按下;第二部分:按键是否有效(按键消抖);第三部分:确定有效按键的种类(单击还是长按);第四部分:等待按键释放。

    3. 按键程序的源代码以及注释

    程序的注释写的很详细,应该是可以读懂的,如果有疑问可以留言讨论。

    以下是key.c 的源代码:

    #define KEY_INPUT P1.0 //按键IO

    #define KEY_STATE_0 0 //按键状态

    #define KEY_STATE_1 1

    #define KEY_STATE_2 2

    #define KEY_STATE_3 3

    #define LONG_KEY_TIME 300 //LONG_KEY_TIME*10MS = 3S

    #define SINGLE_KEY_TIME 3 //SINGLE_KEY_TIME*10MS = 30MS

    #define N_KEY 0 //no click

    #define S_KEY 1 //single click

    #define L_KEY 10 //long press

    void key_driver(void)

    {

    static byte key_state; //按键状态变量

    static word key_time; //按键计时变量

    byte key_press, key_return;

    key_return = N_KEY; // 清除 返回按键值

    key_press = KEY_INPUT; // 读取当前键值

    switch (key_state)

    {

    case KEY_STATE_0: // 按键状态0:判断有无按键按下

    if (!key_press) // 有按键按下

    {

    key_time = 0; // 清零时间间隔计数

    key_state = KEY_STATE_1; // 然后进入 按键状态1

    }

    break;

    case KEY_STATE_1: // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。

    if (!key_press)

    {

    key_time++; // 一次10ms

    if(key_time>=SINGLE_KEY_TIME) // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;

    {

    key_state = KEY_STATE_2; // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键

    }

    }

    else key_state = KEY_STATE_0; // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键

    break;

    case KEY_STATE_2: // 按键状态2:判定按键有效的种类:是单击,还是长按

    if(key_press) // 如果按键在 设定的长按时间 内释放,则判定为单击

    {

    key_return = S_KEY; // 返回 有效按键值:单击

    key_state = KEY_STATE_0; // 返回 按键状态0,继续等待按键

    }

    else

    {

    key_time++;

    if(key_time >= LONG_KEY_TIME) // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按

    {

    key_return = L_KEY; // 返回 有效键值值:长按

    key_state = KEY_STATE_3; // 去状态3,等待按键释放

    }

    }

    break;

    case KEY_STATE_3: // 等待按键释放

    if (key_press)

    {

    key_state = KEY_STATE_0; // 按键释放后,进入 按键状态0 ,进行下一次按键的判定

    }

    break;

    default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候

    key_state = KEY_STATE_0;

    break;

    }

    return key_return; // 返回 按键值

    }

    使用注意:

    1)硬件:按键的一端接地(GND),另一端接IO口。IO为输入,一定要有上拉电阻。

    2)定时器:这里为了精确的定时,所以使用了定时器,定时器的时间是10ms。

    3)扫描周期:调用此函数时,一定确保”扫描周期“要小于10ms。不然按键内所涉及的时间就会不准,会偏大。所涉及的时间包括消抖时长,按键长按时长等。

    扫描周期定义:从 第一次进入按键扫描程序 开始,到第二次进入按键扫描程序时 结束,之间所用的时间。

    测量扫描周期的方法:可以在按键扫描程序的第一句,添加IO口取反函数,然后用示波器查看改IO口,其IO口周期的一般就是扫描周期了。

    4. 按键程序的使用实例

    这里以C51位硬件平台进行实例讲解

    1)实例程序的功能:

    单击:点亮LED1

    长按:熄灭LED1

    2)硬件:

    按键IO:P1.0

    LED1 :P2.0

    以下是 main.c 源代码:

    #include "reg51.h"

    #include "key.c"

    sbit LED1 = P2.0; //定义LEDIO口

    unsigned char g_u8_KeyValue; //按键值

    unsigned char g_flag_10ms_key; //10ms 计时标志

    //timer0,初始化函数 ,定时时间为 10ms

    void T0_Init_10ms(void)

    {

    TMOD |= 0x01;

    TH0 = (65535 - 10000)/256;

    TL0 = (65535 - 10000)%256;

    ET0 = 1;

    TR0 = 1;

    EA = 1;

    }

    //主函数

    void main(void)

    {

    P1.0 = 1; //P1.0 拉高

    T0_Init_10ms(); //定时器0,初始化,定时10ms

    while(1)

    {

    if(g_flag_10ms_key) //等待10ms,定时完成

    {

    g_flag_10ms_key = 0; //清零10ms定时标志

    g_u8_KeyValue = key_driver(); //读取按键值

    switch(g_u8_KeyValue)

    {

    case S_Key: LED1 = 1; break; //单击 点亮LED1

    case L_Key: LED1 = 1; break; //长按 熄灭LED1

    }

    }

    }

    }

    //timer0 中断服务程序

    void IRQ_T0(void) interrupt 1

    {

    g_flag_10ms_key = 1; //置位 10ms 定时标志

    }

    pillarpeng

    2016.3.23 18:00

    …未完待续

    展开全文
  • 检测长按 短按 连击等各种状态按键检测程序,使用C语言编写
  • 按键C语言程序

    2021-05-19 13:07:29
    按键C语言程序zhchxgh | 2009-07-04 01:46:51 阅读:8246 发布文章一共用了四个按钮.#define_KEYDOWN_TEST_TIME(20)unsignedcharIsKeyDown(volatileunsignedcharValue,unsignedcharpin){unsignedlongCurSta...

    长按键C语言程序

    zhchxgh | 2009-07-04 01:46:51    阅读:8246

    db6c9df9ccb71c554faea6ec7ad19010.png发布文章

    一共用了四个按钮.

    #define _KEYDOWN_TEST_TIME      (20)

    unsigned char IsKeyDown(volatile unsigned char Value, unsigned char pin)

    {

    unsigned long CurState = 0, i;

    for(i = 0; i 

    CurState += _GET_BIT(Value, pin)? 0:1;     //键盘接了上拉电阻,低电平才是按下

    if(CurState == _KEYDOWN_TEST_TIME)

    return 1;

    return 0;

    }

    //以下所有值均是以 DealWithKey函数的调用频率为基础的,该频率是定时器2的定时值决定的

    //短按键的计数值,只有当按键检测计数器计数大于等于此值时才认为是一次短按

    #define _KEY_SHORT_CNTR             (2)

    //长按键的计数值,只有当按键检测计数器计数大于等于此值时才认为是一次长按

    #define _KEY_LONG_CNTR              (_KEY_SHORT_CNTR * 3)

    //无按键按下时的按键检测间隔,用于按键消抖动

    #define _KEY_NORMAL_DEVIDER         (2)

    //此值用于按钮长按后,按钮检测函数的执行频率

    #define _ADDMIN_FAST_DEVIDER        (15)

    //此值用于按钮短按后,按钮检测函数的执行频率

    #define _ADDMIN_LONG_DEVIDER        (_ADDMIN_FAST_DEVIDER * 3)

    //此值用于设置蜂鸣器鸣响时间

    #define _BEEPER_DEVIDER             (10)

    void DealWithKey(void)

    {

    static unsigned int AddCntr = 0;

    static unsigned int MinCntr = 0;

    static unsigned int UnitCntr = 0;

    static unsigned int RunCntr = 0;

    static unsigned char BeepCntr = 0;

    static unsigned int DevCntr = 0;

    static unsigned char LastRunState = 0;

    unsigned char temp;

    if(g_State != Setting)  //运行状态, 所有按键都无效

    return;

    if(BeepCntr > 0)        //处理蜂鸣器

    --BeepCntr;

    else

    _BEEPER_OFF;

    if(DevCntr)           //按键处理分频器

    {

    --DevCntr;

    return;

    }

    //这个按钮是可以重复进入的, 长按后先低频率动作, 当动作几次后再高频率动作

    AddCntr = IsKeyDown(_PIN(_TO_KEY_ADD), _KEY_ADD)? AddCntr + 1 : 0;

    if((temp = (AddCntr >= _KEY_LONG_CNTR)) || AddCntr >= _KEY_SHORT_CNTR)

    {

    ...

    }

    //同上

    MinCntr = IsKeyDown(_PIN(_TO_KEY_MIN), _KEY_MIN)? MinCntr + 1 : 0;

    if((temp = (MinCntr >= _KEY_LONG_CNTR)) || MinCntr >= _KEY_SHORT_CNTR)

    {

    ...

    }

    //这个按钮是不可重复进入的, 就是说只有抬起后再按下才动作

    UnitCntr = IsKeyDown(_PIN(_TO_KEY_UNIT), _KEY_UNIT)? UnitCntr + 1 : 0;

    if(UnitCntr == _KEY_SHORT_CNTR)

    {

    ...

    }

    else if(UnitCntr > _KEY_SHORT_CNTR)

    {

    UnitCntr = _KEY_SHORT_CNTR + 1; //禁止重复执行

    }

    //这个按钮是要在按钮抬起后才执行其他函数的

    if(IsKeyDown(_PIN(_TO_KEY_RUN), _KEY_RUN))

    {

    ++RunCntr;

    }

    else

    {

    RunCntr = 0;

    if(LastRunState)            //表明键已经按下后才抬起的

    {

    LastRunState = 0;

    g_State = EmptyInflatting;

    }

    }

    if(RunCntr == _KEY_SHORT_CNTR)

    {

    BeepCntr = _BEEPER_DEVIDER;

    _BEEPER_ON;

    LastRunState = 1;       //此键是抬起时生效.

    }

    else if(RunCntr > _KEY_SHORT_CNTR)

    {

    RunCntr = _KEY_SHORT_CNTR + 1;  //禁止重复执行

    }

    DevCntr = _KEY_NORMAL_DEVIDER;

    }

    *博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

    参与讨论

    请登录...

    登录后参与讨论

    展开全文
  • (1)如果为按键按下到释放的一个过程,t1 如果大于 250ms 认为按键有效 否则 按键无效,不做处理。 (2)如果联系两个双脉冲,脉冲之间相差时间t2 < 1S 认为是 双按键 否则 判定为两次不相干的按键行为。 (3...

    【一】:按键的模型
    (1)单击按键: 按键按下到释放的一个过程,t1 如果大于 50ms.
    在这里插入图片描述
    (2)双击按键:如果两个脉冲之间相差时间t2 < 200ms 认为是 双按键
    否则 判定为两次不相干的按键行为。
    <同样可以判定连续多次按键,但是一般没什么意义>
    在这里插入图片描述
    (3)长按键:如果按下时间t3 >=500ms 判定为长按键
    在这里插入图片描述
    【二】主函数的处理
    按键的处理函数: void APP_KEY_Task(void) 。 需要每5ms 调用一次
    该函数需要判断上次状态last,以及当前的状态now。

    读取IO获取now状态
    判断last和now状态
    if last=0,now=0 则回调act0
    if last=0,now=1 则回调act1
    if last=1,now=0 则回调act2
    if last=1,now=1 则回调act3
    保存当前状态last=now

    所以主函数就显得比较简单:

    void  act0 ( KEY_StateMachine *   pStateMachine);
    void  act1 ( KEY_StateMachine *   pStateMachine);
    void  act2 ( KEY_StateMachine *   pStateMachine);
    void  act3 ( KEY_StateMachine *   pStateMachine);
    
    ActionFunType transition_table[KEY_STATES][KEY_STATES]={
    {&act3,&act0,},
    {&act2,&act1,},
    };
    
    void KEY_GPIO_DEAL(MYKEY_TYPE* mykey)
    {
    	 KEY_State  State_now= KEY_STATES_RELEASE ;
    	 if(GPIO_ReadInputDataBit(mykey->keyset.GPIOx,mykey->keyset.Pin)==KEY_PUSH)State_now= KEY_STATES_PUSH;     //读取当前按键状态
    	
       (*transition_table[mykey->Machine.State_last][State_now] )( (KEY_StateMachine *) (&(mykey->Machine))  );  //根据状态 *FUNC【last】【now】 执行对应的处理函数
    	
    	  mykey->Machine.State_last=State_now;  //保存当前的按键状态
    }
    

    这个函数数值中依次对应关系为:
    在这里插入图片描述
    其中act0: 表示 从释放状态到按下,为按下按键的瞬间
    其中act1: 表示 从按下状态到按下,为保持按下的状态
    其中act2: 表示 从按下状态到释放,为释放按键的瞬间
    其中act3: 表示 从释放状态到释放,为保持释放的状态

    在这一步中我们不需要关系act0–3回调函数执行了什么,我们关系的是当前状态和上一个状态是否按下,然后执行哪种回调处理即可!

    【三】按键的判断的处理。
    定义一个结构体:

    typedef struct
    {
      KEY_State         State_last;       //记录当前的时间
      uint32_t          usTime;        //记录按下的时间
      uint32_t          usTS;          //记录释放的时间
      uint32_t          usKeyDtcNum;	 //记录脉冲数
      KeyDeal           NO_PRO_Deal;
      KeyDeal           SHOURT_Deal;
      KeyDeal           LONG_Deal;
      KeyDeal           DOUBLE_Deal;
    }KEY_StateMachine,*KEY_pStateMachine;
    

    依次保存上一次调用时候的状态:State_last,
    按下保持时间的计时:usTime
    释放保持时间的计时:usTS
    满足连续单击按钮的次数:usKeyDtcNum

    执行:act0: usTime=0

    执行:act1: usTime++
    if(usTime== 500ms)

    usKeyDtcNum=0; //清空连续单击按钮的次数
    LONG_Deal(); //回调长按键处理
    } //

    在长按键处理上 如果==500s 那么一直按只会调用一次(不考虑溢出)如果加上判断可以实现长按快速增加数值的,例如:像SMC表头长按按键快速增减,随着长按的时间的增加,数值增加的速度也会加快。

    执行:act2: usTS=0
    if( 50ms < usTime< 200ms)
    {
    usKeyDtcNum++; //连续单击按钮的次数增加
    }

    执行:act3:
    if(usTS<200ms)usTS++
    else{
    if( usKeyDtcNum == 1)SHOURT_Deal)(); //短按键处理
    if(usKeyDtcNum >= 2) DOUBLE_Deal)(); //双击按键处理
    usKeyDtcNum=0; usTS=0; //清空标志
    }

    这里可以判断单击,双击,甚至连续三击。。(双击之上的判断没什么意义)

    附:

    #include "bsp/key/bsp_key.h"
    
    
    
     MYKEY_TYPE  MYKEY1 = {
     	{RCC_APB2Periph_GPIOB,GPIOB,GPIO_Pin_4},
    	{0,0,0,0,0,0,0,0, },
     };
     
      MYKEY_TYPE  MYKEY2 = {
     	{RCC_APB2Periph_GPIOB,GPIOB,GPIO_Pin_3},
    	{0,0,0,0,0,0,0,0, },
     };
    
    
    void  act0 ( KEY_StateMachine *   pStateMachine);
    void  act1 ( KEY_StateMachine *   pStateMachine);
    void  act2 ( KEY_StateMachine *   pStateMachine);
    void  act3 ( KEY_StateMachine *   pStateMachine);
    
    
    ActionFunType transition_table[KEY_STATES][KEY_STATES]={
    {&act3,&act0,},
    {&act2,&act1,},
    };
    
    
    
    
     
     void KEY_GPIO_Init( MYKEY_TYPE* mykey )
    {
      GPIO_InitTypeDef GPIO_InitStructure;
      RCC_APB2PeriphClockCmd(mykey->keyset.RCC_AHB1Periph, ENABLE);	
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   
      GPIO_InitStructure.GPIO_Pin = mykey->keyset.Pin;  
      GPIO_Init(mykey->GPIOx, &GPIO_InitStructure);
      mykey->Machine.State_last=0;
      mykey->Machine.usKeyDtcNum=0;
      mykey->Machine.usTime=0;
      mykey->Machine.usTS=0;
    }
    
    
    
    void KEY_GPIO_DEAL(MYKEY_TYPE* mykey)
    {
    	 KEY_State  State_now= KEY_STATES_RELEASE ;
    	 if(GPIO_ReadInputDataBit(mykey->keyset.GPIOx,mykey->keyset.Pin)==KEY_PUSH)State_now= KEY_STATES_PUSH;     //读取当前按键状态
    	
       (*transition_table[mykey->Machine.State_last][State_now] )( (KEY_StateMachine *) (&(mykey->Machine))  );  //根据状态 *FUNC【last】【now】 执行对应的处理函数
    	
    	  mykey->Machine.State_last=State_now;  //保存当前的按键状态
    }
    
    
    
    //释放状态被按下
    void  act0 ( KEY_StateMachine *  pStateMachine)
    {
       pStateMachine->usTime=0;
    }
    //按下状态
    void  act1 ( KEY_StateMachine *   pStateMachine)
    {
    	 uint32_t number=0;
       pStateMachine->usTime++;
    	 if( pStateMachine->usTime ==  KEY_PUSH_0500MS  )
    	 {
    		pStateMachine->usKeyDtcNum=0;
    	  (*pStateMachine->LONG_Deal)(); //长按键处理
    	 }		 
    }
    //按下状态被释放
    void  act2 ( KEY_StateMachine *   pStateMachine)
    {
       pStateMachine->usTS=0;
    	 if ( ( pStateMachine->usTime >KEY_PUSH_0050MS) && ( pStateMachine->usTime <KEY_PUSH_0200MS) )
    	 {
    	   pStateMachine->usKeyDtcNum++;
    	 }
    }
    //释放状态
    void  act3 ( KEY_StateMachine *   pStateMachine)
    {
    	 if( pStateMachine->usTS < KEY_PUSH_0200MS )
    	 {
    	     pStateMachine->usTS++;
    	 }else
    	 {
    	   if(pStateMachine->usKeyDtcNum == 1)
    		 {
    		   (*pStateMachine->SHOURT_Deal)(); //短按键处理
    		 } 
    		 if(pStateMachine->usKeyDtcNum >= 2)
    		 {
    		    (*pStateMachine->DOUBLE_Deal)(); //双击按键处理
    		 }
         pStateMachine->usKeyDtcNum=0;
    		 pStateMachine->usTS=0;		 
    		 
    	 }
    }
    /*********************END OF FILE*********************/
    
    #ifndef __BSP_KEY_H__
    #define __BSP_KEY_H__
    
    /* 包含头文件 ----------------------------------------------------------------*/
    #include <stm32f10x.h>
    
    /* 类型定义 --------------------------------------------------------------*/
    typedef enum
    {
      KEY_UP   = 0,
      KEY_DOWN = 1,
    }KEYState_TypeDef;
    
    #define KEY_PUSH               0
    #define KEY_PUSH_0050MS        10    //定义按键判断时间  10X5ms= 50MS
    #define KEY_PUSH_0200MS        40    //定义按键判断时间   40X5ms=200MS
    #define KEY_PUSH_0500MS        100   //定义按键判断时间   100X5ms=500MS
    
    
    typedef int KEY_State;
    typedef int KEY_Condition;
    
    //状态
    #define KEY_STATES            2
    #define KEY_STATES_RELEASE    0
    #define KEY_STATES_PUSH       1
    
    
    
    typedef void  (*KeyDeal)( void);
    
    typedef struct
    {
      KEY_State         State_last;       //记录当前的状态
    	uint32_t          usTime;        //记录按下的时间
      uint32_t          usTS;          //记录释放的时间
      uint32_t          usKeyDtcNum;	 //记录脉冲数
    	KeyDeal           NO_PRO_Deal;
    	KeyDeal           SHOURT_Deal;
    	KeyDeal           LONG_Deal;
    	KeyDeal           DOUBLE_Deal;
    	
    }KEY_StateMachine,*KEY_pStateMachine;
     
    typedef void  (*ActionFunType)( KEY_pStateMachine  pStateMachine);
    typedef struct
    {
    	uint32_t   RCC_AHB1Periph;
    	GPIO_TypeDef*   GPIOx;
    	uint16_t        Pin;
    }MYKEY_SET_TYPE;
    typedef struct
    {
    	MYKEY_SET_TYPE    keyset;
    	KEY_StateMachine  Machine;
    }MYKEY_TYPE;
    
    
    
    
    //PB3 PB6 PB8
    /* 宏定义 --------------------------------------------------------------------*/
    #define KEY1_RCC_CLOCKGPIO            RCC_APB2Periph_GPIOB
    #define KEY1_GPIO_PIN                 GPIO_Pin_3
    #define KEY1_GPIO                     GPIOB
    #define KEY1_DOWN_LEVEL               0  /* 根据原理图设计,KEY1按下时引脚为低电平,所以这里设置为0 */
    
    #define KEY2_RCC_CLOCKGPIO            RCC_APB2Periph_GPIOB
    #define KEY2_GPIO_PIN                 GPIO_Pin_6
    #define KEY2_GPIO                     GPIOB
    #define KEY2_DOWN_LEVEL               0  /* 根据原理图设计,KEY1按下时引脚为低电平,所以这里设置为0 */
    
    extern  MYKEY_TYPE  MYKEY1;
    extern  MYKEY_TYPE  MYKEY2;
    void KEY_GPIO_Init( MYKEY_TYPE* mykey );
    void KEY_GPIO_DEAL(MYKEY_TYPE* mykey);
    
    
    
    #endif  // __BSP_KEY_H__
    
    /*****END OF FILE****/
    
    

    调用:如果使用的不是操作系统的话,可以让主函数每5ms调用一次即可。本函数的回调函数尽量不要搞成阻塞的。如果使用操作系统,阻塞一些也没啥毛病。。。

    void led0_task(void *pvParameters)
    {  
    	  MYKEY1.Machine.NO_PRO_Deal=callback10;
    	  MYKEY1.Machine.SHOURT_Deal=callback11;
    	  MYKEY1.Machine.DOUBLE_Deal=callback12;
    	  MYKEY1.Machine.LONG_Deal  =callback13;
    	  KEY_GPIO_Init( &MYKEY1 );	
    	  MYKEY2.Machine.NO_PRO_Deal=callback20;
    	  MYKEY2.Machine.SHOURT_Deal=callback21;
    	  MYKEY2.Machine.DOUBLE_Deal=callback22;
    	  MYKEY2.Machine.LONG_Deal  =callback23;
    	  KEY_GPIO_Init( &MYKEY2 );	
        while(1)
        {	 
    		   KEY_GPIO_DEAL(&MYKEY1);
    		   KEY_GPIO_DEAL(&MYKEY2);
                vTaskDelay(5);
        }
    }  
    
    展开全文
  • if(state_1 == S_key) //双击 { /*双击按键实现呼吸灯功能*/ state_1 = 0; b_key_led = 1; b_key_smg = 0; seg = 0x00; seg_l = 0x00; } if(state_1 == D_key) //单按 { /*单击实现数码管走时*/ state_1 = 0; b_...
  • 原理:将按键这一事件的过程划分成如下几个状态://stata 函数运行状态//0: 初始状态//1: 第一洗按键按下//2: 第一次长按抬起//3: 第一次短按抬起//4: 第二次按键按下//5: 第二次按键抬起利用定时器记录系统...
  • STATE_KIDEL:如果有按键,查表,看是第几个按键。(排除8个IO口中,你不用做按键的那些IO。另外也是keyport中是从0开始的,而记在temp中是从0开始的)。Key_ThisValue=temp+1; 当前键值KeyState=STATTE_KDOWN; 按键...
  • 一个按键扫描的程序很经典,有单击 双击 还有长按 都可以自己设置时间参数,而且双击的时候不会出发单击,里面的算法思想很经典,我经常使用可以拿来学习一下··
  • no 0#define key_click1#define key_double2#define key_long3#define key_inputP30/***************************************************************************程序功能:一个按键的单击、双击、长按。...
  • 利用定时器,外部中断,串口,GPIO完成的一个stm32小项目。
  • button drive杰杰自己写的一个按键驱动,支持单双击、连按、长按;采用回调处理按键事件(自定义消抖时间),使用只需3步,创建按键按键事件与回调处理函数链接映射,周期检查按键。前言前几天写了个按键驱动,参考...
  • 不影响使用.// 如有朋友发现问题所在请联系我./*********************************************************/#include #define KEY_IO P1 //按键所连的IO口#define NO_KEY_VALUE 0xf //当按键没有被按下时IO口的值#...
  • #include "keyboard.h"/***************************************************************************程序功能:一个按键的单击、双击、长按。三种按键方式,然后做不同的处理。这里以P1口的LED变化作为测试单击:...
  • c语言如何实现组合键

    2021-05-20 04:15:41
    单击开始,单击 控制面板,然后双击“区域和语言选项”。2. 在语言选项卡上的“文字服务和输入语言”下,单击详细信息。3. 在首选项下,单击语言栏。4,选择“关闭高级文字服务”复选框,,把里面的钩去掉.三.其次设置...
  • 按键】[独立按键] - 2:双击

    千次阅读 多人点赞 2016-03-29 10:28:55
    1)在预设的时间间隔内完成第二次【单击】,按键释放后,响应返回有效键值【双击】。 2)如果第二次按下键并一直按住,当按住的时间超过设定的时间间隔(300ms)后,会响应第一个【单击】,并返回有效键值【单击】...
  • #include #include"intrins.h"sbit key=P3^5;sbit LED=P3^4;unsigned char L,value,time,num;bit S,flag;voiddelay_ms(unsigned char z){unsigned int x,y;for(x=z; x>0; x--)for(y=848; y>...
  • 上一篇文章记录了TM1638驱动的显示模块的显示功能C语言程序,详见TM1638显示板(8数码管+8LED+8按键)驱动程序(显示功能),本文分享按键的驱动,以及按键的去抖动等操作。 模块如下图: 笔者采用的MCU是STM32F103...
  • 在xp系统中,很多使用VC++6.0编译C程序的用户们都经常会遇到C语言程序闪退的问题,在编译器中调试运行的时候一切正常,可将DEBUG中生成的EXE文件拿出来双击运行却发现程序运行完后就闪退了。怎么办?今天小编介绍系统...
  • 前言正好工作中用到按键处理,需要处理单击、长按等按键事件,然后就造了这么一个轮子,为了以后更方便地加入其它的项目中使用,遂将其开源到 GitHub 中。后面发现 RT-Thread 软件包里也有一个开源的按键库 ...
  • C语言编写的单片机流水灯程序的软件和硬件,可以让八个LED轮流点亮,每个灯点亮和熄灭时间均为1秒。是利用单片机I/O口控制外部设备的简单例子。当然,在你掌握了本程序后,完全可以充分发挥你的想象,改变一下程序...
  • 在嵌入式系统尤其是单片机系统中经常用到按键检测和处理,这里提供一个标准的驱动函数模块MultiButton,能够提供按下、弹起、单击、双击、连击、长按等按键事件。 MultiButton 是一个小巧简单易用的事件驱动型按键...
  • 当我们写完这个程序 编译完成后单击左上角的叹号运行 可以看到一切正常 按下任意按键后窗口才会消失。很容易就能搞定了,下面就给大家讲解一下C语言程序闪退的快速处理方法:1、我们以最经典的HELLOWOR...
  • C语言程序设计上机指导书及答案》由会员分享,可在线阅读,更多相关《C语言程序设计上机指导书及答案(36页珍藏版)》请在人人文库网上搜索。1、姓 名:学 号:专 业:日 期:指导原则:促进学生针对实际问题,用所...
  • 第九节:独立按键的双击按键触发。开场白:上一节讲了在定时中断函数里处理独立按键的扫描程序,这种结构的程序我用在了很多项目上。这一节教大家如何实现按键双击触发的功能,这种功能类似鼠标的双击。要教会大家一...
  • /*发送和接收程序:即主机和从机可共用此程序程序效果:通过主机发送,从机接收在主机中通过记下按键按下的次数,主机中显示最后按下的六个数值,并发送给从机,从机也显示这六个数值单片机类型:stc89c52完整程序...
  • 基于51单片机的独立按键单击、双击,长按,多次按的项目工程一、前言1、基于51单片机的独立按键单击、双击,长按,多次按的项目工程包括用Keil软件编写单片机C语言程序和用Proteus软件仿真单片机外围电路2、基于51...
  • 编了个C语言的键盘程序有点问题,请指点下![复制链接]做了个机械手,想用键盘来控制抓,放物品,现在他显示字符时有点错,高手能帮我在keil里跑下,把我的这个错改下吗?谢谢了!原程序如下:(P2.0--P2.7 是段选,P1.0--P1.5是...
  • C语言的基本框架的第1章 C语言的基本框架 上机指导本节将提供4个实验的指导,通过本节内容的学习和实践,读者可以更好地了解C语言程序,并熟悉Turbo C 2.0集成环境。【实验1.1】 设计简单菜单界面。1.实验题目...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,843
精华内容 737
关键字:

双击按键程序c语言

友情链接: simpleModel_SOC_UKF.rar