嵌入式Linux的三种按键驱动方式

1、类似传统的mcu开发方式,基于设备树,需要编写相应的驱动程序

         io初始化,中断申请注册,中断处理。mcu一般都有固定的中断处理函数,一般都有weak函数,一般只要重新改函数就行。linux方面需要按gpio号去申请irq中断号。

//设备树直接使用led口拿来做按键,图省事
mqrled {
	led-gpios = <&pio PB 4 GPIO_ACTIVE_HIGH>;
};


部分关键代码

//实际产品应用需要额外加timer配合做消抖动
static irqreturn_t btn_irq(int irq, void *dev_id)
{

	if(gpio_get_value(LED_IO))
		printk(KERN_DEBUG" release key_irq:%d\n",irq);
	else
		printk(KERN_DEBUG" press key_irq:%d\n",irq);
	return IRQ_HANDLED;
}



struct device_node* led_node;
led_node = of_find_node_by_path("/mqrled"); 
if(led_node == NULL)
{
	printk(KERN_DEBUG"no led dts!!!\n");
}
LED_IO = of_get_named_gpio(led_node, "led-gpios", 0);
printk(KERN_DEBUG"LED_IO is:%d\n",LED_IO);

//io号申请中断号
key_irq = gpio_to_irq(LED_IO);
printk(KERN_DEBUG"key_irq:%d\n",key_irq);


//注册中断
ret = request_irq(key_irq, btn_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq",NULL);
if(ret){
	printk("request irq failed!\n");
	return -1;
}



//测试

[  233.129895]  release key_irq:67
[  237.762791]  press key_irq:67
[  237.773132]  release key_irq:67
[  237.787830]  press key_irq:67
[  237.812533]  release key_irq:67
[  237.816057]  press key_irq:67
[  237.880647]  release key_irq:67
[  237.905658]  press key_irq:67
[  238.049449]  release key_irq:67
[  238.052980]  press key_irq:67
[  238.056313]  release key_irq:67
[  238.059838]  release key_irq:67
[  238.063358]  press key_irq:67
[  238.105547]  release key_irq:67

root@TinaLinux:/mnt/UDISK# cat /proc/interrupts
           CPU0       CPU1
 17:          0          0     GIC-0  29 Level     arch_timer
 18:      46975      23928     GIC-0  30 Level     arch_timer
 21:          0          0     GIC-0  91 Level     timer@2050000
 24:          0          0     GIC-0  96 Level     2010000.iommu
 26:          0          0     GIC-0  82 Level     3002000.dma-controller
 34:        507          0     GIC-0  34 Level     uart0
 37:        233          0     GIC-0  72 Level     mmc0
 38:         89          0     GIC-0  73 Level     mmc1
 39:      45455          0     GIC-0  47 Level     spi0
 40:          0          0     GIC-0  98 Level     cedar_dev
 41:          0          0     GIC-0  43 Level     sunxi-i2c2
 42:          0          0     GIC-0  89 Level     sunxi-gpadc
 47:          0          0     GIC-0 121 Level     5410000.g2d
 48:      14620          0     GIC-0 122 Level     dispaly
 55:       1597          0     GIC-0  61 Level     sunxi_usb_udc
 58:          0          0     GIC-0  65 Level     ehci_hcd:usb1
 59:          0          0     GIC-0  66 Level     ohci_hcd:usb2
 60:          0          0     GIC-0  57 Level     audio jack irq
 67:         47          0  sunxi_pio_edge   4 Edge      key_irq //注册的按键中断,47为中断次数
197:          0          0  sunxi_pio_edge 134 Edge      4020000.sdmmc cd
IPI0:          0          0  CPU wakeup interrupts
IPI1:          0          0  Timer broadcast interrupts
IPI2:      22684      45858  Rescheduling interrupts
IPI3:          5          2  Function call interrupts
IPI4:          0          0  CPU stop interrupts
IPI5:          0          0  IRQ work interrupts
IPI6:          0          0  completion interrupts

2、基于内核的按键中断输入子系统

          像按键指示灯等这种简单的驱动一般都不需要自己去额外写驱动,linux强大的子系统都已经包含进去。配合设备树只要编写对应的设备树节点就可以让内核通过平台驱动方式装载对应的设备。内核本身支持中断按键和轮询按键的输入子系统方式。

        内核配置需要对应开启

       内核的代码实现位置在drivers/input/keyboard/gpio-keys.c

        按键中断的设备树节点如下:

gpio-keys {
	compatible = "gpio-keys";//必须固定为gpio-keys
	autorepeat;
	status = "okay";
	upisrkey {
		label = "GPIO Key UP";
		linux,code = <103>;
		gpios = <&pio PB 4 GPIO_ACTIVE_HIGH>;
	};
};

        设备树更新系统启动后启动log可以看到probe到该节点,并生产input1

[    3.169705] input: gpio-keys as /devices/platform/gpio-keys/input/input1

root@TinaLinux:/# ls /dev/input/
event0  event1  event2
root@TinaLinux:/# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="gpio-keys"
P: Phys=gpio-keys/input0--------可以看到生产的input对应gpio key
S: Sysfs=/devices/platform/gpio-keys/input/input1
U: Uniq=
H: Handlers=event1
B: PROP=0
B: EV=100003
B: KEY=80 0 0 0


root@TinaLinux:/# cat /proc/interrupts
           CPU0       CPU1
 17:          0          0     GIC-0  29 Level     arch_timer
 18:      28023      14274     GIC-0  30 Level     arch_timer
 21:          0          0     GIC-0  91 Level     timer@2050000
 24:          0          0     GIC-0  96 Level     2010000.iommu
 26:          0          0     GIC-0  82 Level     3002000.dma-controller
 34:        266          0     GIC-0  34 Level     uart0
 37:        264          0     GIC-0  72 Level     mmc0
 38:         89          0     GIC-0  73 Level     mmc1
 39:      45331          0     GIC-0  47 Level     spi0
 40:          0          0     GIC-0  98 Level     cedar_dev
 41:          0          0     GIC-0  43 Level     sunxi-i2c2
 42:          0          0     GIC-0  89 Level     sunxi-gpadc
 47:          0          0     GIC-0 121 Level     5410000.g2d
 48:       8864          0     GIC-0 122 Level     dispaly
 55:        985          0     GIC-0  61 Level     sunxi_usb_udc
 58:          0          0     GIC-0  65 Level     ehci_hcd:usb1
 59:          0          0     GIC-0  66 Level     ohci_hcd:usb2
 60:          0          0     GIC-0  57 Level     audio jack irq
 67:          1          0  sunxi_pio_edge   4 Edge      GPIO Key UP //对应的中断信息以及中断发生次数

root@TinaLinux:/# cat /dev/input/event1 | hexdump
0000000 0267 0000 00cd 0009 0001 0067 0001 0000
0000010 0267 0000 00cd 0009 0000 0000 0000 0000
0000020 0267 0000 71c8 000b 0001 0067 0000 0000
0000030 0267 0000 71c8 000b 0000 0000 0000 0000
0000040 0267 0000 aa48 000c 0001 0067 0001 0000
0000050 0267 0000 aa48 000c 0000 0000 0000 0000
0000060 0267 0000 30e9 000e 0001 0067 0000 0000
0000070 0267 0000 30e9 000e 0000 0000 0000 0000
0000080 0269 0000 0e08 000c 0001 0067 0001 0000
0000090 0269 0000 0e08 000c 0000 0000 0000 0000
00000a0 026a 0000 c359 0000 0001 0067 0002 0000

//倒数第三列为按键keycode, 倒数第二列为按键按下类型,短按 长按还是放开

3、基于内核的按键轮询输入子系统

        内核内部实现代码位置:drivers/input/keyboard/gpio-keys-polled.c

        轮询按键的设备树节点

 gpio_keys_polled {
		compatible = "gpio-keys-polled";//必须为该名称内核才可以识别到
		poll-interval = <100>;
		autorepeat;
        status = "okay";
		downpollkey {
			label = "GPIO Key DOWN";
			linux,code = <108>;
			gpios = <&pio PB 5 GPIO_ACTIVE_HIGH>;
		};
   };


//设备树更新下载后内核启动后可以看到probe到该节点并生成input0

[    2.371525] input: gpio_keys_polled as /devices/platform/gpio_keys_polled/input/input0

root@TinaLinux:/# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="gpio_keys_polled"
P: Phys=gpio-keys-polled/input0
S: Sysfs=/devices/platform/gpio_keys_polled/input/input0
U: Uniq=
H: Handlers=event0
B: PROP=0
B: EV=100003
B: KEY=1000 0 0 0

root@TinaLinux:/#  cat /dev/input/event0 | hexdump
0000000 0070 0000 4ef1 0009 0001 006c 0001 0000
0000010 0070 0000 4ef1 0009 0000 0000 0000 0000
0000020 0070 0000 aa53 000c 0001 006c 0000 0000
0000030 0070 0000 aa53 000c 0000 0000 0000 0000
0000040 0072 0000 9c69 0000 0001 006c 0001 0000
0000050 0072 0000 9c69 0000 0000 0000 0000 0000
0000060 0072 0000 93ed 0004 0001 006c 0002 0000
0000070 0072 0000 93ed 0004 0000 0000 0001 0000
0000080 0072 0000 5738 0005 0001 006c 0002 0000
0000090 0072 0000 5738 0005 0000 0000 0001 0000
00000a0 0072 0000 1a8d 0006 0001 006c 0002 0000
00000b0 0072 0000 1a8d 0006 0000 0000 0001 0000
00000c0 0072 0000 ddd7 0006 0001 006c 0002 0000
00000d0 0072 0000 ddd7 0006 0000 0000 0001 0000
00000e0 0072 0000 a12d 0007 0001 006c 0002 0000

        2,3种方式得益于内核按键输入子系统的支持,不需要额外写内核驱动代码,应用层可以直接读取event文件就可以进行按键识别。

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值