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

📄 eth.c

📁 基于51单片机和RTL8019以太网控制器的嵌入式以太网控制程序。
💻 C
📖 第 1 页 / 共 3 页
字号:
//-----------------------------------------------------------------------------
// Net ETH.C
//
// This module is the Ethernet layer
//-----------------------------------------------------------------------------

#include <general.h>

bit txd_buffer_select=0;   		//选择网卡的发送缓冲区		//用于标识网卡是否收到数据包
sbit P10=P1^0;
sbit P11=P1^1;
sbit P16=P1^6;
void  Delay10ms();


#define MaxLenARPtable	10			//ARP表长度
#define MaxLenPingBuf   10			//PING缓冲区长度
xdata union arp_table_type arp_tab[MaxLenARPtable];	   //ARP表,存在外部RAM区里
xdata struct ping_table_type ping_table[MaxLenPingBuf];	   //ping表,在外部RAM里
xdata union netcard rxdnet;							   //接收缓冲区
xdata union netcard txdnet;							   //发送缓冲区

xdata union Ethernet_address my_ethernet_address;	   //本机的以太网地址					   //存放网卡的MAC地址.在初始化网卡时,用该数组里的内容对PAR0~PARA5进行赋值
													    //当然,在初始化之前一定要从X5045里读出该参数.在调试时,可以先对该数组赋值.
xdata union Ethernet_address gateway_ethernet_address; //网关的以太网地址
xdata union Ethernet_address ping_ethernet_address;	   //用来ping的以太网地址

xdata union IP_address my_ip_address;				   //本机的ip地址
xdata union IP_address temp_ip_address;				   //用于存放临时IP地址
xdata union IP_address gateway_ip_address;	           //网关的ip地址
xdata union IP_address mask_ip_address;	               //子网掩码
xdata union IP_address ping_ip_address;	               //用于ping命令
unsigned char index=0;								   //ARP table 循环加入点
unsigned int frameindex=0;							   //IP包的序列号



//unsigned char xdata netRxBuf[MCU_RECV_RAM];	//收发缓冲区实体
//unsigned char xdata *pNetIn,*pNetOut;

extern xdata struct wait arpwait;		//用于等待ARP.
extern unsigned char data WriteBuf;	//写内容
extern unsigned char data addr0,addr1;	//地址


//------------------------------------------------------------------------
// Initialize the Cirrus Logic 8019 chip
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//函数功能:选择页面
//
//入参:	页码pagenumber
//
//返回值:	无
//
//作者:
//
//注释:	Mingtree
//日期:	2004-09-19
//------------------------------------------------------------------------

void page(unsigned char pagenumber)
{
	unsigned char data temp;
	temp=reg00;
	temp=temp&0x3B ;//不改变RD2—RD0,以及最后两位0011 1011
	pagenumber=pagenumber <<6;
	temp=temp | pagenumber;
	reg00=temp;
}
//------------------------------------------------------------------------
//函数功能:将网卡软复位
//
//入参:	无
//
//返回值:	无
//
//作者:
//
//注释:	Mingtree
//日期:	2004-09-19
//------------------------------------------------------------------------

void Rtl8019AS_Reset() //复位网卡
{
//	unsigned char data temp;
	//对18h进行读写操作
//	page(0);
//	reg18=temp;
//	temp=reg18;
	P16=1;
	Delay10ms();
	P16=0;

}

/*
void ReadRtl8019NodeID(void)//读出网卡的物理地址存到my_ethernet_address.bytes[6]里
{
	unsigned char data i;
	page(0);
	reg09=0;	//读取网卡的ram的地址为0x0000
	reg08=0;
	reg0b=0;
	reg0a=12;	//读取12个字节
	reg00=0x0a;	//读ram
	for (i=0;i<6;i++)
	{
//    	my_hwaddr[i]=reg10;
//    	my_hwaddr[i]=reg10;
   	}
}
*/
//------------------------------------------------------------------------
//函数功能:设置网卡的MAC地址
//
//入参:	无
//
//返回值:	无
//
//作者:
//
//注释:	Mingtree
//日期:	2004-09-19
//------------------------------------------------------------------------
void WriteRtl8019NodeID()
{
	page(1);
	reg01=my_ethernet_address.bytes[0];
	reg02=my_ethernet_address.bytes[1];
	reg03=my_ethernet_address.bytes[2];
	reg04=my_ethernet_address.bytes[3];
	reg05=my_ethernet_address.bytes[4];
	reg06=my_ethernet_address.bytes[5];
	page(0);
}
//------------------------------------------------------------------------
//函数功能:初始化网卡
//
//入参:	无
//
//返回值:	无
//
//作者:
//
//注释:	Mingtree
//日期:	2004-09-19
//------------------------------------------------------------------------
void init_8019(void)
{
	Rtl8019AS_Reset();		//复位8019
	reg00=0x21;				//使芯片处于停止模式,这时进行寄存器设置 停止模式下,将不会发送和接收数据包
	Delay10ms();			//延时500毫秒,确保芯片进入停止模式
	page(0);
	reg0a=0x00;
	reg0b=0x00;
	reg0c= 0xe0;			//monitor mode (no packet receive)
	reg0d= 0xe2;			//loop back mode 使芯片处于mon和loopback模式,跟外部网络断开
	//使用0x40-0x4B为网卡的发送缓冲区,共12页,刚好可以存储2个最大的以太网包。
	//使用0x4c-0x7f为网卡的接收缓冲区,共52页。
	reg01=0x4c;				//PSTART
	reg02=0x80;				//PSTOP
	reg03=0x4c;				//BNRY
	reg04=0x40;				//TPSR
	reg07=0xff;				//清除所有中断标志位
	reg0f=0x00;				//disable all interrupt
	reg0e=0xc8;				//byte dma 8位dma方式
	page(1);
	reg07=0x4d;	reg08=0x00;	reg09=0x00;	reg0a=0x00;	reg0b=0x00;
	reg0c=0x00;	reg0d=0x00;	reg0e=0x00;	reg0f=0x00;
	reg00=0x22;				//这时让芯片开始工作
//	ReadRtl8019NodeID();	//读出网卡的物理地址48位
	WriteRtl8019NodeID();	//将网卡地址写入到mar寄存器
	page(0);
	reg0c=0xcc;				//将网卡设置成正常的模式,跟外部网络连接
	reg0d=0xe0;
	
	//设置单片机接收缓冲区实体
//	pNetIn = netRxBuf;
//	pNetOut	= netRxBuf;
	reg00=0x22;				//这时让芯片开始工作
	reg07=0xff;				//清除所有中断标志位
}
//------------------------------------------------------------------------
//函数功能:发送一个包
//
//入参:	指向发送包联合体的指针(netcard *类型),发送字节数
//
//返回值:	无
//
//作者:
//
//注释:	Mingtree
//日期:	2004-09-28(MIDDLE AUTUMN)
//------------------------------------------------------------------------
void send_packet(union netcard xdata *pTxdnet,unsigned int Length)//ne2000发包子程序
{//发送一个数据包的命令,长度最小为60字节,最大1514字节需要发送的数据包要先存放在txdnet缓冲区
	unsigned char i;
	unsigned int ii;

	page(0);
	if(Length<60) Length=60;
    for(i=0;i<3;i++)
    	pTxdnet->etherframe.uSourceID[i]=my_ethernet_address.words[i];
	//如果上一个包用低地址,则这次用高地址.也就是高低地址轮流使用
    txd_buffer_select=!txd_buffer_select;
	if(txd_buffer_select)
		reg09=0x40 ;		//txdwrite highaddress
	else
		reg09=0x46 ;		//txdwrite highaddress
	reg08=0x00; 			//read page address low
	reg0b=Length>>8;		//read count high
	reg0a=Length&0xFF;		//read count low;
	reg00=0x12;				//write dma, page0
	//加4的原因是8019as的收发包的结构不一样
	for(ii=4;ii<Length+4;ii++)
		reg10=pTxdnet->bytes.bytebuf[ii];

	/* 以下3句为中止dma的操作            */
	reg0b=0x00;		//read count high   中止DMA操作
	reg0a=0x00;		//read count low;
	reg00=0x22;		//complete dma page 0

	//下面的循环的作用是保证上一个包已经成功发送。发送完成的标志是REG00的第二位为0,
	//发送成功(发送没有错误)的标志是发送状态寄存器(REG04)最后一位为1.读者Mingtree注释.
	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;	//txd packet start;
	else reg04=0x46;					//txd packet start;

	reg06=Length>>8;		//high byte counter
	reg05=Length&0xFF;		//low byte counter

	reg00=0x3E;				//to sendpacket;
}
//------------------------------------------------------------------------
//函数功能:接收一个包
//
//入参:	指向发送包联合体的指针(netcard *类型).接收的包的长度在包首部里.
//
//返回值:	unsigned char类型的值,0表示没收到包,1表示收到包
//
//作者:
//
//注释:	Mingtree
//日期:	2004-09-28(MIDDLE AUTUMN)
//------------------------------------------------------------------------
unsigned char recv_packet(union netcard xdata *pRxdnet)//ne2000收包子程序
{
	unsigned char i;
	unsigned int ii;
	unsigned char bnry,curr;
//	unsigned char ucPacket;		//收到包的数目,最多收208个包,所以可以用一个字节
//	unsigned char bPacket;		//表示是否还有包
//	unsigned char xdata *pTemp;
//	bPacket = TRUE;

	page(0);
	reg07=0xFF;
	bnry=reg03;				//bnry page have read 读页指针
	page(1);
	curr=reg07;				//curr writepoint 8019写页指针
	page(0);
	if(curr==0)
		return 0;			
	//bnry=bnry++;
	bnry++;
	if(bnry>0x7F) bnry=0x4C;
	if(bnry!=curr)
	{			//此时表示有新的数据包在缓冲区里
		//读取一包的前18个字节:4字节的8019头部,6字节目的地址,6字节原地址,2字节协议
		//在任何操作都最好返回page0
		page(0);
		reg09=bnry;			//read page address high
		reg08=0x00; 		//read page address low
		reg0b=0x00;			//read count high
		reg0a=18;			//read count low;
		reg00=0x0A;			//read dma
		for(i=0;i<18;i++)
			pRxdnet->bytes.bytebuf[i] = reg10;

		/* 以下3句为中止dma的操作,可以不要            */
		reg0b=0x00;		//read count high   中止DMA操作
		reg0a=0x00;		//read count low;
		reg00=0x22;		//complete dma page 0

		i=pRxdnet->bytes.bytebuf[3];	//将长度字段的高低字节掉转
		pRxdnet->bytes.bytebuf[3]=pRxdnet->bytes.bytebuf[2];
		pRxdnet->bytes.bytebuf[2]=i;
		pRxdnet->etherframe.uLength=pRxdnet->etherframe.uLength-4;//去掉4个字节的CRC
	
		//表示读入的数据包有效
		if(((pRxdnet->bytes.bytebuf[0]&0x01)==0)||(pRxdnet->bytes.bytebuf[1]>0x7F)||(pRxdnet->bytes.bytebuf[1]<0x4C)||(pRxdnet->bytes.bytebuf[2]>0x06)){
			//接收状态错误,或者next_page_start错误或者长度错误,将丢弃所有数据包
			page(1);
			curr=reg07;		//page1
			page(0);		//切换回page0
			bnry=curr-1;
			if(bnry<0x4C) bnry=0x7F;
			reg03=bnry; 	//write to bnry
			return 0;
		}
		else
		{//表示数据包是完好的.读取剩下的数据
			if((pRxdnet->etherframe.protocal==0x0800)||(pRxdnet->etherframe.protocal==0x0806))
			{
				page(0);
				//协议为IP或ARP才接收
				reg09=bnry;			//read page address high
				reg08=0x04;			//read page address low
				reg0b=pRxdnet->etherframe.uLength>>8;		//read count high
				reg0a=pRxdnet->etherframe.uLength&0xFF;	//read count low;
				reg00=0x0A;			//read dma
				for(ii=4;ii<pRxdnet->etherframe.uLength+4;ii++)
          			pRxdnet->bytes.bytebuf[ii]=reg10;
					/* 以下3句为中止dma的操作,可以不要            */
				reg0b=0x00;		//read count high   中止DMA操作
				reg0a=0x00;		//read count low;
				reg00=0x22;		//complete dma page 0

				bnry=pRxdnet->bytes.bytebuf[1]-1;//next page start-1
				if(bnry<0x4C) bnry=0x7F;
				reg03=bnry; 			//write to bnry
				return 1;
			}	
			bnry=pRxdnet->bytes.bytebuf[1]-1;//next page start-1
			if(bnry<0x4C) bnry=0x7F;
			reg03=bnry; 			//write to bnry
			return 0;				//have new packet
		}
	}
	return 0;	
}
//------------------------------------------------------------------------
//函数功能:向指定的IP地址发送一个ARP请求
//
//入参:	IP地址
//
//返回值:	无
//
//作者:
//
//注释:	Mingtree
//日期:	2004-09-28(MIDDLE AUTUMN)
//------------------------------------------------------------------------
void arp_request(union IP_address ip_address)//ARP请求
{
	unsigned char i;
	txdnet.etherframe.protocal=0x0806;//arp protocal
	for(i=0;i<3;i++){//复制对方网卡地址或网关地址
   		txdnet.etherframe.uDestID[i]=0xffff;//广播地址
		//指定以太网数据包首部中的源MAC地址
		txdnet.etherframe.uSourceID[i]=my_ethernet_address.words[i];
		txdnet.arpframe.sourcenodeid[i]=my_ethernet_address.words[i];
		txdnet.arpframe.destnodeid[i]=0x0000;
    }

	for(i=0;i<2;i++)
		txdnet.arpframe.sourceip[i]=my_ip_address.words[i];
    txdnet.arpframe.destip[0]=ip_address.words[0];
    txdnet.arpframe.destip[1]=ip_address.words[1];
	txdnet.arpframe.harewaretype=0x0001;
	txdnet.arpframe.protocaltype=0x0800;
	txdnet.arpframe.halength=0x06;
	txdnet.arpframe.palength=0x04;
 	txdnet.arpframe.operation=0x0001;
	for(i=0x2E;i<(0x2E+18);i++)
		txdnet.bytes.bytebuf[i]=0x00;
	send_packet(&txdnet,60);
}
//------------------------------------------------------------------------
//函数功能:对ARP请求进行应答
//
//入参:	无
//
//返回值:	无
//
//作者:
//
//注释:	Mingtree
//日期:	2004-09-29
//------------------------------------------------------------------------
void arp_answer()//ARP应答
{
	unsigned char i;
	if (rxdnet.arpframe.destip[0]==my_ip_address.words[0])
	if (rxdnet.arpframe.destip[1]==my_ip_address.words[1])
        {//表示是向我这个ip地址的请求
    	   for(i=16;i<64;i++)//复制arp到发送缓冲区
    		txdnet.bytes.bytebuf[i]=rxdnet.bytes.bytebuf[i];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -