单片机驱动DM9000网卡芯片

发布者:RadiantBreeze最新更新时间:2015-11-18 来源: eefocus关键字:单片机驱动  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网卡芯片(详细调试过程)【下】

图4 显示寄存器值

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

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

的十进制数。

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

void main(void)

{

    unsigned int i;

    unsigned char c;

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

    DM9000_init();//初始化网卡

    sendpacket(60);

    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;

    }

}

    编译调试,运行结果如下: 【转】单片机驱动DM9000网卡芯片(详细调试过程)【下】

图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请求报文的头部格式。 【转】单片机驱动DM9000网卡芯片(详细调试过程)【下】

图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请求,这里是需要目标机填充的。[page]


    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;

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

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

{

//以太网首部

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

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

ARPBUF->ethhdr.type = 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

个字节

     }

}

    保存运行调试。 【转】单片机驱动DM9000网卡芯片(详细调试过程)【下】

图7 主机MAC地址

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

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

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

关键字:单片机驱动  DM9000  网卡芯片 引用地址:单片机驱动DM9000网卡芯片

上一篇:STC单片机EEPROM的应用和程序
下一篇:对ADC12模块的心得——msp430f5529

推荐阅读最新更新时间:2024-03-16 14:40

51单片机驱动ADC0809片内RAM存转换结果汇编程序
;入口:通道1的模拟量, ;出口:片内RAM开辟一个数据区,用于存放A/D转换结果, IN0 IN7的结果 ;分别存于30H 37H 8个单元中 AD0809: MOV R1,#01H ACALL AD0809_1 RET AD0809_1:MOV DPTR,# ;通道地址 MOV A,R1 ;送通道号 MOVX @DPTR,A;启动转换 WAIT: NOP JNB R1.7,WAIT ;P1.7为EOC信号 为1完成,0,转换中。 MOVX A,@DPTR ;转换完成 XCH A,R1 ADD A,#30H XCH A,R1 MOV @R1,A RET
[单片机]
51单片机+74HC138驱动16*96点阵显示汉字的Proteus仿真+源代码
1 6*96点阵仿真原理图如下 单片机源码如下: #include reg52.h #define uchar unsigned char #define uint unsigned int #define ulong unsigned long #define CTRL_PORT P2 #define DATA_PORT P0 #define ADDR_PORT P1 uchar code *p; uchar code zifu ={ {0x00,0x01,0x00,0x01,0x3F,0x01,0xA0,0x7F,0xA1,0x20,0x52,0x12,0x14,0x02,0x08,0
[单片机]
51<font color='red'>单片机</font>+74HC138<font color='red'>驱动</font>16*96点阵显示汉字的Proteus仿真+源代码
u-boot-2009.08在mini2440上的移植(四)---增加DM9000驱动和命令自动补全功能
移植环境 1,主机环境:VMare下CentOS 5.5 ,1G内存。 2,集成开发环境:Elipse IDE 3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-eabi-gcc v4.5.1。 4,开发板:mini2440,2M nor flash,128M nand flash。 5,u-boot版本:u-boot-2009.08 6,参考文章: http://blogold.chinaunix.net/u3/101649/showart.php?id=2105215 http://blog.chinaunix.net/space.php?uid=23787856&do=blog&id=115382
[单片机]
51单片机+74hc595锁存器驱动一个静态数码管
实验开发板HC6800 v2.8 (淘宝可以查到) 将JP2 与JP3相连即可,注意排线要反接 代码如下: /* * 标题: 试验数码管上如何显示数字(共阳极) * * * * 连接方法:P2 与P3 用8PIN排线连接 * * * * * / #include reg51.h #include intrins.h void delay(unsigned int i); //函数声名 // 此表为 LED 的字模,0~F un
[单片机]
51<font color='red'>单片机</font>+74hc595锁存器<font color='red'>驱动</font>一个静态数码管
51单片机驱动12位AD转换TLC2543电路图+程序
下面是电路图和仿真图: TI公司的12位AD转换TLC2543芯片比ADC0832的8位AD转换芯片,精度要高很多,ADC0832的精度是255分之1,而TLC2543 由于二进制数的位数是12bit,所以精度要高出很多,它的精度为4096分之一。以下为89C51单片机控制C语言程序和电路连接图。完整的工程文件及hex文件下载:http://www.51hei.com/f/tlccadc.rar 是用stc89c51单片机制作的 成品正在使用中. #include reg51.h #define uint unsigned int #define uchar unsigned char sbit cs=P1^0;
[单片机]
51<font color='red'>单片机</font><font color='red'>驱动</font>12位AD转换TLC2543电路图+程序
基于A3992和单片机的两相步进电机驱动系统
1 引言 步进电机定位准确且与数字电路接口连接方便.无需反馈就能实现准确的角位移,在数控机床等许多领域中均得到了广泛应用。但是,传统的步进电机定位系统是由控制器件产生脉冲,然后加在环形分配器和功率驱动部分,最后连接至电机的控制方式,其软硬件的实现都较为复杂,成本偏高,难以满足现代工业发展所需的精度和集成度等要求。采用美国Allegro公司推出的一款易操作,内置功率驱动的A3992型两相步进电机微步距驱动器,以C805117300单片机为控制核心设计了一个驱动控制电路。该驱动控制电路能简单方便实现电机的微步距控制,不仅解决了步进电机步距角大的问题。提高了步进电机的分辨率,减弱或消除了步进电机的低频振动.也改善了电机的其他性能
[单片机]
单片机如何根据LCD时序图来写底层驱动
一般来说,LCD 模块的控制都是通过 MCU 对 LCD 模块的内部寄存器、显存进行操作来最终完成的;在此我们设计了三个基本的时序控制程序,分别是: 写寄存器函数(LCD_RegWrite) 数据写函数(LCD_DataWrite) 数据读函数(LCD_DataRead) 这三个函数需要严格的按照 LCD 所要求的时序来编写,下面可以看看 MzL02 模块时序图: 图 3.2 MzL02 模块的 6800 时序示意 注意:上图是该模块的控制 IC 资料中的原版时序图,其实有些示意不是太稳妥(少标出了RW 线信号的要求),或者说是不太严谨,不过这些不作讨论,请看分析即可;而 EP 的有效触发沿在图中很有可能示
[单片机]
<font color='red'>单片机</font>如何根据LCD时序图来写底层<font color='red'>驱动</font>
51单片机驱动1602液晶汇编语言程序
LCMRS EQU P2.4 LCMRW EQU P2.5 LCMEN EQU P2.6 LCMDATA EQU P0 ORG 0000H LJMP MAIN ORG 0030H MAIN: MOV SP,#60H LCALL LCMSET LCALL LCMCLR MOV A,#80H LCALL LCMWR0 MOV DPTR,#TAB0 LCALL LCMWR2 MOV A,#0C0H LCALL LCMWR0 MOV DPTR,#TAB1 LCALL LCMWR2 SJMP $ TAB0: DB I AM YUAN MING ,00H TAB1: DB NICE TO MEET YOU ,00H LCMLAY:
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • Linux内核移植
    实验步骤:(1)准备工作(2)修改顶层Makefile(3)修改falsh 分区(4)配置编译内核下面以Linux2 6 30 4内核移植到gec2440为例:一、准备 ...
  • S5PV210 PWM定时器
    第一节 S5PV210的PWM定时器S5PV210共有5个32bit的PWM定时器,其中定时器0、1、2、3有PWM功能,定时器4没有输出引脚。PWM定时器使用PCLK_PS ...
  • S5PV210 NAND Flash
    NAND Flash关于NAND FlashS5PV210的NAND Flash控制器有如下特点:1) 支持512byte,2k,4k,8k的页大小2) 通过各种软件模式来进行NAND Fl ...
  • S5PV210串口
    串口设置之输入输出字符S5PV210 UART相关说明 通用异步收发器简称UART,即UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTER,它用来 ...
  • S5PV210按键控制LED
    原理图如图所示:查询用户手册得到:程序例子:(完整代码见“代码下载链接”)1、轮询的方式查询按键事件 *main c* 核心代码如下:while(1 ...
  • S5PV210控制蜂鸣器
  • S5PV210的启动过程
  • S5PV210点亮LED
  • S5PV210启动过程详解
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved