定时器去抖动

来源:互联网 发布:cpi数据 编辑:程序博客网 时间:2024/05/17 03:32

前面程序按键速度较快时出现按下打印几个相同值的情况,这个和机械的抖动有关,现在使用定时器去抖动

#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/irq.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/arch/regs-gpio.h>#include <asm/hardware.h>#include <linux/poll.h>static struct class *sevendrv_class;static struct class_device*sevendrv_class_dev;volatile unsigned long *gpfcon;volatile unsigned long *gpfdat;volatile unsigned long *gpgcon;volatile unsigned long *gpgdat;static struct timer_list buttons_timer;/*第一步:定义一个定时器结构体buttons_timer*/static DECLARE_WAIT_QUEUE_HEAD(button_waitq);/* 中断事件标志, 中断服务程序将它置1,seven_drv_read将它清0 */static volatile int ev_press = 0;static struct fasync_struct *button_async;struct pin_desc{unsigned int pin;unsigned int key_val;};/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 *//* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */static unsigned char key_val;struct pin_desc pins_desc[4] = {{S3C2410_GPF0, 0x01},{S3C2410_GPF2, 0x02},{S3C2410_GPG3, 0x03},{S3C2410_GPG11, 0x04},};//static atomic_t canopen = ATOMIC_INIT(1);     //定义原子变量并初始化为1static DECLARE_MUTEX(button_lock);     //定义互斥锁static struct pin_desc *irq_pd =NULL;static irqreturn_t buttons_irq(int irq, void *dev_id){/*保存键值*/irq_pd = (struct pin_desc *)dev_id;/*第三步:修改定时器,消抖动,最后一次时调用超时函数  *buttons_timer_function *修改定时器10ms,按键有抖动,而抖动时间肯定小于10ms,所以 *第一次抖动修改定时器,定时器延后抖动发生 的10ms *第N-1次抖动修改定时器,定时器延后抖动发生 的10ms *最后一次(第N次)抖动发生,定时器修改到抖动发生后10ms *N次抖动后10ms,即N次的定时器超时时间10ms到后,调用定时器 *处理函数buttons_timer_function */mod_timer(&buttons_timer, jiffies+HZ/100);return IRQ_RETVAL(IRQ_HANDLED);}static int seven_drv_open(struct inode *inode, struct file *file){#if 0if (!atomic_dec_and_test(&canopen)){atomic_inc(&canopen);return -EBUSY;}#endifif (file->f_flags & O_NONBLOCK){if (down_trylock(&button_lock))return -EBUSY;}else{/* 获取信号量 */down(&button_lock);}/* 配置GPF0,2为输入引脚 *//* 配置GPG3,11为输入引脚 */request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);return 0;}ssize_t seven_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos){if (size != 1)return -EINVAL;if (file->f_flags & O_NONBLOCK){if (!ev_press)return -EAGAIN;}else{/* 如果没有按键动作, 休眠 */wait_event_interruptible(button_waitq, ev_press);}/* 如果有按键动作, 返回键值 */copy_to_user(buf, &key_val, 1);ev_press = 0;return 1;}int seven_drv_close(struct inode *inode, struct file *file){//atomic_inc(&canopen);free_irq(IRQ_EINT0, &pins_desc[0]);free_irq(IRQ_EINT2, &pins_desc[1]);free_irq(IRQ_EINT11, &pins_desc[2]);free_irq(IRQ_EINT19, &pins_desc[3]);up(&button_lock);return 0;}static unsigned seven_drv_poll(struct file *file, poll_table *wait){unsigned int mask = 0;poll_wait(file, &button_waitq, wait); // 不会立即休眠if (ev_press)mask |= POLLIN | POLLRDNORM;return mask;}static int seven_drv_fasync (int fd, struct file *filp, int on){printk("driver: seven_drv_fasync\n");return fasync_helper (fd, filp, on, &button_async);}static struct file_operations sencod_drv_fops = {    .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */    .open    =  seven_drv_open,     .read =seven_drv_read,   .release =  seven_drv_close,.poll    =  seven_drv_poll,.fasync =  seven_drv_fasync,};/*第四步:最后一次抖动的上升沿或下降沿10ms后调用buttons_timer_function*/static void buttons_timer_function(unsigned date){struct pin_desc * pindesc = irq_pd;unsigned int pinval;/*add_timer添加时就产生了定时器超时,所以需要判断*/if(!pindesc) return;pinval = s3c2410_gpio_getpin(pindesc->pin);if (pinval){/* 松开 */key_val = 0x80 | pindesc->key_val;}else{/* 按下 */key_val = pindesc->key_val;}    ev_press = 1;                  /* 表示中断发生了 */    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */kill_fasync (&button_async, SIGIO, POLL_IN);}int major;static int seven_drv_init(void){/*第二步:初始化buttons_timer, 并启用定时器*//*buttons_timer为结构体双向链表,我只需要填充一个项,第一次将定时器加入链表,需要初始化整个链表*/init_timer(&buttons_timer);/*初始化定时器结构体成员function,function为定时器超时后调用的函数buttons_timer_function*/buttons_timer.function = buttons_timer_function;/*注册定时器并运行*/add_timer(&buttons_timer);major = register_chrdev(0, "seven_drv", &sencod_drv_fops);sevendrv_class = class_create(THIS_MODULE, "seven_drv");sevendrv_class_dev = class_device_create(sevendrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);gpfdat = gpfcon + 1;gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);gpgdat = gpgcon + 1;return 0;}static void seven_drv_exit(void){unregister_chrdev(major, "seven_drv");class_device_unregister(sevendrv_class_dev);class_destroy(sevendrv_class);iounmap(gpfcon);iounmap(gpgcon);return 0;}module_init(seven_drv_init);module_exit(seven_drv_exit);MODULE_LICENSE("GPL");

mod_timer(&buttons_timer, jiffies+HZ/100);jiffies表示系统启动到现在的tick数,比如jiffies=50,过了一段时间jiffies=55则产生了55-50个系统定时器中断,现在HZ=100,即产生一个定时器中断,1个tick的时间产生了一个定时器中断,而tick为HZ的倒数,即1秒产生100个定时器中断,一个定时器中断为10ms


测试代码:

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <poll.h>#include <signal.h>#include <sys/types.h>#include <unistd.h>#include <fcntl.h>/* sevendrvtest   */int main(int argc, char **argv){unsigned char key_val;int ret,fd;int Oflags;//signal(SIGIO, my_signal_fun);fd = open("/dev/buttons", O_RDWR );if (fd < 0){printf("can't open!\n");return -1;}//fcntl(fd, F_SETOWN, getpid());//Oflags = fcntl(fd, F_GETFL); //fcntl(fd, F_SETFL, Oflags | FASYNC);while (1){ret = read(fd, &key_val, 1);printf("key_val: 0x%x, ret = %d\n", key_val, ret);//sleep(5);}

测试结果:

# insmod seven_drv.ko # lsmodModule                  Size  Used by    Not taintedseven_drv               4740  0 # ./sevendrvtest &# ./sevendrvtest &# ./sevendrvtest &# ./sevendrvtest &# ps  PID  Uid        VSZ Stat Command    1 0          3092 S   init         2 0               SW< [kthreadd]    3 0               SWN [ksoftirqd/0]    4 0               SW< [watchdog/0]    5 0               SW< [events/0]    6 0               SW< [khelper]   55 0               SW< [kblockd/0]   56 0               SW< [ksuspend_usbd]   59 0               SW< [khubd]   61 0               SW< [kseriod]   73 0               SW  [pdflush]   74 0               SW  [pdflush]   75 0               SW< [kswapd0]   76 0               SW< [aio/0]  710 0               SW< [mtdblockd]  745 0               SW< [kmmcd]  762 0               SW< [rpciod/0]  770 0          3096 S   -sh   776 0          1308 S   ./sevendrvtest   777 0          1308 D   ./sevendrvtest   778 0          1308 D   ./sevendrvtest   779 0          1308 D   ./sevendrvtest   780 0          3096 R   ps # key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1key_val: 0x1, ret = 1key_val: 0x81, ret = 1

也可以用异步通知,驱动程序不变,测试源码改为:


#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <unistd.h>#include <signal.h>/*sevendrvtest   */int fd;void my_signal_func(int signum){unsigned char key_val;//printf("signum = %d\n", signum);read(fd, &key_val, 1);printf("key_val = 0x%x\n", key_val);}int main(int argc, char **argv){int O_FLAGS,ret=0;unsigned char key_val=0;signal( SIGIO, my_signal_func); /*安装信号处理函数*/fd = open("/dev/buttons", O_RDWR);if (fd < 0){printf("can't open!, fd = %d\n", fd);return -1;}fcntl( fd, F_SETOWN, getpid());O_FLAGS = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, O_FLAGS|O_ASYNC);while (1){sleep(5);  //屏蔽掉,因为read没有按键产生,six_drv_read会休眠}return 0;}

测试结果:

# ps  PID  Uid        VSZ Stat Command    1 0          3092 S   init         2 0               SW< [kthreadd]    3 0               SWN [ksoftirqd/0]    4 0               SW< [watchdog/0]    5 0               SW< [events/0]    6 0               SW< [khelper]   55 0               SW< [kblockd/0]   56 0               SW< [ksuspend_usbd]   59 0               SW< [khubd]   61 0               SW< [kseriod]   73 0               SW  [pdflush]   74 0               SW  [pdflush]   75 0               SW< [kswapd0]   76 0               SW< [aio/0]  710 0               SW< [mtdblockd]  745 0               SW< [kmmcd]  762 0               SW< [rpciod/0]  770 0          3096 S   -sh   776 0          1312 S   ./sevendrvtest   777 0          1308 D   ./sevendrvtest   778 0          1308 D   ./sevendrvtest   779 0          1308 D   ./sevendrvtest   781 0          3096 R   ps # kill -9 776 777 778 779# [4] + Killed                     ./sevendrvtest[3] + Killed                     ./sevendrvtest[2] + Killed                     ./sevendrvtest[1] + Killed                     ./sevendrvtest# # ./sevendrvtest &# driver: sixth_drv_fasync# ./sevendrvtest &# ./sevendrvtest &# ./sevendrvtest &# ps  PID  Uid        VSZ Stat Command    1 0          3092 S   init         2 0               SW< [kthreadd]    3 0               SWN [ksoftirqd/0]    4 0               SW< [watchdog/0]    5 0               SW< [events/0]    6 0               SW< [khelper]   55 0               SW< [kblockd/0]   56 0               SW< [ksuspend_usbd]   59 0               SW< [khubd]   61 0               SW< [kseriod]   73 0               SW  [pdflush]   74 0               SW  [pdflush]   75 0               SW< [kswapd0]   76 0               SW< [aio/0]  710 0               SW< [mtdblockd]  745 0               SW< [kmmcd]  762 0               SW< [rpciod/0]  770 0          3096 S   -sh   782 0          1308 S   ./sevendrvtest   783 0          1308 D   ./sevendrvtest   784 0          1308 D   ./sevendrvtest   785 0          1308 D   ./sevendrvtest   786 0          3096 R   ps # key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x2key_val = 0x82key_val = 0x2key_val = 0x82key_val = 0x2key_val = 0x82key_val = 0x2key_val = 0x82key_val = 0x2key_val = 0x82key_val = 0x2key_val = 0x82key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1key_val = 0x81key_val = 0x1

计时5sS3C2410 Timer Tick由965663变为966585,966585-965663=922,可知大约5s ,1000此定时器中断,即HZ=200,而在本实验中在HZ上ctrl+鼠标左键,HZ=100,和内核的并不相同

# cat proc/interrupts            CPU0 16:        179    s3c-ext0  S2 18:        194    s3c-ext0  S3 30:     965663         s3c  S3C2410 Timer Tick 32:          0         s3c  s3c2410-lcd 33:          0         s3c  s3c-mci 34:          0         s3c  I2SSDI 35:          0         s3c  I2SSDO 37:         12         s3c  s3c-mci 42:          0         s3c  ohci_hcd:usb1 43:          0         s3c  s3c2440-i2c 51:       1613     s3c-ext  eth0 55:          0     s3c-ext  S4 60:          0     s3c-ext  s3c-mci 63:          0     s3c-ext  S5 70:        176   s3c-uart0  s3c2440-uart 71:       1067   s3c-uart0  s3c2440-uart 79:         20     s3c-adc  s3c2410_action 80:      20332     s3c-adc  s3c2410_action 83:          0           -  s3c2410-wdtErr:          0# cat proc/interrupts            CPU0 16:        179    s3c-ext0  S2 18:        194    s3c-ext0  S3 30:     966585         s3c  S3C2410 Timer Tick 32:          0         s3c  s3c2410-lcd 33:          0         s3c  s3c-mci 34:          0         s3c  I2SSDI 35:          0         s3c  I2SSDO 37:         12         s3c  s3c-mci 42:          0         s3c  ohci_hcd:usb1 43:          0         s3c  s3c2440-i2c 51:       1623     s3c-ext  eth0 55:          0     s3c-ext  S4 60:          0     s3c-ext  s3c-mci 63:          0     s3c-ext  S5 70:        178   s3c-uart0  s3c2440-uart 71:       1104   s3c-uart0  s3c2440-uart 79:         20     s3c-adc  s3c2410_action


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 qq钱包忘记支付密码怎么办 零钱包密码忘了怎么办 关爱通密码知道卡号忘了怎么办 卡号的密码忘了怎么办 银行卡号密码忘了怎么办 微信超出单月支付限额怎么办 行李箱三位数密码忘记了怎么办 手机忘记4位数密码怎么办 win7登入密码忘记了怎么办 电脑登入密码忘记了怎么办 电脑忘记登入密码怎么办 qq钱包支付密码忘了怎么办 财付通转走我卡里的钱怎么办 银行卡资金通过财付通被盗怎么办 社保卡忘了密码怎么办 医保卡忘了密码怎么办 手机qq红包忘记支付密码怎么办 微信红包忘记支付密码怎么办 充点话费充错了怎么办 qq转账记录删除了怎么办 qq转账记录删了怎么办 qq怎么办?q币转给微信 q币送不了别人怎么办 新qq号忘记了怎么办 手机qq登不上去怎么办 qq的账号忘了怎么办 微信红包密码输错锁了怎么办 陌陌钱包异常钱怎么办 对公账户转错了怎么办 微信零钱转账限额怎么办 微信红包充错话费怎么办 qq支付20万限额怎么办 qq红包20万限额怎么办 微信充qb冲错了怎么办 液相色谱柱干了怎么办 微信钱包充流量没到账怎么办 qq买流量不到账怎么办 冲q币电话冲错号了怎么办 下载cf什么文件损坏怎么办 cf老是36_2怎么办啊 永辉超市积分卡怎么办