<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 單片機驅(qū)動DM9000網(wǎng)卡芯片詳細調(diào)試過程

          單片機驅(qū)動DM9000網(wǎng)卡芯片詳細調(diào)試過程

          作者: 時間:2016-10-07 來源:網(wǎng)絡(luò) 收藏

            4、驗證初始化中的各個函數(shù)。

          本文引用地址:http://www.ex-cimer.com/article/201610/310907.htm

            下面我們來看一下,上面所寫的初始化函數(shù)是否可用。以上我們寫好了三個函數(shù),分別為

            _init(),sendpacket()和receivepacket(),保存并命名為dm9000.c。既然我們要進行調(diào)試,當(dāng)

            然要有結(jié)果輸出,根據(jù)自己的處理器的情況寫一個串口程序,這些函數(shù)是學(xué)某個單片機的基礎(chǔ),這里不

            做詳細介紹,用到是時候會在函數(shù)里注釋一下。

            接下來我們來寫個主函數(shù),新建C文件,命名為mian.c,填寫如下函數(shù):

            void main(void)

            {

            unsigned int i;

            unsigned char c;

            uart0_init();//初始化串口,調(diào)試時用到

            _init();//初始化網(wǎng)卡

            print_regs();/*通過串口,將中的寄存器打印出來,顯示在超級終端上。此函數(shù)根據(jù)自己

            的處理器進行修改,功能僅僅是讀DM9000寄存器dm9000_reg_read(),再通過串口打印出來而已*/

            }

            函數(shù)寫好,保存文件,連接硬件,連接網(wǎng)線到電腦上或局域網(wǎng)上,運行結(jié)果如下圖所示:

           

            圖4 顯示寄存器值

            這里首先檢查,各個控制寄存器是否是自己寫進去的值,在檢查狀態(tài)寄存器是否正確,其中主要要

            看NSR寄存器的bit[5]是否為“1”,該位表示是否連接成功。本例中NSR的值為40H,括號里的數(shù)為對應(yīng)

            的十進制數(shù)。

            下面我們將主函數(shù)改進一下,增加個中斷接收函數(shù),查看是否能接收到數(shù)據(jù)。

            void main(void)

            {

            unsigned int i;

            unsigned char c;

            uart0_init();//初始化串口,調(diào)試時用到

            DM9000_init();//初始化網(wǎng)卡

            /********************************************************************************/

            /*這一部分要根據(jù)自己的處理器情況,將DM9000的INT引腳連接到處理器的外部中斷上,打開中斷*/

            /********************************************************************************/

            sendpacket(60);/*我事先已經(jīng)在Buffer[]中存儲了ARP請求數(shù)據(jù)包,這里就直接發(fā)送了,以便接收

            ARP應(yīng)答包。大家可以先參考后面講的ARP協(xié)議,根據(jù)自己機器的情況,將數(shù)據(jù)事先存到Buffer[]中*/

            while(1);//等待中斷

            }

            void int_issue(void) //中斷處理函數(shù),需要根據(jù)自己的處理器進行設(shè)置

            {

            unsigned int i;

            i = receivepacket(Buffer);//將數(shù)據(jù)讀取到Buffer中。

            int_again :

            if(i == 0)

            {

            return;

            }

            else

            {

            print_buffer();//將接收到的所有數(shù)據(jù)打印出來

            while(1);//停止在這里等待觀察,注意:實際應(yīng)用中是不允許停止在中斷中的。

            }

            /************************************************************************************/

            /*這里加上這一段,目的是判斷中斷期間是否接收到其它數(shù)據(jù)包。有則加以處理。不加也完全可以*/

            /* 根據(jù)自己的處理器,判斷處理器是否還處在中斷狀態(tài),若是則進行如下操作,不是則跳過該段。*/

            i = receivepacket(Buffer);

            if(i != 0)

            {

            goto int_again;

            }

            /************************************************************************************/

            }

            編譯調(diào)試,運行結(jié)果如下:

           

            圖5 接收數(shù)據(jù)包中的數(shù)據(jù)

            這是一個ARP應(yīng)答包,包含了我電腦上的MAC地址和局域網(wǎng)內(nèi)的IP地址。反正我也不是啥重要人物,

            這里就不保密了,呵呵。

            如果一些順利,到這里對DM9000網(wǎng)卡的初始化工作就完成了。如果出現(xiàn)問題,出現(xiàn)問題首先要

            檢查寄存器的值是否正確??梢詫M9000中的寄存器打印出來,查看到底是哪里的問題。如果打印出的

            值很混亂,在確保串口程序無誤的前提下,查看硬件連接,以及寄存器讀寫時序是否正確,重復(fù)調(diào)試幾

            次查找原因。

            三、ARP協(xié)議的實現(xiàn)

            1、ARP協(xié)議原理簡述

            ARP協(xié)議(Address Resolution Protocol 地址解析協(xié)議),在局域網(wǎng)中,網(wǎng)絡(luò)中實際傳輸?shù)氖?ldquo;

            幀”,幀里面有目標(biāo)主機的MAC地址。在以太網(wǎng)中,一個注意要和另一個主機進行直接通信,必須要知

            道目標(biāo)主機的MAC地址。這個MAC地址就是標(biāo)識我們的網(wǎng)卡唯一性的地址。但這個目標(biāo)MAC地址是如

            何獲得的呢?這就用到了我們這里講到的地址解析協(xié)議。所有“地址解析”,就是主機在發(fā)送幀前將目

            標(biāo)IP地址轉(zhuǎn)換成MAC地址的過程。ARP協(xié)議的基本功能就是通過目標(biāo)設(shè)備的IP地址,查詢目標(biāo)設(shè)備的MAC

            地址,以保證通信的順利進行。所以在第一次通信前,我們知道目標(biāo)機的IP地址,想要獲知目標(biāo)機的

            MAC地址,就要發(fā)送ARP報文(即ARP數(shù)據(jù)包)。它的傳輸過程簡單的說就是:我知道目標(biāo)機的IP地址,

            那么我就向網(wǎng)絡(luò)中所有的機器發(fā)送一個ARP請求,請求中有目標(biāo)機的IP地址,請求的意思是目標(biāo)機要是

            收到了此請求,就把你的MAC地址告訴我。如果目標(biāo)機不存在,那么此請求自然不會有人回應(yīng)。若目標(biāo)

            機接收到了此請求,它就會發(fā)送一個ARP應(yīng)答,這個應(yīng)答是明確發(fā)給請求者的,應(yīng)答中有MAC地址。我接

            到了這個應(yīng)答,我就知道了目標(biāo)機的MAC地址,就可以進行以后的通信了。因為每次通信都要用到MAC地

            址。

            ARP報文被封裝在以太網(wǎng)幀頭部中傳輸,如圖為ARP請求報文的頭部格式。

           

            圖6 用于以太網(wǎng)的ARP請求或應(yīng)答分組格式

            注意,以太網(wǎng)的傳輸存儲是“大端格式”,即先發(fā)送高字節(jié)后發(fā)送低字節(jié)。例如,兩個字節(jié)的數(shù)據(jù)

            ,先發(fā)送高8位后發(fā)送低8位。所以接收數(shù)據(jù)的時候要注意存儲順序。

            整個報文分成兩部分,以太網(wǎng)首部和ARP請求/應(yīng)答。下面挑重點講述。

            “以太網(wǎng)目的地址”字段:若是發(fā)送ARP請求,應(yīng)填寫廣播類型的MAC地址FF-FF-FF-FF-FF-FF,意思是

            讓網(wǎng)絡(luò)上的所有機器接收到;

            “幀類型”字段:填寫08-06表示次報文是ARP協(xié)議;

            “硬件類型”字段:填寫00-01表示以太網(wǎng)地址,即MAC地址;

            “協(xié)議類型”字段:填寫08-00表示IP,即通過IP地址查詢MAC地址;

            “硬件地址長度”字段:MAC地址長度為6(以字節(jié)為單位);

            “協(xié)議地址長度”字段:IP地址長度為4(以字節(jié)為單位);

            “操作類型”字段:ARP數(shù)據(jù)包類型,0表示ARP請求,1表示ARP應(yīng)答;

            “目的以太網(wǎng)地址”字段:若是發(fā)送ARP請求,這里是需要目標(biāo)機填充的。

            2、ARP的處理程序

            ARP協(xié)議原理很簡單,下面我們來編寫ARP協(xié)議的處理函數(shù)。新建文件命名為arp.c,填寫如下函數(shù)

           ?。?/p>

            unsigned char mac_addr[6] = {*,*,*,*,*,*};

            unsigned char ip_addr[4] = { 192, 168, *, * };

            unsigned char host_ip_addr[4] = { 192, 168, *, * };

            unsigned char host_mac_addr[6]={ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

            unsigned char Buffer[1000];

            uint16 packet_len;

            /*這些全局變量,在前面將的文件中有些已經(jīng)有過定義,這里要注意在前面加上“extern”關(guān)鍵字。“

            *”應(yīng)該根據(jù)自己的機器修改*/

            #define HON(n) ((((uint16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))

            /*此宏定義是將小端格式存儲的字(兩個字節(jié))轉(zhuǎn)換成大端格式存儲*/

            void arp_request(void) //發(fā)送ARP請求數(shù)據(jù)包

            {

            //以太網(wǎng)首部

            memcpy(ARPBUF->ethhdr.d_mac, host_mac_addr, 6);

            /*字符串拷貝函數(shù),文件要包含頭文件。參數(shù)依次是,拷貝目標(biāo)指針,拷貝數(shù)據(jù)源指針,拷

            貝字符數(shù)*/

            memcpy(ARPBUF->ethhdr.s_mac, mac_addr, 6);

            ARPBUF->ethhdr.type = HON( 0x0806 );

            /*小端格式的編譯器,可以用HON()宏來轉(zhuǎn)換成大端格式,如果你的編譯器是大端格式,直接填寫

            0x0806即可*/

            /*就是簡單的按照協(xié)議格式填充,以下同*/

            //ARP首部

            ARPBUF->hwtype = HON( 1 );

            ARPBUF->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=42

            sendpacket( Buffer, packet_len );

            }

            注釋:ARPBUF的宏定義和ARP首部結(jié)構(gòu),在前面已經(jīng)講過。同時注意執(zhí)行該函數(shù)時中斷的處理。這里沒

            作處理。

            看上去很easy吧,下面函數(shù)實現(xiàn)接收ARP請求或接收ARP應(yīng)答的處理。

            unsigned char arp_process(void)//ARP接收函數(shù),成功返回1,否則返回0

            {

            //簡單判斷ARP數(shù)據(jù)包有無損壞,有損壞則丟棄,不予處理

            if( packet_len < 28 )//ARP數(shù)據(jù)長度為28字節(jié)為無效數(shù)據(jù)

            {

            return 0;

            }

            switch ( HON( ARPBUF->opcode ) )

            {

            case 0 : //處理ARP請求

            if( ARPBUF->dipaddr[0] == ip_addr[0] &&

            ARPBUF->dipaddr[1] == ip_addr[1] &&

            ARPBUF->dipaddr[2] == ip_addr[2] &&

            ARPBUF->dipaddr[3] == ip_addr[3] )//判斷是否是自己的IP,是否向自己詢問MAC地址

            。

            {

            ARPBUF->opcode = HON( 2 );//設(shè)置為ARP應(yīng)答

            memcpy(ARPBUF->dmac, ARPBUF->smac, 6);

            memcpy(ARPBUF->ethhdr.d_mac, ARPBUF->smac, 6);

            memcpy(ARPBUF->smac, mac_addr, 6);

            memcpy(ARPBUF->ethhdr.s_mac, mac_addr, 6);

            memcpy(ARPBUF->dipaddr, ARPBUF->sipaddr, 4);

            memcpy(ARPBUF->sipaddr, ip_addr, 4);

            ARPBUF->ethhdr.type = HON( 0x0806 );

            packet_len = 42;

            sendpacket( Buffer, packet_len );//發(fā)送ARP數(shù)據(jù)包

            return 1;

            }

            else

            {

            return 0;

            }

            break;

            case 1 : //處理ARP應(yīng)答

            if( ARPBUF->dipaddr[0] == ip_addr[0] &&

            ARPBUF->dipaddr[1] == ip_addr[1] &&

            ARPBUF->dipaddr[2] == ip_addr[2] &&

            ARPBUF->dipaddr[3] == ip_addr[3] )//再次判斷IP,是否是給自己的應(yīng)答

            {

            memcpy(host_mac_addr, ARPBUF->smac, 6);//保存服務(wù)器MAC地址

            return 1;

            }

            else

            {

            return 0;

            }

            break;

            default ://不是ARP協(xié)議

            return 0;

            }

            }

            根據(jù)ARP協(xié)議格式看這兩個函數(shù)并不困難。于是我們又得到兩個函數(shù):arp_request()和

            arp_process()。

            3、ARP程序調(diào)試

            下面我們修改主函數(shù)和中斷處理函數(shù)。

            將mian()函數(shù)中的“sendpacket(60);”語句換成“arp_request();”語句。

            void int_issue(void) //中斷處理函數(shù),需要根據(jù)自己的處理器進行設(shè)置

            {

            unsigned int i;

            i = receivepacket(Buffer);//將數(shù)據(jù)讀取到Buffer中。

            if(i == 0)

            {

            return;

            }

            else

            {

            i = arp_process();

            if(i == 1)//判斷是否是ARP協(xié)議

            print_hostmacaddr();//打印目標(biāo)機的MAC地址,就是用串口打印host_mac_addr[]中的6

            個字節(jié)

            }

            }

            保存運行調(diào)試。

           

            圖7 主機MAC地址

            至此,關(guān)于DM9000的調(diào)試過程就完成了。之后我還調(diào)試了UDP通訊、TCP通訊等,主要是關(guān)于協(xié)議的

            處理了,這里就不介紹了。有興趣的朋友可以參看《TCP/IP協(xié)議》第一卷,將會有很大幫助。希望這些

            調(diào)試過程能為讀者或多火燒的提供些有用的信息,也歡迎大家和我一起討論。


          上一頁 1 2 下一頁

          關(guān)鍵詞: DM9000 芯片

          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();