RTL8019编程指南
(未完待续)
绪言
——单片机如何控制以太网网卡进行传输数据,如何加载TCP/IP协议连接到互联网,这些都是一些令人感兴趣的问题。
——可以说以太网和TCP/IP协议已经成为使用最广泛的协议,而其它总线协议如RS485、RS232,CAN,LANWORKS,都只是一些局部系统的总线。
——围绕以太网而制造的集线器,交换机已进入大小公司,企业,家庭。我现在在众达天网公司,由于公司是搞电脑防火墙的,所以对网络的接触也越来越多,我研究的主要是网络的底层,并掌握了很多网络
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
工具如(SNIFFER),对以太网和TCP/IP协议的研究就更加深入了。
——我比较熟悉的网卡是10M的网卡,100M的以太网卡还在研究之中。曾经用单片机(89C52)控制和驱动10M的NE2000兼容型以太网卡与电脑主机传输数据。
——现在将我的一些研究成果写成一系列的文单,提供给大家。也许有一天研究了100M的网卡之后,可以让单片机驱动它,那是可能的事,只不过接口可能会复杂一些。
——我所写的驱动程序并不是
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
的,因为我没有学过UNIX,无法使用UNIX提供的原代码。如果能使用UNIX的原代码,那将是很好的事。我也正在接触UNIX和VC++,DDK等方面的
内容
财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容
,希望有一天能够重写我现在所写的驱动程序。
——我知道有很多人在了解单片机与以太网方面的东西,在BBS上也发现了很多这方面的内容,有些人的研究甚至比我还深入,我也希望能跟这些人交流交流,如果对我的文章感兴趣 ,当然可以给我发电子邮件啦。
——在接下来的文章将介绍以太网协议,网卡驱动,IP协议,ICMP协议,ARP协议,TCP协议等 。
----为帮助读者开发该tcp/ip的应用,本站制作了以太网开发板,可以购买。
1.1. 以太网协议
——--以太网协议(用于10MBPS的以太网,作者以下所说的以太网均指10M以太网,而不是100M,1000M的以太网)
——以太网协议有两种,一种是IEEE802.2/IEEE802.3,还有一种是以太网的封装格式。
——现代的操作系统均能同时支持这两种类型的协议格式。因此对我们来说只需要了解其中的一种就够了,特别是对单片机来说,不可能支持太多的协议格式。
——以太网的物理传输帧:(仅介绍第二种格式)
PR
SD
DA
SA
TYPE
DATA
PAD
FCS
56位
8位
48位
48位
16位
不超过1500字节
可选
32位
——PR:同步位,用于收发双方的时钟同步,同时也指明了传输的速率(10M和100M的时钟频率不一样,所以100M网卡可以兼容10M网卡),是56位的二进制数101010101010.....
——SD: 分隔位,表示下面跟着的是真正的数据,而不是同步时钟,为8位的10101011,跟同步位不同的是最后2位是11而不是10.
——DA:目的地址,以太网的地址为48位(6个字节)二进制地址,表明该帧传输给哪个网卡.如果为FFFFFFFFFFFF,则是广播地址,广播地址的数据可以被任何网卡接收到.
——SA:源地址,48位,表明该帧的数据是哪个网卡发的,即发送端的网卡地址,同样是6个字节.
----TYPE:类型字段,表明该帧的数据是什么类型的数据,不同的协议的类型字段不同。如:0800H 表示数据为IP包,0806H 表示数据为ARP包,814CH是SNMP包,8137H为IPX/SPX包,(小于0600H的值是用于IEEE802的,表示数据包的长度。)
----DATA:数据段 ,该段数据不能超过1500字节。因为以太网规定整个传输包的最大长度不能超过1514字节。(14字节为DA,SA,TYPE)
----PAD:填充位。由于以太网帧传输的数据包最小不能小于60字节, 除去(DA,SA,TYPE 14字节),还必须传输46字节的数据,当数据段的数据不足46字节时,后面补000000.....(当然也可以补其它值)
----FCS:32位数据校验位.为32位的CRC校验,该校验由网卡自动计算,自动生成,自动校验,自动在数据段后面填入.对于数据的校验算法,我们无需了解.
----事实上,PR,SD,PAD,FCS这几个数据段我们不用理它 ,它是由网卡自动产生的,我们要理的是DA,SA,TYPE,DATA四个段的内容.
----所有数据位的传输由低位开始(但传输的位流是用曼彻斯特编码的)
----以太网的冲突退避算法就不介绍了,它是由硬件自动执行的.
DA+SA+TYPE+DATA+PAD最小为60字节,最大为1514字节.
----以太网卡可以接收三种地址的数据,一个是广播地位,一个是多播地址(我们用不上),一个是它自已的地址.但网卡也可以设置为接收任何数据包(用于网络分析和监控).
----任何两个网卡的物理地址都是不一样的,是世界上唯一的,网卡地址由专门机构分配.不同厂家使用不同地址段,同一厂家的任何两个网卡的地址也是唯一的.根据网卡的地址段(网卡地址的前三个字节),可以知道网卡的生产厂家.有些网卡的地址也可以由用户去设定,但一般不需要.
1.2. 网卡上电复位
----当你买到一个新的RTL8019AS网卡,你要先将该网卡设置为以下的配置:
操作方式Operating Mode:跳线方式Jumperless(不是即插即用Plug and Play)
端口I/O base:0240-25FH
中断Interrupt: 2/9(我的程序没有用到网卡中断,所以也可以不用设置)
你要将这个网卡插到你的电脑里,用这个网卡带的设置程序RSET8019.exe将这个卡按照上面的配置设置好。(最好在纯DOS方式下设置) .
--在介绍网卡驱动程序之前,先介绍一下RTL8019AS的基本情况:
1.3. 输入输出地址:
共32个,地址偏移量为00H--1FH,(对应于240H--25FH,240H的地址偏移量为0,241H的地址偏移量为1,。。。25FH的地址偏移量为1FH)。
其中00H--0FH共16个地址,为寄存器地址。
10H--17H共8个地址,为DMA地址。
18H--1FH共8个地址,为复位端口。
对于8位的操作方式,上面的地址中只有18个是有用的:
00H--0FH共16个寄存器地址。
10H DMA地址 (10H--17H的8个地址是一样的,都可以用来做DMA端口,只要用其中的一个就可以了)
1FH 复位地址。(18H到1FH共8个地址都是复位地址,每个地址的功能都是一样的,只要其中的一个就可以了,但实际上只有18H,1AH,1CH,1EH这几个复位端口是有效的,其他不要使用,有些兼容卡不支持19H,1BH,1DH等奇数地址的复位)
1.4. 跟复位有关的引脚:
RSTDRV连接到ISA总线的RSTDRV的引脚上。RSTDRV同时也是ISA总线的复位信号。RSTDRV为高电平有效,至少需要 800ns的宽度。给该引脚施加一个1us以上的高电平就可以复位。施加一个高电平之后,然后施加一个低电平。
RSTDRV从高电平到低电平之后要等多久,单片机才可以对网卡进行操作?
复位的过程将执行一些操作,比如将93c46读入,将内部寄存器初始化等。这些至少需要2毫秒的时间。我们推荐大家等待更久的时间之后才对网卡操作,比如100毫秒之后才对它操作,以确保完全复位。
对RSTDRV可以接单片机的一个引脚进行对网卡的复位。但也可以直接将RSTDRV跟单片机的RESET引脚并联,单片机复位的时候,网卡也复位,以减少一个单片机的引脚的使用。这种情况下,为了保证能够完全复位,可以使用下面介绍的热复位代码。
1.5. 跟复位有关的寄存器:
18H--1FH共8个地址,为复位端口。对该端口偶数地址的读,或者写入任何数,都引起网卡的复位。
1.6. 跟复位有关的标志位:
其中的第7位RST跟复位有关。
网卡执行正确的复位之后该位为1。在linux或windows的驱动程序中,一般在复位之后检查该标志位以确认是否正确复位,特别是在即插即用的检测过程中。对于我们用单片机控制网卡来说,我们可以不检查该标志位,因为如果复位不正常的情况通常是网卡坏了。
1.7. 寄存器:
00H--0FH共16个地址是寄存器地址。
寄存器分成4页PAGE0--PAGE3,但NE2000兼容的寄存器只有3页(Page0-Page2),(第四页是RTL8019AS自己定义的,我们不用去管这些寄存器,因为你对第四页的寄存器的操作仅对这个网卡是有效的,如果你换成其他Ne2000兼容的网卡,例如DM9008,DP8390等,你的程序将无法正常运行。 为了保证驱动程序对所有Ne2000的网卡有效,不要去操作第四页的寄存器)
由于寄存器较多,我将在用到该寄存器的时候才对该寄存器介绍。
1.8. 对网卡进行复位:
这是网卡驱动程序的需要做的第一个内容,由于我们将网卡设置为跳线模式,而不是即插即用的模式,RTL8019AS.PDF中介绍的PLUG and PLAY的一些过程,我们不需要做,因为单片机的资源有限,能够减少的操作,都尽量减少。
程序从main()开始执行:
#include
/*my.h 为作者所用的头文件,包含所有89c52寄存器的大写和小写的定义,
和一些常用的子函数,一些宏的定义*/
main()
{
delaymsecond(10);//延时大约1秒,保证电源稳定和网卡自身的上电完成。
netcardreset();//复位网卡的子程序
。。。。
}
下面介绍网卡的复位子程序:
#define reg1f XBYTE[0xdf00] //网卡的复位端口的地址,对应于网卡的地址25FH。
#define uint unsigned int //uint 代表unsigned int ,作者一般使用缩写uint
#define uchar unsigned char //uchar 代表unsigned char,我比较懒,不愿意多写
sbit reset=p3^4; //单片机的p3.4脚连接到网卡的RSTDRV复位引脚
void netcardreset()
{
uint data i;
uchar data temp;
reset=1; //使网卡的RSTDRV引脚变成高电平,网卡是高电平复位的。
for(i=0;i<250;i++);//延时程序,至少需要
reset=0; //使网卡的RSTDRV引脚变成低电平,网卡上电复位完毕
for(i=0;i<250;i++);
temp=reg1f;//读网卡的复位端口
reg1f=temp; //写网卡的复位端口
for(i=0;i<250;i++);
}
上面所讲的实际上是网卡复位的两种情况,
reset=1;reset=0相当于冷复位
temp=reg1f;reg1f=temp相当于热复位
对网卡的复位端口的读或写将复位网卡,网卡内部将执行复位过程。读写是随意的,写入任意的数都将复位网卡。
实际上只要使用冷复位就可以了,热复位程序可以不要。热复位主要在电脑里有用,冷复位就像电脑的冷启动,热复位相当于电脑的热启动。
--作者的复位网卡的过程是简化了的,一个电脑里的复位过程是比较复杂的,如果你有网卡驱动的UNIX,LINUX程序的源代码,它的代码将会做一些判断和检查,检查网卡是否存在,和是否工作正常,和是否存在地址和中断冲突 。但在我们的这个系统里可以省去这些,我们认为网卡的地址和I/O是没有冲突和正常工作的。当然如果读者愿意,也可以写一些检查代码。
1.9. 网卡初始化
---- 完成复位之后,你要对网卡的工作参数进行设置.以使网卡开始工作.先介绍一个子函数
1.10. void page(uchar pagenumber)
#define reg00 XBYTE[0xc000] //对应于地址240H 为命令寄存器CR地址
void page(uchar pagenumber)
{
uchar data temp;
temp=reg00;//command register
temp=temp&0x3f;
pagenumber=pagenumber <<6;
temp=temp | pagenumber;
reg00=temp;
}
错误修正:(2001年11月10日) :以上程序有问题,在中断驱动或发送数据包不作等待时,因为发送数据包的命令是让TXP置位,如果在发送数据包的过程中,使用该函数,就会不断地向外发送数据包.原因是TXP置位之后,只能是发完数据包的时候,由网卡内部将TXP位清0,命令不能使TXP清0,对该位写入0没有作用.读取时要屏蔽该位,上面的程序修正如下,请用户使用下面的程序:
void page(uchar pagenumber)
{uchar data temp;
temp=reg00;
temp=temp&0x3B; //注意不是0x3F ,TXP位在平时一定要置为0.
pagenumber=pagenumber<<6
temp=temp|pagenumber;
reg00=temp;
}
从实验当中也发现,只要再置位TXP位就可以重发该数据包(重发数据包时,不需要设置TPSTART,TBCR0,TBCR1).
作用是选择指定的页,网卡共有4页寄存器,Ne2000兼容的有3页。第四页可以不用。
1.11. reg00命令寄存器:
CR,command register,地址偏移量00H,为一个字节
位
7
6
5
4
3
2
1
0
名字
PS1
PS0
RD2
RD1
RD0
TXP
STA
STP
· PS1和PS0这两个位用来选择寄存器页,
PS1 PS0=00时选择寄存器页0,=01时选择寄存器页1, =10时选择寄存器页2,=11时选择寄存器页3.上面的程序的参数为pagenumber,用来指定第几页。
temp=reg00 ;//读入命令寄存器的值。
temp=temp&0x3b;//将高2位,即PS1,PS0清0
pagenumber=pagenumber<<6;//将低2位移至高端
temp=temp|pagenumber, //写入高2位
reg00=temp; //设置第几页
当然也可以写成更加简单的几句:
temp=reg00&0x3B;
pagenumber=pagenumber<<6;
reg00=temp|pagenumber;
但这样对读者来说不好理解。
从执行的速度来说,上面的代码也不是最快的。但作者主要讲述原理,而不是探讨最快的实现。
· RD2,RD1,RD0这3个位代表要执行的功能。
=001 读网卡内存
=010 写网卡内存
=011 发送网卡数据包
=1** 完成或结束DMA的读写操作
· TXP这个位写入1时发送数据包,发完自动清零
· STA,STP这两个位用来启动命令或停止命令
=10 启动命令
=01 停止命令
1.12. 下面介绍网卡的初始化子程序:
void ne2000init()
{
reg00=0x21; //选择页0的寄存器,网卡停止运行,因为还没有初始化。
reg01=0x4c; //寄存器Pstart
reg02=0x80; //Pstop
reg03=0x4c; //BNRY
reg04=0x45; //TPSR
reg0c=0xcc; //RCR
reg0d=0xe0; //TCR
reg0e=0xc8; //DCR 数据配置寄存器 8位数据dma
reg0f=0x00; //IMR disable all interrupt
page(1); //选择页1的寄存器
reg07=0x4d; //CURR
reg08=0x00; //MAR0
reg09=0x41; //MAR1
reg0a=0x00; //MAR2
reg0b=0x80; //MAR3
reg0c=0x00; //MAR4
reg0d=0x00; //MAR5
reg0e=0x00; //MAR6
reg0f=0x00; //MAR7
reg00=0x22;//选择页0寄存器,网卡执行命令。
}
PSTART 接收缓冲区的起始页的地址。
PSTOP 接收缓冲区的结束页地址。(该页不用于接收)
BNRY 指向最后一个已经读取的页(读指针)
CURR 当前的接收结束页地址。(写指针)
--网卡含有16K字节的RAM,地址为0x4000-0x7fff(指的是网卡上的存储地址,而不是ISA总线的地址,是网卡工作用的存储器),每256个字节称为一页,共有64页。页的地址就是地址的高8位,页地址为0x40--0x7f 。这16k的ram的一部分用来存放接收的数据包,一部分用来存储待发送的数据包。当然也可以给用户使用。(例如把网卡设置成使用8K的ram,另外8K的ram就可以用来给单片机作为存储器,但我没有这样做,原因是操作网卡上的ram比较复杂)
---在我的程序中使用0x40-0x4B为网卡的发送缓冲区,共12页,刚好可以存储2个最大的以太网包。使用0x4c-0x7f为网卡的接收缓冲区,共52页。因此PSTART=0x4c,PSTOP=0x80(0x80为停止页,就是直到0x7f,是接收缓冲区,不包括0x80) 刚开始,网卡没有接收到任何数据包,所以,BNRY设置为指向第一个接收缓冲区的页0x4c)
这四个寄存器用于接收的设置。
--CURR是网卡写内存的指针。它指向当前正在写的页的下一页。那么初始化它就应该指向0x4c+1=0x4d 。网卡写完接收缓冲区一页,就将这个页地址加一,
CURR=CURR+1。这是网卡自动加的。当加到最后的空页(这里是0x80,PSTOP)时,将CURR置为接收缓冲区的第一页(这里是0x4c,PSTART),也是网卡自动完成的。当CURR=BNRY时,表示缓冲区全部被存满,数据没有被用户读走,这时网卡将停止往内存写数据,新收到的数据包将被丢弃不要,而不覆盖旧的数据。此时实际上出现了内存溢出。
---而BNRR要由用户来操作。用户从网卡读走一页数据,要将BNRY加一,然后再写到BNRY寄存器。 当BNRY加到最后的空页(0x80,PSTOP)时,同样要将BNRY变成第一个接收页(PSTART,0x4c)BNRY=0x4c;
---CURR和BNRY主要用来控制缓冲区的存取过程,保证能顺次写入和读出)。
当CURR=BNRY+1(或当BNRY=0x7f ,CURR=0x4c)时,网卡的接收缓冲区里没有数据,表示没有收到数据包。 用户通过这个判断知道没有包可以读。当上述条件不成立时,表示接收到新的数据包。然后用户应该读取数据包,直到上述条件成立时,表示所以数据包已经读完,此时停止读取数据包。
--TPSR 为发送页的起始页地址。初始化为指向第一个发送缓冲区的页,0x40。
--RCR 接收配置寄存器,设置为使用接收缓冲区,仅接收自己的地址的数据包(以及广播地址数据包)和多点播送地址包,小于64字节的包丢弃(这是协议的规定,设置成接收是用于网络分析),校验错的数据包不接收。
--TCR 发送配置寄存器,启用crc自动生成和自动校验,工作在正常模式。
--DCR 数据配置寄存器,设置为使用FIFO缓存,普通模式,8位数据传输模式,字节顺序为高位字节在前,低位字节在后(符合我们的习惯)(如果用16位的单片机,设置成16位的数据总线操作会更快,但80c52是8位总线的单片机)
--IMR 中断屏蔽寄存器,设置成0x00,屏蔽所有的中断。设置成0xff将允许中断)
--MAR0--MAR8是设置多点播送的参数,这点我也不是很清楚,我从电脑读出来是什么数,我也将这8个寄存器设置成这几个数. 由于我们不使用多点播送,所以不要紧,只要保证网卡能正常工作就可以了。
--PAGE2的寄存器是只读的,所以不可以设置,不用设置
--PAGE3的寄存器不是NE2000兼容的,所以也不用设置。
1.13. 读取网卡的网卡地址
---- 完成上面的过程之后,网卡还不能正确的接收数据包,因为我们还没有对网卡的物理地址(网卡地址,48位的地址)进行设置。网卡还不知道它应该什么地址的数据包。要对网卡的物理地址进行设置,就必须知道网卡的物理地址是多少。
1.14. 读取网卡的物理地址的子程序:
union u
{
uint word;
struct{uchar high;uchar low;}
bytes;
};
//我定义的数据结构,为两个字节的结构
//可以按照uint(unsigned int)来读取,也可以按照高低字节high和low来读取。
union u mynodeid[3];//存储网卡的物理地址
union u protocal; //临时变量
void readmynodeid()
{
uchar data i,temp;
page(0);
reg09=0;//寄存器RSAR1 dma read highaddress=0
reg08=0;//RSAR0 dma read lowaddress=0;
reg0b=0; //RBCR1 read count high
reg0a=12;//RBCR0 count low
reg00=0x0a;//dma read and start
for (i=0;i<6;i++)
{
temp=reg10;//读取一个字节
if (i % 2==0)
{protocal.bytes.high=temp;}
else {protocal.bytes.low=temp;mynodeid[i/2].word=protocal.word;}
temp=reg10;//读取一个重复的字节,这个字节被丢弃
}
}
1.15. 256字节的RAM
--网卡除了16k(地址0x4000-0x7FFFF)的接收发送存储RAM之外,还有别的RAM,还有一块大小为256字节的RAM,地址为0x0000-0x00FF,这部分RAM是eeprom 93C46的影像存储(不完全一样),存储的内容的一部分跟93C46存储的是一样的。 网卡在上电的时候将93C46的一部分内容读到这256字节的RAM里。
存储是WORD类型,其中地址:
0x0000-0x000b共12个字节是网卡的物理地址。(网卡的物理地址是6个字节的,为什么要用12字节?因为这12字节是重复存储的。例如网卡物理地址0x52544CC118CF,存储在0x0000-0x000b里是这样的:
525254544C4CC1C11818CFCF
我们可以看到单和双的地址存储的是一样的。0x000b后面的地址存储的是生产厂商的代码和产品标识代码,也是单双地址重复存储,这里就不说了。
1.16. 这个程序又用到4个新的寄存器:
RSAR1 RSAR0 RBCR1 RBCR0
这4个寄存器是专门用于读取网卡上面的ram的。
RSAR1 网卡上的RAM的起始地址高8位
RSAR0 网卡上的RAM的起始地址低8位
--程序中的reg09,reg08都设成0,所以是从网卡上的0x0000地址开始读。
RBCR1 要读取的字节数的计数(高8位)
RBCR0 要读取的字节数的计数(低8位)
--程序中的reg0b=0,reg0a=12,所以要读取12个字节。
reg00=0x0a 的意思是进行DMA的内存读取操作。
--结果将网卡地址存储在mynodeid[3](共6个字节)里。
}
1.17. 设置网卡地址
以下程序是设置网卡的地址,只有符合这个地址的数据包才接收.
void writemynodeid()
{
page(1);
reg01=mynodeid[0].bytes.high; //PAR0
reg02=mynodeid[0].bytes.low; //PAR1
reg03=mynodeid[1].bytes.high; //PAR2
reg04=mynodeid[1].bytes.low; //PAR3
reg05=mynodeid[2].bytes.high; //PAR4
reg06=mynodeid[2].bytes.low; //PAR5
}
又用到几个新的寄存器,是页1的几个寄存器:
PAR0,PAR1, PAR2, PAR3,PAR4,PAR5
这几个寄存器是网卡的工作时候用的地址,只有符合这个地址的数据包才接收,这个地址是可以设置为其他的值,不一定设置为网卡的物理地址,为了不跟别的网卡地址冲突,最好设置为网卡的地址,(如果用户需要设置为其他的值,也是可以的).
1.18. RTL8019AS的跳线方式 rtl8019as有3种工作方式:
第一种为跳线方式,网卡的i/o和中断由跳线决定
第二种为即插即用方式,由软件进行自动配置plug and play
第三种为免跳线方式,网卡的i/o和中断由外接的93c46里的内容决定。
我们买到的网卡一般只支持第2和第3种。在嵌入式应用的 场合,如果可以不使用93c46的话,可以降低成本,同时又减少连线。那么我们如何使用第1种方式跳线方式呢?网卡使用哪种方式由rtl8019as的第65脚JP决定。我们来看引脚图:
第65脚jp是输入引脚,当65脚为低电平时,8019工作在第2种或第3种方式,具体由93c46里的内容决定。我们买到的 rtl8019as网卡一般第65脚为悬空的,rtl8019as悬空时,引脚的 输入状态为低电平(其他引脚也是这样,悬空的输入脚的电平为低电平,里面有一个100k的下拉电阻),网卡工作在第2,3种工作方式,需要使用93c46芯片。如果我们把65脚接高电平(vcc),那么网卡的i/o和中断就不是用93c46的内容决定,这时不需要使用93c46,可以不接93c46。那么这时候的i/o和中断irq是多少呢?这时需要用到
64,65,78,79,80,81,82,84,85等引脚。
64脚aui,该引脚决定使用aui还是bnc接口。我们用的网卡的接口一般是bnc的,很少用aui。bnc接口方式支持8线双绞或同轴电缆。高电平时使用aui接口,悬空为低电平,使用bnc接口。我们将该引脚悬空即可。
65脚jp 为高电平时(接到vcc或通过一个10k的电阻上拉)使用跳线方式,这时芯片的i/o地址由以下几个引脚85,84,82,81(IOS3..IOS0)决定:
芯片的中断线由以下引脚80,79,78(IRQS2..IRQS0)决定:
芯片的brom地址由以下引脚72,71,69,68,67(BS4..BS0)决定:
在嵌入式领域一般都不用该brom。brom是boot rom的缩写。在电脑里用来做无盘工作站时候用到,可以从网卡进行引导,而不是从a盘,c盘等引导系统。
网络接口类型由74,77(PL0,PL1)引脚决定:
我们使用第一种自动检测就可以了。会自动检测接口类型然后进行工作。自动检测是用同轴还是双绞线。
作为一个例子来自http://8052.lphard.cz的电路图,该电路图没有使用中断方式工作,使用跳线方式,所以没有接93c46,I/O地址用的是300H,网络接口为bnc(双绞线),没有使用brom),他使用at89c8252单片机运行在14.74兆赫,支持http协议,24c512用来存储网页,FC22为耦合隔离变压器模块:
1.19. 网卡地址和多点播送(组播)及广播
1.20. 以太网的地址为48位由ieee统一分配给网卡制造商,每个网卡的地址都必须是全球唯一的。共6个字节的长度
字节
5
4
3
2
1
0
位
47。。40
39。。32
31。。24
23。。16
15。。8
7。。0
例子
08
00
09
A0
4A
B1
我们需要注意的是以太网地址的第32位是组播地址的标志位:
位
47。。33
32
31。。24
23。。0
制造厂商标识
组播标志位
制造厂商标识
系列号
共6个字节,其中前面3个字节(除了第32位),组成制造厂商的标识,每个制造厂商的前3个字节是不同的,如果两个网卡的前面3个字节是一样的,那么这个卡是同一个公司制造的。同时通过该3个字节就可以反过来知道这个卡是哪个厂制造的。后面3个字节为系列号,由制造厂商给自己生产的网卡分配一个号码,不同网卡的号码必须不同, 网卡地址的制造厂商的3个字节的标识中,例如上面的08:00:09 ,080009 是惠普公司的标识,表示这个卡是惠普公司制造的。3个字节的第一个字节,必须为偶数,上面的08是一个偶数,是因为第32位,就是第一个字节的最低位是组播标识,必须为0。
以下X0:XX:XX:XX:XX:XX
X2:XX:XX:XX:XX:XX
X4:XX:XX:XX:XX:XX
X6:XX:XX:XX:XX:XX
X8:XX:XX:XX:XX:XX
XA:XX:XX:XX:XX:XX
XC:XX:XX:XX:XX:XX
XE:XX:XX:XX:XX:XX
为合法的以太网网卡地址。上面的X代表0-F中的任一个。如果你不是购买网卡,而是自己购买芯片制造,那么地址怎么办?可以自己使用一个还没有被ieee分配的厂商编号就可以了。就算是使用已经分配的厂商编号也没有不可,只要你能保证在你使用的局域网内,任何两个网卡的地址不一样就可以了。
1.21. 地址 FF:FF:FF:FF:FF:FF 为广播地址
只能用在目的地址段,不能作为源地址段。目的地址为广播地址的数据包,可以被一个局域网内的所有网卡接收到。
地址X1:XX:XX:XX:XX:XX
X3:XX:XX:XX:XX:XX
X5:XX:XX:XX:XX:XX
X7:XX:XX:XX:XX:XX
X9:XX:XX:XX:XX:XX
XB:XX:XX:XX:XX:XX
XD:XX:XX:XX:XX:XX
XF:XX:XX:XX:XX:XX
为组播地址,只能作为目的地址,不能作为源地址。组播地址可以被支持该组播地址的一组网卡接收到。组播地址主要用在视频广播,远程唤醒(通过发一个特殊的数据包使网卡产生一个中断信号,启动电脑),游戏(多个人在局域网里联机打游戏)里等。
以下是一些具体的组播地址:
地址 范围
01:00:5E:00:00:00---01:00:5E:7F:FF:FF 用于ip地址的组播
其他组播地址跟tcp/ip无关,不做介绍。
1.22. 网卡可以接收以下3种地址的数据包:
第一种 目的地址跟自己的网卡地址是一样的数据包
第二种 目的地址为FF:FF:FF:FF:FF:FF广播地址的数据包
第三种 目的地址为跟自己的组播地址范围相同的数据包
那么在以太网的应用当中,如果你希望你的数据包只发给一个网卡,目的地址用对方的网卡地址
如果你想把数据包发给所有的网卡,目的地址用广播地址
如果你想把数据包发给一组网卡,目的地址用组播地址。
rtl8019跟网卡地址有关的寄存器:
物理地址寄存器,位于page1,共6个字节,这就是网卡的地址,复位之后该6个寄存器的值是不定的。
要由用户将网卡地址写入到该6个寄存器中,以后网卡接收到的数据包,会将数据包的目的地址跟这6个寄存器的值进行比较,结果相同的数据包被接收下来。上电复位时从93c46读入的网卡地址不会自动写入到这里,而是放在rtl8019as的内存地址0000H,0002H,0004H,0006H,0008H,000AH,0000CH里。你的程序要从这6个内存地址里读出网卡地址,写入到PAR0-5 共6个寄存器地址里。如果你的系统没有使用93c46来存储该网卡地址,那么要由你的软件自行产生或分配一个网卡地址,写入到6个寄存器里(比如你可以把网卡地址存储在单片机的flash rom里,存储在24c02的eeprom里等)。
1.23. 跟组播地址有关的寄存器:
为8个寄存器,提供对组播地址的过滤。跟crc的逻辑有关。我对于该8个寄存器跟组播地址的关系不是很清楚,也没有找到相关的资料。将该8个寄存器全部写入0FFH,可以接收所有的组播地址地数据包。全部写入0,将不接收任何组播地址的数据包。在windows 98操作系统里,操作系统写入到这8个寄存器的值为:
MAR0 :00H
MAR1 :41H
MAR2 :00H
MAR3 :80H
MAR4 :00H
MAR5 :00H
MAR6 :00H
MAR7 :00H
写入的这8个值跟具体的组播地址是什么关系?我也不知道。lphard的
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
是写入8个0xff 。
那么在嵌入式应用中应该如何处理?建议为全部写入0xff。如果不想支持组播,可以不用理这8个寄存器,或全部写入0。
1.24. 跟网卡地址有关的标志位:
其中的第3位ATD,0为正常操作,1为由组播地址控制(用作流控)。我们把这个位设置为0。
我们不需要使用流控,因为流控的标准不被所有的网卡支持,有些网卡支持,有些不支持。
其中的PRO,AM,AB跟地址有关:
PRO为1时,将接收所有的数据包,不管任何地址, 统统收下来。通常用在一些网桥,或一些用来监视网络的电脑里。sniffer软件就是利用这个特性,将以太网上所有数据包都收下来进行分析,以统计以太网里的数据传输率,冲突,出错情况,网卡地址情况,ip数据包等情况。
PRO为0时,接收跟自己的地址一样的数据包,其他目的地址的被丢弃(不包括广播和组播包)。我们设置为0就可以了。
AM=1时,接收组播地址的数据包,AM=0时,不接收组播地址的数据包。 将该位根据你的情况设置为1或0,推荐设置为1。
AB=1时,接收广播地址的数据包,AB=0时,不接收广播地址FF:FF:FF:FF:FF:FF的数据包。该位要设置为1,才能实现tcp/ip协议
PHY跟地址有关:
为接收的情况报告。
参考:IP组播地址转换为以太网组播地址
1.25. 组播地址
大家知道,IP地址空间被划分为A、B、C三类。第四类即D类地址被保留用做组播地址。在第四版的IP协议(IPv4)中,从224.0.0.0到239.255.255.255间的所有IP地址都属于D类地址。
组播地址中最重要的是第24位到27位间的这四位,对应到十进制是224到239,其它28位保留用做组播的组标识,如下图所示:
图1 组播地址示意图
IPv4的组播地址在网络层要转换成网络物理地址。对一个单播的网络地址,通过ARP协议可以获取与IP地址对应的物理地址。但在组播方式下ARP协议无法完成类似功能,必须得用其它的
方法
快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载
获取物理地址。在下面列出的RFC文档中提出了完成这个转换过程的方法:
RFC1112:Multicast IPv4 to Ethernet physical address correspondence
RFC1390:Correspondence to FDDI
RFC1469:Correspondence to Token-Ring networks
在最大的以太网地址范围内,转换过程是这样的:将以太网地址的前24位最固定为01:00:5E,这几位是重要的标志位。紧接着的一位固定为0,其它23位用IPv4组播地址中的低23位来填充。该转换过程如下图所示:
图2 地址转换示意图
例如,组播地址为224.0.0.5其以太网物理地址为01:00:5E:00:00:05。
还有一些特殊的IPv4组播地址:
224.0.0.1:标识子网中的所有主机。同一个子网中具有组播功能的主机都是这个组的成员。
224.0.0.2:该地址用来标识网络中每个具有组播功有的路由器。
224.0.0.0----224.0.0.255范围内的地址被分配给了低层次的协议。向这些范围内的地址发送数据包,有组播功能的路由器将不会为其提供路由。
239.0.0.0----239.255.255.255间的地址分配用做管理用途。这些地址被分配给局部的每一个组织,但不可以分配到组织外部,组织内的路由器不向在组织外的地址提供路由。
除了上面列出的部分组播地址外,还有许多的组播地址。在最新版本的RFC文档“Assinged Numbers”中有完整的介绍。
下面的表中列出了全部的组播地址空间,同时还列出了相应的地址段的常用名称及其TTL(IP包的存活时间)。在IPv4组播方式下,TTL有双重意义:正如大家所知的,TTL原本用来控制数据包在网络中的存活时间,防止由于路由器配置错误导致出现数据包传播的死循环;在组播方式下,它还代表了数据包的活动范围,如:数据包在网络中能够传送多远?这样就可以基于数据包的分类来定义其传送范围。
范围 TTL 地址区间 描述节点(Node) 0 只能向本机发送的数据包,不能向网络中的其它接口传送链路(Link) 1 224.0.0.0-224.0.0.255 只能在发送主机所在的一个子网内的传送,不会通过路由器转发。
部门 32 239.255.0.0-239.255.255.255 只在整个组织下的一个部门内(Department) 传送
组织 64 239.192.0.0--239.195.255.255 在整个组织内传送(Organization)
全局(Global)255 224.0.1.0--238.255.255.255 没有限制,可全局范围内传送
1.26. 组播的工作过程
在局域网内,主机的网络接口将到目的主机的数据包发送到高层,这些数据包中的目的地址是物理接口地址或广播地址。
如果主机已经加入到一个组播组中,主机的网络接口就会识别出发送到该组成员的数据包。
因此,如果主机接口的物理地址为80:C0:F6:A0:4A:B1,其加入的组播组为224.0.1.10,则发送给主机的数据包中的目的地址必是下面三种类型之一:
接口地址:80:C0:F6:A0:4A:B1
广播地址:FF:FF:FF:FF:FF:FF
组播地址:01:00:5E:00:01:0A
广域网中,路由器必须支持组播路由。当主机中运行的进程加入到某个组播组中时,主机向子网中的所有组播路由器发送IGMP(Internet分组管理协议)报文,告诉路由器凡是发送到这个组播组的组播报文都必须发送到本地的子网中,这样主机的进程就可以接收到报文了。子网中的路由器再通知其它的路由器,这些路由器就知道该将组播报文转发到哪些子网中去。
子网中的路由器也向224.0.0.1发送一个IGMP报文(224.0.0.1代表组中的全部主机),要求组中的主机提供组的相关信息。组中的主机收到这个报文后,都各将计数器的值设为随机值,当计数器递减为0时再向路由器发送应答。这样就防止了组中所有的主机同时向路由器发送应答,造成网络拥塞。主机向组播地址发送一个报文做为对路由器的应答,组中的其它主机一旦看到这个应答报文,就不再发送应答报文了,因为组中的主机向路由器提供的都是相同的信息,所以子网路由器只需得到组中一个主机提供的信息就可以了。
如果组中的主机都退出了,路由器就收不到应答,因此路由器认为该组目前没有主机加入,遂停止到该子网报文的路由。IGMPv2的解决方案是:组中的主机在退出时向224.0.0.2 发送报文通知组播路由器。
1.27. 太网组播地址过滤寄存器的计算
终于找到关于RTL8019AS里的 MAR0-MAR7的计算的程序,源程序是80x86的汇编,我把它转换成了在keil c51里的程序,以便可以在51单片机里使用。
跟组播地址有关的寄存器:
为8个寄存器,提供对组播地址的过滤。跟crc的逻辑有关。MAR0-7 全部设置为0xff时,将接收所有的组播数据包,将MAR0-7 全部设置为0x00时,将不接收所有组播地址的数据包。在windows98里,该值被设置为:
MAR0=0x00;
MAR1=0x41;
MAR2=0x00;
MAR3=0x80;
MAR4=0x00;
MAR5=0x00;
MAR6=0x00;
MAR7=0x00;
用户在嵌入式的应用当中,可以设置为全部0xff,也可以对特定的组播地址(比如你用在网络电台广播)进行计算,生成一个你需要的过滤参数。建议该过滤的算法不写在单片机里,最好是先算好,存储在单片机里,用的时候直接调用,以节省单片机的程序空间。
这8个寄存器的值是根据组播地址数组的值生成的,提供对组播地址的过滤,过滤掉一些不属于自己接收组播数据包。
1.28. 如何接收8019一个数据包
我们在上面谈到了网卡的ram的结构,网卡ram是以256字节为一页,是按页存储的结构,16位的ram的地址的高8位又叫页码.
网卡的16k的ram地址从0x4000-0x7fff,从页0x40到页0x7f,一共有64页.这64页被用来接收和发送数据包用.
一般把前面的12页用来存放发送的数据包,后面的52页用来存放接收的数据包.
当然你也可以配置成前面52页用来接收,而后面的12页用来发送.
或者你也可以不使用那么多的缓冲区,比如只用32页来做为缓冲区,前面的6页用来发送,接下来的26页用来接收,而把空出来的32页给单片机使用,用来存储别的数据.
那么哪些页被用来做接收缓冲区由两个寄存器决定:
Pstart(page start register)
Pstop(page stop register)
PSTART,PSTOP是16位ram地址的高8位,也就是页码.
举个例子:
PSTART=0x4c
PSTOP =0x80
这时网卡将使用0x4c00-0x7fff的ram来存储接收到的数据包.PSTOP是0x80而不是0x7f,PSTOP的意思是,从该页开始的页不能做为 接收缓冲区.而PSTART的意思是从这一页开始做为接收缓冲区.
因此PSTART=0x4c ,PSTOP=0x7f+1=0x80,PSTOP被设置为(最后一页的页码+1).
再如:
PSTART=0x40
PSTOP=0x60
那么网卡使用0x4000-0x5FFF做为接收缓冲区.
而我的程序的设置是PSTART=0x4c PSTOP=0x80
而页0x40--0x4b共12页做为发送数据缓冲区,为什么用12页,是因为最大的一个数据包是1514字节+4字节校验.一个最大的数据包需要6页=256*6=1536字节.
12页可以放两个最大的包.我们把前6页0x40--0x45称为发送缓冲1,接下来的6页0x46--0x4B称为发送缓冲2.
这两个发送缓冲的作用是:
用户可以将数据包放在发送缓冲1,然后启动发送.发送的过程中,如果用户还有数据包要发,那么这时把要发的数据包放在发送缓冲2(一边发送,一边把下一包放到缓冲区里),等到发完发送缓冲1的数据包就可以马上启动发送缓冲2的数据包.这样可以不断地进行发送数据.
我们设置了接收缓冲区之后,那么接收到的第一个数据包放在哪里呢?这由CURR决定.
控制接收缓冲区的有两个寄存器CURR,BNRY.CURR是网卡写缓冲区的指针,指向此时要写的页.
BNRY是读指针,指向用户已经读走的页.
那么要知道网卡正在写哪一个字节的数据,读取CLDA1,CLDA0的值就知道了.
那么如何初始化CURR,BNRY这两个指针呢?
初始化的时候使BNRY=CURR-1页,
例如:
CURR=0x4d
BNRY=0x4c
要注意的是:如果
CURR=0x4c(第一个接收页)
那么BNRY=0x7f(最后一个接收页)
写成语言就是:
BNRY=CURR-1;
if(BNRY<0x4c)BNRY=0x7f;
这就是两者的初始化的关系式.
初始化CURR=0x4d,表示第一个收到的数据包将存放在0x4d00地址开始的缓冲区.
初始化CURR=0x4c,表示第一个收到的数据包将存放在0x4c00地址开始的缓冲区.
CURR只初始化一次,以后都不用再去修改它.
我的设置是CURR=0x4d.
网卡收到一个数据包,假如是一个短数据包,只要一页就可以存储的,那么这时候CURR将会被加一.CURR将等于0x4d+1=0x4e.
假如需要两页来存储,那么CURR将等于0x4d+2=0x4f
如果CURR等于结束页PSTOP,也就是CURR>0x7f时,CURR将被重置成等于PSTART=0x4c.
CURR是网卡内部自己控制的.用户不需要干预.
网卡存储一定是按页存储,不满一页,也使用一页,下一包将用下一页开始存储.
举个例子;
CURR=0x4f
BNRY=0x4e
这时收到一个数据包
这是一个典型的ARP应答包,数据包发往52:54:ab:3d:8e:2c,发送者的网卡地址为
00:d0:09:68:f7:1e ,类型为0806
假设我的网卡地址是52:54:ab:3d:8e:2c,那么可以收到该包
这时
CURR=0x50
BNRY=0x4e
那么收到一包之后BNRY=CURR-2,而不是BNRY=CURR-1,也就是说两个指针差了两页,而不是一页.也就是说当CURR , BNRY 两个指针差2页或2页以上时,表示网卡收到新的数据包.(检查是否有新的数据包要用到这个关系,没有新的数据包时,两者指针只差一页).
数据包只有60个字节的数据,那么网卡将用CURR指向的页0x4f来存储该包数据.
存储内容如下:
0x4f00:015040005254AB3D8E2C00D00968F71E
0x4f10:0806000108000604000200D00968F71E
0x4f20:C0A800015254AB3D8E2CC0A800070000
0x4f30:00000000000000000000000000000000
0x4f40:492E24C8
我们可以看到前面和后面都加了一些东西,中间的才是数据.
共加了8个字节的内容(共用了68个字节).
那么前面的4个字节的含义为:
前面的4个字节为:01504000
第一个字节0x01为接收的状态,也就是RSR(接收状态寄存器的值)
该字节Receive Status含义:
那么根据上面的标志位的定义,0x01=0000 0001B,也就是标志位PRX=1 ,表示这个数据包接收良好,没有错误.CRC=0,表示校验正确.PHY=0,表示这不是广播数据包.
第2个字节0x50 Next Packet Pointer,是一个指针,表示下一个数据包将存储在0x50页开始的地址0x5000.事实上等于此时的CURR=0x50.
第3和第4是接收的长度.表示该数据包的长度.这里是0x4000,要注意的是长度的高位和低位是颠倒的:
Receive Byte Count1=0x00
Receive Byte Count0=0x40
长度应该是0x0040=64字节.60字节是内容,4字节校验.
最后面的