⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ethernet_51.c

📁 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 + -