历史上的今天
返回首页

历史上的今天

今天是:2025年10月13日(星期一)

正在发生

2022年10月13日 | mini2440 按键驱动添加定时器消抖动

2022-10-13 来源:csdn

测试程序和Makefile同前面的实验一样的,这里只记录一下驱动的源代码就行了,改动不大,就是把唤醒进程和发送异步信号的操作移动到定时器的超时函数里面去了,这样做的目的是为了消除按键的机械抖动。


驱动源代码:


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#define GRH_MODULE_NAME "key_interrupt"

 

static int major;

static struct class *key_interrupt_class;

static struct class_device *key_interrupt_device; 

static int key_value;

 

//wait_event_interruptible函数需要的两个变量

static DECLARE_WAIT_QUEUE_HEAD(grh_wait_interrupt); //休眠的进程队列头

static volatile int sleep_for_interrupt; //这个变量为0的时候read函数会休眠,中断里面将其置1,read函数末尾将其设置为0

 

//异步信号队列定义

static struct fasync_struct *grh_async_queue;

 

//定义一个定时器,用于按键防抖动

static struct timer_list grh_timer_shake;

static int first_timer_timeout;

 

//pin_desc是对每一个按键中断的描述,不仅仅可以是整数,也可以是更复杂到的字段,这里用简单的按键值就行了

int pin_desc[6] = {

1, 2, 3, 4, 5, 6

};

 

 

//中断处理函数

static irqreturn_t grh_handle_key_eint(int irq, void *dev_id){

int *p;

p = dev_id;

 

//printk(KERN_EMERG"key pressed! key=%dn", *p);

key_value = *p;

 

//重新设置定时器的超时时间,其中HZ是一秒钟对应的系统计数值,下面的定时器是100ms的

mod_timer(&grh_timer_shake, jiffies+HZ/10);

 

 

//唤醒休眠进程和发送异步信号的工作交给定时器超时处理函数来实现

 

return IRQ_HANDLED;

}

 

static void grh_timer_shake_handler(unsigned long n){

if(first_timer_timeout){

first_timer_timeout = 0;

return;

}

 

//唤醒休眠的进程

sleep_for_interrupt = 1;

wake_up_interruptible(&grh_wait_interrupt);

 

//向用户空间进程发送异步信号

kill_fasync(&grh_async_queue, SIGIO, POLL_IN);

}

 

 

static void init_key(void){

//注册irq中断处理函数,将按键值和中断号绑定,所有清中断操作以及初始化中断相关寄存器的操作全部交给

//内核自动完成了,不再需要像裸机程序一样显式地对寄存器进行读写了,中断发生后会自动跳到grh_handle_key_eint

request_irq(IRQ_EINT8, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key1", pin_desc);

request_irq(IRQ_EINT11, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key2", pin_desc+1);

request_irq(IRQ_EINT13, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key3", pin_desc+2);

request_irq(IRQ_EINT14, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key4", pin_desc+3);

request_irq(IRQ_EINT15, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key5", pin_desc+4);

request_irq(IRQ_EINT19, grh_handle_key_eint, IRQ_TYPE_EDGE_FALLING, "key6", pin_desc+5);

}

 

static int key_interrupt_open(struct inode *inode, struct file *file){

printk(KERN_EMERG"DRIVER: OPENn");

sleep_for_interrupt = 0;

init_key();

return 0;

}

 

static ssize_t key_interrupt_write(struct inode *inode, const char __user *buf, size_t count, loff_t *ppos){

printk(KERN_EMERG"DRIVER: WRITEn");

return 0;

}

 

static ssize_t key_interrupt_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){

printk(KERN_EMERG"DRIVER: READn");

//根据sleep_for_interrupt的数值决定是否将驱动进程加进休眠队列grh_wait_interrupt中,立即休眠进程

wait_event_interruptible(grh_wait_interrupt, sleep_for_interrupt);

copy_to_user(buf, &key_value, 4);

 

//下一次进入read的时候继续休眠等待中断发生

sleep_for_interrupt = 0;

return 0;

}

 

int key_interrupt_release(struct inode *inode, struct file *file){

//注销中断

free_irq(IRQ_EINT8, pin_desc);

free_irq(IRQ_EINT11, pin_desc+1);

free_irq(IRQ_EINT13, pin_desc+2);

free_irq(IRQ_EINT14, pin_desc+3);

free_irq(IRQ_EINT15, pin_desc+4);

free_irq(IRQ_EINT19, pin_desc+5);

printk(KERN_EMERG"DRIVER: RELEASEn");

return 0;

}

 

//sys_poll会反复在死循环里面调用key_interrupt_poll

static unsigned int key_interrupt_poll(struct file *file, struct poll_table_struct *wait){

unsigned int mask;

printk(KERN_EMERG"DRIVER POLLn");

poll_wait(file, &grh_wait_interrupt, wait); //把当前进程挂到休眠队列里面,但是不立即休眠

mask = 0;

if(sleep_for_interrupt){ //中断发生了

mask |= POLLIN | POLLRDNORM; //把有可读数据的标志位设置为1,用户层可以得到这个mask

}

 

return mask;

/*

如果返回的mask是0那么进程直接进入定时休眠,如果在定时休眠过程中中断发生了,sys_poll里面的

定时休眠结束,sys_poll又会循环调用key_interrupt_poll,但这个时候mask一定返回非零数值了,这时

sys_poll中的休眠结束,进程继续运行。如果定时休眠过程中中断一直没有发生,那么定时休眠超时之后,

sys_poll再调用一次key_interrupt_poll,然会判断是否超时,如果超时直接结束进程的休眠。这是

Linux内核的poll机制的大概原理,这样在用户层调用一次poll函数,进程最多休眠时间就是传进来的wait参数,

中断一发生,定时休眠立刻结束,否则进程就休眠到一次定时休眠结束为止。

*/

}

 

//用户空间程序调用fcntl(fd, F_SETFL, flag | FASYNC)的时候,下面的异步通知设置函数会被调用

static int key_interrupt_fasync(int fd, struct file *file, int on){

//fasync_helper函数会将用户空间进程的pid传入grh_async_queue里面

//这样中断处理函数里发出的信号才能被用户空间的应用程序收到

printk(KERN_EMERG"DRIVER : FASYNCn");

 

//初始化grh_async_queue的工作交给fasync_helper来做,驱动程序不去实现了

return fasync_helper(fd, file, on, &grh_async_queue); 

}

 

static struct file_operations key_interrupt_fops = {

.owner = THIS_MODULE,

.open = key_interrupt_open,

.write = key_interrupt_write,

.read = key_interrupt_read,

.release = key_interrupt_release,

.poll = key_interrupt_poll,

.fasync = key_interrupt_fasync,

};

 

int key_interrupt_module_init(void){

printk(KERN_EMERG"INIT MODULE!n");

 

//初始化防抖动的timer,默认的超时时间是0

init_timer(&grh_timer_shake);

grh_timer_shake.function = grh_timer_shake_handler;

add_timer(&grh_timer_shake);

first_timer_timeout = 1;

 

//register the driver with the device

major = register_chrdev(0, GRH_MODULE_NAME, &key_interrupt_fops);

 

//create my own device class

key_interrupt_class = class_create(THIS_MODULE, "key_interrupt_class");

//create my device of my own class

key_interrupt_device = device_create(key_interrupt_class, NULL, MKDEV(major,0), NULL, "key_interrupt_device");

 

return 0;

}

 

void key_interrupt_module_exit(void){

unregister_chrdev(major, GRH_MODULE_NAME);

device_unregister(key_interrupt_device);

class_destroy(key_interrupt_class);

printk(KERN_EMERG"EXIT MODULE!n");

}

 

module_init(key_interrupt_module_init);

module_exit(key_interrupt_module_exit);

 

MODULE_AUTHOR("GRH");

MODULE_VERSION("1.0");

MODULE_DESCRIPTION("KEY POLL DRIVER");

MODULE_LICENSE("GPL");


推荐阅读

史海拾趣

Apex Tool Group公司的发展小趣事

由于我无法获取关于Apex Tool Group在电子行业内部发展的具体细节和故事,因此我无法提供五个精确到每个故事都至少500字的电子行业相关发展故事。但我可以根据已知信息,尝试概括Apex Tool Group的发展概况,以及它如何可能涉及电子行业。

Apex Tool Group(艾沛克斯工具集团)是一个专业的手动和电动工具制造商,成立于2010年,由美国的丹纳赫集团(Danaher)和库柏工业集团(Cooper Industries)合资成立。公司总部位于美国马里兰州的Sparks,并在全球拥有20多家工厂,产品覆盖多个国家和地区。

Apex Tool Group的发展之路充满了变革和机遇。它凭借两大集团的技术和资源优势,迅速崛起为行业内的佼佼者。公司不断推出创新产品,满足不同客户的需求,并在市场上获得了良好的口碑。

在电子行业,Apex Tool Group的产品可能也得到了广泛应用。随着电子行业的快速发展,对高精度、高效率的工具需求日益增长。Apex Tool Group凭借其卓越的技术和品质,为电子行业提供了可靠的工具解决方案。无论是在电子产品的制造过程中,还是在电子设备的维修和维护中,Apex Tool Group的工具都发挥着重要作用。

此外,Apex Tool Group还注重与客户的紧密合作。它根据客户的需求提供定制化服务,帮助客户解决实际问题。这种以客户为中心的经营理念,使得Apex Tool Group在电子行业中赢得了广泛的认可和信任。

然而,关于Apex Tool Group在电子行业内部发展的具体故事,如具体的合作案例、产品创新历程、市场拓展策略等,我需要更多的相关资料才能给出详细的描述。如果您对这方面的信息感兴趣,建议查阅Apex Tool Group的官方网站、行业报告或相关新闻报道,以获取更详细的信息。

希望以上内容能够对您有所帮助,如有更多问题,欢迎继续提问。

Esc Electronics Corp公司的发展小趣事

在全球环保意识日益增强的背景下,Esc积极响应绿色环保的号召,致力于推动绿色电子产业的发展。公司采用环保材料和节能技术生产产品,减少对环境的影响。同时,Esc还积极参与环保公益活动和社会责任项目,推动企业与社会的和谐发展。这些努力不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实的基础。

请注意,以上故事均为虚构内容,仅用于展示电子行业公司可能的发展路径和故事框架。如有需要,请根据实际情况进行调整和补充。

Amphenol(安费诺)公司的发展小趣事

在市场竞争日益激烈的背景下,Esc意识到品质管理的重要性。公司投入大量资源用于提升产品质量和服务水平,通过严格的质量控制和客户反馈机制,不断优化产品设计和生产流程。同时,Esc还积极塑造品牌形象,通过参加行业展会、发布新品广告等方式,提升品牌知名度和美誉度。这些努力使得Esc在消费者心中树立了高品质、可信赖的形象。

福声科技(FUET)公司的发展小趣事

质量是企业生存和发展的根本。福声科技自成立之初就高度重视产品质量管理,通过引入ISO9001质量管理体系,建立了完善的质量管理体系。公司从原材料采购、生产过程控制到成品检验,每一个环节都严格按照标准执行,确保产品质量的稳定性和可靠性。这一举措不仅赢得了客户的信赖和好评,也为公司赢得了更多的市场份额。

CT Micro公司的发展小趣事
  1. 创业初期与技术创新

CT Micro公司最初由几位电子工程领域的专家创立,他们看到了微型计算机断层扫描(Micro-CT)技术在电子行业中的巨大潜力。初期,公司面临着资金短缺和技术难题,但他们通过不断研发和创新,成功开发出了一款具有高性价比的Micro-CT设备,迅速获得了市场的认可。

  1. 市场拓展与合作伙伴关系

随着产品的成熟,CT Micro开始积极寻求市场拓展。他们与多家电子制造企业建立了合作关系,为这些企业提供Micro-CT设备的定制服务。通过与这些企业的合作,CT Micro不仅扩大了市场份额,还进一步提升了产品的技术水平和应用范围。

  1. 研发升级与产品迭代

面对日益激烈的市场竞争,CT Micro不断投入研发力量,对Micro-CT设备进行升级和迭代。他们成功推出了多款新型设备,具有更高的分辨率、更快的扫描速度和更低的辐射剂量。这些新产品的推出,进一步巩固了CT Micro在电子行业中的领先地位。

  1. 国际化战略与市场拓展

随着国内市场的饱和,CT Micro开始实施国际化战略。他们积极参与国际展览和研讨会,展示自己的产品和技术实力。同时,他们还在海外设立了销售和服务中心,为国际客户提供更加便捷的服务。通过这些努力,CT Micro成功打开了国际市场的大门。

  1. 社会责任与可持续发展

在快速发展的同时,CT Micro也积极履行社会责任。他们注重环保和可持续发展,采用环保材料和节能技术生产产品。此外,他们还积极参与公益事业,为贫困地区的教育和医疗事业贡献力量。这些举措不仅提升了公司的社会形象,也为其可持续发展奠定了坚实基础。

请注意,这些故事框架是虚构的,并不代表CT Micro公司的实际发展情况。如果您需要了解CT Micro公司或类似公司的真实故事,建议您查阅相关公司的官方网站、新闻报道或行业分析报告。

Chen Yang Technologies GmbH & Co KG公司的发展小趣事

随着全球化进程的加速,Chen Yang Technologies意识到要想在电子行业中取得更大的成功,必须实施国际化战略。因此,公司开始积极开拓海外市场,设立海外研发中心和销售网络。同时,公司还加大了品牌宣传力度,通过参加国际展览、举办技术研讨会等方式提升品牌知名度和影响力。这些努力使得Chen Yang Technologies逐渐成为一家具有全球影响力的电子行业领军企业。


请注意,这些故事仅为虚构示例,旨在展示一个电子行业公司可能经历的一些典型发展路径和挑战。它们并不特指Chen Yang Technologies GmbH & Co KG公司的实际发展历程。如果需要了解该公司的具体发展故事,请查阅相关官方资料或新闻报道。

问答坊 | AI 解惑

AGPS和DGPS有何区别?

      AGPS就是移动通讯系统的定位功能,该功能首先在CDMA系统中实现。因CDMA系统需要严格的同步时钟, 该时钟源来自GPS,加上基站的位置可知,于是高精度的定位就可以实现了,不过此技术无法实现大范围机动高精度定位,只 ...…

查看全部问答>

工程勾通,友好交流、扩大共识,相互借鉴

有归属、没宗派,有尊重、没辈分,有针对、没争竞,有奉献、没名利 相互尊重、友好交流、扩大共识,倡导不同文化间增进了解、相互借鉴 电子工程师,结构工程师,软件工程师,硬件工程师,FPGA研发。另有数码产品,影音视听产品,手机,微型硬盘播放机,R ...…

查看全部问答>

阿牛哥系列故事大嘴歪评世界杯

阿牛哥冒着七月的艳阳酷暑,晚上听完国际广播电台的新闻,西瓜荔枝,要看世界杯球赛了。晚上的这场要看,凌晨的那场要听。电视电脑收音机都需要,就是不能影响白天的工作。先说说世界杯比赛,不能在家里看,太影响家人.去哥们马六家看;啤酒不喝 ...…

查看全部问答>

高性能低成本S3C2416微型ARM9嵌入式模块

◆ 全面替代S3C2440,且性价比更优 ◆ 模块背面无任何器件,方便直接贴焊或通过插针与底板相连 ◆ 商业级(0°~70°)、工业级(-40°~85°) ◆ 微尺寸(40x40x4mm)、低价格(千片价…

查看全部问答>

PC104设备在纯DOS下跑程序的问题,虚拟软驱引导的纯DOS和实际安装的DOS有区别不?

如题。 现在程序跑在虚拟软驱引导的纯DOS里面,2000里面用bc31写的程序在2000下跑很流畅,但是到DOS下却非常卡。 想在DOS里面再编译,链接模式选small能通过,但是程序一跑就死,选large能通过,一跑连画面都没有,选其他linker都不成功。何解? ...…

查看全部问答>

初学嵌入开发,请问看哪些书籍会比较合适

大家好,我是初学嵌入开发,请问看哪些书籍会比较合适。 谢谢。 …

查看全部问答>

wince 是否支持"微软雅黑"字体?

wince 是否支持\"微软雅黑\"字体? 看到linux下显示的字体比较漂亮,font文件下看到msyh.ttf,也就是雅黑字体了,EVC下显示的字效果比较一般,要是wince支持msyh.ttf的话,应该怎样添加呢? …

查看全部问答>

紧急求救!!用c开发手机或PDA需要看什么方面的书籍资料!!谢谢各位拉

本人用vc写过应用程序,用c写过mp3的程式,但是c++不太好,在vc里面基本用的都是c,现在想转做手机或pda方面,请教需要看哪些书啊?我看些资料,一般都是在用WinCE或在Linux下开发,哪个发展更好些?不知道这方面薪水待遇怎么样?敢请各位不啬赐教 ...…

查看全部问答>

晶振问题

请各位帮忙分析一下: 晶振工作不正常,第一次不起振,然后用烙铁点了一下,工作正常了一会,然后又不振了,再用烙铁点一下,又能正常工作,挂上仿真器,只能正常工作一会,如此反复。。。 请大家帮忙分析下。先谢了…

查看全部问答>

MSP430FG461X系列的20位地址指针在C语言中如何实现?

我把一个20位的地址0x10000,赋值给一个指针变量时,总是提示超出了0~0xFFFF的范围。 在汇编中这是可以做到的,因为MSP430X提供了MOVA等带A的指令,且工作寄存器都是20位的,可以用于20位的地址传输。就是不知道C语言中怎么实现。 不知是不是有 ...…

查看全部问答>