基于ARM的W5100底層驅(qū)動(dòng)設(shè)計(jì)
嵌入式操作系統(tǒng)的引入大大提高了嵌入式系統(tǒng)的功能,方便了嵌入式應(yīng)用軟件的設(shè)計(jì),但同時(shí)也占用了寶貴的嵌入式資源。
本文引用地址:http://www.ex-cimer.com/article/201611/318470.htm嵌入式操作系統(tǒng)大多采用組件化、模塊化的設(shè)計(jì)思想,以搭積木的方式通過互連構(gòu)造軟件,因而是可配置的。但是由于操作系統(tǒng)的多樣性,不同操作系統(tǒng)提供的配置方式迥異且繁簡(jiǎn)不一。而由于硬件平臺(tái)的多樣性,即使是相同的操作系統(tǒng),其應(yīng)用配置也有差別。結(jié)果是,應(yīng)用程序開發(fā)者必須熟悉不同的硬件平臺(tái)和操作系統(tǒng)才能進(jìn)行有效的應(yīng)用開發(fā),增加了應(yīng)用開發(fā)的難度。特別是網(wǎng)絡(luò)化嵌入式應(yīng)用一般出現(xiàn)在比較大型的項(xiàng)目中,復(fù)雜度和難度大大增加。因此,提高網(wǎng)絡(luò)化嵌入式應(yīng)用產(chǎn)品質(zhì)量、縮短開發(fā)周期、降低開發(fā)成本是開發(fā)人員面臨的迫切要求。
1 開發(fā)模式方案選擇
面向?qū)ο蟮姆椒?、設(shè)計(jì)模式的思想是當(dāng)前實(shí)現(xiàn)軟件模塊化、提高軟件可復(fù)用性的最優(yōu)方法。面向?qū)ο缶幊陶Z(yǔ)言、組件和構(gòu)架是被廣泛認(rèn)可的、用以降低軟件成本并提高軟件質(zhì)量的技術(shù)。
面向?qū)ο蟮闹饕锰幵谟谒鼜?qiáng)調(diào)模塊性和可擴(kuò)展性,將易變的實(shí)現(xiàn)細(xì)節(jié)封裝在穩(wěn)定的接口后面,增強(qiáng)了軟件的可復(fù)用性。但是,在目前的嵌入式實(shí)時(shí)系統(tǒng)中采用面向?qū)ο蟮姆椒ㄟM(jìn)行上層軟件的設(shè)計(jì)還有很多困難。最主要的,就是底層實(shí)時(shí)操作系統(tǒng)沒有提供有力支持,即使上層軟件勉強(qiáng)采用了面向?qū)ο蟮姆椒?,代碼的模塊化、可移植性、可復(fù)用性也難有提高。
因此,為了避免采用傳統(tǒng)操作系統(tǒng)的開發(fā)模式帶來復(fù)雜問題,本文采用一種自定義的裸機(jī)開發(fā)模式。該模式避免了不同操作系統(tǒng)平臺(tái)改變帶來復(fù)雜的問題。其創(chuàng)建項(xiàng)目過程沒有復(fù)雜的裁剪,只有根據(jù)需要添加相關(guān)驅(qū)動(dòng)和編寫適當(dāng)應(yīng)用層代碼。即使是硬件平臺(tái)的改變,也只是根據(jù)硬件配置不同改變其條件編譯而已。
2 自定義裸機(jī)開發(fā)模式
自定義開發(fā)模式下的應(yīng)用軟件體系結(jié)構(gòu)如圖1所示。該體系結(jié)構(gòu)包含管理層、應(yīng)用層、控件層、虛設(shè)備層和實(shí)設(shè)備層。其中管理層處于類似于操作系統(tǒng)中“內(nèi)核”的地位,為其他層的管理者。
圖1
自定義開發(fā)模式下的應(yīng)用軟件體系結(jié)構(gòu)
跟PC機(jī)上的Windows應(yīng)用軟件類似,應(yīng)用層是由一個(gè)或者多個(gè)窗口組成的,有可視窗口和不可視窗口。其中各個(gè)窗口中又包含一個(gè)或者多個(gè)控件??丶榇翱谔峁└鞣N服務(wù),由設(shè)備層提供支撐。在控件層和實(shí)設(shè)備層中間有一個(gè)虛設(shè)備層。
根據(jù)設(shè)備功能的復(fù)雜程度,虛設(shè)備分為簡(jiǎn)單的虛設(shè)備和復(fù)合虛設(shè)備。實(shí)設(shè)備分為簡(jiǎn)單的實(shí)設(shè)備和復(fù)合實(shí)設(shè)備。其中復(fù)合設(shè)備是由簡(jiǎn)單設(shè)備組合而成。
從類的關(guān)系看,虛設(shè)備層就是含有虛函數(shù)的基類,該函數(shù)一般沒有實(shí)現(xiàn),只是聲明了接口,實(shí)設(shè)備層就是從該基類繼承下來的,具體實(shí)現(xiàn)是由該實(shí)設(shè)備層來完成。由于接口的穩(wěn)定性,這就保證了底層硬件改變時(shí),應(yīng)用層的程序幾乎可以沒有改變或者改變甚小。
3
自定義開發(fā)模式下的W5100驅(qū)動(dòng)編寫
3.1
接口電路說明
本驅(qū)動(dòng)設(shè)計(jì)采用W5100串行SPI接口。SPI接口模式只需要4個(gè)引腳進(jìn)行數(shù)據(jù)通信,分別為SCLK、/SS(SPI從模式選擇輸入引腳,低電平有效)、MOSI、MISO。W5100
的SPI_EN 引腳高電平表示SPI
使能,/RESET引腳低電平實(shí)現(xiàn)W5100芯片的復(fù)位。本項(xiàng)目選擇的MCU芯片為L(zhǎng)PC2138,其中W5100與LPC2138對(duì)應(yīng)引腳連線如表1所列。
表1 LPC2138與W5100對(duì)應(yīng)引腳連線說明
3.2 W5100驅(qū)動(dòng)分析
本驅(qū)動(dòng)開發(fā)環(huán)境為:CodeWarrior for ARM Developer Suite
V1.2。
在自定義開發(fā)模式中,前期編寫好的驅(qū)動(dòng)類有引腳類、SPI類、外部中斷類,就是所謂簡(jiǎn)單設(shè)備。這些類及其頭文件的具體介紹略——編者注。
在使用W5100前需要操作其/SS引腳,選中W5100芯片SPI從模式。初次配置或者重新配置W5100相關(guān)參數(shù)前,需要操作其/RESET引腳,讓所有原來配置復(fù)位。配置W5100相關(guān)參數(shù)是通過SPI讀寫操作來完成的。
W5100從網(wǎng)絡(luò)上接收了一個(gè)數(shù)據(jù)包后,會(huì)讓其/INT引腳從高電平變?yōu)榈碗娖?。在本?xiàng)目中,把該引腳跟LPC2138的外部中斷1引腳相連,如果開啟了外部中斷1,那么就觸發(fā)一個(gè)外部中斷。該外部中斷服務(wù)里面應(yīng)當(dāng)有實(shí)現(xiàn)LPC2138訪問W5100,并讀取W5100里面接收到的數(shù)據(jù)包的功能。LPC2138獲取W5100里面的數(shù)據(jù)包,必須通過SPI讀寫操作的配合才能實(shí)現(xiàn)。
綜合上面的分析,該W5100驅(qū)動(dòng)應(yīng)當(dāng)是由引腳類、外部中斷類、SPI操作類互相配合完成,因此W5100驅(qū)動(dòng)是一個(gè)復(fù)合設(shè)備。
3.3
W5100實(shí)設(shè)備驅(qū)動(dòng)編寫
本驅(qū)動(dòng)針對(duì)W5100采用UDP協(xié)議進(jìn)行網(wǎng)絡(luò)通信功能來編寫。
首先所有實(shí)設(shè)備都必須從一個(gè)虛設(shè)備下繼承下來。創(chuàng)建一個(gè)名為Ip_NetWork_Virtual_Device網(wǎng)絡(luò)虛設(shè)備,其部分頭文件略——編者注。
由于網(wǎng)絡(luò)通信應(yīng)用的芯片有多種,但是無論是哪種芯片,實(shí)現(xiàn)的功能都離不開網(wǎng)絡(luò)包的讀和寫。因此在該虛類里的聲明都是共用的功能。基類里面含有虛函數(shù),就是聲明了接口,但是沒有具體的實(shí)現(xiàn),具體的實(shí)現(xiàn)由其具體的實(shí)設(shè)備來完成。在繼承中,如果基類和派生類中定義了同名的成員函數(shù),當(dāng)用基類指針指向公有派生類的對(duì)象后,可以使用虛函數(shù)來實(shí)現(xiàn)通過基類指針找到相應(yīng)的派生類成員函數(shù)[11]。
W5100的實(shí)設(shè)備NetWork_W5100類的部分頭文件略——編者注。
3.4
W5100實(shí)設(shè)備驅(qū)動(dòng)說明
3.4.1 虛設(shè)備類指針
在W5100實(shí)設(shè)備頭文件中有:
Spi_Virtual_Device*
SpiPort;
OutEint_Virtual_Device* IntDevice;
PinDevice_Virtual_Device *
W5100_Cs;
PinDevice_Virtual_Device *
W5100_RESET;
由于W5100實(shí)設(shè)備需要幾個(gè)簡(jiǎn)單設(shè)備配合來完成其功能,因此設(shè)計(jì)W5100實(shí)設(shè)備驅(qū)動(dòng)擁有這些簡(jiǎn)單設(shè)備的指針,可以看出這些指針是指向簡(jiǎn)單虛設(shè)備對(duì)象的指針。
聲明為指向基類對(duì)象的指針,當(dāng)它指向公有派生類對(duì)象時(shí),可以利用它來直接訪問派生類中從基類繼承下來的成員,不能直接訪問公有派生類中特定的成員。
采用面向?qū)ο笾心J骄幊谭▌t中的依賴反轉(zhuǎn)法則:依賴抽象而不依賴具體[12]。
在main.cpp首先聲明如下的實(shí)設(shè)備,如下:
OutInt_2138 NetOutInt; //外部中斷類實(shí)設(shè)備對(duì)象
NetWork_W5100
Net5100;//W5100實(shí)設(shè)備對(duì)象
Spi0_Driver_Lpc Spi0;//SPI實(shí)設(shè)備對(duì)象
Pin_LPC2138 PIN023;
//引腳實(shí)設(shè)備對(duì)象
Pin_LPC2138 PIN031;
//引腳實(shí)設(shè)備對(duì)象
接著在main.cpp采用如下代碼完成Net5100和簡(jiǎn)單設(shè)備NetOutInt、Spi0、PIN023、PIN031等的關(guān)聯(lián):
NetOutInt.WorkModel=Fall_Eage;//表示下降沿觸發(fā)
NetOutInt.SubDeviceName=Eint1;//表示使用外部中斷1
NetOutInt.Ini();
NetOutInt.Father=&Net5100;
Net5100.SpiPort=&Spi0;//設(shè)置Spi0和SpiPort指針關(guān)聯(lián)
Net5100.W5100_Cs=&
PIN023; //設(shè)置片選引腳關(guān)聯(lián)
Net5100.W5100_RESET=& PIN031;
//設(shè)置復(fù)位引腳關(guān)聯(lián)
在“Net5100.SpiPort=&Spi0”中SpiPort是指向某基類對(duì)象的指針,Spi0是該基類的派生類對(duì)象,該語(yǔ)句實(shí)現(xiàn)把該指針指向其派生類對(duì)象。因此就可以利用該指針直接訪問該公有派生類從基類繼承來的成員。同樣,可以利用W5100_Cs和W5100_RESET等基類對(duì)象指針直接訪問該基類的派生類——Pin_LPC2138類從基類繼承下來的成員,即引腳的操作函數(shù)等。
在NetWork_W5100中有W5100_Send_Receive_Data函數(shù)就是利用這個(gè)技術(shù),該函數(shù)如下:
char
NetWork_W5100::W5100_Send_Receive_Data(char dat){
char
i;
W5100_Cs->Clear();
i=SpiPort->SPI_Send_Receive_Data(dat);
W5100_Cs->Set();
return
i;
}
NetWork_W5100類對(duì)象能實(shí)現(xiàn)SPI讀寫操作,是因?yàn)槠鋼碛幸粋€(gè)SPI虛設(shè)備的指針。同理,能實(shí)現(xiàn)對(duì)引腳操作是因?yàn)槠鋼碛幸粋€(gè)引腳虛設(shè)備的指針。
3.4.2
外部中斷實(shí)設(shè)備和W5100實(shí)設(shè)備關(guān)聯(lián)
NetOutInt是一個(gè)外部中斷類對(duì)象,使用前首先對(duì)該對(duì)象進(jìn)行初始化,其中代碼“NetOutInt.SubDeviceName=Eint1”表示該類對(duì)象和外部中斷1產(chǎn)生了綁定。
在本項(xiàng)目測(cè)試中,W5100從網(wǎng)絡(luò)接收到一個(gè)數(shù)據(jù)包后觸發(fā)了一個(gè)外部中斷1中斷。該W5100實(shí)設(shè)備類對(duì)象Net5100感知該事件,從而對(duì)該事件進(jìn)行處理,接著把該消息發(fā)布給其所支撐的控件。
main.cpp中有“NetOutInt.Father=&Net5100;”,其中Father是一個(gè)指針,該指針來源如下:
class
Object{
public:
……
Object
*Father;
……
};
由于所有設(shè)備類都是從該類間接繼承下來,所以都擁有這個(gè)Father指針。
“NetOutInt.Father=&Net5100;”的目的是把Net5100對(duì)象地址賦給該指針,因此該指針就指向Net5100,說明NetOutInt擁有一個(gè)指向Net5100的指針。main.cpp中,外部中斷1的服務(wù)程序代碼如下:
void
__irq
IRQ_Eint1(){
NetOutInt.HardInt(Null);
VICVectAddr=0×00;
NetOutInt.ClearInt();
}
“NetOutInt.HardInt(Null);”其本質(zhì)就是調(diào)用到HardInt函數(shù),如下:
void
OutInt_2138::HardInt(Device*
IntDevice){
……
this->Msg.MsgID=Sys_Msg_OutInt;
this->Msg.Parm1=this->SubDeviceName;
this->Father->Message(Msg);
……
}
“this->Father->Message(Msg);”即中斷服務(wù)最后把該工作交給Father指針指向的Net5100,接著該對(duì)象調(diào)用了其Message函數(shù)。NetWork_W5100類的Message函數(shù)偽代碼如下:
void
NetWork_W5100::Message(MessageBody SystemMsg){
if
Socket3
SelectSocket(3);
if Socket2
SelectSocket(2);
if
Socket1
SelectSocket(1);
else
SelectSocket(0);
};
其中NetWork_W5100類的SelectSocket函數(shù)如下:
void
NetWork_W5100::SelectSocket(char socket){
uint16
address,inttype;
address=COMMON_BASE+0×100*socket+0×0402;
inttype=NetWork_Read(address);
if((inttype&0×04)==0×04){
//接收數(shù)據(jù)引起中斷
S_UDP_RX_Process(socket,&ReceiveBuffer[0],&ReceiveBuffer[8]);
//從對(duì)應(yīng)的Socket接收數(shù)據(jù)
Msg.MsgID=Sys_Msg_UdpGetData;
Msg.Msg=&ReceiveBuffer[0];
VclPointer[socket]->Message(Msg);
//向支撐控件發(fā)送消息
}
NetWork_Write(address,0xFF);//清除所有的中斷
}
可見,W5100驅(qū)動(dòng)最后把網(wǎng)絡(luò)接收到數(shù)據(jù)包作為一個(gè)消息發(fā)給其所支撐的上層控件。
4
W5100驅(qū)動(dòng)測(cè)試
4.1 測(cè)試方案
在PC機(jī)上,利用網(wǎng)絡(luò)測(cè)試工具TCP/UDP
Socke調(diào)試工具V2.2,通過網(wǎng)絡(luò)向W5100的終端發(fā)送一個(gè)數(shù)據(jù)包。當(dāng)該終端接收到該數(shù)據(jù)包后,把該包往PC機(jī)終端發(fā)送。如果發(fā)送和接收的數(shù)據(jù)包一致,說明通信測(cè)試成功。
4.2
測(cè)試過程
PC機(jī)端的IP地址為192.168.1.103,某端口號(hào)為9000。W5100本身地址設(shè)置為192.168.1.101,某端口號(hào)為9000。PC機(jī)往W5100終端發(fā)送數(shù)據(jù)包,在如圖2所示操作界面的數(shù)據(jù)發(fā)送窗口輸入“Hello,
This is a happy word!”字符串后,點(diǎn)擊“發(fā)送數(shù)據(jù)”,在操作界面的數(shù)據(jù)接收窗口接收到“Hello, This is a happy
word!”,并且在操作界面上方顯示“對(duì)方IP:192.168.1.101,對(duì)方端口:9000”,這跟W5100終端設(shè)置是一致的,說明雙方的通信成功。
結(jié)語(yǔ)
W5100驅(qū)動(dòng)的創(chuàng)建過程非常復(fù)雜,但是對(duì)于編寫好的驅(qū)動(dòng),應(yīng)用者只需要了解該接口使用的說明,而不用關(guān)心其復(fù)雜的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。如果其他項(xiàng)目需要用到W5100,只需要把該驅(qū)動(dòng)添加到該項(xiàng)目中即可,從而實(shí)現(xiàn)驅(qū)動(dòng)的復(fù)用,避免重復(fù)的工作,縮短項(xiàng)目開發(fā)周期。如果下次要使用W5100驅(qū)動(dòng)的其他功能,如TCP協(xié)議通信,只需要在原來驅(qū)動(dòng)上添加相應(yīng)的函數(shù)即可,因此維護(hù)起來更加方便。
評(píng)論