📄 main.c
字号:
//程序从main()开始执行:
#define reg00 XBYTE[0xc000] /* 240H*/
#define reg01 XBYTE[0xc100] /* 241H*/
#define reg02 XBYTE[0xc200] /* 242H*/
#define reg03 XBYTE[0xc300] /* 243H*/
#define reg04 XBYTE[0xc400] /* 244H*/
#define reg05 XBYTE[0xc500] /* 245H*/
#define reg06 XBYTE[0xc600] /* 246H*/
#define reg07 XBYTE[0xc700] /* 247H*/
#define reg08 XBYTE[0xc800] /* 248H*/
#define reg09 XBYTE[0xc900] /* 249H*/
#define reg0a XBYTE[0xca00] /* 24aH*/
#define reg0b XBYTE[0xcb00] /* 24bH*/
#define reg0c XBYTE[0xcc00] /* 24cH*/
#define reg0d XBYTE[0xcd00] /* 24dH*/
#define reg0e XBYTE[0xce00] /* 24eH*/
#define reg0f XBYTE[0xcf00] /* 24fH*/
#define reg10 XBYTE[0xd000] /* 250H*/
#define reg11 XBYTE[0xd100] /* 251H*/
#define reg12 XBYTE[0xd200] /* 252H*/
#define reg13 XBYTE[0xd300] /* 253H*/
#define reg14 XBYTE[0xd400] /* 254H*/
#define reg15 XBYTE[0xd500] /* 255H*/
#define reg16 XBYTE[0xd600] /* 256H*/
#define reg17 XBYTE[0xd700] /* 257H*/
#define reg18 XBYTE[0xd800] /* 258H*/
#define reg19 XBYTE[0xd900] /* 259H*/
#define reg1a XBYTE[0xda00] /* 25aH*/
#define reg1b XBYTE[0xdb00] /* 25bH*/
#define reg1c XBYTE[0xdc00] /* 25cH*/
#define reg1d XBYTE[0xdd00] /* 25dH*/
#define reg1e XBYTE[0xde00] /* 25eH*/
#define reg1f XBYTE[0xdf00] /* 25fH*/
#define uint unsigned int //uint 代表unsigned int ,作者一般使用缩写uint
#define uchar unsigned char //uchar 代表unsigned char,我比较懒,不愿意多写
//extern uchar data XBYTE[0xdf00];
#include <AT89X51.H>
#include <ABSACC.h>
void delaymsecond();
void netcardreset();
void ne2000init();
main()
{
delaymsecond();//延时大约1秒,保证电源稳定和网卡自身的上电完成。
netcardreset();//复位网卡的子程序
ne2000init();//网卡初始化子程序
}
void delaymsecond()
{
uint i,j;
for (i=0;i<1000;i++)
for (j=0;j<120;j++)
;
}
//-------------------------------------------------------------------------------------
//网卡的复位子程序:
//#define reg1f XBYTE[0xdf00] //网卡的复位端口的地址,对应于网卡的地址25FH。
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++);
*/
}
//---------------------------------------------------------------------------------------
//对网卡的工作参数进行设置
//#define reg00 XBYTE[0xc000] //对应于地址240H 为命令寄存器CR地址
void page(uchar pagenumber)
{ uchar data temp;
temp=reg00;//command register
temp=temp&0x3B;
pagenumber=pagenumber <<6;
temp=temp | pagenumber;
reg00=temp;
}
//---------------------------------------------------------------------------------------
//网卡的初始化子程序
void ne2000init()
{
reg00=0x21; //选择页0的寄存器,网卡停止运行,因为还没有初始化。 0010 0001
reg01=0x4c; //寄存器Pstart 0x4c-0x80,考虑0x4c-0x60 datasheet p15 0100 1100
reg02=0x80; //Pstop
reg03=0x4c; //BNRY 读指针
reg04=0x40; //TPSR 为发送页的起始页地址。初始化为指向第一个发送缓冲区的页,0x40。
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兼容的,所以也不用设置。
*/
//----------------------------------------------------------------------------------------------------------
//读取网卡的物理地址
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 0000 1010
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;//读取一个重复的字节,这个字节被丢弃 修改
}
}
//这样,RTL8019AS复位后读取93C46中配置好的内容,对应设置配置寄存器CONFIG1的值为00H,
//CONFIG1的低4位IOS3~0用于选择I/O基地址。IOS3~0设置值均为0时,RTL8019AS选择的端口I/O基地址为300H。
//物理地址寄存器,位于page1,共6个字节,这就是网卡的地址,复位之后该6个寄存器的值是不定的。
//要由用户将网卡地址写入到该6个寄存器中,以后网卡接收到的数据包,会将数据包的目的地址跟这6个寄存器的值进行比较
//,结果相同的数据包被接收下来。上电复位时从93c46读入的网卡地址不会自动写入到这里,而是放在rtl8019as的内存地址
//0000H,0002H,0004H,0006H,0008H,000AH,0000CH里。你的程序要从这6个内存地址里读出网卡地址,写入到PAR0-5 共6个
//寄存器地址里。如果你的系统没有使用93c46来存储该网卡地址,那么要由你的软件自行产生或分配一个网卡地址,写入到
//6个寄存器里(比如你可以把网卡地址存储在单片机的flash rom里,存储在24c02的eeprom里等)。
//------------------------------------------------------------------------------------------------------------
//设置网卡的物理地址
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
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -