📄 ethernet_51.c
字号:
#include "51Ethernet.h"
/************** 主函数 ***********************/
void main(void)
{
delay(1000); //延时1s,保证电源和网卡自身的上电完成
ClearISR(); //上电后清除中断状态寄存器ISR子程序
NICRst(); // RTL8019AS热复位寄存器
RTL8019Init(); // 初始化RTL8019AS
while(1)
{
SendPacket(union netcard *txdnet,uint length);
RecvPacket(union netcard *rxdnet);
}
}
/* ***************延时t毫秒 *********************/
void delay(uint t)
{
uint i;
while(t--)
{
/************* 对于12M时钟,约延时1ms ***********/
for (i=0;i<125;i++)
}
}
/* *****************RTL8019AS热复位 ******************/
void NICRst()
{
uchar i,tmp;
tmp=REG1f; // 读RTL8019AS的复位端口
REG1f=tmp; // 写RTL8019AS的复位端口
for(i=0;i<250;i++); //适当延时
}
/**********通过CR寄存器的PS1和PS0设置寄存器页**********/
void SelectPage(uchar pagenum)
{
uchar tmp;
tmp=REG00;
tmp=tmp&0x3B; // 注意不是0x3F,TXP位在不发送时要置0
pagenum=pagenum<<6;
tmp=tmp|pagenum;
REG00=tmp;
}
/***********初始化RTL8019AS,设置PAGE0、PAGE1*******************/
/**使用0x40-0x4b为网卡的发送缓冲区,共12页,刚好存储2个最大的以太网数据包。
使用0x4c-0x7f为网卡的接收缓冲区,共52页。因此PSTART=0x4c,PSTOP=0x80
(0x80为停止页,接收缓冲区直到0x7f,不包括0x80)。刚开始时,网卡没有接收
到任何数据包,因此BNRY设置为指向第一个接收缓冲区的页0x4c)**/
void RTL8019Init()
{
REG00=0x21; // 选择页0的寄存器,网卡停止运行,因为还没有初始化
REG01=0x4c; // 寄存器PSTART,设置接收缓冲区的起始页的地址
REG02=0x80; // 寄存器PSTOP,设置接收缓冲区的结束页的地址
REG03=0x4c; // 寄存器BNRY,设置为指向第一个接收缓冲区的页0x4c(用作读指针)
REG04=0x40; // 寄存器TPSR,发送起始页地址初始化为指向第一个发送缓冲区的页
REG0c=0xcc; /* 接收配置寄存器RCR,设置为仅接收自己地址的数据包以及广播地址
和多点播送地址数据包,小于64字节的包丢弃,校验错的数据包不接收 */
REG0d=0xe0; // 发送配置寄存器TCR,设置为启用CRC自动生成和校验,正常模式工作
REG0e=0xc8; /* 数据配置寄存器DCR,设置为使用FIFO缓存,普通模式,8位数据传输,
字节顺序为高位字节在前,低位字节在后 */
REG0f=0x00; // 中断屏蔽寄存器IMR,设置为屏蔽所有中断
SelectPage(1); // 选择页1的寄存器
REG07=0x4d; // 寄存器CURR,设置为指向当前正在写的页的下一页(用作写指针)
/******** 多址地址寄存器MAR0-MAR7均设置为0x00************/
REG08=0x00; // MAR0
REG09=0x00; // MAR1
REG0a=0x00; // MAR2
REG0b=0x80; // MAR3
REG0c=0x00; // MAR4
REG0d=0x00; // MAR5
REG0e=0x00; // MAR6
REG0f=0x00; // MAR7
GetPhyAddr(); // 获取以太网物理地址
REG00=0x22; // 选择页0寄存器,执行命令。
}
/********************上电后清除ISR寄存器***********************/
void ClearISR()
{
SelectPage(0);
REG07=REG07|0xff;
}
/* 获取以太网物理地址 */
void GetPhyAddr()
{
uchar tmp;
SelectPage(0); // 选择页0
REG08=0; // 远程DMA起始地址低位寄存器RSAR0,设置为0
REG09=0; // 远程DMA起始地址高位寄存器RSAR1,设置为0
REG0a=12; // 远程DMA计数器低位寄存器RBCR0,设置为12
REG0b=0; // 远程DMA计数器高位寄存器RBCR1,设置为0
REG00=0x0a; // 远程DMA,启动命令
SelectPage(1); // 选择页1
tmp=REG10; // 读取一个字节
REG01=tmp; // 写入PAR0
tmp=REG10; // 读取一个重复的字节,这个字节被丢弃
tmp=REG10; // 读取一个字节
REG02=tmp; // 写入PAR1
tmp=REG10; // 读取一个重复的字节,这个字节被丢弃
tmp=REG10; // 读取一个字节
REG03=tmp; // 写入PAR2
tmp=REG10; // 读取一个重复的字节,这个字节被丢弃
tmp=REG10; // 读取一个字节
REG04=tmp; // 写入PAR3
tmp=REG10; // 读取一个重复的字节,这个字节被丢弃
tmp=REG10; // 读取一个字节
REG05=tmp; // 写入PAR4
tmp=REG10; // 读取一个重复的字节,这个字节被丢弃
tmp=REG10; // 读取一个字节
REG06=tmp; // 写入PAR5
}
void SendPacket(union netcard *txdnet,uint length)//发送数据包子程序
/*发送一个数据包的命令,长度最小为60字节,最大1514字节需要发送的数据包要先存放在txdnet缓冲区*/
{
uchar i;
uint ii;
SelectPage(0);
if(length<60) length=60;
for(i=0;i<3;i++)
txdnet->etherframe.sourcenodeid[i]=my_ethernet_address.words[i];
txd_buffer_select=!txd_buffer_select;
if(txd_buffer_select)
REG09=0x40 ; //远程开始地址的高位
else
REG09=0x46 ; //远程开始地址的高位
REG08=0x00; //远程开始地址的低位
REG0b=length>>8; //远程字节计数器的高位
REG0a=legth&0xFF; //远程字节计数器的低位;
REG00=0x12; //写DMA
for(ii=4;ii reg10=txdnet->bytes.bytebuf[ii]);
for(i=0;i<6;i++){ //最多重发6次
for(ii=0;ii<1000;ii++) //检查TXP是否为低
if((REG00&0x04)==0) break;
if((REG04&0x01)!=0) break;//表示发送成功
REG00=0x3E;
}
if(txd_buffer_select) REG04=0x40; //开始发送数据包
else REG04=0x46; //开始发送数据包
REG06=length>>8; //发送字节计数器高字节
REG05=length&0xFF; //发送字节计数器低字节
REG00=0x3E; //发送数据
}
bit RecvPacket(union netcard *rxdnet) //接收数据包子程序
{
unsigned char i;
unsigned int ii;
unsigned char bnry,curr;
SelectPage(0);
REG07=0xFF;
bnry=REG03; //边界指针
SelectPage(1);
curr=REG07; //当前缓冲器页指针
SelectPage(0);
if(curr==0)
return 0; //缓冲器内没有新的数据包
bnry=bnry++;
if(bnry>0x7F) bnry=0x4C;
if(bnry!=curr){
/***此时表示有新的数据包在缓冲区里读取一包的前18个字节:4字节的8019头部,
6字节目的地址,6字节原地址,2字节协议,在任何操作都最好返回page0*****/
SelectPage(0);
REG09=bnry; //当前远程DMA地址高8位
REG08=0x00; //当前远程DMA地址高8位
REG0b=0x00; //字节计数器高8位
REG0a=18; //字节计数器低8位
REG00=0x0A; //远程DMA读命令
for(i=0;i<18;i++)
rxdnet->bytes.bytebuf[i]=REG10;
i=rxdnet->bytes.bytebuf[3]; //将长度字段的高低字节互换
rxdnet->bytes.bytebuf[3]=rxdnet->bytes.bytebuf[2];
rxdnet->bytes.bytebuf[2]=i;
rxdnet->etherframe.length=rxdnet->etherframe.length-4;//去掉4个字节的CRC
//表示读入的数据包有效
if(((rxdnet->bytes.bytebuf[0]&0x01)==0)||(rxdnet->bytes.bytebuf[1]>0x7F)||(rxdnet->bytes.bytebuf[1]<0x4C)||(rxdnet->bytes.bytebuf[2]>0x06)){
//接收状态错误,或者next_page_start错误或者长度错误,将丢弃所有数据包
SelectPage(1);
curr=REG07;
SelectPage(0); //切换回page0
bnry=curr-1;
if(bnry<0x4C) bnry=0x7F;
REG03=bnry; //write to bnry
return 0;
}
else{ //表示数据包是完好的.读取剩下的数据
if((rxdnet->etherframe.protocal==0x0800)||(rxdnet->etherframe.protocal==0x0806)){
REG09=bnry;
REG08=4;
REG0b=rxdnet->etherframe.length>>8;
REG0a=rxdnet->etherframe.length&0xFF;
REG00=0x0A;
for(ii=4;iietherframe.length+4;ii++)
rxdnet->bytes.bytebuf[ii]=REG10;
}
bnry=rxdnet->bytes.bytebuf[1]-1; //开始新的一页
if(bnry<0x4C) bnry=0x7F;
REG03=bnry;
return 1; //开始接收一个新的数据包
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -