前面的按鍵驅(qū)動(dòng)方式都是應(yīng)用程序通過(guò)主動(dòng)查詢的方式獲得按鍵值的:
1、查詢方式
2、中斷方式
3、poll機(jī)制
下面介紹第四種按鍵驅(qū)動(dòng)的方式
4、異步通知:它可以做到應(yīng)用程序不用隨時(shí)去查詢按鍵的狀態(tài),而等待有按鍵被按下后,驅(qū)動(dòng)程序主動(dòng)發(fā)消息給應(yīng)用程序,應(yīng)用程序再去處理。
比如說(shuō):kill -9 pid即是一種發(fā)信號(hào)的過(guò)程:其中9就是信號(hào)值,pid就是被發(fā)送的進(jìn)程的進(jìn)程號(hào)
a、一個(gè)簡(jiǎn)單的異步通知的例子
b、編寫測(cè)試程序?qū)崿F(xiàn)異步通知
c、更改按鍵驅(qū)動(dòng)實(shí)現(xiàn)異步通知
1、一個(gè)簡(jiǎn)單的異步通知的例子
直接看到程序源碼,可以看到這個(gè)程序在主程序里面什么事情也沒(méi)有做,一直處于睡眠狀態(tài)。
#include void my_signal_test(int signum) { static int cnt = 0; printf('signal = %d,%d timesn',signum,++cnt); } int main(int argc,char **argv) { signal(SIGUSR1, my_signal_test);//建立一個(gè)信號(hào)函數(shù),接收的信號(hào)是SIGUSR1表示用戶可用的信號(hào)值 while(1) { sleep(1000); } return 0; } 首先這個(gè)程序調(diào)用了signal這個(gè)C庫(kù)中的函數(shù),在linux下查詢它的用法輸入man 2 signal #include typedef void (*sighandler_t)(int);//信號(hào)函數(shù)原型,它的參數(shù)是信號(hào)值 sighandler_t signal(int signum, sighandler_t handler);//函數(shù),其中signum代表發(fā)送的信號(hào)值,handler表示信號(hào)函數(shù) 編譯這個(gè)程序,然后在命令行輸入kill -USR1 2333,my_signal函數(shù)被運(yùn)行。 2、更改測(cè)試程序?qū)崿F(xiàn)異步通知 直接看代碼,從代碼可以看出,實(shí)現(xiàn)異步通知在應(yīng)用層需要如下幾步: 1、利用signal(SIGIO, fifth_testsignal)函數(shù)注冊(cè)一個(gè)信號(hào),信號(hào)處理的函數(shù)為fifth_testsignal。SISGIO說(shuō)明是IO信號(hào)量,因?yàn)榘存I驅(qū)動(dòng)屬于IO型的。 2、利用fcntl(fd, F_SETOWN, getpid())函數(shù)將本應(yīng)用程序的進(jìn)程號(hào)告訴給內(nèi)核,最終使得驅(qū)動(dòng)程序可以成功發(fā)送信號(hào)給應(yīng)用程序。 3、利用fcntl(fd, F_SETFL, oflags | FASYNC)函數(shù)改變fasync標(biāo)記,最終會(huì)調(diào)用到驅(qū)動(dòng)的faync > fasync_helper。 4、signal、與fcntl的系統(tǒng)調(diào)用過(guò)程比較復(fù)雜,后面再去分析。這里只能記住是怎么使用它們來(lái)是實(shí)現(xiàn)異步通知的功能。 #include #include #include #include #include #include static int fd; static void fifth_testsignal(int signum) { unsigned char key_val; printf('signal = %dn',signum); read(fd, &key_val, 1);//讀取按鍵數(shù)據(jù),只有收到按鍵數(shù)據(jù)驅(qū)動(dòng)層才會(huì)發(fā)送消息給應(yīng)用層。 printf('signumkey_val: 0x%xnn',key_val); } /* *usage ./buttonstest */ int main(int argc, char **argv) { char* filename='dev/buttons'; int oflags; fd = open(filename, O_RDWR);//打開dev/firstdrv設(shè)備文件 if (fd < 0)//小于0說(shuō)明沒(méi)有成功 { printf('error, can't open %sn', filename); return 0; } if(argc !=1) { printf('Usage : %s ',argv[0]); return 0; } signal(SIGIO, fifth_testsignal);//注冊(cè)一個(gè)信號(hào),函數(shù)為fifth_testsignal fcntl(fd, F_SETOWN, getpid()); // 告訴內(nèi)核,發(fā)給誰(shuí) oflags = fcntl(fd, F_GETFL); //取得當(dāng)前的狀態(tài) fcntl(fd, F_SETFL, oflags | FASYNC); // 改變fasync標(biāo)記,最終會(huì)調(diào)用到驅(qū)動(dòng)的faync > fasync_helper:初始化/釋放fasync_struct while(1) { sleep(1000); } return 0; } 3、更改按鍵驅(qū)動(dòng)實(shí)現(xiàn)異步通知功能 與原先的按鍵驅(qū)動(dòng)程序相比: 1、定義fasync_struct結(jié)構(gòu) struct fasync_struct *fifth_fasync;//定義fasync_struct結(jié)構(gòu) 2、在fifth_drv_ops 結(jié)構(gòu)體中增加fifth_drv_fasync異步通知處理函數(shù) static struct file_operations fifth_drv_ops = { .owner = THIS_MODULE, .open = fifth_drv_open, .read = fifth_drv_read, .release = fifth_drv_close, .poll = fifth_drv_poll, .fasync = fifth_drv_fasync,//增加異步通知處理的函數(shù) }; 3、編寫fifth_drv_fasync異步通知處理函數(shù),這個(gè)函數(shù)會(huì)在C庫(kù)函數(shù)fcntl設(shè)置FASYNC時(shí)被調(diào)用 static int fifth_drv_fasync(int fd, struct file * file, int on) { int err; printk('fansync_helpern'); err = fasync_helper(fd, file, on, &fifth_fasync);//利用fasync_helper初始化fifth_fasync if (err < 0) return err; return 0; } 下面是完整的代碼 #include #include #include #include #include #include #include #include #include #include #include #include //#include static struct class *fifth_drv_class;//類 static struct class_device *fifth_drv_class_dev;//類下面的設(shè)備 static int fifthmajor; static unsigned long *gpfcon = NULL; static unsigned long *gpfdat = NULL; static unsigned long *gpgcon = NULL; static unsigned long *gpgdat = NULL; struct fasync_struct *fifth_fasync;//定義fasync_struct結(jié)構(gòu) static unsigned int key_val; struct pin_desc { unsigned int pin; unsigned int key_val; }; static struct pin_desc pins_desc[4] = { {S3C2410_GPF0,0x01}, {S3C2410_GPF2,0x02}, {S3C2410_GPG3,0x03}, {S3C2410_GPG11,0x04} }; unsigned int ev_press; DECLARE_WAIT_QUEUE_HEAD(button_waitq);//注冊(cè)一個(gè)等待隊(duì)列button_waitq /* *0x01、0x02、0x03、0x04表示按鍵被按下 */ /* *0x81、0x82、0x83、0x84表示按鍵被松開 */ /* *利用dev_id的值為pins_desc來(lái)判斷是哪一個(gè)按鍵被按下或松開 */ static irqreturn_t buttons_irq(int irq, void *dev_id) { unsigned int pin_val; struct pin_desc * pin_desc = (struct pin_desc *)dev_id;//取得哪個(gè)按鍵被按下的狀態(tài) pin_val = s3c2410_gpio_getpin(pin_desc->pin); if(pin_val) //按鍵松開 key_val = 0x80 | pin_desc->key_val; else key_val = pin_desc->key_val; wake_up_interruptible(&button_waitq); /* 喚醒休眠的進(jìn)程 */ ev_press = 1; kill_fasync(&fifth_fasync, SIGIO, POLL_IN);//發(fā)生信號(hào)給進(jìn)程 return IRQ_HANDLED; } static int fifth_drv_open (struct inode * inode, struct file * file) { int ret; ret = request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, 's1', (void * )&pins_desc[0]); if(ret) { printk('open failed 1n'); return -1; } ret = request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, 's2', (void * )& pins_desc[1]); if(ret) { printk('open failed 2n'); return -1; } ret = request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, 's3', (void * )&pins_desc[2]); if(ret) { printk('open failed 3n'); return -1; } ret = request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, 's4', (void * )&pins_desc[3]); if(ret) { printk('open failed 4n'); return -1; } return 0; } static int fifth_drv_close(struct inode * inode, struct file * file) { free_irq(IRQ_EINT0 ,(void * )&pins_desc[0]); free_irq(IRQ_EINT2 ,(void * )& pins_desc[1]); free_irq(IRQ_EINT11 ,(void * )&pins_desc[2]); free_irq(IRQ_EINT19 ,(void * )&pins_desc[3]); return 0; } static ssize_t fifth_drv_read(struct file * file, char __user * userbuf, size_t count, loff_t * off) { int ret; if(count != 1) { printk('read errorn'); return -1; } // wait_event_interruptible(button_waitq, ev_press);//將當(dāng)前進(jìn)程放入等待隊(duì)列button_waitq中 ret = copy_to_user(userbuf, &key_val, 1); ev_press = 0;//按鍵已經(jīng)處理可以繼續(xù)睡眠 if(ret) { printk('copy errorn'); return -1; } return 1; } static unsigned int fifth_drv_poll(struct file *file, poll_table *wait) { unsigned int ret = 0; poll_wait(file, &button_waitq, wait);//將當(dāng)前進(jìn)程放到button_waitq列表 if(ev_press) ret |=POLLIN;//說(shuō)明有數(shù)據(jù)被取到了 return ret; } static int fifth_drv_fasync(int fd, struct file * file, int on) { int err; printk('fansync_helpern'); err = fasync_helper(fd, file, on, &fifth_fasync);//利用fasync_helper初始化fifth_fasync if (err < 0) return err; return 0; } static struct file_operations fifth_drv_ops = { .owner = THIS_MODULE, .open = fifth_drv_open, .read = fifth_drv_read, .release = fifth_drv_close, .poll = fifth_drv_poll, .fasync = fifth_drv_fasync,//增加異步通知處理的函數(shù) }; static int fifth_drv_init(void) { fifthmajor = register_chrdev(0, 'buttons', &fifth_drv_ops);//注冊(cè)驅(qū)動(dòng)程序 if(fifthmajor < 0) printk('failes 1 buttons_drv registern'); fifth_drv_class = class_create(THIS_MODULE, 'buttons');//創(chuàng)建類 if(fifth_drv_class < 0) printk('failes 2 buttons_drv registern'); fifth_drv_class_dev = class_device_create(fifth_drv_class, NULL, MKDEV(fifthmajor,0), NULL,'buttons');//創(chuàng)建設(shè)備節(jié)點(diǎn) if(fifth_drv_class_dev < 0) printk('failes 3 buttons_drv registern'); gpfcon = ioremap(0x56000050, 16);//重映射 gpfdat = gpfcon + 1; gpgcon = ioremap(0x56000060, 16);//重映射 gpgdat = gpgcon + 1; printk('register buttons_drvn'); return 0;
上一篇:Linux驅(qū)動(dòng)之異步OR同步,阻塞OR非阻塞概念介紹
下一篇:Linux驅(qū)動(dòng)之poll機(jī)制的理解與簡(jiǎn)單使用
推薦閱讀最新更新時(shí)間:2025-06-07 23:41



設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲(chǔ)html,css,js文件,以及網(wǎng)頁(yè)和arduino的通訊
- ESP32 freeRTOS使用測(cè)試
- API調(diào)用小記(Touchdesigner和ESP32)
- 關(guān)于ESP32/8266使用async-mqtt-client庫(kù)的一些基本介紹
- arduino環(huán)境下利用ESP32控制舵狗(初始位置的調(diào)試)
- LTM4602HV 演示板、28V、6A 降壓模塊穩(wěn)壓器
- PCB書簽 尺子 卡片
- PeanutPI
- 平衡自行車+獨(dú)輪車
- AM1DR-1209SZ 9V 1 瓦 DC-DC 轉(zhuǎn)換器的典型應(yīng)用
- NCV33074ADR2G 直流耦合反相放大器最大輸出擺幅的典型應(yīng)用
- 【明日方舟】羅德島本艦主控板V6.2
- DC795A,使用 LT5527EUF 4.5V 至 5.25V 高線性下變頻混頻器的演示板
- XL4016可調(diào)恒壓恒流實(shí)驗(yàn)電源
- 帶內(nèi)部開關(guān)的 PAM2863 2A LED 驅(qū)動(dòng)器的典型應(yīng)用
- SABIC將亮相PCIM ASIA 2021,展示ELCRES? HTV150電容薄膜
- Arm DevSummit 2021報(bào)名開啟,相聚云端共話前沿技術(shù)
- RISC-V正向HPC市場(chǎng)急速拓展
- 三星 Galaxy S21 FE 已經(jīng)大規(guī)模出貨,歐洲市場(chǎng)貨源充足
- STM32HAL庫(kù)普通模式串口收發(fā)
- OPPO Find X4 Pro設(shè)計(jì)專利:屏下前攝,后置方形副屏
- 數(shù)字電橋LCR測(cè)試儀原理
- S3C2410:DMA介紹
- 傳日本Denso將投資臺(tái)積電與索尼合資的熊本晶圓廠
- 雷達(dá)測(cè)速儀在的應(yīng)用及如何加強(qiáng)管理
- 如何為您的應(yīng)用選擇光傳感器
- Samtec新型農(nóng)業(yè)漫談系列二 | 垂直農(nóng)業(yè)案列分享
- Samtec應(yīng)用科普 | C-V2X技術(shù)在汽車領(lǐng)域的應(yīng)用
- 尼得科運(yùn)動(dòng)&能源事業(yè)本部在印度卡納塔克邦胡布利舉行新工廠竣工儀式
- 貿(mào)澤開售Qorvo適用于5G和mMIMO應(yīng)用的新型QPA9822線性5G高增益/高驅(qū)動(dòng)放大器
- 邊緣計(jì)算網(wǎng)關(guān)工業(yè)物聯(lián)網(wǎng)應(yīng)用:空壓機(jī)遠(yuǎn)程運(yùn)維監(jiān)控管理
- 納芯微電子工業(yè)控制、機(jī)器人解決方案器件選型概述
- 使用瑞薩電子RZ/T2H產(chǎn)品實(shí)現(xiàn)多關(guān)節(jié)機(jī)器人
- 新能源純電動(dòng)汽車無(wú)法行駛故障分析
- AI玩具,還是AI工具?
- ARM架構(gòu)上網(wǎng)本電源解決方案
- wince的啟動(dòng)速度的問(wèn)題
- 一個(gè)課程設(shè)計(jì):基于單片機(jī)的波形發(fā)生器的設(shè)計(jì)
- 威世的產(chǎn)品不錯(cuò)的!支持
- Linux/UNIX人才培訓(xùn)
- 求助tm4c123gxl需要一個(gè)5分鐘左右的延時(shí)程序!??!
- GPTMMIS和GPTMRIS差異
- 無(wú)線電源在工業(yè)應(yīng)用中的價(jià)值?
- 吉時(shí)利推出經(jīng)濟(jì)型、可編程的5位半數(shù)字多用表(DMM)拓展數(shù)字多用表系列產(chǎn)品
- 如何用430測(cè)量交流電壓,并且實(shí)現(xiàn)過(guò)壓欠壓保護(hù)