📄 网卡初始化.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0032)http://www.laogu.com/MY/tcp8.htm -->
<!-- saved from url=(0051)http://www.p8s.com.cn/magazine/files20002/lm/Lm.htm --><HTML><HEAD><TITLE>单片机与TCP/IP网络</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<STYLE>.normal {
FONT-SIZE: 16pt; COLOR: #ff6666; LINE-HEIGHT: normal
}
.ourfont {
FONT-SIZE: 9pt; COLOR: #808080; LINE-HEIGHT: 13pt
}
A:link {
COLOR: #004080; FONT-FAMILY: "新细明体"; TEXT-DECORATION: underline
}
A:hover {
COLOR: #ff0000; TEXT-DECORATION: underline
}
</STYLE>
<META content="MSHTML 6.00.2900.3429" name=GENERATOR></HEAD>
<BODY bgColor=#d5eaea leftMargin=0 topMargin=0>
<P> </P>
<DIV align=center>
<CENTER>
<TABLE borderColor=#008080 height=1277 cellSpacing=4 cellPadding=4 width=600
border=6>
<TBODY>
<TR>
<TD width=600>
<P align=center><SPAN style="FONT-SIZE: 9pt"><FONT face=隶书 color=#800080
size=4> </FONT><FONT face=宋体> </FONT></SPAN><FONT face=隶书
color=#800080 size=4><STRONG>单片机与TCP/IP网络<BR></STRONG></FONT><FONT
color=#800080><STRONG>--版主 老古</STRONG></FONT><FONT face=隶书
color=#800080><STRONG> <A href="http://www.laogu.com/"
target=_blank>http://www.laogu.com/</A></STRONG></FONT></P>
<P align=center><FONT color=#ff0033>(八)网卡初始化</FONT></P><B>
<HR color=#800080>
</B>
<P align=left>---- 完成复位之后,你要对网卡的工作参数进行设置.以使网卡开始工作.<BR>先介绍一个子函数<BR>#define
reg00 XBYTE[0xc000] //对应于地址240H 为命令寄存器CR地址</P>
<P align=left>void page(uchar pagenumber)<BR>{ uchar data temp;
<BR>temp=reg00;//command register <BR>temp=temp&<FONT
color=#ff0000>0x3f</FONT>;<BR>pagenumber=pagenumber <<6;
<BR>temp=temp | pagenumber;<BR>reg00=temp;<BR>}<BR><BR><FONT
color=#ff3333>错误修正:(2001年11月10日)
:以上程序有问题,在中断驱动或发送数据包不作等待时,因为发送数据包的命令是让TXP置位,如果在发送数据包的过程中,使用该函数,就会不断地向外发送数据包.原因是TXP置位之后,只能是发完数据包的时候,由网卡内部将TXP位清0,命令不能使TXP清0,对该位写入0没有作用.读取时要屏蔽该位,上面的程序修正如下,请用户使用下面的程序:<BR>void
page(uchar pagenumber)<BR>{uchar data
temp;<BR>temp=reg00;<BR>temp=temp&<FONT color=#3333cc>0x3B</FONT>;
//注意不是0x3F
,TXP位在平时一定要置为0.<BR>pagenumber=pagenumber<<6<BR>temp=temp|pagenumber;<BR>reg00=temp;<BR>}<BR>从实验当中也发现,只要再置位TXP位就可以重发该数据包(重发数据包时,不需要设置TPSTART,TBCR0,TBCR1).
</FONT></P>
<P align=left>作用是选择指定的页,网卡共有4页寄存器,Ne2000兼容的有3页。第四页可以不用。 </P>
<P align=left>reg00命令寄存器:CR,command register,地址偏移量00H,为一个字节</P>
<TABLE cellSpacing=1 cellPadding=0 width=755 bgColor=#ccffff border=1>
<TBODY>
<TR>
<TD>位</TD>
<TD>7</TD>
<TD>6</TD>
<TD>5</TD>
<TD>4</TD>
<TD>3</TD>
<TD>2</TD>
<TD>1</TD>
<TD>0</TD></TR>
<TR>
<TD>名字</TD>
<TD>PS1</TD>
<TD>PS0</TD>
<TD>RD2</TD>
<TD>RD1</TD>
<TD>RD0</TD>
<TD>TXP</TD>
<TD>STA</TD>
<TD>STP</TD></TR>
<TR>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD></TR></TBODY></TABLE>
<P align=left>PS1和PS0这两个位用来选择寄存器页,PS1 PS0=00时选择寄存器页0,=01时选择寄存器页1,
=10时选择寄存器页2,=11时选择寄存器页3.<BR>上面的程序的参数为pagenumber,用来指定第几页。<BR>temp=reg00
;//读入命令寄存器的值。<BR>temp=temp&0x3f;//将高2位,即PS1,PS0清0<BR>pagenumber=pagenumber<<6;//将低2位移至高端<BR>temp=temp|pagenumber,
//写入高2位<BR>reg00=temp; //设置第几页</P>
<P
align=left>当然也可以写成更加简单的几句:<BR>temp=reg00&0x3f;<BR>pagenumber=pagenumber<<6;<BR>reg00=temp|pagenumber;
</P>
<P
align=left>但这样对读者来说不好理解。<BR>从执行的速度来说,上面的代码也不是最快的。但作者主要讲述原理,而不是探讨最快的实现。<BR>--RD2,RD1,RD0这3个位代表要执行的功能。<BR>=001
读网卡内存<BR>=010 写网卡内存<BR>=011 发送网卡数据包<BR>=1**
完成或结束DMA的读写操作<BR>---TXP这个位写入1时发送数据包,发完自动清零<BR>---STA,STP这两个位用来启动命令或停止命令<BR>=10
启动命令<BR>=01 停止命令</P>
<P align=left>下面介绍网卡的初始化子程序:<BR>void ne2000init()<BR>{ reg00=0x21;
//选择页0的寄存器,网卡停止运行,因为还没有初始化。<BR>reg01=0x4c; //寄存器Pstart<BR>reg02=0x80;
//Pstop<BR>reg03=0x4c; //BNRY<BR>reg04=0x45; //TPSR<BR>reg0c=0xcc;
//RCR<BR>reg0d=0xe0; //TCR<BR>reg0e=0xc8; //DCR 数据配置寄存器 8位数据dma
<BR>reg0f=0x00; //IMR disable all interrupt <BR>page(1);
//选择页1的寄存器<BR>reg07=0x4d; //CURR<BR>reg08=0x00; //MAR0<BR>reg09=0x41;
//MAR1<BR>reg0a=0x00; //MAR2<BR>reg0b=0x80; //MAR3<BR>reg0c=0x00;
//MAR4<BR>reg0d=0x00; //MAR5<BR>reg0e=0x00; //MAR6<BR>reg0f=0x00;
//MAR7<BR>reg00=0x22;//选择页0寄存器,网卡执行命令。 </P>
<P align=left><BR>} <BR><BR>PSTART 接收缓冲区的起始页的地址。<BR>PSTOP
接收缓冲区的结束页地址。(该页不用于接收)<BR>BNRY 指向最后一个已经读取的页(读指针)<BR>CURR
当前的接收结束页地址。(写指针)<BR><BR>--网卡含有16K字节的RAM,地址为0x4000-0x7fff(指的是网卡上的存储地址,而不是ISA总线的地址,是网卡工作用的存储器),每256个字节称为一页,共有64页。页的地址就是地址的高8位,页地址为0x40--0x7f
。这16k的ram的一部分用来存放接收的数据包,一部分用来存储待发送的数据包。当然也可以给用户使用。(例如把网卡设置成使用8K的ram,另外8K的ram就可以用来给单片机作为存储器,但我没有这样做,原因是操作网卡上的ram比较复杂)<BR>---在我的程序中使用0x40-0x4B为网卡的发送缓冲区,共12页,刚好可以存储2个最大的以太网包。使用0x4c-0x7f为网卡的接收缓冲区,共52页。因此PSTART=0x4c,PSTOP=0x80(0x80为停止页,就是直到0x7f,是接收缓冲区,不包括0x80)
刚开始,网卡没有接收到任何数据包,所以,BNRY设置为指向第一个接收缓冲区的页0x4c)
<BR>这四个寄存器用于接收的设置。<BR>--CURR是网卡写内存的指针。它指向当前正在写的页的下一页。那么初始化它就应该指向0x4c+1=0x4d
。网卡写完接收缓冲区一页,就将这个页地址加一,<BR>CURR=CURR+1。这是网卡自动加的。当加到最后的空页(这里是0x80,PSTOP)时,将CURR置为接收缓冲区的第一页(这里是0x4c,PSTART),也是网卡自动完成的。当CURR=BNRY时,表示缓冲区全部被存满,数据没有被用户读走,这时网卡将停止往内存写数据,新收到的数据包将被丢弃不要,而不覆盖旧的数据。此时实际上出现了内存溢出。<BR>---而BNRR要由用户来操作。用户从网卡读走一页数据,要将BNRY加一,然后再写到BNRY寄存器。
当BNRY加到最后的空页(0x80,PSTOP)时,同样要将BNRY变成第一个接收页(PSTART,0x4c)BNRY=0x4c;<BR>---CURR和BNRY主要用来控制缓冲区的存取过程,保证能顺次写入和读出)。<BR>当CURR=BNRY+1(或当BNRY=0x7f
,CURR=0x4c)时,网卡的接收缓冲区里没有数据,表示没有收到数据包。
用户通过这个判断知道没有包可以读。当上述条件不成立时,表示接收到新的数据包。然后用户应该读取数据包,直到上述条件成立时,表示所以数据包已经读完,此时停止读取数据包。<BR>--TPSR
为发送页的起始页地址。初始化为指向第一个发送缓冲区的页,0x40。<BR>--RCR
接收配置寄存器,设置为使用接收缓冲区,仅接收自己的地址的数据包(以及广播地址数据包)和多点播送地址包,小于64字节的包丢弃(这是协议的规定,设置成接收是用于网络分析),校验错的数据包不接收。<BR>--TCR
发送配置寄存器,启用crc自动生成和自动校验,工作在正常模式。<BR>--DCR
数据配置寄存器,设置为使用FIFO缓存,普通模式,8位数据传输模式,字节顺序为高位字节在前,低位字节在后(符合我们的习惯)(如果用16位的单片机,设置成16位的数据总线操作会更快,但80c52是8位总线的单片机)<BR>--IMR
中断屏蔽寄存器,设置成0x00,屏蔽所有的中断。设置成0xff将允许中断)<BR>--MAR0--MAR8是设置多点播送的参数,这点我也不是很清楚,我从电脑读出来是什么数,我也将这8个寄存器设置成这几个数.
由于我们不使用多点播送,所以不要紧,只要保证网卡能正常工作就可以了。<BR>--PAGE2的寄存器是只读的,所以不可以设置,不用设置,PAGE3的寄存器不是NE2000兼容的,所以也不用设置。
</P>
<P align=justify><FONT
size=+1>(未完)</FONT></P></TD></TR></TBODY></TABLE></CENTER></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -