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

📄 rtl8019.c

📁 AVR单片机基础上的以太网协议编程
💻 C
字号:
/**************************************************************************
**
**    文件: RTL8019.c
**    描述: 该文件完成以太网卡的初始化和收发程序
**
**************************************************************************/

//include library files
#include  <stdio.h>
#include  <string.h>
#include  <iom128v.h>
#include  <macros.h>

//include user defined files
#include  "Define.h"
#include  "Global_Variable.h"
#include  "RTL8019.h"

/**************************************************************************
**
**    函数: void Delay(uchar)
**    描述: 该函数完成整数倍的5ms软件延时
**
**************************************************************************/
void Delay(uchar N5ms)       //5ms
{
    uchar i,j;
	
    for(;N5ms>0;N5ms--)
    {
        for(i=200;i>0;i--)
        {
            for(j=200;j>0;j--)
            ;
        }
    }
}

/**************************************************************************
**
**    函数: void RTL8019_Init(void)
**    描述: 该函数完成以太网卡的初始化
**
**************************************************************************/
void RTL8019_Init(void)
{ 
    //enable output pin for resetting the RTL8019
    sbi(RTL8019_RESET_DDR,RTL8019_RESET_PIN);
   
    //硬复位
    sbi(RTL8019_RESET_PORT,RTL8019_RESET_PIN);
    Delay(1);
    cbi(RTL8019_RESET_PORT,RTL8019_RESET_PIN);
    
	//软复位
    writeRTL(ISR,readRTL(ISR));
    Delay(1);
 
    writeRTL(CR,0x21);          //选择Page 0,停止模式,进行初始化
    Delay(2);                   //延时10ms,确保进入停止模式
    while(readRTL(CR) !=0x21)
    writeRTL(CR,0x21);
   
    writeRTL(ISR,0xff);         //清除中断状态
    writeRTL(IMR, 0x00);        //不允许中断,查询模式
    writeRTL(DCR,0xC8);         //数据配置寄存器,字节DMA模式
    writeRTL(TCR,0xe0);         //正常模式
    writeRTL(RCR,0xc4);         //正常模式,接收广播包,但不接收组播包
   
    writeRTL(PSTART,RXSTART_INIT);     //接收起始页
    writeRTL(PSTOP,RXSTOP_INIT);       //接收停止页  
    writeRTL(BNRY,RXSTART_INIT);       //边界指针,指向接收缓冲环中第一个还未被主机读取的页面
    writeRTL(TPSR,TXSTART_INIT);       //发送起始页
   
    writeRTL(RBCR0,0x00);       //远程DMA字节计数寄存器清零
    writeRTL(RBCR1,0x00);
    
    writeRTL(CR,0x61);                 //选择Page 1
    writeRTL(CURR,RXSTART_INIT);       //当前页寄存器,记录第一个用于包接收的缓冲环的页地址

    //设置本地MAC地址
    writeRTL(PAR0,My_MAC[0]);
    writeRTL(PAR1,My_MAC[1]);
    writeRTL(PAR2,My_MAC[2]);
    writeRTL(PAR3,My_MAC[3]);
    writeRTL(PAR4,My_MAC[4]);
    writeRTL(PAR5,My_MAC[5]);
}

/**************************************************************************
**
**    函数: void Page_Select(uchar)
**    描述: 该函数完成以太网卡页面的选择,入口参数选择0、1、2
**
**************************************************************************/
void Page_Select(uchar pagenumber)
{
    uchar VAR;
	
    VAR = readRTL(CR);
    VAR &= 0x3b;  //TXP清零
    pagenumber = pagenumber<<6;
    VAR |= pagenumber;
    writeRTL(CR, VAR);
}

/**************************************************************************
**
**    函数: void Over_Run(void)
**    描述: 该函数完成以太网卡接收缓冲环溢出的处理
**
**************************************************************************/
void Over_Run(void)
{
    uchar dataL,resend=0;
 
    dataL = readRTL(CR);
    writeRTL(CR,0x21);
    Delay(1);
    writeRTL(RBCR1,0x00);
    writeRTL(RBCR0,0x00);
 
    if(dataL&0x04)    //正在发送
    {
        dataL = readRTL(ISR);
        if((dataL&0x02)||(dataL&0x08))
        resend=0;
        else
        resend=1;
    }
    writeRTL(TCR,0x02);
    writeRTL(CR,0x22);
    writeRTL(BNRY,RXSTART_INIT);
    writeRTL(CR,0x62);
    writeRTL(CURR,RXSTART_INIT);
    writeRTL(CR,0x22);
    writeRTL(ISR,0x10);
    writeRTL(TCR,0x00);
    writeRTL(ISR,0xff);
}
 
/**************************************************************************
**
**    函数: void Send_Packet(uchar *,uint)
**    描述: 该函数完成以太网包的发送,
            入口参数分别为指向发送缓冲区的指针和发送的包长度
**
**************************************************************************/
void Send_Packet(uchar *sendbuffer,uint length)
{
    uchar i,sendLength;
    uint count;
  
    Page_Select(0);
    sendLength=(length>=ETHERNET_MIN_PACKET_LENGTH) ? length : ETHERNET_MIN_PACKET_LENGTH;
   
    //等待发送结束,TXP位为1说明正在发送,为0表示发完或出错
    for(count=1000;count>0;count--)
    if((readRTL(CR)&(1<<CR_TXP))==0)
	break;
   
    writeRTL(ISR,(1<<ISR_PTX));            //清除发送的中断标志   
    writeRTL(RBCR1,(uchar)(length>>8));    //远程计数高字节
    writeRTL(RBCR0,(uchar)(length&0xff));  //远程计数低字节
    writeRTL(TPSR,TXSTART_INIT);           //发送起始页
    writeRTL(RSAR1,0x40);                          
    writeRTL(RSAR0,0x00);                  //发送的起始地址
    writeRTL(CR,0x12);                     //远程写DMA,Page0
    
	//远程DMA写
	for(i=0;i<length;i++)
    writeRTL(RDMARORT,sendbuffer[i]);
	 
   //以下为终止DMA操作
   count=5000;
   while(((readRTL(ISR)&(1<<ISR_RDC))==0)&&count)
   count--;
   writeRTL(ISR,(1<<ISR_RDC));             //清除DMA完成的中断标志
   writeRTL(RBCR1,0x00);
   writeRTL(RBCR0,0x00);
   writeRTL(CR,0x22);                      //完成DMA
   
   //启动包发送  
   writeRTL(TBCR1,(uchar)(sendLength>>8));    //发送计数高字节
   writeRTL(TBCR0,(uchar)(sendLength&0xff));  //发送计数低字节
   writeRTL(CR,0x3e);        
}

/**************************************************************************
**
**    函数: void Receive_Packet(uchar *,uint)
**    描述: 该函数完成以太网包的接收,
            入口参数分别为指向接收缓冲区的指针,返回接收到的数据的长度
**
**************************************************************************/
uint Receive_Packet(uchar *MCU_Receivebuffer)
{
    volatile uchar bnry,curr=0;
    uchar pageheader[4]; //远程DMA接收头4B的接收状态
    uint  i=0,rxlen=0;
    uchar nextPage; 
  
    curr= readRTL(ISR);
    if(curr & (1<<ISR_OVW)) //判断接收缓冲环是否溢出
    Over_Run(); //执行接收缓冲环溢出处理函数
	  
    writeRTL(CR,0x62); //选择Page 1
    curr = readRTL(CURR); //读当前页寄存器
  
    writeRTL(CR,0x22); //选择Page 0
    bnry = readRTL(BNRY); //读边界寄存器

    if((bnry>=RXSTOP_INIT)||(bnry<RXSTART_INIT))  //边缘指针无效,复位缓存区并退出
    {
	    writeRTL(BNRY,RXSTART_INIT);         
	    Page_Select(1);
        writeRTL(CURR,RXSTART_INIT);      
        Page_Select(0);
	    return 0;
	}
    if((curr>=RXSTOP_INIT)||(curr<RXSTART_INIT))  //边缘指针无效,复位缓存区并退出
    {
	    Page_Select(1);
        writeRTL(CURR,RXSTART_INIT);
        Page_Select(0);	  
	    return 0;
	}

    if(bnry==curr)                                //没有数据包,返回
    return 0;

    writeRTL(ISR,(1<<ISR_PRX));  //有数据,清除接收的中断标志	
	
    //初始化DMA,远程DMA接收头4B的接收状态
    writeRTL(RBCR1,0x00);
    writeRTL(RBCR0,0x04); //设置远程DMA字节计数器
    writeRTL(RSAR1,bnry);
    writeRTL(RSAR0,0x00); //设置远程DMA起始地址寄存器
    writeRTL(CR,0x0a); //远程读
    for(i=0;i<4;i++)
    pageheader[i] = readRTL(RDMARORT);
  
    writeRTL(CR,0x22);//结束DMA操作
    Delay(1);
    
	for(i=20;i>0;i--)
    if(readRTL(ISR)&(1<<ISR_RDC)) //远程DMA操作完成则跳出循环
	break;
    writeRTL(ISR,(1<<ISR_RDC));   //清除远程DMA操作完成中断标志
	
	//接收状态错误或接收的包长度>1500b,或下一页指针无效
    if(((pageheader[0]&0x01)==0)||(pageheader[3]>0x06)||\
	  (pageheader[1]>=RXSTOP_INIT)||(pageheader[1]<RXSTART_INIT))
    {
	    Page_Select(1);
	    bnry=readRTL(CURR);
	    Page_Select(0);
	    writeRTL(BNRY,bnry);
	    writeRTL(ISR,0xff); 
        return 0;
    }
  
    //MCU接收数据包
    rxlen=(pageheader[packetLenH]<<8)+pageheader[packetLenL];
    nextPage=pageheader[nextblock];
    rxlen -=4;
    if(rxlen>Max_Size)
    {
	    Page_Select(1);
	    bnry=readRTL(CURR);
	    Page_Select(0);
	    writeRTL(BNRY,bnry);
	    writeRTL(ISR,0xff); 
        return 0;
	}
  
    writeRTL(RBCR1,(uchar)(rxlen>>8));
    writeRTL(RBCR0,(uchar)(rxlen&0xff));
    writeRTL(RSAR1,bnry);
    writeRTL(RSAR0,4);
    writeRTL(CR,0x0a); //远程读
    for(i=0;i<rxlen;i++)
    MCU_Receivebuffer[i] = readRTL(RDMARORT);
   
    //结束DMA操作
    writeRTL(RBCR1,0x00);
    writeRTL(RBCR0,0x00);
    writeRTL(CR,0x22);
    for(i=20;i>0;i--)
    if(readRTL(ISR)&(1<<ISR_RDC))
	break;
    
	writeRTL(ISR,(1<<ISR_RDC));
    writeRTL(BNRY,nextPage);
  
    return rxlen;
}

/******************* End Of File **********************/ 

⌨️ 快捷键说明

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