GPIO-KEY的实现原理及使用方法

本文将以imx6q的板子和相应BSP代码来详细描述在linux下, 使用GPIO当做按键的实现原理及使用方法。

Linux 内核下的 drivers/input/keyboard/gpio_keys.c实现了一个体系结构无关的GPIO按键驱动,使用此按键驱动,只需在相应的板级支持包中(imx6q的是board-mx6q-sabresd.c)定义相关的数据即可。驱动的实现非常简单,但是较适合于实现独立式按键驱动。

gpio-keys是基于input架构实现的一个通用GPIO按键驱动。该驱动基于platform_driver架构,实现了驱动和设备分离,符合Linux设备驱动模型的思想。工程中的按键驱动我们一般都会基于gpio-keys来写,所以我们有必要对gpio_keys进行分析。

一.   GPIO-KEY的实现原理

1.      定义GPIO按键:

首先定义一个gpio_keys_button的数组, 该类型定义了一个具体的GPIO按键信息

arch\arm\mach-mx6\board-mx6q-sabresd.c:

static struct gpio_keys_buttonsabresd_buttons[] = {

GPIO_BUTTON(SABRESD_VOLUME_UP,KEY_VOLUMEUP, 1, "volume-up", 0, 1),

GPIO_BUTTON(SABRESD_VOLUME_DN,KEY_POWER, 1, "volume-down", 1, 1),

 

/*addby aaron 2015.6.29*/

#ifdef FEATURE_YUTONG_ICARD2

GPIO_BUTTON(SABRESD_KEY_MENU,248, 1, "menu-key", 0, 3),

GPIO_BUTTON(SABRESD_KEY_UP,249, 1, "up-key", 0, 3),

GPIO_BUTTON(SABRESD_KEY_DOWN,250, 1, "down-key", 0, 3),

GPIO_BUTTON(SABRESD_KEY_CONFIRM,251, 1, "confirm-key", 0, 3),

GPIO_BUTTON(SABRESD_KEY_ICCARD_DET,247, 1, "iccard-det", 0, 3),

#endif

/*endby aaron*/

};

 

struct gpio_keys_button类型如下, 这是对按键的描述:

include\linux\gpio_keys.h:

struct gpio_keys_button {

/*Configuration parameters */

unsignedint code;   /* input event code (KEY_*,SW_*) */

intgpio;

intactive_low;

constchar *desc;

unsignedint type;    /* input event type (EV_KEY,EV_SW, EV_ABS) */

int wakeup;               /* configure the button as awake-up source */

intdebounce_interval;    /* debounce ticksinterval in msecs */

boolcan_disable;

intvalue;           /* axis value for EV_ABS*/

};

 

宏 GPIO_BUTTON()就是初始化每个gpio_key的描述:

arch\arm\mach-mx6\board-mx6q-sabresd.c:

#define GPIO_BUTTON(gpio_num, ev_code,act_low, descr, wake, debounce)      \

{                                                                           \

.gpio                   = gpio_num,                                 \

.type                  = EV_KEY,                            \

.code                  = ev_code,                                    \

.active_low      = act_low,                                     \

.desc                  = "btn " descr,                             \

.wakeup            = wake,                                         \

.debounce_interval= debounce,                                 \

}

 

接着定义一个gpio_keys_platform_data变量:

arch\arm\mach-mx6\board-mx6q-sabresd.c:

staticstruct gpio_keys_platform_data new_sabresd_button_data = {

         .buttons   = new_sabresd_buttons,

         .nbuttons = ARRAY_SIZE(new_sabresd_buttons),

};

 

struct gpio_keys_platform_data的定义也在gpio_keys.h中:

include\linux\gpio_keys.h:

structgpio_keys_platform_data {

         struct gpio_keys_button *buttons;

         int nbuttons;

         unsigned int poll_interval;       /* polling interval in msecs -

                                                  for polling driver only */

         unsigned int rep:1;           /* enable input subsystem auto repeat*/

         int (*enable)(struct device *dev);

         void (*disable)(struct device *dev);

         const char *name;            /* input device name */

};

 

2.      把 1 中定义的new_sabresd_button_data 注册到系统中去:

我们把gpio_key当成一个platform_device设备, 所以要先定义一个platform_device设备:

arch\arm\mach-mx6\board-mx6q-sabresd.c:

staticstruct platform_device sabresd_button_device = {

         .name                ="gpio-keys", /*名字非常关键, 找驱动就靠它来匹配了*/

         .id              =-1,

         .num_resources  = 0,

};

 

然后把我们定义的gpio_key 跟这个platform_device设备绑定在一起:

arch\arm\mach-mx6\board-mx6q-sabresd.c:

platform_device_add_data(&sabresd_button_device,

                    &new_sabresd_button_data,

                             sizeof(new_sabresd_button_data));

 

最后注册到系统中去:

arch\arm\mach-mx6\board-mx6q-sabresd.c:

platform_device_register(&sabresd_button_device);

 

其中, platform_device_add_data()函数如下:

drivers/base/platform.c:

intplatform_device_add_data(struct platform_device *pdev, const void *data,

                                 size_t size)

{

         void *d = NULL;

 

         if (data) {

                   d = kmemdup(data, size,GFP_KERNEL); /*分配memory,并把data的内容拷贝进去*/

                   if (!d)

                            return -ENOMEM;

         }

 

         kfree(pdev->dev.platform_data);

         pdev->dev.platform_data = d;  /*把gpio_key绑定到这个platform_device上去*/

         return 0;

}

 

3.      匹配驱动:

当用platform_device_register()把 gpio_key的platform_device的添加到系统中去后, 系统会去匹配是否有合适的驱动, 这里对应的驱动就是:gpio_keys.c, 很显然这是一个platform_driver的驱动:

drivers/input/keyboard/gpio_keys.c:

static struct platform_drivergpio_keys_device_driver = {

.probe                = gpio_keys_probe,

.remove            = __devexit_p(gpio_keys_remove),

.driver                = {

           .name       = "gpio-keys",   /*发现没有, 名字跟设备的名字一模一样*/

           .owner     = THIS_MODULE,

#ifdef CONFIG_PM

           .pm  = &gpio_keys_pm_ops,

#endif

}

};

系统能找到这个驱动, 主要就是因为他们的名字都是: gpio-keys, 这个很关键。 接下来我们就来分析一下这个驱动, 首先找到设备后, 会调用probe函数, 这里就是gpio_keys_probe();

在gpio_keys_probe()函数中, 会注册一个input设备, 并创建相应的设备文件。

 

二. GPIO_KEY使用

使用方式比较简单,和普通的文件操作一样, 先打开设备文件, 再读文件获取键值即可:

1.      打开设备文件,

我的设备上gpio_key对应的设备文件是/dev/input/event0, 不同的平台设备文件可能会有差异, 如果不清楚对应的设备文件, 可以用下面的命令来查看:

 

打开设备代码如下:

/*1.key device*/

fd_key= open(KEY_DEVICE_FILE, O_RDONLY);

if(fd_key< 0) {

           LOGE("can'topen key device file");

           returnfd_key;

}

 

2.      获取按键值及按键类型:

 

         struct input_event key_evt;

 

monitor_key:

         ret = read(fd_key, (unsigned char*)&key_evt, sizeof(struct input_event)); /*阻塞型读函数*/

         if(ret < 0) {

                   LOGE("read key eventfailed :%d", ret);

         }

         /*filter unknown key*/

         else if(key_evt.code != 248&&     /*KEY_MENU*/ 

                             key_evt.code != 249 &&    /*KEY_UP*/

                             key_evt.code != 250 &&    /*KEY_DOWN*/

                             key_evt.code != 251 &&    /*KEY_CONFIRM*/

                             key_evt.code != 247){     /*ICCARD detect pin*/

                   LOGE("unknown key code:%d", key_evt.code);

                   goto monitor_key;

         }

         else {  /*valid key*/

           /*

            * key_val[0..7] = key code

            * key_val[8] = key value: 0 - released, 1 - pressed.

            */

                   key_val = ((int8_t)key_evt.value<< 8) | ((uint8_t)key_evt.code);

                   //LOGE("get key eventcode:%d, value:%d, type:%d, %d", key_evt.code, key_evt.value,key_evt.type, key_val);

         }

 

         return key_val;

 

实际上就是调用一个阻塞型的读函数, 所以这个函数尽量放在单独的一个线程中处理, 键值就是在前面板级支持包中定义并注册的值。

 

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: GPIO Key是一种通过GPIO(General Purpose Input/Output)接口连接的物理按键,它用于输入设备上的用户操作,如按键开关或按钮。在很多电子设备中,GPIO Key通常用作一种快速和简单的方式来控制设备的各种功能。 ### 回答2: GPIO是General Purpose Input/Output的缩写,中文意为通用输入/输出口。GPIO是一种用于控制嵌入式设备的通用接口。它可以作为输入口,用于读取外部传感器、开关等设备的状态;也可以作为输出口,用于控制外部执行器、LED灯等设备的工作状态。 GPIOKey是在嵌入式设备中用于响应按键输入的一种特殊类型的GPIO口。通常,嵌入式设备的按键都通过GPIOKey与按键开关进行连接。当按键被按下时,相应的GPIO口会检测到电平的变化,并将这个变化通知给嵌入式设备的处理器或控制芯片。 通过GPIOKey,嵌入式设备可以实现按键的各种功能,如控制音频播放、调整亮度、切换界面等。在软件开发过程中,开发者通常会通过GPIO接口与GPIOKey进行交互,监听按键状态的变化,并根据按键的操作来触发相应的功能或事件。 使用GPIOKey进行按键输入的设计灵活、方便,无论是单个按键还是多个按键,都可以通过这种方式来实现。硬件设计者可以根据需要,自由选择合适的GPIOKey,并将其与按键开关进行连接,从而满足特定的按键功能需求。 ### 回答3: GPIOKey 是一种用于控制输入输出设备的接口。GPIO 是 General-Purpose Input/Output 的简称,意为通用输入/输出。它是一种通用的数字接口,可以通过软件控制来实现与外部设备的通信。 GPIOKey 通常被用于单片机、嵌入式系统、树莓派等电子设备中,用来连接和控制各种不同类型的设备,如按钮、开关、传感器等。通过 GPIOKey 可以将这些外部设备的输入或者输出与系统进行交互。 GPIOKey 的工作原理是通过在接口上设置不同的电位状态,从而控制与之相连的外部设备的行为。例如,可以将 GPIOKey 接口设置为高电平或低电平,以控制灯光的亮灭、驱动舵机的角度、读取按钮的按下事件等。 GPIOKey 具有灵活性和可编程性,可以通过编程语言或者相应的库对其进行控制。它的使用简单,只需设置相应的引脚状态即可实现与外设的通信和控制。 总之,GPIOKey 是一种通用输入/输出接口,用于控制与之相连的外部设备的行为。它在电子设备中扮演着重要的角色,可以使系统与外部设备之间的交互变得更加方便和灵活。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值