<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 使用C++構建嵌入式開(kāi)發(fā)框架

使用C++構建嵌入式開(kāi)發(fā)框架

作者: 時(shí)間:2004-12-11 來(lái)源:網(wǎng)絡(luò ) 收藏
摘要:作為一種大粒度的重用技術(shù)在桌面軟件中得到了廣泛應用,而在領(lǐng)域,目前還沒(méi)有一套完整的標準可供。本文以通信領(lǐng)域的軟件為例,介紹C++語(yǔ)言,在A(yíng)RM平臺Nucleus plus操作系統下實(shí)現開(kāi)發(fā)EFC的方法和應用實(shí)例。

關(guān)鍵詞:框架 C++ ARM Nucleus MFC EFC 面向對象

1 框架概述

1.1 什么是框架

國外著(zhù)名的軟件設計大師Ralph Johnson對面向對象技術(shù)進(jìn)行了長(cháng)期而深入的研究。在他的主頁(yè)中,對框架進(jìn)行了如下定義:A framework is a reusable design expressed as a set of abstract classes and the way their instances collaborate.It is a reusable design for all or part of a software system.(框架是整個(gè)系統或系統的一部分的可重用性設計,由一組抽象出來(lái)的類(lèi)及其實(shí)例間的相互作用方式組成。)

框架把一個(gè)系統有機地分解成一組相對獨立的構件,并定義了各個(gè)構件間的接口和作用關(guān)系,符合軟件工程中設計的模塊化、獨立化和信息隱藏等特征??蚣芴峁┝艘粋€(gè)大粒度的重用技術(shù),即不僅支持源代碼級的重用,而且支持分析和設計以及體系結構的重用,因而被認為是一種最有前途的面向對象技術(shù)。

框架必須是健壯的、可擴展的、靈活的,它要求基于開(kāi)放或共享標準??蚣艿脑O計要力求做到完備性、靈活性、可擴展性、可理解性,同時(shí)抽象能用于不同的場(chǎng)合;用戶(hù)能輕松地添加和修改功能,定制框架;用戶(hù)和框架的交互清晰,文檔齊全??蚣茉O計的一個(gè)核心問(wèn)題就是發(fā)現可重用的設計和“熱點(diǎn)”,以保證框架具備充分的靈活性,戶(hù)能在已有構件的基礎上生成應用程序,實(shí)現“零代碼編寫(xiě)”的理想目標。

1.2 如何設計框架

目前框架的設計大都采用實(shí)踐法。實(shí)踐法是指從若干個(gè)具體的典型應用中,抽象出現似點(diǎn)來(lái)框架;框架反過(guò)來(lái)又應用于不同的問(wèn)題,并在解決不同問(wèn)題的過(guò)程中得到更新;在框架的設計和實(shí)現的兩步中,不斷反復,等到框架逐漸成熟時(shí),需要修改和反復的內容就會(huì )越來(lái)越小。具體步驟為:分析問(wèn)題域,確定所需框架,從一類(lèi)應用而不是單個(gè)的程序去分析、比較各種不同的軟件解決方案,尋求這些方案的共性和每個(gè)程度的唯一性特性。這些共性,尤其是那些經(jīng)常被多個(gè)程序使用的部分將成為框架的基礎。然后,定義框架體系結構并設計,包括設計用戶(hù)與框架間的交互、給用戶(hù)提供的最終工具等。

框架的實(shí)現:包括框架核心類(lèi)的實(shí)現、框架的測試、框架的試運行、框架的反復更新。

框架的部署:包括文檔的提供和分發(fā)過(guò)程、為用戶(hù)提供技術(shù)支持、維護和更新框架。

2 嵌入式框架EFC

框架技術(shù)在桌面軟件的開(kāi)發(fā)中得到了廣泛的應用,但在嵌入式開(kāi)發(fā)領(lǐng)域,由于嵌入式開(kāi)發(fā)的多樣性及嵌入式操作系統的多樣性,目前還沒(méi)有一套完整的開(kāi)發(fā)框架可供使用。因此,在嵌入式軟件開(kāi)發(fā)中常常是從底層做起,應用程序和RTOS密不可分。這樣的開(kāi)發(fā)方式不但效率不高,也不利于軟件的移植。

EFC(Embedded Foundation Classes)即嵌入式基礎類(lèi)庫,是筆者借鑒Microsoft公司的MFC(微軟基礎類(lèi)庫―桌面系統框架庫的工業(yè)標準)的一套在A(yíng)RM平臺Nucleus plus操作系統下的嵌入式開(kāi)發(fā)框架。由于框架全部采用C++開(kāi)發(fā),沒(méi)有和處理器相關(guān)的匯編代碼,所以在其它硬件平臺可不加修改地使用。如果更換不同的操作系統,則需要修改操作系統抽象層的部分代碼;但由于EFC提供給上層應用程序的接口不變,所以應用程序不需要修改代碼。

圖2 EFC靜態(tài)結構圖

就軟件的層次來(lái)說(shuō),EFC是一個(gè)操作系統之上、應用程序之下的中間件,如圖1所示。在EFC中有一個(gè)操作系統抽象層,對RTOS進(jìn)行了抽象和封裝,提供包括任務(wù)(task)、/O驅動(dòng)(driver)、定時(shí)器(timer)、信號量(semaphore)、消息隊列(quecue)、事件(event group)、郵箱(mailBox)、管道(pipe)以及高級中斷(HISR)等基本服務(wù)的封裝。為上層應用程序提供更高級的統一編程接口,它樣就使應用軟件的開(kāi)發(fā)與具體的軟件平臺無(wú)關(guān),解決了嵌入式應用軟件的移植問(wèn)題。

在圖1中,各模塊之間有交界表明模塊之間有接口關(guān)系。EFC、應用程序以及RTOS都和硬件驅動(dòng)有接口:EFC要使用一部分核心驅動(dòng)(例如實(shí)時(shí)時(shí)鐘的驅動(dòng)、ARM串口和網(wǎng)口的驅動(dòng)、I2C總線(xiàn)的驅動(dòng)等);應用程序中調用的驅動(dòng)是針對具體設備的;RTOS所需要的驅動(dòng)就是系統的BSP部分。

EFC的靜態(tài)結構圖(類(lèi)圖)如圖2所示。類(lèi)圖是在UML(統一建模語(yǔ)言)中用類(lèi)和它們之間的關(guān)系描述系統的一種圖示。類(lèi)用類(lèi)名、類(lèi)的屬性以及操作來(lái)表示,在圖中為簡(jiǎn)單起見(jiàn),省略了屬性和操作;類(lèi)與類(lèi)之間的關(guān)系使用不同的連線(xiàn)表示,圖中帶空心三角箭頭的連線(xiàn)表示繼承關(guān)系,兩端帶數字的連線(xiàn)表示關(guān)聯(lián)關(guān)系。在類(lèi)圖中,類(lèi)的屬性/方法的可見(jiàn)性使用“+”、“-”及“#”表示:“+”表示公共的(public),“-”表示私有的(private),“#”表示受保護的(protected)。

從圖2中可以看出,CMessage、CRTApp、CDevice、Cboard及Cinterface都派生于公共的類(lèi)CRTObject。CRTApp對象中有受保護的CMessage、CEventLog、Cuser及CDevice各一個(gè)。CDevice對象中有一個(gè)或多個(gè)CBoard對象,相應的每個(gè)CBorad對象中有0個(gè)到多個(gè)CxxxInterace對象。

2.1 基本數據類(lèi)型

一個(gè)框架,需要一些基本的元素,這些元素要在框架的構造以及應用程序開(kāi)發(fā)中大量使用。這些基本數據類(lèi)型包括字符串類(lèi)CString、集合類(lèi)CArray、Clist及Cmap。CString包括一個(gè)長(cháng)度可變的字符序列,提供使用非常直觀(guān)方便的運算符(例如+,+=,=,==,!=)和一些Todouble()、Tolong()、Tohex()等);CArray是具有內建索元素很快的檢索速度;Clist為其所存儲的每一個(gè)元素,都提供了兩個(gè)指針,分別指向位于其前和其后的元素,形成一個(gè)雙向鏈表,這使得插入和刪除操作十分快捷;CMap為其存儲的每個(gè)數據都附帶一個(gè)關(guān)鍵字,并以關(guān)鍵字所組成的一個(gè)hash表作為索引,從而使得元素搜索、增加和刪除操作都具有很高的效率。

2.2 RTOS的抽象和封裝

CRTObject是一個(gè)EFC中最基礎的類(lèi),它不但是EFC中CRTApp、CDevice等類(lèi)的基類(lèi),而且可以作為所有使用EFC的嵌入式開(kāi)發(fā)人員定義新的類(lèi)的超類(lèi)。CRTObject類(lèi)在EFC中主要承擔RTOS抽象和封裝任務(wù)。它提供了下面一些最基本的功能:

*CRTObject對RTOS的常用對象進(jìn)行了封裝,提供包括Task、Driver、Timer、Event Group、Semaphore、Queue、Pipe、Mailbox等的創(chuàng )建、刪除、查找等功能的成員函數。這些函數提供了一個(gè)簡(jiǎn)單有效的方法來(lái)使用RTOS的對象。使用這些函數能夠保證對象創(chuàng )建與銷(xiāo)毀的安全性,而不會(huì )造成內存泄漏。

*CRTObject提供了對RTTI(Run-Time Type Information,運行時(shí)類(lèi)型信息)的支持,在新的C++標準中,RTTI已經(jīng)是C++的一個(gè)功能,但并不是所有的編譯器都提供支持這些新特性,ADS1.2就不支持。所以在這里參考MFC,通過(guò)宏的方式為每個(gè)類(lèi)定義一個(gè)CRuntimeClass類(lèi)型的靜態(tài)常量和相關(guān)的成員函數。CRuntimeClass結構保證了類(lèi)型的靜態(tài)常量和相關(guān)的成員函數。CRuntimeClass結構保存了類(lèi)的名稱(chēng)、大小等信息,這樣我們就能在程序運行時(shí)確定對象的具體類(lèi)型。

*CRTObject還提供了把類(lèi)的成員函數作為任務(wù)及定時(shí)器的回調函數的功能。在Nucleus中,任務(wù)和定時(shí)器的回調函數只能是全局函數或者類(lèi)的靜態(tài)成員函數,這在面向對象的開(kāi)發(fā)中很不方便。這里通過(guò)把成員函數指針和對象的this指針作為參數傳遞給RTOS,在RTOS調用公共回調函數時(shí)再取出來(lái)。通過(guò)函數指針的方式去調用類(lèi)的成員函數,這樣把有派生于CRTObject的類(lèi)就可方便地使用成員函數作為任務(wù)、定時(shí)器等對象的回調函數。

2.3 應用程序類(lèi)CRTApp

CRTApp類(lèi)用來(lái)定義整個(gè)應用程序對象,提供系統初始化、管理其它對象以及運行應用程序的功能。任何使用EFC框架的應用程序有且只能有一個(gè)派生于此類(lèi)的對象。CRTApp對象中包含了動(dòng)態(tài)創(chuàng )建的CMessage、CEventLog、CDevice及Cuser對象。

通過(guò)在Nucleus的入口函數Application_Initialize中創(chuàng )建系統初始化任務(wù)(回調函數為CRTApp類(lèi)的成員函數InitTask),來(lái)把系統控制權交給CRTApp對象,在其中完成其它對象的創(chuàng )建、系統的配置以及初始化任務(wù)。

2.4 文件系統

在嵌入式設備中通常使用Flash存儲器來(lái)保存程序代碼和數據,每片Flash一般由一定數量大小不等的扇區組成。它在讀取方面與普通RAM存儲器類(lèi)似,可以實(shí)現隨機的讀取,但在寫(xiě)入操作上卻有很大的不同。Flash中只有空白的單元才可以進(jìn)行寫(xiě)入操作,要向非空的單元寫(xiě)入數據,需要先擦除整個(gè)扇區。所以程序中如果直接對Flash進(jìn)行操作會(huì )很不方便。最好的辦法就是在其上構造一個(gè)文件系統,文件系統提供簡(jiǎn)便、可靠的接口供上層使用,而把復雜的操作屏蔽在文件系統內部。

這里文件系統包括內存文件系統和Flash文件系統。CFile是一個(gè)抽象類(lèi),只是定義文件系統的接口函數(例如Open、Read、Write、Seek、GetLength、Close等),具體的實(shí)現在CMemFile(內存文件)及CFlashFile(Flash文件)類(lèi)中完成。

2.5 設備管理

在EFC中,設備管理由CDevice、CBoard、CInterface及其派生類(lèi)完成。CDevice類(lèi)代表整個(gè)設備,1個(gè)設備中包含1到多個(gè)CBoard對象,而每個(gè)CBoard對象中又包含0個(gè)到多個(gè)接口對象(CInterface類(lèi)的派生類(lèi)對象)。這樣以來(lái),嵌入式設備(僅限通信領(lǐng)域)都可由這幾個(gè)類(lèi)組合而成,大大簡(jiǎn)化了軟件的設計。

2.6 命令處理

CMessage類(lèi)是系統的命令處理模塊,它直接派生于CRTObject類(lèi)。它的功能主要是接收網(wǎng)管軟件通過(guò)串口或網(wǎng)口發(fā)送未來(lái)的各種命令,完成對設備的配置管理、性能管理、告警管理、安全管理和維護管理等管理功能。CMessage類(lèi)主要有表1所列的任務(wù)。

表1 CMessage類(lèi)中的任務(wù)

任務(wù)名稱(chēng)任務(wù)處理函數說(shuō) 明
TCP服務(wù)器監聽(tīng)任務(wù)TCPServerTask用于監聽(tīng)客戶(hù)端的連接請求
TCP響應任務(wù)TCPEchoTask對每客戶(hù)端的連接都創(chuàng )建一響應任務(wù)
串口任務(wù)UartTask通過(guò)串口對系統進(jìn)行管理
TFTP備分份任務(wù)TFTPClientPutTask備份應用程序和系統配置文件
TFTP升級任務(wù)TFTPClientGetTask用于升級應用程序及修改用戶(hù)配置文件

2.7 其它模塊

CFlash類(lèi)封裝對Flash芯片的操作,主要包括讀、寫(xiě)、擦除等操作。從圖2可以看出,CEventLog和CFlashFile類(lèi)中都包含CFlash對象;CEventLog類(lèi)記錄系統中的發(fā)生的事件以及系統運行過(guò)程中產(chǎn)生的告警信息。為了實(shí)現掉電保存功能,這些事件都保存在Flash芯片中;Cuser類(lèi)用來(lái)對系統的用戶(hù)進(jìn)行管理,防止對系統非授權的訪(fǎng)問(wèn)。

3 使用EFC的設計方案舉例

這里以在通信和工業(yè)自動(dòng)化領(lǐng)域使用較多的串口服務(wù)器為例,來(lái)說(shuō)明使用FEC嵌入式開(kāi)發(fā)框架的設計方案。串口服務(wù)器是一種可把多路異步RS232/RS485串行數據與通過(guò)以太網(wǎng)口傳送的TCP/IP數據包進(jìn)行相互轉換,使傳統的異步串行數據信息能通過(guò)Internet或Intranet傳送或共享的設備。

設每個(gè)串口對應TCP/IP的一個(gè)端口,則可畫(huà)出圖3所示的靜態(tài)結構圖(圖中SerSvr是Server的簡(jiǎn)寫(xiě))。

從圖3可以看出,共對五個(gè)類(lèi)進(jìn)行了派生。CSerSvrMessage類(lèi)派生于CMessage類(lèi),用于通過(guò)網(wǎng)管對串口服務(wù)器進(jìn)行管理(這里具體命令略);CserSvrDevice類(lèi)派生于CDevice類(lèi),代表串口服務(wù)器設備;CserSvrDevice類(lèi)對象中有一個(gè)或多個(gè)派生于CBoard類(lèi)的CserSvrBoard類(lèi)對象,而每個(gè)CserSvrBoard類(lèi)對象擁有一個(gè)或多個(gè)派生于CasyInterface類(lèi)的CSerSvrInterface類(lèi)對象;ScerSvrApp類(lèi)派生于CRTApp類(lèi),代表整個(gè)應用程序,并重載了虛函數OnCreateMessage()及OnCreateDevice(),用來(lái)在其中創(chuàng )建系統的CSerSvrMessage和CserSvrDevice類(lèi)的實(shí)例來(lái)代替系統默認的CMessage和CDevice實(shí)例。

圖3 串口服務(wù)器系統軟件靜態(tài)結構圖

串口類(lèi)CSerSvrInterface的設計是整個(gè)設計的關(guān)鍵,在每個(gè)串口類(lèi)中都有一個(gè)TCP監聽(tīng)任務(wù)TCPServerTask用來(lái)作為服務(wù)器去監聽(tīng)客戶(hù)端的連接;一個(gè)TCP客戶(hù)端任務(wù)TCPClientTask用來(lái)連接其它服務(wù)器。無(wú)論是通過(guò)TCPServerTask還是TCPClientTask建立連接后,就掛起這兩個(gè)任務(wù)而啟動(dòng)另外兩個(gè)任務(wù)TCPSendTask和TCPRecvTask,它們分別用來(lái)通過(guò)網(wǎng)口發(fā)送數據和接收數據。TCPSendTask每隔10ms(對波特率為115.2K的情況,10ms最多收到的字節數為115200/(8+2)/1000*10=115.2字節,所以串口的FIFO應大于116字節)把從串口讀到的數據打包從網(wǎng)口發(fā)送出去;而TCPTecvTask使用阻塞方式讀取網(wǎng)口數據。在讀到數據后,根據串口發(fā)送緩沖區的情況慢慢通過(guò)串口往外發(fā)送,沒(méi)發(fā)送完之前就不進(jìn)行下一次從網(wǎng)口的數據讀取。這樣把串口類(lèi)設計成一個(gè)完備的處理類(lèi),設備中每塊板有多少串口就在CSerSvrBoard類(lèi)的實(shí)例中有多少CSerSvrInterface類(lèi)的實(shí)例。硬件模塊化的結構簡(jiǎn)單地對應軟件模塊化的結構。

結語(yǔ)

本文講述了在嵌入式軟件開(kāi)發(fā)中使用C++構建系統開(kāi)發(fā)框架的方法,并給出了框架的模型和應用實(shí)例??梢钥闯?,使用面向對象的框架技術(shù)對于提高開(kāi)發(fā)效率、降低開(kāi)發(fā)難度、規范開(kāi)發(fā)模式、便于軟件的移植和維護方面,具有傳統面向過(guò)程的開(kāi)發(fā)方法不可比擬的優(yōu)勢。

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>