单片机驱动DM9000网卡芯片(详细调试过程)【下】

   

http://hi.baidu.com/mcu8031/blog/item/c95903138671c625dc540171.html

单片机驱动DM9000网卡芯片(详细调试过程)【下】

4、验证初始化中的各个函数。

下面我们来看一下,上面所写的初始化函数是否可用。以上我们写好了三个函数,分别为

DM9000_init(),sendpacket()和receivepacket(),保存并命名为dm9000.c。既然我们要进行调试,当

然要有结果输出,根据自己的处理器的情况写一个串口程序,这些函数是学某个单片机的基础,这里不

做详细介绍,用到是时候会在函数里注释一下。

接下来我们来写个主函数,新建C文件,命名为mian.c,填写如下函数:

void main(void)

{

    unsigned int i;

    unsigned char c;

    uart0_init();//初始化串口,调试时用到

    DM9000_init();//初始化网卡

    print_regs();/*通过串口,将DM9000中的寄存器打印出来,显示在超级终端上。此函数根据自己

的处理器进行修改,功能仅仅是读DM9000寄存器dm9000_reg_read(),再通过串口打印出来而已*/

}

函数写好,保存文件,连接硬件,连接网线到电脑上或局域网上,运行结果如下图所示: clip_image001

图4 显示寄存器值

这里首先检查,各个控制寄存器是否是自己写进去的值,在检查状态寄存器是否正确,其中主要要

看NSR寄存器的bit[6]是否为“1”,该位表示是否连接成功。本例中NSR的值为40H,括号里的数为对应

的十进制数。

下面我们将主函数改进一下,增加个中断接收函数,查看是否能接收到数据。

void main(void)

{

    unsigned int i;

    unsigned char c;

    uart0_init();//初始化串口,调试时用到

    DM9000_init();//初始化网卡

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

/*这一部分要根据自己的处理器情况,将DM9000的INT引脚连接到处理器的外部中断上,打开中断*/

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

    sendpacket(60);/*我事先已经在Buffer[]中存储了ARP请求数据包,这里就直接发送了,以便接收

ARP应答包。大家可以先参考后面讲的ARP协议,根据自己机器的情况,将数据事先存到Buffer[]中*/

    while(1);//等待中断

}

void int_issue(void) //中断处理函数,需要根据自己的处理器进行设置

{

    unsigned int i;

    i = receivepacket(Buffer);//将数据读取到Buffer中。

int_again :

    if(i == 0)

    {

        return;

    }

     else

     {

        print_buffer();//将接收到的所有数据打印出来

         while(1);//停止在这里等待观察,注意:实际应用中是不允许停止在中断中的。

     }

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

/*这里加上这一段,目的是判断中断期间是否接收到其它数据包。有则加以处理。不加也完全可以*/

/* 根据自己的处理器,判断处理器是否还处在中断状态,若是则进行如下操作,不是则跳过该段。*/

    i = receivepacket(Buffer);

    if(i != 0)

    {

        goto int_again;

    }

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

}

编译调试,运行结果如下: clip_image002

图5 接收数据包中的数据

这是一个ARP应答包,包含了我电脑上的MAC地址和局域网内的IP地址。反正我也不是啥重要人物,

这里就不保密了,呵呵。

如果一些顺利,到这里对DM9000网卡芯片的初始化工作就完成了。如果出现问题,首先要

检查寄存器的值是否正确。可以将DM9000中的寄存器打印出来,查看到底是哪里的问题。如果打印出的

值很混乱,在确保串口程序无误的前提下,查看硬件连接,以及寄存器读写时序是否正确,重复调试几

次查找原因。

三、ARP协议的实现

    1、ARP协议原理简述

    ARP协议(Address Resolution Protocol 地址解析协议),在局域网中,网络中实际传输的是“

帧”,帧里面有目标主机的MAC地址。在以太网中,一个注意要和另一个主机进行直接通信,必须要知

道目标主机的MAC地址。这个MAC地址就是标识我们的网卡芯片唯一性的地址。但这个目标MAC地址是如

何获得的呢?这就用到了我们这里讲到的地址解析协议。所有“地址解析”,就是主机在发送帧前将目

标IP地址转换成MAC地址的过程。ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC

地址,以保证通信的顺利进行。所以在第一次通信前,我们知道目标机的IP地址,想要获知目标机的

MAC地址,就要发送ARP报文(即ARP数据包)。它的传输过程简单的说就是:我知道目标机的IP地址,

那么我就向网络中所有的机器发送一个ARP请求,请求中有目标机的IP地址,请求的意思是目标机要是

收到了此请求,就把你的MAC地址告诉我。如果目标机不存在,那么此请求自然不会有人回应。若目标

机接收到了此请求,它就会发送一个ARP应答,这个应答是明确发给请求者的,应答中有MAC地址。我接

到了这个应答,我就知道了目标机的MAC地址,就可以进行以后的通信了。因为每次通信都要用到MAC地

址。

    ARP报文被封装在以太网帧头部中传输,如图为ARP请求报文的头部格式。 clip_image003

图6 用于以太网的ARP请求或应答分组格式

注意,以太网的传输存储是“大端格式”,即先发送高字节后发送低字节。例如,两个字节的数据

,先发送高8位后发送低8位。所以接收数据的时候要注意存储顺序。

整个报文分成两部分,以太网首部和ARP请求/应答。下面挑重点讲述。

“以太网目的地址”字段:若是发送ARP请求,应填写广播类型的MAC地址FF-FF-FF-FF-FF-FF,意思是

让网络上的所有机器接收到;

“帧类型”字段:填写08-06表示次报文是ARP协议;

“硬件类型”字段:填写00-01表示以太网地址,即MAC地址;

“协议类型”字段:填写08-00表示IP,即通过IP地址查询MAC地址;

“硬件地址长度”字段:MAC地址长度为6(以字节为单位);

“协议地址长度”字段:IP地址长度为4(以字节为单位);

“操作类型”字段:ARP数据包类型,0表示ARP请求,1表示ARP应答;

“目的以太网地址”字段:若是发送ARP请求,这里是需要目标机填充的。

    2、ARP的处理程序

    ARP协议原理很简单,下面我们来编写ARP协议的处理函数。新建文件命名为arp.c,填写如下函数

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;

/*这些全局变量,在前面将的文件中有些已经有过定义,这里要注意在前面加上“extern”关键字。“

*”应该根据自己的机器修改*/

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

/*此宏定义是将小端格式存储的字(两个字节)转换成大端格式存储*/

void arp_request(void) //发送ARP请求数据包

{

//以太网首部

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

/*字符串拷贝函数,文件要包含<string.h>头文件。参数依次是,拷贝目标指针,拷贝数据源指针,拷

贝字符数*/

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

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

/*小端格式的编译器,可以用HON()宏来转换成大端格式,如果你的编译器是大端格式,直接填写

0x0806即可*/

/*就是简单的按照协议格式填充,以下同*/

//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首部结构,在前面已经讲过。同时注意执行该函数时中断的处理。这里没

作处理。

看上去很easy吧,下面函数实现接收ARP请求或接收ARP应答的处理。

unsigned char arp_process(void)//ARP接收函数,成功返回1,否则返回0

{

//简单判断ARP数据包有无损坏,有损坏则丢弃,不予处理

if( packet_len < 28 )//ARP数据长度为28字节为无效数据

{

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 );//设置为ARP应答

             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 );//发送ARP数据包

             return 1;

         }

         else

         {

             return 0;

         }

         break;

   case 1    : //处理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,是否是给自己的应答

         {

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

          return 1;

         }

         else

         {

             return 0;

         }

         break;

default     ://不是ARP协议

         return 0;

}

}

根据ARP协议格式看这两个函数并不困难。于是我们又得到两个函数:arp_request()和

arp_process()。

    3、ARP程序调试

下面我们修改主函数和中断处理函数。

将mian()函数中的“sendpacket(60);”语句换成“arp_request();”语句。

void int_issue(void) //中断处理函数,需要根据自己的处理器进行设置

{

    unsigned int i;

    i = receivepacket(Buffer);//将数据读取到Buffer中。

    if(i == 0)

    {

        return;

    }

     else

     {

         i = arp_process();

         if(i == 1)//判断是否是ARP协议

             print_hostmacaddr();//打印目标机的MAC地址,就是用串口打印host_mac_addr[]中的6

个字节

     }

}

保存运行调试。 clip_image004

图7 主机MAC地址

至此,关于DM9000的调试过程就完成了。之后我还调试了UDP通讯、TCP通讯等,主要是关于协议的

处理了,这里就不介绍了。有兴趣的朋友可以参看《TCP/IP协议》第一卷,将会有很大帮助。希望这些

调试过程能为读者或多或少的提供些有用的信息,也欢迎大家和我一起讨论。

我的Email:mengqx25@163.com

转载于:https://www.cnblogs.com/xilentz/archive/2010/07/12/1775611.html

单片机多功能调试助手分两个版本,分别是:含CH375 DLL版本、无DLL版本,它们的区别主要体现在是否对CH37X USB提供支持。为了减少对服务器的负担,现在单片机多功能调试助手只提供无DLL的版本,即不对CH372/CH375 USB芯片提供支持,只支持HID USB设备!含有DLL版本的暂只提供给购买开发板的买家! 在此感谢网络上众多的朋友的反馈与建议,没有他们的支持就没有该软件的茁壮成长!本人会继续努力进行更新,为大家提供一个功能完善与稳定的调试工具,为大家节省不必要的时间。 本软件的使用手册可到www.smartmcu.com进行下载! 作者: 温子祺 联系方式:wenziqi@hotmail.com或wenziqi@gmail.com 博客: http://www.cnblogs.com/wenziqi 淘宝: http://shop61791934.taobao.com/ 官网: www.smartmcu.com 注:软件版权归作者所有,未经作者允许,禁止用于商业用途,违者必究! ===================================================== 2015-12-12 (1)内嵌了蓝牙调试助手功能。 ===================================================== 2015-12-8 (1)在Win7以上系统执行更稳定,默认支持管理员运行。 ===================================================== 2013-07-23 (1)增强稳定性 ===================================================== 2012-05-21 (1)优化了Ping和TCP连接过程 (2)开放了检验源码 ===================================================== 2012-02-06 (1)发送区域支持保存发送数据256字节 ===================================================== 2011-10-17 (1)帧换行功能可调 ===================================================== 2011-07-10 (1)串口、USB、网咯接收数据时能够自动对\n和\r\n进行识别 注意:Windows默认对'\r\n'进行换行的 Linux 默认对‘\n’进行换行的 ===================================================== 2011-07-26 (1)修正了PING会出现大延时的问题 (2)修正了网络调试发送计数错误的BUG ===================================================== 2011-07-24 (1)数据校验修正和添加了部分功能 (2)服务器支持多项发送 ===================================================== 2011-07-10 (1)串口、USB、网络接收数据时能够自动对\n和\r\n进行识别 注意:Windows默认对'\r\n'进行换行的 Linux 默认对‘\n’进行换行的 ===================================================== 2011-05-05 (1)串口调试添加Modem模式 ===================================================== 2011-04-25 (1)修正Ping过慢的BUG ===================================================== 2011-04-20 (1)在接收区添加了右键菜单(清空、显示控制、文本输出控制) ===================================================== 2011-04-13 (1)修正串口调试隐藏BUG (2)提升了界面启动的速度 ===================================================== 2011-04-07 (1)发送数据支持回车换行 (2)修正了C51代码向导的BUG ===================================================== 2011-03-31 (1)修改了清空发送和清空接收的BUG ===================================================== 2011-03-24 (1)修改了下载功能 (2)修正了HexToText 和 HexToBin ===================================================== 2011-03-03 (1)在C51代码向导当中增加了计算软件延时的功能 (2)修正了通信端口监视不正常的BUG (3)解决了回车键会退出界面的BUG ===================================================== 2011-02-28 (1)在串口、USB、网络接收数据的过程中,能够正确显示当前接收数据的速度 (2)在C51代码向导当中增加了输出为Keil工程的功能,方便编译 ===================================================== 2011-02-25 (1)增加了双击文本框可以保存数据记录的功能 (2)增加了Hex/Bin文件输出文本的功能 ===================================================== 2011-02-20 (1)修正了在连续发送的逻辑BUG (2)修正了串口监视关闭时发生内存错误的BUG ===================================================== 2011-02-13 (1)修正了在无USB HID设备的情况下还能够打开USB设备的BUG ===================================================== 2011-02-11 (1)修正了界面风格,防止在不同的系统显示不一致! ===================================================== 2011-02-07 (1)修复了部分BUG,如串口高级监视、代码生成等。 (2)编码转换增强、调试工具增强(支持帧换行,方便分析数据)! (3)USB支持自动寻找设备! ===================================================== 2011-01-31 (1)添加了串口高级监视功能,能够监视其他应用程序的串口通信。 (2)添加了8051单片机代码生成功能。(懒人的必备O(∩_∩)O哈哈~) ===================================================== 2011-01-15 (1)修正了发送大量数据出错的BUG ===================================================== 2011-01-13 (1)修正了串口、USB、网络监视的BUG ===================================================== 2011-01-08 (1)新增加COM、USB、NET多项发送功能,更加利于调试! ===================================================== 2011-01-02 (1)调整了界面,让其显示更加多的数据! ===================================================== 2010-12-28 (1)修正Hex接收会出错的BUG ===================================================== 2010-12-21 (1)完美支持中文字数据收发 ===================================================== 2010-12-14 (1)修正COM、USB、NET、SERVER接收数据时会出现乱码的BUG (2)优化了线程接收数据的策略 ===================================================== 2010-12-10 (1)支持USB、网络接口监视 (2)优化了自动升级策略 (3)增强了位图输出16进制数功能(支持单色图、16位图、24位图) (4)具有自动保存参数功能 ===================================================== 2010-12-02 (1)修正了串口检测、接收策略, (2)添加了串口监视功能 (3)添加了BCC校验 (4)增强字模制作功能(支持特殊字符、英文、汉字等) ===================================================== 2010-11-29 (1)添加了记录发送、接收字节数的统计功能 (2)添加了自动检测新版本的功能 ===================================================== 2010-11-25 (1)添加了连续发送的功能 (2)添加了在线下载新版本的功能 (3)完善服务器功能 (4)完善了字模输出(摆脱外接字符文件) (5)完善了位图转16进制文件功能,可保存为C文件 ===================================================== 2010-11-02 (1)添加了服务器功能,网络调试更方便! (2)界面更加宽阔,显示更多的信息! ===================================================== 2010-09-26 (1)修正了单片机功能助手运行时间长导致的假死问题。(多谢网友提供宝贵的意见) ===================================================== 2010-09-01 (1)修正了串口类,提升接收数据的效率。 ===================================================== 2010-08-03 (1)在检验值计算支持TCP/IP校验和计算 (2)在NET调试新增加了Ping功能 ===================================================== 2010-07-28 (1)修正CRC计算错误 ===================================================== 2010-07-15 (1)修正打开关闭串口,接收数据文本框数据丢失 (2)串口对话框更为简洁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值