GPIO按键的长按、短按、连发——C程序

不借助GPIO中断,采用轮询的方式,实现按键的长按、短按、连发

 

参考:https://blog.csdn.net/qq_31151689/article/details/85228441

百度快照:http://cache.baiducontent.com/c?m=9d78d513d99603f405fa950e1a66d571695297134dc0a46468d5e35fe3654c324171e2cb30521213a3c36b6671b83958fd814765367337c799dff84ccabae27938895723061d913666c46facdc3023d567d004e6f55fa1f8b12592ddcfce8f0a0e9f44050dd1b1dd061714bd33a7522ca0e58e4f615e13b9ea3361f5526a7adf651be719aefd643941d2ad831d51c92dd0611b91a936&p=85769a479d8211a05bed9362544f97&newp=90759a46d6c416e04ea4f82d02148f231610db2151d7d31f6b82c825d7331b001c3bbfb423261403d7cf7d6604af4f5beef7307237012ba3dda5c91d9fb4c57479df68223970&user=baidu&fm=sc&query=gpio%B0%B4%BC%FC%B3%A4%B0%B4%B6%CC%B0%B4C%D3%EF%D1%D4&qid=a2d95b6400011865&p1=8

 

#include <stdio.h>
#include <time.h>

// 定义长按键的TICK数, 以及连发间隔的TICK数, 单位是毫秒ms
#define KEY_DEBOUNCE_PERIOD     20   // 延时消抖时间
#define KEY_LONG_PERIOD         1000
#define KEY_CONTINUE_PERIOD     200

#define TRUE    1
#define FALSE   0

typedef unsigned int Bool;

typedef enum {
    LOW = 0,
    HIGH
} KEY_LEVEL_E;

typedef enum
{
    KEY1 = 0,
    KEY2,
    KEY3,
    KEY4,
    KEY_MAX_NUM
} KEY_NUM_E;

// 定义按键返回值状态(按下,长按,连发,释放,无动作)
typedef enum {
    KEY_NULL = 0,
    KEY_DOWN,
    KEY_LONG,
    KEY_CONTINUE,
    KEY_UP
} KEY_VALUE_E;

typedef enum {
    KEY_STATE_INIT = 0,
    KEY_STATE_WOBBLE,
    KEY_STATE_PRESS,
    KEY_STATE_LONG,
    KEY_STATE_CONTINUE,
    KEY_STATE_RELEASE
} KEY_STATE_E;

typedef struct
{
    KEY_NUM_E eKeyId;
    KEY_LEVEL_E eKeyLevel;         //key level(low or high)
    unsigned int downTick;
    unsigned int upTick;
    KEY_STATE_E eKeyCurState;      //key cur state(fsm)
    KEY_STATE_E eKeyLastState;     //key last state(fsm)
    Bool bStateChangedFlag;        //state changed flag
    KEY_VALUE_E eLastKeyValue;     //key value
} KEY_HANDLE_T;

typedef void (*pf)(void);

typedef struct
{
    pf keyDownAction;
    pf keyLongAction;
    pf keyContinueAction;
    pf keyUpAction;
} KEY_FUNCTION_T;

KEY_HANDLE_T keyList[KEY_MAX_NUM] =
{
    {KEY1, LOW, 0, 0, KEY_STATE_INIT, KEY_STATE_INIT, FALSE, KEY_NULL},
    {KEY2, LOW, 0, 0, KEY_STATE_INIT, KEY_STATE_INIT, FALSE, KEY_NULL},
    {KEY3, LOW, 0, 0, KEY_STATE_INIT, KEY_STATE_INIT, FALSE, KEY_NULL},
    {KEY4, LOW, 0, 0, KEY_STATE_INIT, KEY_STATE_INIT, FALSE, KEY_NULL}
};


// 用于获取当前时间, 单位是毫秒ms
unsigned int getTime0(void)
{
    struct timespec time;

    clock_gettime(CLOCK_MONOTONIC, &time);

    return ((time.tv_sec * 1000) + (time.tv_nsec/1000000));
}

unsigned int timeDiffFromNow(unsigned int time0)
{
    unsigned int cur = 0;
    struct timespec time;

    clock_gettime(CLOCK_MONOTONIC, &time);

    cur = (time.tv_sec * 1000) + (time.tv_nsec/1000000);

    return cur - time0;
}

void keyScan(KEY_HANDLE_T* key)
{
    // gpioReadPin()需根据你的平台来写
    if(HIGH == gpioReadPin(key->eKeyId))
    {
        // 根据原理图, HIGH代表松开
        key->eKeyLevel = HIGH;
    }
    else
    {
        // 根据原理图, LOW代表按下
        key->eKeyLevel = LOW;
    }

    // 获取当前key是按下还是松开
    KEY_LEVEL_E level = key->eKeyLevel;

    key->eLastKeyValue = KEY_NULL;

    switch(key->eKeyCurState)
    {
        case KEY_STATE_INIT:
            if(LOW == level)
            {
                key->downTick = getTime0();

                key->bStateChangedFlag = TRUE;
                key->eKeyCurState = KEY_STATE_WOBBLE;
            }
            break;

        case KEY_STATE_WOBBLE:
            if(LOW == level)
            {
                if(timeDiffFromNow(key->downTick) >= KEY_DEBOUNCE_PERIOD)
                {
                    key->bStateChangedFlag = TRUE;
                    key->eKeyCurState = KEY_STATE_PRESS;
                }
            }
            else
            {
                key->bStateChangedFlag = TRUE;
                key->eKeyCurState = KEY_STATE_INIT;
            }
            break;

        case KEY_STATE_PRESS:
            if(TRUE == key->bStateChangedFlag)
            {
                key->bStateChangedFlag = FALSE;
                key->eLastKeyValue = KEY_DOWN;
            }

            if(LOW == level)
            {
                if(timeDiffFromNow(key->downTick) >= KEY_LONG_PERIOD)
                {
                    key->bStateChangedFlag = TRUE;
                    key->eKeyCurState = KEY_STATE_LONG;
                }
            }
            else
            {
                key->upTick = getTime0();

                key->bStateChangedFlag = TRUE;
                key->eKeyCurState = KEY_STATE_RELEASE;
            }
            break;

        case KEY_STATE_LONG:
            if(TRUE == key->bStateChangedFlag)
            {
                key->bStateChangedFlag = FALSE;
                key->eLastKeyValue = KEY_LONG;
            }

            if(LOW == level)
            {
                if(timeDiffFromNow(key->downTick) >= (KEY_LONG_PERIOD + KEY_CONTINUE_PERIOD))
                {
                    key->downTick = getTime0();

                    key->bStateChangedFlag = TRUE;
                    key->eKeyCurState = KEY_STATE_CONTINUE;
                }
            }
            else
            {
                key->upTick = getTime0();

                key->bStateChangedFlag = TRUE;
                key->eKeyCurState = KEY_STATE_RELEASE;
            }
            break;

        case KEY_STATE_CONTINUE:
            if(TRUE == key->bStateChangedFlag)
            {
                key->bStateChangedFlag = FALSE;
                key->eLastKeyValue = KEY_CONTINUE;
            }

            if(LOW == level)
            {
                if(timeDiffFromNow(key->downTick) >= KEY_CONTINUE_PERIOD)
                {
                    key->downTick = getTime0();

                    key->bStateChangedFlag = TRUE;
                    key->eKeyCurState = KEY_STATE_CONTINUE;
                }
            }
            else
            {
                key->upTick = getTime0();

                key->bStateChangedFlag = TRUE;
                key->eKeyCurState = KEY_STATE_RELEASE;
            }
            break;

        case KEY_STATE_RELEASE:
            if(timeDiffFromNow(key->upTick) >= KEY_DEBOUNCE_PERIOD) // 松开按键也来个消抖
            {
                if(TRUE == key->bStateChangedFlag)
                {
                    key->bStateChangedFlag = FALSE;
                    key->eLastKeyValue = KEY_UP;
                }

                key->bStateChangedFlag = TRUE;
                key->eKeyCurState = KEY_STATE_INIT;
            }
            else
            {
                if(LOW == level)
                {
                    key->eKeyCurState = key->eKeyLastState;
                }
            }
            break;

        default:
            break;
    }

    key->eKeyLastState = key->eKeyCurState;
}

void key1DownAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key1LongAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key1ContinueAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key1UpAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key2DownAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key2LongAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key2ContinueAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key2UpAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key3DownAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key3LongAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key3ContinueAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key3UpAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key4DownAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key4LongAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key4ContinueAction(void)
{
    printf("%s\n", __FUNCTION__);
}

void key4UpAction(void)
{
    printf("%s\n", __FUNCTION__);
}

KEY_FUNCTION_T keyMapList[KEY_MAX_NUM] =
{
    {key1DownAction, key1LongAction, key1ContinueAction, key1UpAction}, //KEY1
    {key2DownAction, key2LongAction, key2ContinueAction, key2UpAction}, //KEY2
    {key3DownAction, key3LongAction, key3ContinueAction, key3UpAction}, //KEY3
    {key4DownAction, key4LongAction, key4ContinueAction, key4UpAction}, //KEY4
};

void keyMapHandle(KEY_HANDLE_T *key, KEY_FUNCTION_T *keyMap)
{
    unsigned char keyValue = key->eLastKeyValue;

    if(KEY_NULL == keyValue)
    {
        return;
    }
    else
    {
        switch(keyValue)
        {
            case KEY_DOWN:
                if(keyMap->keyDownAction != NULL)
                {
                    keyMap->keyDownAction();
                }
                break;

            case KEY_LONG:
                if(keyMap->keyLongAction != NULL)
                {
                    keyMap->keyLongAction();
                }
                break;

            case KEY_CONTINUE:
                if(keyMap->keyContinueAction != NULL)
                {
                    keyMap->keyContinueAction();
                }
                break;

            case KEY_UP:
                if(keyMap->keyUpAction != NULL)
                {
                    keyMap->keyUpAction();
                }
                break;

            default:
                break;
        }
    }
}

int main(void)
{
    KEY_NUM_E keyId = KEY_MAX_NUM;

    while(1)
    {
        for(keyId=KEY1; keyId<KEY_MAX_NUM; keyId++)
        {
            keyScan(&keyList[keyId]);
        }

        for(keyId=KEY1; keyId<KEY_MAX_NUM; keyId++)
        {
            keyMapHandle(&keyList[keyId], &keyMapList[keyId]);
        }

        usleep(10*1000);
    }

    return 0;
}

 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Arduino和STM32都是常用的单片机开发板,用于各种电子项目和嵌入式系统的开发。下面我将用300字介绍如何使用这两种开发板编写按键按和短按程序。 对于Arduino开发板,可以使用内置的库函数来实现按键按和短按的功能。首先,需要通过数字IO口连接一个机械按键并设置为输入模式。然后,在程序中设置一个计时器,用来检测按键的按下时间。通过判断按键按下的持续时间来确定是按还是短按。 以下是Arduino的示例代码: ```Arduino const int buttonPin = 2; // 连接按键的数字IO口 int buttonState = 0; // 按键状态 unsigned long buttonTimer = 0; // 按键计时器 bool isLongPress = false; // 是否按 void setup() { pinMode(buttonPin, INPUT); Serial.begin(9600); } void loop() { buttonState = digitalRead(buttonPin); if (buttonState == HIGH) { if (buttonTimer == 0) { buttonTimer = millis(); // 记录按下的起始时间 } } else { if (buttonTimer != 0) { if (millis() - buttonTimer > 1000) { isLongPress = true; } else { isLongPress = false; } buttonTimer = 0; // 清空计时器 } } if (isLongPress) { Serial.println("Button long press"); } else { Serial.println("Button short press"); } delay(100); // 延时100毫秒 } ``` 对于STM32开发板,可以使用CubeMX和HAL库来实现按键按和短按的功能。首先,在CubeMX中配置按键对应的GPIO口,并设置为输入模式。然后,在程序中使用HAL库提供的函数来检测按键的状态和按下时间。通过判断按键按下的持续时间来确定是按还是短按。 以下是STM32的示例代码: ```C #include "main.h" #include "stdio.h" #include "stm32f1xx_hal.h" GPIO_TypeDef* BUTTON_GPIO_Port = GPIOA; uint16_t BUTTON_Pin = GPIO_PIN_0; uint32_t buttonTimer = 0; _Bool isLongPress = 0; void SystemClock_Config(void); static void MX_GPIO_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); while (1) { if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_SET) { if (buttonTimer == 0) { buttonTimer = HAL_GetTick(); } } else { if (buttonTimer != 0) { if (HAL_GetTick() - buttonTimer > 1000) { isLongPress = 1; } else { isLongPress = 0; } buttonTimer = 0; } } if (isLongPress) { printf("Button long press\n"); } else { printf("Button short press\n"); } HAL_Delay(100); } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /**Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /**Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_AFIO_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` 以上就是使用Arduino和STM32开发板编写按键按和短按程序的方法。你可以根据自己的需求进行修改和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值