嵌入式Linux驅(qū)動(dòng)程序和QT.ppt
《嵌入式Linux驅(qū)動(dòng)程序和QT.ppt》由會(huì)員分享,可在線閱讀,更多相關(guān)《嵌入式Linux驅(qū)動(dòng)程序和QT.ppt(47頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
嵌入式Linux驅(qū)動(dòng)程序開(kāi)發(fā),遼寧工程技術(shù)大學(xué)電信學(xué)院,1嵌入式Linux的設(shè)備管理,,Linux將設(shè)備分成兩大類:一類是塊設(shè)備,類似磁盤以記錄塊或扇區(qū)為單位,成塊進(jìn)行輸入/輸出的設(shè)備;另一類是字符設(shè)備,類似鍵盤以字符為單位,逐個(gè)進(jìn)行輸入/輸出的設(shè)備。網(wǎng)路設(shè)備是介于塊設(shè)備和字符設(shè)備之間的一種特殊設(shè)備。塊設(shè)備接口僅支持面向塊的I/O操作,所有I/O操作都通過(guò)在內(nèi)核地址空間中的I/O緩沖區(qū)進(jìn)行,它可以支持隨機(jī)存取的功能。文件系統(tǒng)通常都建立在塊設(shè)備上。字符設(shè)備接口支持面向字符的I/O操作,由于它們不經(jīng)過(guò)系統(tǒng)的快速緩存,所以它們負(fù)責(zé)管理自己的緩沖區(qū)結(jié)構(gòu)。字符設(shè)備接口只支持順序存取的功能,一般不能進(jìn)行任意長(zhǎng)度的I/O請(qǐng)求,而是限制I/O請(qǐng)求的長(zhǎng)度必須是設(shè)備要求的基本塊長(zhǎng)的倍數(shù)。處理器與設(shè)備間數(shù)據(jù)交換方式處理器與外設(shè)之間傳輸數(shù)據(jù)的控制方式通常有3種:查詢方式、中斷方式和直接內(nèi)存存取(DMA)方式。1.查詢方式設(shè)備驅(qū)動(dòng)程序通過(guò)設(shè)備的I/O端口空間,以及存儲(chǔ)器空間完成數(shù)據(jù)的交換。例如,網(wǎng)卡一般將自己的內(nèi)部寄存器映射為設(shè)備的I/O端口,而顯示卡則利用大量的存儲(chǔ)器空間作為視頻信息的存儲(chǔ)空間。利用這些地址空間,驅(qū)動(dòng)程序可以向外設(shè)發(fā)送指定的操作指令。通常來(lái)講,由于外設(shè)的操作耗時(shí)較長(zhǎng),因此,當(dāng)處理器實(shí)際執(zhí)行了操作指令之后,驅(qū)動(dòng)程序可采用查詢方式等待外設(shè)完成操作。驅(qū)動(dòng)程序在提交命令之后,開(kāi)始查詢?cè)O(shè)備的狀態(tài)寄存器,當(dāng)狀態(tài)寄存器表明操作完成時(shí),驅(qū)動(dòng)程序可繼續(xù)后續(xù)處理。查詢方式的優(yōu)點(diǎn)是硬件開(kāi)銷小,使用起來(lái)比較簡(jiǎn)單。但在此方式下,CPU要不斷地查詢外設(shè)的狀態(tài),當(dāng)外設(shè)未準(zhǔn)備好時(shí),就只能循環(huán)等待,不能執(zhí)行其他程序,這樣就浪費(fèi)了CPU的大量時(shí)間,降低了處理器的利用率。,2.中斷方式查詢方式白白浪費(fèi)了大量的處理器時(shí)間,而中斷方式才是多任務(wù)操作系統(tǒng)中最有效利用處理器的方式。當(dāng)CPU進(jìn)行主程序操作時(shí),外設(shè)的數(shù)據(jù)已存入端口的數(shù)據(jù)輸入寄存器,或端口的數(shù)據(jù)輸出寄存器已空,此時(shí)由外設(shè)通過(guò)接口電路向CPU發(fā)出中斷請(qǐng)求信號(hào)。CPU在滿足一定條件下,暫停執(zhí)行當(dāng)前正在執(zhí)行的主程序,轉(zhuǎn)入執(zhí)行相應(yīng)能夠進(jìn)行輸入/輸出操作的子程序,待輸入/輸出操作執(zhí)行完畢之后,CPU再返回并繼續(xù)執(zhí)行原來(lái)被中斷的主程序。這樣,CPU就避免了把大量時(shí)間耗費(fèi)在等待、查詢外設(shè)狀態(tài)的操作上,使其工作效率得以大大提高。中斷方式的原理示意圖如下圖所示。能夠向CPU發(fā)出中斷請(qǐng)求的設(shè)備或事件稱為中斷源。中斷源向CPU發(fā)出中斷請(qǐng)求,若優(yōu)先級(jí)別最高,則CPU在滿足一定的條件時(shí),可中斷當(dāng)前程序的運(yùn)行,保護(hù)好被中斷的主程序的斷點(diǎn)及現(xiàn)場(chǎng)信息,然后根據(jù)中斷源提供的信息,找到中斷服務(wù)子程序的入口地址,轉(zhuǎn)去執(zhí)行新的程序段,這就是中斷響應(yīng)。CPU響應(yīng)中斷是有條件的,如內(nèi)部允許中斷、中斷未被屏蔽、當(dāng)前指令執(zhí)行完等。CPU響應(yīng)中斷以后,就會(huì)中止當(dāng)前的程序,轉(zhuǎn)去執(zhí)行一個(gè)中斷服務(wù)子程序,以完成為相應(yīng)設(shè)備的服務(wù)。系統(tǒng)引入中斷機(jī)制后,CPU與外設(shè)處于“并行”工作狀態(tài),便于實(shí)現(xiàn)信息的實(shí)時(shí)處理和系統(tǒng)的故障處理。,3.直接訪問(wèn)內(nèi)存(DMA)方式利用中斷,系統(tǒng)和設(shè)備之間可以通過(guò)設(shè)備驅(qū)動(dòng)程序傳送數(shù)據(jù),但是,當(dāng)傳送的數(shù)據(jù)量很大時(shí),因?yàn)橹袛嗵幚砩系难舆t,利用中斷方式的效率會(huì)大大降低。而直接內(nèi)存訪問(wèn)(DMA)可以解決這一問(wèn)題。DMA可允許設(shè)備和系統(tǒng)內(nèi)存間在沒(méi)有處理器參與的情況下傳輸大量數(shù)據(jù)。設(shè)備驅(qū)動(dòng)程序在利用DMA之前,需要選擇DMA通道并定義相關(guān)寄存器,以及數(shù)據(jù)的傳輸方向,即讀取或?qū)懭?,然后將設(shè)備設(shè)定為利用該DMA通道傳輸數(shù)據(jù)。設(shè)備完成設(shè)置之后,可以立即利用該DMA通道在設(shè)備和系統(tǒng)的內(nèi)存之間傳輸數(shù)據(jù),傳輸完畢后產(chǎn)生中斷以便通知驅(qū)動(dòng)程序進(jìn)行后續(xù)處理。在利用DMA進(jìn)行數(shù)據(jù)傳輸?shù)耐瑫r(shí),處理器仍然可以繼續(xù)執(zhí)行指令。,設(shè)備驅(qū)動(dòng)程序的概念,設(shè)備驅(qū)動(dòng)程序?qū)嶋H是處理和操作硬件控制器的軟件,從本質(zhì)上講,是內(nèi)核中具有最高特權(quán)級(jí)的、駐留內(nèi)存的、可共享的底層硬件處理例程。驅(qū)動(dòng)程序是內(nèi)核的一部分,是操作系統(tǒng)內(nèi)核與硬件設(shè)備的直接接口,驅(qū)動(dòng)程序屏蔽了硬件的細(xì)節(jié),完成以下功能:?對(duì)設(shè)備初始化和釋放;?對(duì)設(shè)備進(jìn)行管理,包括實(shí)時(shí)參數(shù)設(shè)置,以及提供對(duì)設(shè)備的操作接口;?讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)或者回送應(yīng)用程序請(qǐng)求的數(shù)據(jù);?檢測(cè)和處理設(shè)備出現(xiàn)的錯(cuò)誤。Linux操作系統(tǒng)將所有的設(shè)備全部看成文件,并通過(guò)文件的操作界面進(jìn)行操作。對(duì)用戶程序而言,設(shè)備驅(qū)動(dòng)程序隱藏了設(shè)備的具體細(xì)節(jié),對(duì)各種不同設(shè)備提供了一致的接口,一般來(lái)說(shuō),是把設(shè)備映射為一個(gè)特殊的設(shè)備文件,用戶程序可以像對(duì)其他文件一樣對(duì)此設(shè)備文件進(jìn)行操作。這意味著:?由于每一個(gè)設(shè)備至少由文件系統(tǒng)的一個(gè)文件代表,因而都有一個(gè)“文件名”。?應(yīng)用程序通??梢酝ㄟ^(guò)系統(tǒng)調(diào)用open()打開(kāi)設(shè)備文件,建立起與目標(biāo)設(shè)備的連接。?打開(kāi)了代表著目標(biāo)設(shè)備的文件,即建立起與設(shè)備的連接后,可以通過(guò)read()、write()、ioctl()等常規(guī)的文件操作對(duì)目標(biāo)設(shè)備進(jìn)行操作。設(shè)備文件的屬性由三部分信息組成:第一部分是文件的類型,第二部分是一個(gè)主設(shè)備號(hào),第三部分是一個(gè)次設(shè)備號(hào)。其中類型和主設(shè)備號(hào)結(jié)合在一起惟一地確定了設(shè)備文件驅(qū)動(dòng)程序及其界面,而次設(shè)備號(hào)則說(shuō)明目標(biāo)設(shè)備是同類設(shè)備中的第幾個(gè)。由于Linux中將設(shè)備當(dāng)做文件處理,所以對(duì)設(shè)備進(jìn)行操作的調(diào)用格式與對(duì)文件的操作類似,主要包括open()、read()、write()、ioctl()、close()等。應(yīng)用程序發(fā)出系統(tǒng)調(diào)用命令后,會(huì)從用戶態(tài)轉(zhuǎn)到核心態(tài),通過(guò)內(nèi)核將open()這樣的系統(tǒng)調(diào)用轉(zhuǎn)換成對(duì)物理設(shè)備的操作。,驅(qū)動(dòng)程序結(jié)構(gòu),1.自動(dòng)配置和初始化子程序,用來(lái)檢測(cè)所需驅(qū)動(dòng)的硬件設(shè)備是否工作正常、對(duì)正常工作的設(shè)備及其相關(guān)驅(qū)動(dòng)程序所需要的軟件狀態(tài)進(jìn)行初始化。2.服務(wù)于I/O請(qǐng)求的子程序,該子程序稱為驅(qū)動(dòng)程序的上半部。這部分程序在執(zhí)行時(shí),系統(tǒng)仍認(rèn)為與進(jìn)行調(diào)用的進(jìn)程屬于同一個(gè)進(jìn)程,只是由用戶態(tài)變成了核心態(tài),可以在其中調(diào)用sleep()等與進(jìn)程運(yùn)行環(huán)境有關(guān)的函數(shù)。3.中斷服務(wù)程序,又稱為驅(qū)動(dòng)程序的下半部,由Linux系統(tǒng)來(lái)接收硬件中斷,再由系統(tǒng)調(diào)用中斷服務(wù)子程序。在系統(tǒng)內(nèi)部,I/O設(shè)備的存取通過(guò)一組固定的入口點(diǎn)來(lái)進(jìn)行,入口點(diǎn)也可以理解為設(shè)備的句柄,就是對(duì)設(shè)備進(jìn)行操作的基本函數(shù)。字符型設(shè)備驅(qū)動(dòng)程序提供如下幾個(gè)入口點(diǎn):?open入口點(diǎn)。打開(kāi)設(shè)備準(zhǔn)備I/O操作。對(duì)字符設(shè)備文件進(jìn)行打開(kāi)操作,都會(huì)調(diào)用設(shè)備的open入口點(diǎn)。open子程序必須對(duì)將要進(jìn)行的I/O操作做好必要的準(zhǔn)備工作,如清除緩沖區(qū)等。如果設(shè)備是獨(dú)占的,即同一時(shí)刻只能有一個(gè)程序訪問(wèn)此設(shè)備,則open子程序必須設(shè)置一些標(biāo)志以表示設(shè)備處于忙狀態(tài)。?close入口點(diǎn)。關(guān)閉一個(gè)設(shè)備。當(dāng)最后一次使用設(shè)備完成后,調(diào)用close子程序。獨(dú)占設(shè)備必須標(biāo)記設(shè)備方可再次使用。?read入口點(diǎn)。從設(shè)備上讀數(shù)據(jù)。對(duì)于有緩沖區(qū)的I/O操作,一般是從緩沖區(qū)里讀數(shù)據(jù)。對(duì)字符設(shè)備文件進(jìn)行讀操作將調(diào)用read子程序。?write入口點(diǎn)。往設(shè)備上寫數(shù)據(jù)。對(duì)于有緩沖區(qū)的I/O操作,一般是把數(shù)據(jù)寫入緩沖區(qū)里。對(duì)字符設(shè)備文件進(jìn)行寫操作將調(diào)用write子程序。?ioctl入口點(diǎn)。執(zhí)行讀、寫之外的操作。?select入口點(diǎn)。檢查設(shè)備,看數(shù)據(jù)是否可讀或設(shè)備是否可用于寫數(shù)據(jù)。select系統(tǒng)調(diào)用在檢查與設(shè)備文件相關(guān)的文件描述符時(shí)使用select入口點(diǎn)。,structfile_operations{structmodule*owner;loff_t(*llseek)(structfile*,loff_t,int);ssize_t(*read)(structfile*,char*,size_t,loff_t*);ssize_t(*write)(structfile*,constchar*,size_t,loff_t*);int(*readdir)(structfile*,void*,filldir_t);unsignedint(*poll)(structfile*,structpoll_table_struct*);int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);int(*mmap)(structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*flush)(structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structfile*,structdentry*,intdatasync);int(*fasync)(int,structfile*,int);int(*lock)(structfile*,int,structfile_lock*);ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);};?lseek,移動(dòng)文件指針的位置,只能用于可以隨機(jī)存取的設(shè)備。?read,進(jìn)行讀操作,buf為存放讀取結(jié)果的緩沖區(qū),count為所要讀取的數(shù)據(jù)長(zhǎng)度。?write,進(jìn)行寫操作,與read類似。?select,進(jìn)行選擇操作。?ioctl,進(jìn)行讀、寫以外的其他操作。?mmap,用于把設(shè)備的內(nèi)容映射到地址空間,一般只有塊設(shè)備驅(qū)動(dòng)程序使用。?open,打開(kāi)設(shè)備進(jìn)行I/O操作。返回0表示成功,返回負(fù)數(shù)表示失敗。?release,即close操作。,structfile主要用于與文件系統(tǒng)相關(guān)的設(shè)備驅(qū)動(dòng)程序,可提供關(guān)于被打開(kāi)的文件的信息,定義如下:structfile{structlist_headf_list;structdentry*f_dentry;structvfsmount*f_vfsmnt;structfile_operations*f_op;atomic_tf_count;unsignedintf_flags;mode_tf_mode;loff_tf_pos;unsignedlongf_reada,f_ramax,f_raend,f_ralen,f_rawin;structfown_structf_owner;unsignedintf_uid,f_gid;intf_error;unsignedlongf_version;/*neededforttydriver,andmaybeothers*/void*private_data;/*preallocatedhelperkiobuftospeedupO_DIRECT*/structkiobuf*f_iobuf;longf_iobuf_lock;};在用戶自己的驅(qū)動(dòng)程序中,首先要根據(jù)驅(qū)動(dòng)程序的功能,完成file_operations結(jié)構(gòu)中函數(shù)的實(shí)現(xiàn)。不需要的函數(shù)接口可以直接在file_operations結(jié)構(gòu)中初始化為NULL。file_operations中的變量會(huì)在驅(qū)動(dòng)程序初始化時(shí),注冊(cè)到系統(tǒng)內(nèi)部。每個(gè)進(jìn)程對(duì)設(shè)備的操作,都會(huì)根據(jù)主次設(shè)備號(hào),轉(zhuǎn)換成對(duì)file_operations結(jié)構(gòu)的訪問(wèn)。,2設(shè)備驅(qū)動(dòng)程序的開(kāi)發(fā)過(guò)程,由于嵌入式設(shè)備由于硬件種類非常豐富,在默認(rèn)的內(nèi)核發(fā)布版中不一定包括所有驅(qū)動(dòng)程序。所以進(jìn)行嵌入式Linux系統(tǒng)的開(kāi)發(fā),很大的工作量是為各種設(shè)備編寫驅(qū)動(dòng)程序。除非系統(tǒng)不使用操作系統(tǒng),程序直接操縱硬件。嵌入式Linux系統(tǒng)驅(qū)動(dòng)程序開(kāi)發(fā)與普通Linux開(kāi)發(fā)沒(méi)有區(qū)別??梢栽谟布a(chǎn)廠家或者Internet上尋找驅(qū)動(dòng)程序,也可以根據(jù)相近的硬件驅(qū)動(dòng)程序來(lái)改寫,這樣可以加快開(kāi)發(fā)速度。實(shí)現(xiàn)一個(gè)嵌入式Linux設(shè)備驅(qū)動(dòng)的大致流程如下。(1)查看原理圖,理解設(shè)備的工作原理。一般嵌入式處理器的生產(chǎn)商提供參考電路,也可以根據(jù)需要自行設(shè)計(jì)。(2)定義設(shè)備號(hào)。設(shè)備由一個(gè)主設(shè)備號(hào)和一個(gè)次設(shè)備號(hào)來(lái)標(biāo)識(shí)。主設(shè)備號(hào)惟一標(biāo)識(shí)了設(shè)備類型,即設(shè)備驅(qū)動(dòng)程序類型,它是塊設(shè)備表或字符設(shè)備表中設(shè)備表項(xiàng)的索引。次設(shè)備號(hào)僅由設(shè)備驅(qū)動(dòng)程序解釋,區(qū)分被一個(gè)設(shè)備驅(qū)動(dòng)控制下的某個(gè)獨(dú)立的設(shè)備。(3)實(shí)現(xiàn)初始化函數(shù)。在驅(qū)動(dòng)程序中實(shí)現(xiàn)驅(qū)動(dòng)的注冊(cè)和卸載。(4)設(shè)計(jì)所要實(shí)現(xiàn)的文件操作,定義file_operations結(jié)構(gòu)。(5)實(shí)現(xiàn)所需的文件操作調(diào)用,如read、write等。(6)實(shí)現(xiàn)中斷服務(wù),并用request_irq向內(nèi)核注冊(cè),中斷并不是每個(gè)設(shè)備驅(qū)動(dòng)所必需的。(7)編譯該驅(qū)動(dòng)程序到內(nèi)核中,或者用insmod命令加載模塊。(8)測(cè)試該設(shè)備,編寫應(yīng)用程序,對(duì)驅(qū)動(dòng)程序進(jìn)行測(cè)試。,模塊化驅(qū)動(dòng)程序設(shè)計(jì),在探討模塊之前,有必要先看一看內(nèi)核模塊與應(yīng)用程序之間的區(qū)別。一個(gè)應(yīng)用從頭到尾完成一個(gè)任務(wù),而模塊則是為以后處理某些請(qǐng)求而注冊(cè)自己,完成這個(gè)任務(wù)后,它的“主”函數(shù)就立即中止了。然而,內(nèi)核源碼僅能連接編譯到內(nèi)核模塊中,不像應(yīng)用那樣有眾多的支持庫(kù),內(nèi)核能調(diào)用的僅是由內(nèi)核開(kāi)放出來(lái)的那些函數(shù)。由于沒(méi)有庫(kù)連接到模塊中,所以源碼文件不應(yīng)該模塊化任何常規(guī)頭文件。與內(nèi)核有關(guān)的所有內(nèi)容都定義在目錄/usr/include/linux和/usr/include/asm下的頭文件中。1.內(nèi)核空間和用戶空間當(dāng)談到軟件時(shí),我們通常稱執(zhí)行態(tài)為“內(nèi)核空間”和“用戶空間”,在Linux系統(tǒng)中,內(nèi)核在最高級(jí)執(zhí)行,也稱為“管理員態(tài)”,在這一級(jí)任何操作都可以執(zhí)行。而應(yīng)用程序則執(zhí)行在最低級(jí),所謂的“用戶態(tài)”,在這一級(jí)處理器禁止對(duì)硬件的直接訪問(wèn)和對(duì)內(nèi)存的未授權(quán)訪問(wèn)。模塊是在所謂的“內(nèi)核空間”中運(yùn)行的,而應(yīng)用程序則是在“用戶空間”中運(yùn)行的。它們分別引用不同的內(nèi)存映射,也就是程序代碼使用不同的“地址空間”。Linux通過(guò)系統(tǒng)調(diào)用和硬件中斷完成從用戶空間到內(nèi)核空間的控制轉(zhuǎn)移。執(zhí)行系統(tǒng)調(diào)用的內(nèi)核代碼在進(jìn)程的上下文中執(zhí)行,它執(zhí)行調(diào)用進(jìn)程的操作而且可以訪問(wèn)進(jìn)程地址空間的數(shù)據(jù)。但處理中斷與此不同,處理中斷的代碼相對(duì)進(jìn)程而言是異步的,而且與任何一個(gè)進(jìn)程都無(wú)關(guān)。模塊的作用就是擴(kuò)展內(nèi)核的功能,是運(yùn)行在內(nèi)核空間的模塊化的代碼。模塊的某些函數(shù)作為系統(tǒng)調(diào)用執(zhí)行,而某些函數(shù)則負(fù)責(zé)處理中斷。,各個(gè)模塊被分別編譯并鏈接成一組目標(biāo)文件,這些文件能被載入正在運(yùn)行的內(nèi)核,或從正在運(yùn)行的內(nèi)核中卸載。必要時(shí)內(nèi)核能請(qǐng)求內(nèi)核守護(hù)進(jìn)程Kerneld對(duì)模塊進(jìn)行加載或卸載。根據(jù)需要?jiǎng)討B(tài)載入模塊可以保證內(nèi)核達(dá)到最小,并且具有很大的靈活性。內(nèi)核模塊一部分保存在Kernel中,另一部分在Modules包中。在項(xiàng)目一開(kāi)始,很多地方對(duì)設(shè)備安裝、使用和改動(dòng)都是通過(guò)編譯進(jìn)內(nèi)核來(lái)實(shí)現(xiàn)的,對(duì)驅(qū)動(dòng)程序稍微做點(diǎn)改動(dòng),就要重新燒寫一遍內(nèi)核,而且燒寫內(nèi)核經(jīng)常容易出錯(cuò),還占用資源。模塊采用的則是另一種途徑,內(nèi)核提供一個(gè)插槽,它就像一個(gè)插件,在需要時(shí),插入內(nèi)核中使用,不需要時(shí)從內(nèi)核中拔出。這一切都由一個(gè)稱為Kerneld的守護(hù)進(jìn)程自動(dòng)處理。2.模塊化的優(yōu)缺點(diǎn)內(nèi)核模塊的動(dòng)態(tài)加載具有以下優(yōu)點(diǎn):將內(nèi)核映像的尺寸保持在最小,并具有最大的靈活性。這便于檢驗(yàn)新的內(nèi)核代碼,而不需要重新編譯內(nèi)核并重新引導(dǎo)。但是,內(nèi)核模塊的引入也對(duì)系統(tǒng)性能和內(nèi)存的利用有負(fù)面影響。裝入的內(nèi)核模塊與其他內(nèi)核部分一樣,具有相同的訪問(wèn)權(quán)限,由此可見(jiàn),差的內(nèi)核模塊會(huì)導(dǎo)致系統(tǒng)崩潰。為了使內(nèi)核模塊能訪問(wèn)所有內(nèi)核資源,內(nèi)核必須維護(hù)符號(hào)表,并在加載和卸載模塊時(shí)修改這些符號(hào)表。由于有些模塊要求利用其他模塊的功能,故內(nèi)核要維護(hù)模塊之間的依賴性。內(nèi)核必須能夠在卸載模塊時(shí)通知模塊,并且要釋放分配給模塊的內(nèi)存和中斷等資源。內(nèi)核版本和模塊版本的不兼容也可能導(dǎo)致系統(tǒng)崩潰,因此,嚴(yán)格的版本檢查是必需的。盡管內(nèi)核模塊的引入同時(shí)帶來(lái)不少問(wèn)題,但是模塊機(jī)制確實(shí)是擴(kuò)充內(nèi)核功能的一種行之有效的方法,也是在內(nèi)核級(jí)進(jìn)行編程的有效途徑。,設(shè)備注冊(cè)和初始化,設(shè)備的驅(qū)動(dòng)程序在加載的時(shí)候首先需要調(diào)用入口函數(shù)init_module(),該函數(shù)最重要的一個(gè)工作就是向內(nèi)核注冊(cè)該設(shè)備,對(duì)于字符設(shè)備調(diào)用register_chrdev()完成注冊(cè)。register_chrdev的定義為:intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);其中,major是為設(shè)備驅(qū)動(dòng)程序向系統(tǒng)申請(qǐng)的主設(shè)備號(hào),如果為0,則系統(tǒng)為此驅(qū)動(dòng)程序動(dòng)態(tài)分配一個(gè)主設(shè)備號(hào)。name是設(shè)備名,fops是對(duì)各個(gè)調(diào)用的入口點(diǎn)說(shuō)明。此函數(shù)返回0時(shí)表示成功;返回-EINVAL,表示申請(qǐng)的主設(shè)備號(hào)非法,主要原因是主設(shè)備號(hào)大于系統(tǒng)所允許的最大設(shè)備號(hào);返回-EBUSY,表示所申請(qǐng)的主設(shè)備號(hào)正在被其他設(shè)備程序使用。如果動(dòng)態(tài)分配主設(shè)備號(hào)成功,此函數(shù)將返回所分配的主設(shè)備號(hào)。如果register_chrdev()操作成功,設(shè)備名就會(huì)出現(xiàn)在/proc/dvices文件中。Linux在/dev目錄中為每個(gè)設(shè)備建立一個(gè)文件,用ls–l命令列出函數(shù)返回值,若小于0,則表示注冊(cè)失?。环祷?或者大于0的值表示注冊(cè)成功。注冊(cè)以后,Linux將設(shè)備名與主、次設(shè)備號(hào)聯(lián)系起來(lái)。當(dāng)有對(duì)此設(shè)備名的訪問(wèn)時(shí),Linux通過(guò)請(qǐng)求訪問(wèn)的設(shè)備名得到主、次設(shè)備號(hào),然后把此訪問(wèn)分發(fā)到對(duì)應(yīng)的設(shè)備驅(qū)動(dòng),設(shè)備驅(qū)動(dòng)再根據(jù)次設(shè)備號(hào)調(diào)用不同的函數(shù)。當(dāng)設(shè)備驅(qū)動(dòng)模塊從Linux內(nèi)核中卸載,對(duì)應(yīng)的主設(shè)備號(hào)必須被釋放。字符設(shè)備在cleanup_module()函數(shù)中調(diào)用unregister_chrdev()來(lái)完成設(shè)備的注銷。unregister_chrdev()的定義為:intunregister_chrdev(unsignedintmajor,constchar*name);此函數(shù)的參數(shù)為主設(shè)備號(hào)major和設(shè)備名name。Linux內(nèi)核把name和major在內(nèi)核注冊(cè)的名稱對(duì)比,如果不相等,卸載失敗,并返回?EINVAL;如果major大于最大的設(shè)備號(hào),也返回?EINVAL。,包括設(shè)備注冊(cè)在內(nèi),設(shè)備驅(qū)動(dòng)的初始化函數(shù)主要完成的功能是有以下5項(xiàng)。(1)對(duì)驅(qū)動(dòng)程序管理的硬件進(jìn)行必要的初始化。對(duì)硬件寄存器進(jìn)行設(shè)置。比如,設(shè)置中斷掩碼,設(shè)置串口的工作方式、并口的數(shù)據(jù)方向等。(2)初始化設(shè)備驅(qū)動(dòng)相關(guān)的參數(shù)。一般說(shuō)來(lái),每個(gè)設(shè)備都要定義一個(gè)設(shè)備變量,用以保存設(shè)備相關(guān)的參數(shù)。在這一步驟里對(duì)設(shè)備變量中的項(xiàng)進(jìn)行初始化。(3)在內(nèi)核注冊(cè)設(shè)備。調(diào)用register_chrdev()函數(shù)來(lái)注冊(cè)設(shè)備。(4)注冊(cè)中斷。如果設(shè)備需要IRQ支持,則要使用request_irq()函數(shù)注冊(cè)中斷。(5)其他初始化工作。初始化部分一般還負(fù)責(zé)給設(shè)備驅(qū)動(dòng)程序申請(qǐng)包括內(nèi)存、時(shí)鐘、I/O端口等在內(nèi)的系統(tǒng)資源,這些資源也可以在open子程序或者其他地方申請(qǐng)。這些資源不用時(shí),應(yīng)該釋放,以利于資源的共享。若驅(qū)動(dòng)程序是內(nèi)核的一部分,初始化函數(shù)則要按如下方式聲明:int__initchr_driver_init(void);其中__init是必不可少的,在系統(tǒng)啟動(dòng)時(shí)會(huì)由內(nèi)核調(diào)用chr_driver_init,完成驅(qū)動(dòng)程序的初始化。當(dāng)驅(qū)動(dòng)程序是以模塊的形式編寫時(shí),則要按照如下方式聲明:intinit_module(void)當(dāng)運(yùn)行后面介紹的insmod命令插入模塊時(shí),會(huì)調(diào)用init_module函數(shù)完成初始化工作。,中斷管理,設(shè)備驅(qū)動(dòng)程序通過(guò)調(diào)用request_irq函數(shù)來(lái)申請(qǐng)中斷,通過(guò)free_irq來(lái)釋放中斷。它們?cè)趌inux/sched.h中的定義如下:intrequest_irq(unsignedintirq,void(*handler)(intirq,voiddev_id,structpt_regs*regs),unsignedlongflags,constchar*device,void*dev_id);voidfree_irq(unsignedintirq,void*dev_id);通常從request_irq函數(shù)返回的值為0時(shí),表示申請(qǐng)成功;負(fù)值表示出現(xiàn)錯(cuò)誤。?irq表示所要申請(qǐng)的硬件中斷號(hào)。?handler為向系統(tǒng)登記的中斷處理子程序,中斷產(chǎn)生時(shí)由系統(tǒng)來(lái)調(diào)用,調(diào)用時(shí)所帶參數(shù)irq為中斷號(hào),dev_id為申請(qǐng)時(shí)告訴系統(tǒng)的設(shè)備標(biāo)識(shí),regs為中斷發(fā)生時(shí)寄存器內(nèi)容。?device為設(shè)備名,將會(huì)出現(xiàn)在/proc/interrupts文件里。?flag是申請(qǐng)時(shí)的選項(xiàng),它決定中斷處理程序的一些特性,其中最重要的是決定中斷處理程序是快速處理程序(flag里設(shè)置了SA_INTERRUPT)還是慢速處理程序(不設(shè)置SA_INTERRUPT)。下面的代碼將在SBC-2410X的Linux中注冊(cè)外部中斷2。eint_irq=IRQ_EINT2;set_external_irq(eint_irq,EXT_FALLING_EDGE,GPIO_PULLUP_DIS);ret_val=request_irq(eint_irq,eint2_handler,“S3C2410Xeint2”,0);if(ret_valGPIO_MODE_SHIFT)#defineGRAB_PULLUP(x)(((x)2.入口函數(shù)模塊的入口函數(shù)leds_init(),所做的工作是點(diǎn)亮I/O端口對(duì)應(yīng)的LED,這些二極管可以作為狀態(tài)指示之用。register_chrdev()完成字符設(shè)備在系統(tǒng)中的注冊(cè),并建立與文件系統(tǒng)的并聯(lián)。staticint__initleds_init(void){intret;inti;/*在內(nèi)核中注冊(cè)設(shè)備*/ret=register_chrdev(LED_MAJOR,DEVICE_NAME,},3.字符設(shè)備定義staticdevfs_handle_tdevfs_handle;4.ioctlioctl入口,執(zhí)行讀、寫之外的操作,通過(guò)參數(shù)cmd設(shè)定命令參數(shù)。staticintleds_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg){switch(cmd){case0:case1:if(arg>4){return-EINVAL;}write_gpio_bit(led_table[arg],!cmd);default:return-EINVAL;}}5.文件系統(tǒng)接口定義staticstructfile_operationsleds_fops={owner:THIS_MODULE,ioctl:leds_ioctl,};6.模塊化module_init(leds_init);module_exit(leds_exit);用insmod命令加載模塊時(shí),調(diào)用module_init();用rmmod命令來(lái)卸載模塊時(shí),調(diào)用module_exit()函數(shù)。,加載運(yùn)行LED驅(qū)動(dòng)程序,1.應(yīng)用程序設(shè)計(jì)#include#include#include#includeintmain(intargc,char**argv){inton;intled_no;intfd;if(argc!=3||sscanf(argv[1],"%d",}該程序首先讀取命令行的參數(shù)輸入,其中參數(shù)argv[1]賦值給led_no,表示發(fā)光二極管的序號(hào);argv[2]賦值給on。led_no的取值范圍是1~3,on取值為0或1,0表示熄滅LED,1表示點(diǎn)亮LED。參數(shù)輸入后通過(guò)fd=open("/dev/leds",0)打開(kāi)設(shè)備文件,在保證參數(shù)輸入正確和設(shè)備文件正確打開(kāi)后,通過(guò)語(yǔ)句ioctl(fd,on,led_no)實(shí)現(xiàn)系統(tǒng)調(diào)用ioctl,并通過(guò)輸入的參數(shù)控制LED。在程序的最后關(guān)閉設(shè)備句柄。,嵌入式圖形用戶界面開(kāi)發(fā)——Qt/Embedded,,GUI概述,目前的桌面機(jī)操作系統(tǒng)大多有著美觀、操作方便、功能齊全的GUI(圖形用戶界面),例如KDE或者GNOME。GUI(圖形用戶界面)是指計(jì)算機(jī)與其使用者之間的對(duì)話接口,可以說(shuō),GUI是當(dāng)今計(jì)算機(jī)技術(shù)的重大成就。它的存在為使用者提供了友好便利的界面,并大大地方便了非專業(yè)用戶的使用,使得人們從繁瑣的命令中解脫出來(lái),可以通過(guò)窗口、菜單方便地進(jìn)行操作。UNIX環(huán)境下的圖形視窗標(biāo)準(zhǔn)為XWindowSystem,Linux是類UNIX系統(tǒng),所以頂層運(yùn)行的GUI系統(tǒng)是兼容X標(biāo)準(zhǔn)的XFree86系統(tǒng)。X標(biāo)準(zhǔn)大致可以劃分XServer、GraphicLibrary(底層繪圖函數(shù)庫(kù))、Toolkits、WindowManager等幾大部分。其好處是具有可擴(kuò)展性、可移植性等優(yōu)點(diǎn),但對(duì)于嵌入式系統(tǒng)而言無(wú)疑太過(guò)龐大、累贅、低效。目前流行的嵌入式GUI與X思路不同,這些GUI一般不局限于X標(biāo)準(zhǔn),更強(qiáng)調(diào)系統(tǒng)的空間和效率。,嵌入式GUI的特點(diǎn),在嵌入式系統(tǒng)中,GUI的地位也越來(lái)越重要,但是不同于桌面機(jī)系統(tǒng),嵌入式GUI要求簡(jiǎn)單、直觀、可靠、占用資源小且反應(yīng)快速,以適應(yīng)系統(tǒng)硬件資源有限的條件。另外,由于嵌入式系統(tǒng)硬件本身的特殊性,嵌入式GUI應(yīng)具備高度可移植性與可裁減性,以適應(yīng)不同的硬件條件和使用需求。?體積??;?運(yùn)行時(shí)耗用系統(tǒng)資源小;?上層接口與硬件無(wú)關(guān),高度可移植;?高可靠性;?在某些應(yīng)用場(chǎng)合應(yīng)具備實(shí)時(shí)性。,Qt/Embedded的特點(diǎn),MiniGUI(1),提起國(guó)內(nèi)的開(kāi)源軟件,就肯定會(huì)提到MiniGUI,它由魏永明先生和眾多志愿者開(kāi)發(fā),是一個(gè)基于Linux的實(shí)時(shí)嵌入式系統(tǒng)的輕量級(jí)圖形用戶界面支持系統(tǒng)。MiniGUI分為最底層的GAL層和IAL層,向上為基于標(biāo)準(zhǔn)POSIX接口中pthread庫(kù)的Mini-thread架構(gòu)和基于Server/Client的Mini-Lite架構(gòu)。其中前者受限于thread模式對(duì)于整個(gè)系統(tǒng)的可靠性——進(jìn)程中某個(gè)thread的意外錯(cuò)誤可能導(dǎo)致整個(gè)進(jìn)程的崩潰,該架構(gòu)應(yīng)用于系統(tǒng)功能較為單一的場(chǎng)合。Mini-Lite應(yīng)用于多進(jìn)程的應(yīng)用場(chǎng)合,采用多進(jìn)程運(yùn)行方式設(shè)計(jì)的Server/Client架構(gòu)能夠較好地解決各個(gè)進(jìn)程之間的窗口管理、Z序剪切等問(wèn)題。MiniGUI還有一種從Mini-Lite衍生出的standalone運(yùn)行模式。與Lite架構(gòu)不同的是,standalone模式一次只能以窗口最大化的方式顯示一個(gè)窗口。這在顯示屏尺寸較小的應(yīng)用場(chǎng)合具有一定的應(yīng)用意義。,MiniGUI(2),MiniGUI的IAL層技術(shù)SVGAlib、LibGGI、基于framebuffer的native圖形引擎以及啞圖形引擎等,對(duì)于Trolltech公司的QVFB在XWindow下也有較好的支持。IAL層則支持Linux標(biāo)準(zhǔn)控制臺(tái)下的GPM鼠標(biāo)服務(wù)、觸摸屏、標(biāo)準(zhǔn)鍵盤等。MiniGUI下豐富的控件資源也是MiniGUI的特點(diǎn)之一。MiniGUI免費(fèi)版本是1.3.3。在該版本的控件中已經(jīng)添加了窗口皮膚、工具條等桌面GUI中的高級(jí)控件支持。對(duì)比其他系統(tǒng),“Mini”是MiniGUI的特色,輕量、高性能和高效率的MiniGUI已經(jīng)應(yīng)用在電視機(jī)頂盒、實(shí)時(shí)控制系統(tǒng)、掌上電腦等諸多場(chǎng)合。,Microwindows,MicrowindowsOpenSourceProject成立的宗旨在于針對(duì)體積小的裝置,建立一套先進(jìn)的視窗環(huán)境,在Linux桌面上通過(guò)交叉編譯可以很容易地制作出Microwindows的程序。Microwindows能夠在沒(méi)有任何操作系統(tǒng)或其他圖形系統(tǒng)的支持下運(yùn)行,它能對(duì)裸顯示設(shè)備進(jìn)行直接操作。這樣,Microwindows就顯得十分小巧,便于移植到各種硬件和軟件系統(tǒng)上。然而Microwindows的免費(fèi)版本進(jìn)展一直很慢,幾乎處于停頓狀態(tài),而且至今為止,國(guó)內(nèi)沒(méi)有任何一家對(duì)Microwindows提供全面技術(shù)支持、服務(wù)和擔(dān)保的專業(yè)公司。,常用GUI比較,Qt/Embedded架構(gòu),Qt/Embedded以原始Qt為基礎(chǔ),并做了許多出色的調(diào)整以適用于嵌入式環(huán)境。Qt/Embedded通過(guò)QtAPI與LinuxI/O設(shè)施直接交互,成為嵌入式Linux端口。同Qt/X11相比,Qt/Embedded很省內(nèi)存,因?yàn)樗恍枰粋€(gè)X服務(wù)器或是Xlib庫(kù),它在底層拋棄了Xlib,采用framebuffer作為底層圖形接口。同時(shí),將外部輸入設(shè)備抽象為keyboard和mouse輸入事件。,,Qt/Embedded窗口系統(tǒng),一個(gè)Qt/Embedded窗口系統(tǒng)包含了一個(gè)或多個(gè)進(jìn)程,其中的一個(gè)進(jìn)程可作為服務(wù)器。該服務(wù)進(jìn)程會(huì)分配客戶顯示區(qū)域,以及產(chǎn)生鼠標(biāo)和鍵盤事件。該服務(wù)進(jìn)程還能夠提供輸入方法和一個(gè)用戶接口給運(yùn)行起來(lái)的客戶應(yīng)用程序。該服務(wù)進(jìn)程其實(shí)就是一個(gè)有某些額外權(quán)限的客戶進(jìn)程??蛻襞c服務(wù)器之間的通信使用共享內(nèi)存的方法實(shí)現(xiàn),通信量應(yīng)該保持最小。這就是Qt/Embedded庫(kù)內(nèi)部層次分明的處理過(guò)程。QProcess類提供了另外一種異步的進(jìn)程間通信機(jī)制。它用于啟動(dòng)一個(gè)外部的程序并且通過(guò)寫一個(gè)標(biāo)準(zhǔn)的輸入和讀取外部程序的標(biāo)準(zhǔn)輸出和錯(cuò)誤碼來(lái)和它們通信。,Qt/Embedded字體(1),Qt/Embedded支持四種不同的字體格式:TrueType字體(TTF),PostscriptType1字體,位圖發(fā)布字體(BDF)和Qt的預(yù)呈現(xiàn)(Pre-rendered)字體(QPF)。Qt還可以通過(guò)增加QFontFactory的子類來(lái)支持其他字體,也可以支持以插件方式出現(xiàn)的反別名字體。每個(gè)TTF或者TYPE1類型的字體首次在圖形或者文本方式的環(huán)境下被使用時(shí),這些字體的字形都會(huì)以指定的大小被預(yù)先呈現(xiàn)出來(lái),呈現(xiàn)的結(jié)果會(huì)被緩沖。根據(jù)給定的字體尺寸(例如10或12點(diǎn)陣)預(yù)先呈現(xiàn)TTF或者TYPE1類型的字體文件并把結(jié)果以QPF的格式保存起來(lái),這樣可以節(jié)省內(nèi)存和CPU的處理時(shí)間。,Qt/Embedded字體(2),QPF文件包含了一些必要的字體,這些字體可以通過(guò)makeqpf工具取得,或者通過(guò)運(yùn)行程序時(shí)加上“-savefonts”選項(xiàng)獲取。如果應(yīng)用程序中使用到的字體都是QPF格式,那么Qt/Embedded將被重新配置,并排除對(duì)TTF和TYPE1類型的字體的編譯,這樣就可以減少Q(mào)t/Embedded的庫(kù)的大小和存儲(chǔ)字體的空間。例如一個(gè)10點(diǎn)陣大小的包含所有ASCII字符的QPF字體文件的大小為1300Byte,這個(gè)文件可以直接從物理存儲(chǔ)格式映射成為內(nèi)存存儲(chǔ)格式。Qt/Embedded的字體通常包括Unicode字體的一部分子集,ASCII和Latin-1。,Qt/Embedded輸入設(shè)備及輸入法,Qt/Embedded3.0支持幾種鼠標(biāo)協(xié)議:BusMouse、IntelliMouse,Microsoft和MouseMan.Qt/Embedded還支持NECVr41XX和iPAQ的觸摸屏。通過(guò)從QWSMouseHandler或者Qcalibra-tedMouseHandler派生子類,開(kāi)發(fā)人員可以讓Qt/Embedded支持更多的客戶指示設(shè)備。對(duì)于非拉丁語(yǔ)系字符(例如阿拉伯,中文,希伯來(lái)和日語(yǔ))的輸入法,需要把它寫成過(guò)濾器的方式,并改變鍵盤的輸入。輸入法的作者應(yīng)該對(duì)全部的QtAPI的使用有完整的認(rèn)識(shí)。在一個(gè)無(wú)鍵盤的設(shè)備上,輸入法成了惟一的輸入字符的手段。Qtopia提供了4種輸入方法:筆跡識(shí)別器、圖形化的標(biāo)準(zhǔn)鍵盤、Unicode鍵盤和基于字典方式提取的鍵盤。,Qt/Embedded屏幕加速,通過(guò)子類化QScreen和QgfxRaster可以實(shí)現(xiàn)硬件加速,從而為屏幕操作帶來(lái)好處。Troll-tech提供了Mach64和Voodoo3視頻卡的硬件加速的驅(qū)動(dòng)例子,同時(shí)可以按照協(xié)議編寫其他的驅(qū)動(dòng)程序。,Qt的支撐工具,Qt包含了許多支持嵌入式系統(tǒng)開(kāi)發(fā)的工具,有兩個(gè)最實(shí)用的工具是qmake和Qtdesigner(圖形設(shè)計(jì)器)。?qmake是一個(gè)為編譯Qt/Embedded庫(kù)和應(yīng)用而提供的Makefile生成器。它能夠根據(jù)一個(gè)工程文件(.pro)產(chǎn)生不同平臺(tái)下的Makefile文件。qmake支持跨平臺(tái)開(kāi)發(fā)和影子生成(影子生成是指當(dāng)工程的源代碼共享給網(wǎng)絡(luò)上的多臺(tái)機(jī)器時(shí),每臺(tái)機(jī)器編譯鏈接這個(gè)工程的代碼將在不同的子路徑下完成,這樣就不會(huì)覆蓋別人的編譯鏈接生成的文件。qmake還易于在不同的配置之間切換。)?Qt圖形設(shè)計(jì)器可以使開(kāi)發(fā)者可視化地設(shè)計(jì)對(duì)話框而不需編寫代碼。使用Qt圖形設(shè)計(jì)器的布局管理可以生成能平滑改變尺寸的對(duì)話框。qmake和Qt圖形設(shè)計(jì)器是完全集成在一起的。,Qt/Embedded信號(hào)和插槽機(jī)制(1),信號(hào)和插槽機(jī)制是Qt的核心機(jī)制,要精通Qt編程就必須對(duì)信號(hào)和插槽有所了解。信號(hào)和插槽是一種高級(jí)接口,應(yīng)用于對(duì)象之間的通信,它是Qt的核心特性,也是Qt區(qū)別于其他工具包的重要地方。信號(hào)和插槽是Qt自行定義的一種通信機(jī)制,它獨(dú)立于標(biāo)準(zhǔn)的C/C++語(yǔ)言,必須借助一個(gè)稱為moc(MetaObjectCompiler)的Qt工具,該工具是一個(gè)C++預(yù)處理程序,它為高層次的事件處理自動(dòng)生成所需要的附加代碼。信號(hào)與插槽機(jī)制是一種強(qiáng)有力的對(duì)象間通信機(jī)制,完全可以取代原始的回調(diào)和消息映射機(jī)制。在Qt中信號(hào)和插槽取代了上述這些凌亂的函數(shù)指針,使得用戶編寫這些通信程序更為簡(jiǎn)潔明了。信號(hào)和插槽能攜帶任意數(shù)量和任意類型的參數(shù),他們是類型完全安全的,因此不會(huì)像回調(diào)函數(shù)那樣產(chǎn)生coredumps。,Qt/Embedded信號(hào)和插槽機(jī)制(2),所有從QObject或其子類(例如Qwidget)派生的類都能夠包含信號(hào)和插槽。當(dāng)對(duì)象改變狀態(tài)時(shí),信號(hào)就由該對(duì)象發(fā)射(emit)出去了,這就是對(duì)象所要做的全部工作,它不知道另一端是誰(shuí)在接收這個(gè)信號(hào)。這就是真正的信息封裝,它確保對(duì)象被當(dāng)作一個(gè)真正的軟件組件來(lái)使用。插槽用于接收信號(hào),但它們是普通的對(duì)象成員函數(shù)。一個(gè)插槽并不知道是否有任何信號(hào)與自己相連接。而且,對(duì)象并不了解具體的通信機(jī)制。用戶可以將很多信號(hào)與單個(gè)插槽進(jìn)行連接,也可以將單個(gè)信號(hào)與很多插槽進(jìn)行連接,甚至將一個(gè)信號(hào)與另外一個(gè)信號(hào)相連接也是可能的,這時(shí)無(wú)論第一個(gè)信號(hào)什么時(shí)候發(fā)射,系統(tǒng)都將立刻發(fā)射第二個(gè)信號(hào)??傊盘?hào)與插槽構(gòu)造了一個(gè)強(qiáng)大的部件編程機(jī)制。,Qt/Embedded信號(hào)和插槽機(jī)制(3),,信號(hào),當(dāng)某個(gè)信號(hào)對(duì)其客戶或所有者內(nèi)部狀態(tài)發(fā)生改變時(shí),信號(hào)就被一個(gè)對(duì)象發(fā)射。只有定義了這個(gè)信號(hào)的類及其派生類才能夠發(fā)射這個(gè)信號(hào)。當(dāng)一個(gè)信號(hào)被發(fā)射時(shí),與其相關(guān)聯(lián)的插槽將被立刻執(zhí)行,就像一個(gè)正常的函數(shù)調(diào)用一樣。信號(hào)-插槽機(jī)制完全獨(dú)立于任何GUI事件循環(huán)。只有當(dāng)所有的槽返回以后發(fā)射函數(shù)(emit)才返回。如果存在多個(gè)槽與某個(gè)信號(hào)相關(guān)聯(lián),那么,當(dāng)這個(gè)信號(hào)被發(fā)射時(shí),這些槽將會(huì)一個(gè)接一個(gè)地執(zhí)行,但是它們執(zhí)行的順序?qū)?huì)是隨機(jī)的、不確定的,用戶不能人為地指定哪個(gè)先執(zhí)行、哪個(gè)后執(zhí)行。,信號(hào)示例:signals:voidmySignal();voidmySignal(intx);voidmySignalParam(intx,inty);,插槽示例:publicslots:voidmySlot();voidmySlot(intx);voidmySignalParam(intx,inty);,插槽,插槽是普通的C++成員函數(shù),可以被正常調(diào)用,它們惟一的特殊性就是很多信號(hào)可以與其相關(guān)聯(lián)。插槽可以有參數(shù),但插槽的參數(shù)不能有缺省值。插槽函數(shù)也分為3種類型,即publicslots、privateslots和protectedslots。?publicslots:在這個(gè)區(qū)內(nèi)聲明的槽意味著任何對(duì)象都可將信號(hào)與之相連接。這對(duì)于組件編程非常有用,用戶可以創(chuàng)建彼此互不了解的對(duì)象,將它們的信號(hào)與槽進(jìn)行連接以便信息能夠正確地傳遞。?protectedslots:在這個(gè)區(qū)內(nèi)聲明的槽意味著當(dāng)前類及其子類可以將信號(hào)與之相連接。這適用于那些槽,它們是類實(shí)現(xiàn)的一部分,但是其界面接口卻面向外部。?privateslots:在這個(gè)區(qū)內(nèi)聲明的槽意味著只有類自己可以將信號(hào)與之相連接。這適用于聯(lián)系非常緊密的類。,信號(hào)與插槽關(guān)聯(lián),通過(guò)調(diào)用QObject對(duì)象的connect()函數(shù)可以將某個(gè)對(duì)象的信號(hào)與另外一個(gè)對(duì)象的插槽函數(shù)或信號(hào)相關(guān)聯(lián),當(dāng)發(fā)射者發(fā)射信號(hào)時(shí),接收者的槽函數(shù)或信號(hào)將被調(diào)用。這個(gè)函數(shù)的作用就是將發(fā)射者sender對(duì)象中的信號(hào)signal與接收者receiver中的member插槽函數(shù)聯(lián)系起來(lái)。當(dāng)指定信號(hào)signal時(shí)必須使用Qt的宏SIGNAL(),當(dāng)指定插槽函數(shù)時(shí)必須使用宏SLOT()。如果發(fā)射者與接收者屬于同一個(gè)對(duì)象的話,那么在connect()調(diào)用中接收者參數(shù)可以省略。,boolQObject::connect(constQObject*sender,constchar*signal,constQObject*receiver,constchar*member)[static],解除信號(hào)與插槽關(guān)聯(lián),當(dāng)信號(hào)與槽沒(méi)有必要繼續(xù)保持關(guān)聯(lián)時(shí),用戶可以使用disconnect()函數(shù)來(lái)斷開(kāi)連接。有3種情況必須使用disconnect()函數(shù)。?斷開(kāi)與某個(gè)對(duì)象相關(guān)聯(lián)的任何對(duì)象?斷開(kāi)與某個(gè)特定信號(hào)的任何關(guān)聯(lián)?斷開(kāi)兩個(gè)對(duì)象之間的關(guān)聯(lián),boolQObject::disconnect(constQObject*sender,constchar*signal,constObject*receiver,constchar*member)[static],常見(jiàn)通用窗口組合(1),常見(jiàn)通用窗口組合(2),- 1.請(qǐng)仔細(xì)閱讀文檔,確保文檔完整性,對(duì)于不預(yù)覽、不比對(duì)內(nèi)容而直接下載帶來(lái)的問(wèn)題本站不予受理。
- 2.下載的文檔,不會(huì)出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請(qǐng)點(diǎn)此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
9.9 積分
下載 |
- 配套講稿:
如PPT文件的首頁(yè)顯示word圖標(biāo),表示該P(yáng)PT已包含配套word講稿。雙擊word圖標(biāo)可打開(kāi)word文檔。
- 特殊限制:
部分文檔作品中含有的國(guó)旗、國(guó)徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計(jì)者僅對(duì)作品中獨(dú)創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- 嵌入式 Linux 驅(qū)動(dòng)程序 QT
鏈接地址:http://m.appdesigncorp.com/p-11531299.html