版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、驅(qū)動(dòng)網(wǎng)卡芯片DM9000A的過程及具體驅(qū)動(dòng)程序 一、電路連接 DM9000E網(wǎng)卡芯片支持8位、16位、32位模式的處理器,通過芯片引腳EEDO(65腳)和WAKEUP(79腳)的復(fù)位值設(shè)置支持的處理器類型,如16位處理器只需將這兩個(gè)引腳接低電平即可,其中WAKEUP內(nèi)部有60K下拉電阻,因此可懸空該引腳,或作為網(wǎng)卡芯片喚醒輸出用。其它型號(hào)請(qǐng)參考相應(yīng)的數(shù)據(jù)手冊(cè)。圖1 DM9000引腳 如圖所示,對(duì)處理器驅(qū)動(dòng)網(wǎng)卡芯片來說,我們比較關(guān)心的有以下幾個(gè)引腳:IOR、IOW、
2、AEN、CMD(SA2)、INT、RST,以及數(shù)據(jù)引腳SD0-SD15-SD31和地址引腳SA4-SA9。其中,地址引腳配合AEN引腳來選通該網(wǎng)卡芯片,對(duì)于大多數(shù)的應(yīng)用來說沒有意義,因?yàn)樵谖覀兊膽?yīng)用中一般只用一個(gè)網(wǎng)卡芯片,而這些地址引腳主要用于在多網(wǎng)卡芯片環(huán)境下選擇其中之一。DM9000工作的默認(rèn)基地址為0x300,這里我們按照默認(rèn)地址選擇,將SA9、SA8接高電平,SA7-DA4接低電平。多網(wǎng)卡環(huán)境可以根據(jù)TXD0-TXD3配置SA4-SA7來選擇不同的網(wǎng)卡,這里不做介紹,有興趣的朋友請(qǐng)參考應(yīng)用手冊(cè)和數(shù)據(jù)手冊(cè)。數(shù)據(jù)引腳SD0-SD31則根據(jù)前面所講的配置處理器模式與處理器的數(shù)據(jù)總線進(jìn)行選擇連
3、接即可,沒用到的引腳懸空。那么,除了地址、數(shù)據(jù)引腳外,剩下的與處理器有關(guān)引腳對(duì)我們來說及其重要了,而與處理器無關(guān)的引腳,只需按照應(yīng)用手冊(cè)連接即可。 IOR和IOW是DM9000的讀寫選擇引腳,低電平有效,即低電平時(shí)進(jìn)行讀(IOR)寫(IOW)操作;AEN是芯片選通引腳,低電平有效,該引腳為低時(shí)才能進(jìn)行讀寫操作;CMD的命令/數(shù)據(jù)切換引腳,低電平時(shí)讀寫命令操作,高電平時(shí)讀寫數(shù)據(jù)操作。 圖2 讀時(shí)序圖3 寫時(shí)序 這些引腳接口和其它單片機(jī)外圍器件的引腳接口基本相同,其使用也一樣。對(duì)于有總線接口的單片機(jī)來說,如51系列,ARM等直
4、接連接即可。對(duì)于沒有總線接口的來說,如AVR mega32等可以直接用I/O引腳模擬總線時(shí)序進(jìn)行連接。連接時(shí)要參考讀寫時(shí)序,如上圖所示。具體連接電路,有時(shí)間我再畫出來,暫時(shí)先略了。 二、編寫驅(qū)動(dòng)程序 在這,我使用C語言編寫驅(qū)動(dòng)程序,這需要非常注意一點(diǎn),即處理器所用的C編譯器使用“大端格式”還是“小端格式”,這可以在相應(yīng)處理器的C編譯器說明上找到。一般比較常見的是小端格式。而對(duì)于8位處理器來說,在編寫驅(qū)動(dòng)程序時(shí),可以不考慮,但是在編寫網(wǎng)絡(luò)協(xié)議的時(shí)候,一定好考慮,因?yàn)榫W(wǎng)絡(luò)協(xié)議的格式是大端格式,而大部分編譯器或者我們習(xí)慣的是小端
5、格式,這一點(diǎn)需要注意。 在DM9000中,只有兩個(gè)可以直接被處理器訪問的寄存器,這里命名為CMD端口和DATA端口。事實(shí)上,DM9000中有許多控制和狀態(tài)寄存器(這些寄存器在上一篇文章中有詳細(xì)的使用說明),但它們都不能直接被處理器訪問,訪問這些控制、狀態(tài)寄存器的方法是:(1)、將寄存器的地址寫到CMD端口;(2)、從DATA端口讀寫寄存器中的數(shù)據(jù); 1、讀、寫寄存器 其實(shí),INDEX端口和DATA端口的就是由芯片上的CMD引腳來區(qū)分的。低電平為INDEX端口,高電平為DATA端口。所以,
6、要想實(shí)現(xiàn)讀寫寄存器,就必須先控制好CMD引腳。 若使用總線接口連接DM9000的話,假設(shè)總線連接后芯片的基地址為0x800300(24根地址總線),只需如下方法:#define DM_ADD (*(volatile unsigned int *) 0x8000300)#define DM_CMD (*(volatile unsigned int *) 0x8000304)/向DM9000寄存器寫數(shù)據(jù)void dm9000_reg_write(unsigned char reg, unsigned char data) ud
7、elay(20);/之前定義的微妙級(jí)延時(shí)函數(shù),這里延時(shí)20us DM_ADD = reg;/將寄存器地址寫到INDEX端口 udelay(20); DM_CMD = data;/將數(shù)據(jù)寫到DATA端口,即寫進(jìn)寄存器/從DM9000寄存器讀數(shù)據(jù)unsigned int dm9000_reg_read(unsigned char reg) udelay(20); DM_ADD = reg;
8、0; udelay(20); return DM_CMD;/將數(shù)據(jù)從寄存器中讀出 只得注意的是前面的兩個(gè)宏定義DM_ADD和DM_CMD,定義的內(nèi)容表示指向無符號(hào)整形變量的指針,在這里0x800300是DM9000命令端口的地址,對(duì)它的賦值操作就相當(dāng)于把數(shù)據(jù)寫到該地址中,即把數(shù)據(jù)寫到DM9000的命令端口中。讀的道理也一樣。這是一種很常見的宏定義,一般在處理器中定義通用寄存器也是這樣定義的。 若沒有總線接口的話,可以使用IO口模擬總線時(shí)序的方法實(shí)現(xiàn)寄存器的讀寫。這里只說明實(shí)現(xiàn)步驟。首先將
9、處理器的I/O端口與DM9000的IOR等引腳直接相連(電平匹配的情況下),又假設(shè)已經(jīng)有宏定義“IOR”I/O端口控制DM9000的IOR引腳,其它端口控制DM9000引腳的命名相同,“PIO1”(根據(jù)處理器情況,可以是8位、16位或32位的I/O端口組成)控制數(shù)據(jù)端口。這樣宏命名更直觀些。寫寄存器的函數(shù)如下:void dm9000_reg_write(unsigned char reg, unsigned char data)PIO1 = reg;AEN = 0;CMD = 0;IOR = 1;IOW = 0;udelay(1);AEN = 1;IOW = 1;udelay(20);PIO1
10、 = data;AEN = 0;CMD = 0;IOR = 1;IOW = 0;udelay(1);AEN = 1;IOW = 1; 讀寄存器的寫法類似,這里就略一下了。這一過程看上去有些復(fù)雜,呵呵,其實(shí)執(zhí)行起來也蠻有效率的,執(zhí)行時(shí)間差不多。這種模擬總線時(shí)序的方式實(shí)際并不復(fù)雜,只是把總線方式下自動(dòng)執(zhí)行的過程手動(dòng)的執(zhí)行了一遍而已。 在DM9000中,還有一些PHY寄存器,也稱之為介質(zhì)無關(guān)接口MII(Media Independent Interface)寄存器。對(duì)這些寄存器的操作會(huì)影響網(wǎng)卡芯片的初始化和網(wǎng)絡(luò)連接,這里不對(duì)其進(jìn)
11、行操作,所以對(duì)這些寄存器的訪問方法這里也略了(在上篇文章中有介紹)。操作不當(dāng)反而使網(wǎng)卡不能連接到網(wǎng)絡(luò)。 至此,我們已經(jīng)寫好了兩個(gè)最基本的函數(shù):dm9000_reg_write()和dm9000_reg_read(),以及前面的宏定義DM_ADD和DM_CMD。下面將一直用到。 2、初始化DM9000網(wǎng)卡芯片。 初始化DM9000網(wǎng)卡芯片的過程,實(shí)質(zhì)上就是填寫、設(shè)置DM9000的控制寄存器的過程,這里以程序?yàn)槔M(jìn)行說明。其中寄存器的名稱宏定義在DM9000.H中已定義好。注:一下函數(shù)中un
12、signed char為一個(gè)字節(jié)unsigned int為兩個(gè)字節(jié)/DM9000初始化void DM9000_init(void) unsigned int i; IO0DIR |= 1 << 8; IO1CLR |= 1 << 8; udelay(500000); IO2SET |= 1 << 8; udelay(500000); &
13、#160; IO1CLR |= 1 << 8; udelay(500000);/*以上部分是利用一個(gè)IO口控制DM9000的RST引腳,使其復(fù)位。這一步可以省略,可以用下面的軟件復(fù)位代替*/ dm9000_reg_write(GPCR, 0x01);/設(shè)置 GPCR(1EH) bit0=1,使DM9000的GPIO3為輸出。 dm9000_reg_write(GPR, 0x00);/GPR bit0=0 使DM9000的GPIO3輸出為低以激活內(nèi)部PHY。
14、0; udelay(5000);/延時(shí)2ms以上等待PHY上電。 dm9000_reg_write(NCR, 0x03);/軟件復(fù)位 udelay(30);/延時(shí)20us以上等待軟件復(fù)位完成 dm9000_reg_write(NCR, 0x00);/復(fù)位完成,設(shè)置正常工作模式。 dm9000_reg_write(NCR, 0x03);/第二次軟件復(fù)位,為了確保軟件復(fù)位完全成功。此步驟是必要的。
15、 udelay(30); dm9000_reg_write(NCR, 0x00);/*以上完成了DM9000的復(fù)位操作*/ dm9000_reg_write(NSR, 0x2c);/清除各種狀態(tài)標(biāo)志位 dm9000_reg_write(ISR, 0x3f);/清除所有中斷標(biāo)志位/*以上清除標(biāo)志位*/ dm9000_reg_write(RCR, 0x39);/接收控制 dm9000_reg_write(TCR, 0x0
16、0);/發(fā)送控制 dm9000_reg_write(BPTR, 0x3f); dm9000_reg_write(FCTR, 0x3a); dm9000_reg_write(RTFCR, 0xff); dm9000_reg_write(SMCR, 0x00);/*以上是功能控制,具體功能參考上一篇文章中的說明,或參考數(shù)據(jù)手冊(cè)的介紹*/ for(i=0; i<6; i+)
17、0; dm9000_reg_write(PAR + i, mac_addri);/mac_addr自己定義一下吧,6個(gè)字節(jié)的MAC地址/*以上存儲(chǔ)MAC地址(網(wǎng)卡物理地址)到芯片中去,這里沒有用EEPROM,所以需要自己寫進(jìn)去*/*關(guān)于MAC地址的說明,要參考網(wǎng)絡(luò)相關(guān)書籍或資料*/ dm9000_reg_write(NSR, 0x2c); dm9000_reg_write(ISR, 0x3f);/*為了保險(xiǎn),上面有清除了一次標(biāo)志位*/ dm9000_r
18、eg_write(IMR, 0x81);/*中斷使能(或者說中斷屏蔽),即開啟我們想要的中斷,關(guān)閉不想要的,這里只開啟的一個(gè)接收中斷*/*以上所有寄存器的具體含義參考上一篇文章,或參考數(shù)據(jù)手冊(cè)*/ 這樣就對(duì)DM9000初始化完成了,怎么樣,挺簡(jiǎn)單的吧。 3、發(fā)送、接收數(shù)據(jù)包 同樣,以程序?yàn)槔?,通過注釋說明。/發(fā)送數(shù)據(jù)包/參數(shù):datas為要發(fā)送的數(shù)據(jù)緩沖區(qū)(以字節(jié)為單位),length為要發(fā)送的數(shù)據(jù)長(zhǎng)度(兩個(gè)字節(jié))。void sendpacket(unsigned char *datas
19、, unsigned int length) unsigned int len, i; dm9000_reg_write(IMR, 0x80);/先禁止網(wǎng)卡中斷,防止在發(fā)送數(shù)據(jù)時(shí)被中斷干擾 len = length; dm9000_reg_write(TXPLH, (len>>8) & 0x0ff); dm9000_reg
20、_write(TXPLL, len & 0x0ff);/*這兩句是將要發(fā)送數(shù)據(jù)的長(zhǎng)度告訴DM9000的寄存器*/ DM_ADD = MWCMD;/這里的寫法是針對(duì)有總線接口的處理器,沒有總線接口的處理器要注意加上時(shí)序。 for(i=0; i<len; i+=2)/16 bit mode udelay(20);
21、; DM_CMD = datasi | (datasi+1<<8); /*上面是將要發(fā)送的數(shù)據(jù)寫到DM9000的內(nèi)部SRAM中的寫FIFO中,注意沒有總線接口的處理器要加上適當(dāng)?shù)臅r(shí)序*/*只需要向這個(gè)寄存器中寫數(shù)據(jù)即可,MWCMD是DM9000內(nèi)部SRAM的DMA指針,根據(jù)處理器模式,寫后自動(dòng)增加*/ dm9000_reg_write(TCR, 0x01);/發(fā)送數(shù)據(jù)到以太網(wǎng)上 while(dm9000_reg_read(NSR) & 0x0c) = 0);/等待數(shù)據(jù)
22、發(fā)送完成 udelay(20); dm9000_reg_write(NSR, 0x2c);/清除狀態(tài)寄存器,由于發(fā)送數(shù)據(jù)沒有設(shè)置中斷,因此不必處理中斷標(biāo)志位 dm9000_reg_write(IMR, 0x81);/DM9000網(wǎng)卡的接收中斷使能 以上是發(fā)送數(shù)據(jù)包,過程很簡(jiǎn)單。而接收數(shù)據(jù)包確需要些說明了。DM9000從網(wǎng)絡(luò)中接到一個(gè)數(shù)據(jù)包后,會(huì)在數(shù)據(jù)包前面加上4個(gè)字節(jié),分別為“01H”、“status”(同RSR寄存器的值)、“LENL”(數(shù)據(jù)包長(zhǎng)度低
23、8位)、“LENH”(數(shù)據(jù)包長(zhǎng)度高8位)。所以首先要讀取這4個(gè)字節(jié)來確定數(shù)據(jù)包的狀態(tài),第一個(gè)字節(jié)“01H”表示接下來的是有效數(shù)據(jù)包,若為“00H”則表示沒有數(shù)據(jù)包,若為其它值則表示網(wǎng)卡沒有正確初始化,需要從新初始化。 如果接收到的數(shù)據(jù)包長(zhǎng)度小于60字節(jié),則DM9000會(huì)自動(dòng)為不足的字節(jié)補(bǔ)上0,使其達(dá)到60字節(jié)。同時(shí),在接收到的數(shù)據(jù)包后DM9000還會(huì)自動(dòng)添加4個(gè)CRC校驗(yàn)字節(jié)??梢圆挥杼幚?。于是,接收到的數(shù)據(jù)包的最小長(zhǎng)度也會(huì)是64字節(jié)。當(dāng)然,可以根據(jù)TCP/IP協(xié)議從首部字節(jié)中出有效字節(jié)數(shù),這部分在后面講解。下面為接收數(shù)據(jù)包的函數(shù)。/接收數(shù)據(jù)包/參數(shù):dat
24、as為接收到是數(shù)據(jù)存儲(chǔ)位置(以字節(jié)為單位)/返回值:接收成功返回?cái)?shù)據(jù)包類型,不成功返回0unsigned int receivepacket(unsigned char *datas) unsigned int i, tem; unsigned int status, len; unsigned char ready; ready = 0;/希望讀取到“01H” status = 0;/數(shù)據(jù)包狀態(tài)
25、0; len = 0; /數(shù)據(jù)包長(zhǎng)度/*以上為有效數(shù)據(jù)包前的4個(gè)狀態(tài)字節(jié)*/ if(dm9000_reg_read(ISR) & 0x01) dm9000_reg_write(ISR, 0x01); /*清除接收中斷標(biāo)志位*/*/*這個(gè)地方遇到了問題,下面的黑色字體語句應(yīng)該替換成成紅色字體,也就是說MRCMDX寄存器如果第一次讀不到數(shù)據(jù),還要讀一次才能確定完全沒有數(shù)據(jù)。在
26、做 PING 實(shí)驗(yàn)時(shí)證明:每個(gè)數(shù)據(jù)包都是通過第二次的讀取MRCMDX寄存器操作而獲知為有效數(shù)據(jù)包的,對(duì)初始化的寄存器做了多次修改依然是此結(jié)果,但是用如下方法來實(shí)現(xiàn),絕不會(huì)漏掉數(shù)據(jù)包。*/ ready = dm9000_reg_read(MRCMDX); / 第一次讀取,一般讀取到的是 00H if(ready & 0x0ff) != 0x01) ready = dm9000_reg_r
27、ead(MRCMDX); / 第二次讀取,總能獲取到數(shù)據(jù) if(ready & 0x01) != 0x01) if(ready & 0x01) != 0x00) /若第二次讀取到的不是 01H 或 00H ,則表示沒有初始化成功
28、60; dm9000_reg_write(IMR, 0x80);/屏幕網(wǎng)卡中斷 DM9000_init();/重新初始化
29、; dm9000_reg_write(IMR, 0x81);/打開網(wǎng)卡中斷 retrun 0;
30、 /* ready = dm9000_reg_read(MRCMDX); / read a byte without pointer increment if(!(ready & 0x01) return 0; */*/*以上表示若接收到的第一個(gè)字節(jié)不是“01H”,則表示沒有數(shù)據(jù)包,返回0*/
31、160; status = dm9000_reg_read(MRCMD); udelay(20); len = DM_CMD; if(!(status & 0xbf00) && (len < 1522) for(i=0; i<len; i+=2)/ 16 bit mode &
32、#160; udelay(20); tem = DM_CMD; datasi = tem & 0x0ff;
33、160; datasi + 1 = (tem >> 8) & 0x0ff; else return 0; /*以上接收數(shù)據(jù)包,注意的地方與發(fā)送數(shù)據(jù)包的地方相同*/
34、if(len > 1000) return 0; if( (HON( ETHBUF->type ) != ETHTYPE_ARP) && (HON( ETHBUF->type ) != ETHTYPE_IP) ) return 0; packet_l
35、en = len;/*以上對(duì)接收到的數(shù)據(jù)包作一些必要的限制,去除大數(shù)據(jù)包,去除非ARP或IP的數(shù)據(jù)包*/ return HON( ETHBUF->type ); /返回?cái)?shù)據(jù)包的類型,這里只選擇是ARP或IP兩種類型 注意:上面的函數(shù)用到了一些宏定義,已經(jīng)在頭文件中定義過,這里說明一下:其中uint16定義為兩個(gè)字節(jié)的變量,根據(jù)C編譯器進(jìn)行定義。unsigned char Buffer1000;/定義了一個(gè)1000字節(jié)的
36、接收發(fā)送緩沖區(qū)uint16 packet_len;/接收、發(fā)送數(shù)據(jù)包的長(zhǎng)度,以字節(jié)為單位。struct eth_hdr /以太網(wǎng)頭部結(jié)構(gòu),為了以后使用方便unsigned char d_mac6; /目的地址unsigned char s_mac6; /源地址uint16 type; /協(xié)議類型;struct arp_hdr /以太網(wǎng)頭部+ARP首部結(jié)構(gòu)struct eth_hdr ethhdr; /以太網(wǎng)首部uint16 hwtype; &
37、#160; /硬件類型(1表示傳輸?shù)氖且蕴W(wǎng)MAC地址)uint16 protocol; /協(xié)議類型(0x0800表示傳輸?shù)氖荌P地址)unsigned char hwlen; /硬件地址長(zhǎng)度(6)unsigned char protolen; /協(xié)議地址長(zhǎng)度(4)uint16 opcode; /操作(1表示ARP請(qǐng)求,2表示ARP應(yīng)答)unsigned char smac6; /
38、發(fā)送端MAC地址unsigned char sipaddr4; /發(fā)送端IP地址unsigned char dmac6; /目的端MAC地址unsigned char dipaddr4; /目的端IP地址;struct ip_hdr /以太網(wǎng)頭部+IP首部結(jié)構(gòu)struct eth_hdr ethhdr; /以太網(wǎng)首部unsigned char vhl, /4位版本號(hào)4位首部長(zhǎng)度(0x45)
39、160; tos; /服務(wù)類型(0) uint16 len, /整個(gè)IP數(shù)據(jù)報(bào)總字節(jié)長(zhǎng)度 ipid, /IP標(biāo)識(shí)
40、0; ipoffset; /3位標(biāo)識(shí)13位偏移unsigned char ttl, /生存時(shí)間(32或64) proto; /協(xié)議(1表示ICM
41、P,2表示IGMP,6表示TCP,17表示UDP)uint16 ipchksum; /首部校驗(yàn)和unsigned char srcipaddr4, /源IP destipaddr4; /目的IP; 以上定義的三種首部結(jié)構(gòu),是根據(jù)TCP/IP協(xié)議的相關(guān)規(guī)范定義的,后面會(huì)對(duì)ARP協(xié)議進(jìn)行詳細(xì)講解。【上半部分完】
42、160; 4、驗(yàn)證初始化中的各個(gè)函數(shù)。 下面我們來看一下,上面所寫的初始化函數(shù)是否可用。以上我們寫好了三個(gè)函數(shù),分別為DM9000_init(),sendpacket()和receivepacket(),保存并命名為dm9000.c。既然我們要進(jìn)行調(diào)試,當(dāng)然要有結(jié)果輸出,根據(jù)自己的處理器的情況寫一個(gè)串口程序,這些函數(shù)是學(xué)某個(gè)單片機(jī)的基礎(chǔ),這里不做詳細(xì)介紹,用到是時(shí)候會(huì)在函數(shù)里注釋一下。 接下來我們來寫個(gè)主函數(shù),新建C文件,命名為mian.c,填寫如下函數(shù):void main(void)
43、unsigned int i; unsigned char c; uart0_init();/初始化串口,調(diào)試時(shí)用到 DM9000_init();/初始化網(wǎng)卡 print_regs();/*通過串口,將DM9000中的寄存器打印出來,顯示在超級(jí)終端上。此函數(shù)根據(jù)自己的處理器進(jìn)行修改,功能僅僅是讀DM9000寄存器dm9000_reg_read(),再通過串口打印出來而已*/ 函數(shù)寫好,保存文件,連接硬件,連接網(wǎng)線到電
44、腦上或局域網(wǎng)上,運(yùn)行結(jié)果如下圖所示: 圖4 顯示寄存器值 這里首先檢查,各個(gè)控制寄存器是否是自己寫進(jìn)去的值,在檢查狀態(tài)寄存器是否正確,其中主要要看NSR寄存器的bit5是否為“1”,該位表示是否連接成功。本例中NSR的值為40H,括號(hào)里的數(shù)為對(duì)應(yīng)的十進(jìn)制數(shù)。 下面我們將主函數(shù)改進(jìn)一下,增加個(gè)中斷接收函數(shù),查看是否能接收到數(shù)據(jù)。void main(void) unsigned int i; unsigned char c;
45、0; uart0_init();/初始化串口,調(diào)試時(shí)用到 DM9000_init();/初始化網(wǎng)卡/*/*這一部分要根據(jù)自己的處理器情況,將DM9000的INT引腳連接到處理器的外部中斷上,打開中斷*/*/ sendpacket(60);/*我事先已經(jīng)在Buffer中存儲(chǔ)了ARP請(qǐng)求數(shù)據(jù)包,這里就直接發(fā)送了,以便接收ARP應(yīng)答包。大家可以先參考后面講的ARP協(xié)議,根據(jù)自己機(jī)器的情況,將數(shù)據(jù)事先存到Buffer中*/ while(1);/等待中斷void int_issue(void) /
46、中斷處理函數(shù),需要根據(jù)自己的處理器進(jìn)行設(shè)置 unsigned int i; i = receivepacket(Buffer);/將數(shù)據(jù)讀取到Buffer中。int_again : if(i = 0) return; else
47、160; print_buffer();/將接收到的所有數(shù)據(jù)打印出來 while(1);/停止在這里等待觀察,注意:實(shí)際應(yīng)用中是不允許停止在中斷中的。 /*/*這里加上這一段,目的是判斷中斷期間是否接收到其它數(shù)據(jù)包。有則加以處理。不加也完全可以*/* 根據(jù)自己的處理器,判斷處理器是否還處在中斷狀態(tài),若是則進(jìn)行如下操作,不是則跳過該段。*/ i =
48、 receivepacket(Buffer); if(i != 0) goto int_again; /*/ 編譯調(diào)試,運(yùn)行結(jié)果如下: 圖5 接收數(shù)據(jù)包中的數(shù)據(jù) 這是一個(gè)ARP應(yīng)答包,包含了我電腦上的MAC地址和局域網(wǎng)內(nèi)的IP地址。 如果一些順利,到這里對(duì)DM9000網(wǎng)卡芯片的初始化工作就完成了。
49、如果出現(xiàn)問題,出現(xiàn)問題首先要檢查寄存器的值是否正確??梢詫M9000中的寄存器打印出來,查看到底是哪里的問題。如果打印出的值很混亂,在確保串口程序無誤的前提下,查看硬件連接,以及寄存器讀寫時(shí)序是否正確,重復(fù)調(diào)試幾次查找原因。 三、ARP協(xié)議的實(shí)現(xiàn) 1、ARP協(xié)議原理簡(jiǎn)述 ARP協(xié)議(Address Resolution Protocol 地址解析協(xié)議),在局域網(wǎng)中,網(wǎng)絡(luò)中實(shí)際傳輸?shù)氖恰皫保瑤锩嬗心繕?biāo)主機(jī)的MAC地址。在以太網(wǎng)中,一個(gè)注意要和另一個(gè)主機(jī)進(jìn)行直接通信,必須要知道目標(biāo)主機(jī)
50、的MAC地址。這個(gè)MAC地址就是標(biāo)識(shí)我們的網(wǎng)卡芯片唯一性的地址。但這個(gè)目標(biāo)MAC地址是如何獲得的呢?這就用到了我們這里講到的地址解析協(xié)議。所有“地址解析”,就是主機(jī)在發(fā)送幀前將目標(biāo)IP地址轉(zhuǎn)換成MAC地址的過程。ARP協(xié)議的基本功能就是通過目標(biāo)設(shè)備的IP地址,查詢目標(biāo)設(shè)備的MAC地址,以保證通信的順利進(jìn)行。所以在第一次通信前,我們知道目標(biāo)機(jī)的IP地址,想要獲知目標(biāo)機(jī)的MAC地址,就要發(fā)送ARP報(bào)文(即ARP數(shù)據(jù)包)。它的傳輸過程簡(jiǎn)單的說就是:我知道目標(biāo)機(jī)的IP地址,那么我就向網(wǎng)絡(luò)中所有的機(jī)器發(fā)送一個(gè)ARP請(qǐng)求,請(qǐng)求中有目標(biāo)機(jī)的IP地址,請(qǐng)求的意思是目標(biāo)機(jī)要是收到了此請(qǐng)求,就把你的MAC地址告訴
51、我。如果目標(biāo)機(jī)不存在,那么此請(qǐng)求自然不會(huì)有人回應(yīng)。若目標(biāo)機(jī)接收到了此請(qǐng)求,它就會(huì)發(fā)送一個(gè)ARP應(yīng)答,這個(gè)應(yīng)答是明確發(fā)給請(qǐng)求者的,應(yīng)答中有MAC地址。我接到了這個(gè)應(yīng)答,我就知道了目標(biāo)機(jī)的MAC地址,就可以進(jìn)行以后的通信了。因?yàn)槊看瓮ㄐ哦家玫組AC地址。 ARP報(bào)文被封裝在以太網(wǎng)幀頭部中傳輸,如圖為ARP請(qǐng)求報(bào)文的頭部格式。 圖6 用于以太網(wǎng)的ARP請(qǐng)求或應(yīng)答分組格式 注意,以太網(wǎng)的傳輸存儲(chǔ)是“大端格式”,即先發(fā)送高字節(jié)后發(fā)送低字節(jié)。例如,兩個(gè)字節(jié)的數(shù)據(jù),先發(fā)送高8位后發(fā)送低8位。所以接收數(shù)據(jù)的時(shí)候要注意存儲(chǔ)順序。
52、; 整個(gè)報(bào)文分成兩部分,以太網(wǎng)首部和ARP請(qǐng)求/應(yīng)答。下面挑重點(diǎn)講述?!耙蕴W(wǎng)目的地址”字段:若是發(fā)送ARP請(qǐng)求,應(yīng)填寫廣播類型的MAC地址FF-FF-FF-FF-FF-FF,意思是讓網(wǎng)絡(luò)上的所有機(jī)器接收到;“幀類型”字段:填寫08-06表示次報(bào)文是ARP協(xié)議;“硬件類型”字段:填寫00-01表示以太網(wǎng)地址,即MAC地址;“協(xié)議類型”字段:填寫08-00表示IP,即通過IP地址查詢MAC地址;“硬件地址長(zhǎng)度”字段:MAC地址長(zhǎng)度為6(以字節(jié)為單位);“協(xié)議地址長(zhǎng)度”字段:IP地址長(zhǎng)度為4(以字節(jié)為單位);“操作類型”字段:ARP數(shù)據(jù)包類型,0表示ARP請(qǐng)求,1表示ARP
53、應(yīng)答;“目的以太網(wǎng)地址”字段:若是發(fā)送ARP請(qǐng)求,這里是需要目標(biāo)機(jī)填充的。 2、ARP的處理程序 ARP協(xié)議原理很簡(jiǎn)單,下面我們來編寫ARP協(xié)議的處理函數(shù)。新建文件命名為arp.c,填寫如下函數(shù):unsigned char mac_addr6 = *,*,*,*,*,*;unsigned char ip_addr4 = 192, 168, *, * ;unsigned char host_ip_addr4 = 192, 168, *, * ;unsigned char host_mac_addr6= 0xff, 0xff,
54、 0xff, 0xff, 0xff, 0xff ; unsigned char Buffer1000;uint16 packet_len;/*這些全局變量,在前面將的文件中有些已經(jīng)有過定義,這里要注意在前面加上“extern”關(guān)鍵字?!?”應(yīng)該根據(jù)自己的機(jī)器修改*/#define HON(n) (uint16)(n) & 0xff) << 8) | (n) & 0xff00) >> 8)/*此宏定義是將小端格式存儲(chǔ)的字(兩個(gè)字節(jié))轉(zhuǎn)換成大端格式存儲(chǔ)*/void arp_request(void) /發(fā)送ARP請(qǐng)求數(shù)據(jù)包/以太網(wǎng)首部memcpy(ARPBU
55、F->ethhdr.d_mac, host_mac_addr, 6);/*字符串拷貝函數(shù),文件要包含<string.h>頭文件。參數(shù)依次是,拷貝目標(biāo)指針,拷貝數(shù)據(jù)源指針,拷貝字符數(shù)*/memcpy(ARPBUF->ethhdr.s_mac, mac_addr, 6);ARPBUF->ethhdr.type = HON( 0x0806 );/*小端格式的編譯器,可以用HON()宏來轉(zhuǎn)換成大端格式,如果你的編譯器是大端格式,直接填寫0x0806即可*/*就是簡(jiǎn)單的按照協(xié)議格式填充,以下同*/ARP首部ARPBUF->hwtype = HON( 1 );ARPBU
56、F->protocol = HON( 0x0800 );ARPBUF->hwlen = 6;ARPBUF->protolen = 4;ARPBUF->opcode = HON( 0 );memcpy(ARPBUF->smac, mac_addr, 6);memcpy(ARPBUF->sipaddr, ip_addr, 4);memcpy(ARPBUF->dipaddr, host_ip_addr, 4);packet_len = 42;/14+28=42sendpacket( Buffer, packet_len );注釋:ARPBUF的宏定義和ARP
57、首部結(jié)構(gòu),在前面已經(jīng)講過。同時(shí)注意執(zhí)行該函數(shù)時(shí)中斷的處理。這里沒作處理。 看上去很easy吧,下面函數(shù)實(shí)現(xiàn)接收ARP請(qǐng)求或接收ARP應(yīng)答的處理。unsigned char arp_process(void)/ARP接收函數(shù),成功返回1,否則返回0/簡(jiǎn)單判斷ARP數(shù)據(jù)包有無損壞,有損壞則丟棄,不予處理if( packet_len < 28 )/ARP數(shù)據(jù)長(zhǎng)度為28字節(jié)為無效數(shù)據(jù)return 0;switch ( HON( ARPBUF->opcode ) ) case 0 : /處理ARP
58、請(qǐng)求 if( ARPBUF->dipaddr0 = ip_addr0 && ARPBUF->dipaddr1 = ip_addr1 && ARPBUF->dipadd
59、r2 = ip_addr2 && ARPBUF->dipaddr3 = ip_addr3 )/判斷是否是自己的IP,是否向自己詢問MAC地址。 ARPBUF->opcode = HON(
60、 2 );/設(shè)置為ARP應(yīng)答 memcpy(ARPBUF->dmac, ARPBUF->smac, 6); memcpy(ARPBUF->ethhdr.d_mac, ARPBUF->smac, 6);
61、160; memcpy(ARPBUF->smac, mac_addr, 6); memcpy(ARPBUF->ethhdr.s_mac, mac_addr, 6); memcpy(ARPBUF->dipaddr, ARPBUF->sipad
62、dr, 4); memcpy(ARPBUF->sipaddr, ip_addr, 4); ARPBUF->ethhdr.type = HON( 0x0806 );
63、60; packet_len = 42; sendpacket( Buffer, packet_len );/發(fā)送ARP數(shù)據(jù)包 return 1; else
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 實(shí)物標(biāo)識(shí)大單元課程設(shè)計(jì)
- 舊房交易合同(標(biāo)準(zhǔn)版)
- 出資經(jīng)營(yíng)合同書(范本)
- 銅精礦冶煉與雜質(zhì)控制技術(shù)考核試卷
- 通信設(shè)備專家級(jí)電池健康狀態(tài)監(jiān)測(cè)考核試卷
- 礦山機(jī)械質(zhì)量管理工具與方法應(yīng)用考核試卷
- 錫冶煉行業(yè)安全生產(chǎn)與監(jiān)管政策考核試卷
- 鍛造工藝在工程機(jī)械行業(yè)的應(yīng)用考核試卷
- 葡萄酒釀造過程中的釀造產(chǎn)業(yè)鏈延伸與拓展考核試卷
- 六年級(jí)人教版音樂知識(shí)解析
- 2024版美團(tuán)商家入駐合作標(biāo)準(zhǔn)協(xié)議書
- 《1.4.1 用空間向量研究直線、平面的位置關(guān)系》教案、導(dǎo)學(xué)案、同步練習(xí)
- 電廠項(xiàng)目選址報(bào)告
- 氨磺必利口服溶液-臨床用藥解讀
- 《陸上風(fēng)電場(chǎng)工程概算定額》(NB-T 31010-2019)
- 華為交換機(jī)檢測(cè)報(bào)告
- 【海天味業(yè)公司人才激勵(lì)機(jī)制現(xiàn)狀、問題及優(yōu)化建議(含問卷)15000字(論文)】
- 大數(shù)據(jù)時(shí)代薪酬管理新變研究
- 農(nóng)業(yè)機(jī)械操作的培訓(xùn)課程
- 腹高壓的護(hù)理
- 備品備件消耗分析報(bào)告
評(píng)論
0/150
提交評(píng)論