Linux按键驱动程序、定时器消抖

使用定时器可以防止因为按键抖动产生的多次响应函数~~


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/percpu.h>

#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>

#define BUT_NAME "buttons"
#define DEVCOUNT 1


struct dev_button
{
	dev_t dev;
	struct cdev *cdev_p;
	struct class * clz;
	struct class_device * clz_dev;
	struct timer_list timer;
};

struct key_dev
{
	char * name;	
	const int irq_num;
	unsigned int pin;
	unsigned int key_status;
};


struct dev_button button_device;
struct key_dev keys[] = {
	{.name = "S2", .irq_num = IRQ_EINT0, .pin = S3C2410_GPF0, .key_status = 0},
	{.name = "s3", .irq_num = IRQ_EINT2, .pin = S3C2410_GPF2, .key_status = 0},
	{.name = "s4", .irq_num = IRQ_EINT11, .pin = S3C2410_GPG3, .key_status = 0},
};


void timer_function(unsigned long data)
{
	struct key_dev * p_dev = (struct key_dev *)data;
	if(p_dev)
	{
		if(p_dev->key_status)
			printk("Key %s pressed!\n", p_dev->name);
		else
			printk("Key %s unpressed!\n", p_dev->name);
	}
	
	
}

irqreturn_t key_handler(int irq, void * param)
{		
	struct key_dev * p_dev = (struct key_dev *)param;
	if(p_dev)
	{
		button_device.timer.data = (unsigned long)p_dev;					
		if(s3c2410_gpio_getpin(p_dev->pin))		
			p_dev->key_status = 0;		
		else		
			p_dev->key_status = 1;		
		mod_timer(&(button_device.timer), jiffies + HZ/100);
	}
	
	return 0;
}


struct file_operations f_ops = {
	.owner = THIS_MODULE,
};

static int __init buttons_init(void)
{
	int error = 0;
	ssize_t i = 0;
	printk("Button's driver is installing...\n");
	if ((error = alloc_chrdev_region(&(button_device.dev), 0, DEVCOUNT, BUT_NAME)) < 0) {
		printk(KERN_ERR
		       "button: Couldn't alloc_chrdev_region, error=%d\n",
		       error);
		goto ERR_REG_DEVT;
	}
	printk("Alloc character region(%d, %d).\n",
		MAJOR(button_device.dev), MINOR(button_device.dev));
	
	button_device.cdev_p = cdev_alloc();
	if(NULL == button_device.cdev_p)	
	{
		printk(KERN_ERR
		       "button: Couldn't cdev_alloc");
		goto ERR_ALLOC;
	}
	printk("Alloc cdev struct.\n");
	
	button_device.cdev_p->ops = &f_ops;

	error = cdev_add(button_device.cdev_p, button_device.dev, DEVCOUNT);
	if(error < 0)
	{
		printk(KERN_ERR
		       "button: Couldn't cdev_add");
		goto ERR_ADD_DEV;
	}
	printk("Add character device.\n");
	
	button_device.clz = class_create(THIS_MODULE, BUT_NAME);
	if(button_device.clz == NULL)
	{
		printk(KERN_ERR
		       "button: Couldn't class_create");
		goto ERR_CLASS_CREATE;
	}
	printk("create class...\n");

	button_device.clz_dev = class_device_create(button_device.clz, NULL, button_device.dev, NULL, BUT_NAME);
	if(NULL == button_device.clz_dev)
	{
		printk(KERN_ERR
		       "button: Couldn't class_device_create");
		goto ERR_DEV_CREATE;
	}
	printk("create device...\n");

	printk("Button's driver installed successfully.\n");


	for(i = 0; i < sizeof(keys)/sizeof(struct key_dev); i++)
	{
		if(0 != request_irq(keys[i].irq_num, key_handler, IRQT_BOTHEDGE, keys[i].name, (void*)(keys + i)))
		{
			printk(KERN_ERR
		       "button: Couldn't request_irq %s\n", keys[i].name);
			goto ERR_REQUEST_IRQ;
		}
		printk("request_irq %d %s successfully\n", keys[i].irq_num,
			keys[i].name);
	}

	init_timer(&button_device.timer);
	button_device.timer.function = &timer_function;
	add_timer(&button_device.timer);			
	return 0;	
ERR_REQUEST_IRQ:
	for( i-=1 ; i >= 0; i--)
		free_irq(keys[i].irq_num, NULL);			
ERR_DEV_CREATE:
	class_destroy(button_device.clz);
ERR_CLASS_CREATE:
	cdev_del(button_device.cdev_p);
ERR_ADD_DEV:
	kfree(button_device.cdev_p);
ERR_ALLOC:
	unregister_chrdev_region(button_device.dev, DEVCOUNT);
ERR_REG_DEVT:	

	printk("Error happened!\n");
	return -1;
}


static void __exit buttons_exit(void)
{
	ssize_t i = 0;
	device_destroy(button_device.clz, button_device.dev);	
	class_destroy(button_device.clz);
	kfree(button_device.cdev_p);
	unregister_chrdev_region(button_device.dev, DEVCOUNT);

	del_timer(&(button_device.timer));
	
	for( i = 0 ; i < sizeof(keys) / sizeof(struct key_dev); i++)
		free_irq(keys[i].irq_num, (void*)(keys + i));	
	return ;
}

module_init(buttons_init);
module_exit(buttons_exit);

MODULE_LICENSE("GPL");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中,实现按键驱动消抖的方法是使用定时器。可以使用Linux内核提供的定时器函数来实现按键消抖的功能。在驱动中,可以使用宏DEFINE_TIMER定义一个定时器,然后使用add_timer函数将该定时器加入到内核的定时器链表中,设置定时器的超时处理函数和定时时间。当按键被触发时,定时器会开始计时,一段时间后超时处理函数会被执行。在超时处理函数中进行按键状态的判断,从而实现按键消抖的效果。通过使用del_timer函数可以在需要的时候移除定时器。在驱动中设置中断名字,并将flags设置为IRQF_SHARED,可以在/proc/interrupts文件中看到对应的中断名字。同时,可以通过dev参数来区分不同的中断,并将dev参数传递给中断处理函数irq_handler_t的第二个参数,从而与request_irq函数的dev参数保持一致。123 #### 引用[.reference_title] - *1* *2* [Linux嵌入式驱动开发16——按键消抖实验(内核定时器)](https://blog.csdn.net/szm1234/article/details/114092741)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *3* [linux按键驱动(中断)](https://blog.csdn.net/Calmer_/article/details/129013301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值