王志超,王宜懷
(1.宿遷學(xué)院計(jì)算機(jī)科學(xué)系,宿遷223800;2.蘇州大學(xué))
構(gòu)件本質(zhì)上是把對(duì)象對(duì)外的接口聲明與對(duì)象內(nèi)部的接口實(shí)現(xiàn)相隔離,一個(gè)構(gòu)件在修改自己的接口時(shí),只影響與修改接口相交互的構(gòu)件,與被修改構(gòu)件相交互的其他構(gòu)件不受影響,因此它的重用性和可擴(kuò)展性更高[1]。
嵌入式底層構(gòu)件(Embedded Underlying Component,EUC)是在硬件構(gòu)件的基礎(chǔ)上,根據(jù)硬件構(gòu)件的實(shí)際功能和接口,實(shí)現(xiàn)與之相對(duì)應(yīng)的硬件驅(qū)動(dòng)模塊的分解,并將硬件驅(qū)動(dòng)底層程序的實(shí)現(xiàn)、頭文件定義及其文件描述封裝成一個(gè)可重用的構(gòu)件實(shí)體,并提供一系列規(guī)范的輸入/輸出接口,供其他嵌入式應(yīng)用程序調(diào)用。底層構(gòu)件同硬件構(gòu)件一樣,也具有被獨(dú)立部署和被第三方組裝的特性[2]。而嵌入式底層軟件則與嵌入式系統(tǒng)硬件模塊相關(guān)聯(lián),具體實(shí)現(xiàn)硬件構(gòu)件功能的程序代碼。
嵌入式軟件構(gòu)件(Embedded Software Componen t,ESC)是實(shí)現(xiàn)一定嵌入式系統(tǒng)功能的一組封裝的、規(guī)范的、可移植的、具有嵌入特性的軟件單元,是組織嵌入式系統(tǒng)的功能單位。
嵌入式軟件構(gòu)件分為高層軟件構(gòu)件和底層軟件構(gòu)件(以下簡(jiǎn)稱“高層構(gòu)件”和“底層構(gòu)件”)。高層構(gòu)件與硬件無(wú)關(guān),而底層構(gòu)件與硬件密不可分,是硬件驅(qū)動(dòng)程序的封裝。在硬件構(gòu)件中,核心構(gòu)件為MCU的最小系統(tǒng)。通常,MCU內(nèi)部包含有GPIO(即通用I/O)口和一些內(nèi)置功能模塊,開發(fā)者可以將通用I/O口的驅(qū)動(dòng)程序封裝為GPIO構(gòu)件。各內(nèi)置功能模塊的驅(qū)動(dòng)程序封裝為功能構(gòu)件,如Freescale公司的MCF52233的功能構(gòu)件有UART構(gòu)件、Flash構(gòu)件、USB構(gòu)件、I2C構(gòu)件等。
在硬件構(gòu)件中,相對(duì)于核心構(gòu)件而言,中間構(gòu)件和終端構(gòu)件是核心構(gòu)件的“外設(shè)”。由這些“外設(shè)”的驅(qū)動(dòng)程序封裝而成的軟件構(gòu)件稱為底層外設(shè)構(gòu)件。不過(guò),值得注意的是,并不是所有的中間構(gòu)件和終端構(gòu)件都可以作為編程對(duì)象[3-4]。例如:鍵盤、LED、LCD等硬件構(gòu)件與編程有關(guān),而電平轉(zhuǎn)換硬件構(gòu)件就與編程無(wú)關(guān),因而不存在相應(yīng)的底層驅(qū)動(dòng)程序,當(dāng)然也就沒(méi)有相應(yīng)的軟件構(gòu)件。
嵌入式硬件構(gòu)件與軟件構(gòu)件的層次模型如圖1所示。底層外設(shè)構(gòu)件可以調(diào)用底層內(nèi)部構(gòu)件,例如LCD構(gòu)件可以調(diào)用GPIO構(gòu)件,PCF8563構(gòu)件(時(shí)鐘構(gòu)件)可以調(diào)用I2C構(gòu)件等。而高層構(gòu)件可以調(diào)用底層外設(shè)構(gòu)件和底層內(nèi)部構(gòu)件中的功能構(gòu)件,而不能直接調(diào)用GPIO構(gòu)件。另外,考慮到幾乎所有的底層內(nèi)部構(gòu)件都涉及到MCU各種寄存器的使用,因此將MCU的所有寄存器定義組織在一起,形成MCU頭文件,以便其他構(gòu)件頭文件中包含該頭文件[5-6]。
圖1 嵌入式硬件構(gòu)件與軟件構(gòu)件的層次模型
底層構(gòu)件是與硬件直接打交道的軟件,由頭文件和源程序文件兩部分組成。
頭文件中的內(nèi)容主要有:包含下層構(gòu)件頭文件的#include語(yǔ)句、用于描述構(gòu)件屬性的宏定義語(yǔ)句以及對(duì)外接口函數(shù)原型說(shuō)明。在頭文件中使用函數(shù)原型,對(duì)于建立代碼模塊和外部接口的規(guī)范、便于他人使用,都是很有幫助的。使用這些函數(shù)的用戶,不需要查找源代碼去了解參數(shù)的具體類型,直接查看函數(shù)原型即可。
源程序文件中存放構(gòu)件的內(nèi)部函數(shù)和外部函數(shù)的定義,即函數(shù)的實(shí)現(xiàn)代碼,以實(shí)現(xiàn)函數(shù)的功能。
在對(duì)底層構(gòu)件進(jìn)行設(shè)計(jì)時(shí),最關(guān)鍵的工作是要對(duì)構(gòu)件的共性和個(gè)性進(jìn)行分析,抽取出構(gòu)件的屬性和對(duì)外接口函數(shù)。盡可能做到:當(dāng)一個(gè)底層構(gòu)件應(yīng)用到不同系統(tǒng)中時(shí),僅需修改構(gòu)件的頭文件,對(duì)于構(gòu)件的源程序文件則不必修改或改動(dòng)很小。
例如,串行通信模塊SCI是大多數(shù)MCU都具有的內(nèi)部模塊。仔細(xì)分析各種MCU串行通信程序發(fā)現(xiàn):在查詢方式下,各種MCU都是根據(jù)狀態(tài)寄存器中的兩個(gè)標(biāo)志位來(lái)判斷是否接收到數(shù)據(jù)和數(shù)據(jù)是否發(fā)送完畢,這就是SCI模塊的共性。對(duì)于不同的MCU,該狀態(tài)寄存器的名稱可能不同,這兩個(gè)標(biāo)志位的位號(hào)也有可能不同。此外,用以設(shè)置波特率、通信格式、是否校驗(yàn)、是否允許中斷等參數(shù)的寄存器也不同,這就是SCI模塊的個(gè)性。分析出了共性和個(gè)性之后,就可以抽取出SCI構(gòu)件的屬性和操作,編制構(gòu)件頭文件和程序文件了。
以Freescale公司的MC68HC908GP32的SCI模塊為例,數(shù)據(jù)寄存器名稱為SCDR,空標(biāo)志位(第7位)和滿標(biāo)志位(第5位)均位于狀態(tài)寄存器SCS1中。SCI構(gòu)件的頭文件(SCI.h)設(shè)計(jì)如下:
在編寫構(gòu)件時(shí),須注意以下幾方面的內(nèi)容:
①構(gòu)件的頭文件和源程序文件的主文件名一致,且為構(gòu)件名。
②屬性和操作的命名統(tǒng)一以構(gòu)件名開頭。這樣做的好處是,當(dāng)使用底層構(gòu)件組裝軟件系統(tǒng)時(shí),可以避免構(gòu)件之間出現(xiàn)同名現(xiàn)象;同時(shí),含義清晰、一目了然。
③對(duì)MCU內(nèi)的模塊寄存器名和端口名進(jìn)行重定義,其他的代碼都將使用宏名對(duì)模塊寄存器和端口進(jìn)行操作。這樣,當(dāng)?shù)讓域?qū)動(dòng)程序移植到其他MCU時(shí),只要修改重定義語(yǔ)句就可以了。
④內(nèi)部函數(shù)與外部函數(shù)要設(shè)計(jì)合理,函數(shù)參數(shù)個(gè)數(shù)及類型要考慮全面。內(nèi)部函數(shù)僅提供給同一構(gòu)件中的其他內(nèi)部函數(shù)或外部函數(shù)調(diào)用,作用域僅限于定義該函數(shù)的文件。外部函數(shù)是對(duì)外接口函數(shù),供上層應(yīng)用程序調(diào)用。在定義外部函數(shù)時(shí),應(yīng)該對(duì)函數(shù)名、函數(shù)功能、入口參數(shù)、函數(shù)返回值、使用說(shuō)明、函數(shù)適用范圍等進(jìn)行詳細(xì)描述,以增強(qiáng)程序的可讀性。上層應(yīng)用程序不能直接對(duì)構(gòu)件的屬性進(jìn)行讀取或設(shè)置,必須借助于該構(gòu)件提供的接口操作函數(shù)來(lái)實(shí)現(xiàn)。
⑤應(yīng)用程序在使用底層構(gòu)件時(shí),嚴(yán)格禁止通過(guò)全局變量來(lái)傳遞參數(shù),所有的數(shù)據(jù)傳遞都要通過(guò)函數(shù)的形式參數(shù)來(lái)接收。這樣做不但使得接口簡(jiǎn)潔,而且避免了全局變量可能引發(fā)的安全隱患。
當(dāng)一個(gè)已設(shè)計(jì)好的底層構(gòu)件移植到另外一個(gè)嵌入式系統(tǒng)中時(shí),其頭文件和程序文件是否需要改動(dòng),這要視具體情況而定。例如:系統(tǒng)的核心構(gòu)件發(fā)生改變(即MCU型號(hào)改變)時(shí),底層內(nèi)部構(gòu)件頭文件和某些對(duì)外接口函數(shù)也要隨之改變,如模塊初始化函數(shù)。以SCI構(gòu)件為例,由于不同MCU的SCI模塊的數(shù)據(jù)寄存器名稱、狀態(tài)寄存器名稱及位定義不同,初始化工作所涉及的波特率、通信格式、是否校驗(yàn)等設(shè)置值也不同,因此當(dāng)MCU改變時(shí),構(gòu)件頭文件中相關(guān)宏定義值和SCI_Init的函數(shù)體實(shí)現(xiàn)代碼也會(huì)有所不同。以Freescale公司的DG 128單片機(jī)為例,其有兩個(gè)串行口SCI0和SCI1。若使用串行口SCI0進(jìn)行收發(fā)數(shù)據(jù),則數(shù)據(jù)寄存器名稱為SCI0DRL,空標(biāo)志位(第7位)和滿標(biāo)志位(第5位)位于狀態(tài)寄存器SCI0SR1中。因此需要將MC68HC908GP32的SCI構(gòu)件頭文件中前三行修改成如下內(nèi)容:
底層構(gòu)件的編程方法在嵌入式系統(tǒng)的開發(fā)中具有舉足輕重的地位。底層軟件開發(fā)的成敗直接關(guān)系著整個(gè)系統(tǒng)穩(wěn)定性和可靠性的好壞。如果開發(fā)人員在編寫底層軟件時(shí)采用軟件工程思想的方法,就可以最大程度地使底層軟件具有良好的可移植性和復(fù)用性。不過(guò)必須說(shuō)明的是,本文提出構(gòu)件化設(shè)計(jì)方法的目的是,在進(jìn)行底層軟件移植時(shí),設(shè)計(jì)人員所做的改動(dòng)盡量小,而不是不作任何改動(dòng)。事實(shí)上,不作任何改動(dòng)是不現(xiàn)實(shí)的。
[1]王宜懷,陳建明,蔣銀珍.基于32位ColdFire構(gòu)建嵌入式系統(tǒng)[M].北京:電子工業(yè)出版社,2009:413-417.
[2]薦紅梅.基于硬件構(gòu)件的嵌入式底層軟件開發(fā)方法研究及其應(yīng)用[D].蘇州:蘇州大學(xué),2008:28-30.
[3]沙占友,王彥朋,孟志永.嵌入式外圍電路設(shè)計(jì)[M].北京:電子工業(yè)出版社,2003:161-173.
[4]桑楠.嵌入式系統(tǒng)原理及應(yīng)用開發(fā)設(shè)計(jì)[M].北京:北京航空航天大學(xué)出版社,2004:121-126.
[5]王宜懷,劉曉升.嵌入式應(yīng)用技術(shù)基礎(chǔ)教程[M].北京:清華大學(xué)出版社,2007:8-15.
[6]王志超.基于MC68HC908GP32的射頻卡密碼認(rèn)證系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[J].微計(jì)算機(jī)信息,2009:79-81.