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

📄 main.c

📁 网卡控制器ENC28J60的AVR单片机ATmega16程序源代码(c),实现232toUDP功能,有非常详细的注释.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*##############################################################################
功能:232toUDP
作者:LHF
时间:2006-09
版本:V1.0
################################################################################
资源分配:	PORTC.2~5:JTAG
##############################################################################*/
//##############################################################################
#include "ENC28j60.h"	
#pragma interrupt_handler INT0_16:2 //定义INT0的中断服务程序
#pragma interrupt_handler INT1_17:3 //定义INT1的中断服务程序
#pragma interrupt_handler Usart_receive:12 //定义接收中断服务程序
#pragma interrupt_handler Timer0:10 //定义定时计数器0的中断服务程序
uchar EIR=0;//存放中断请求标志寄存器的值
uchar Receive_Status[6]={0x00};//存放接收状态向量
uchar EPKTCNT=0x00;//还没处理的数据包个数,当它为0时才能使PKTIF自动清0以响应下次接收中断
uchar DateLen=18;//有效数据长度,这里最大不超过203个字节
uchar MACHead[14]={0x00,0xe0,0x4c,0xc7,0x1b,0x4c,//目标MAC地址
                   0x11,0x22,0x33,0x44,0x55,0x66,//源MAC地址
                   0x08,0x00};//上层协议为IP协议
uchar IpHead[20]={0x45,0x00,
	  			  0x00,0x00,//总长度
				  0x12,0x34,//标识
				  0x40,0x00,//分段偏移量
				  0x80,//生存时间
				  0x11,//上层协议0x11表示是UDP
	  			  0x00,0x00,//IP校验和
	  			  0xc0,0xa8,0x01,0x68,//源IP地址,在此修改源IP地址
				  0xc0,0xa8,0x01,0x64};//目标IP地址,在此修改目标IP地址
uchar UDPpacket[255]={0x00,0x00,0x00,0x00,//源IP地址
                   0xc0,0x00,0x00,0x00,//目标IP地址
				   0x00,0x11,//未定义
				   0x00,0x00,//UDP报长度为26字节8+18=26//到此都是伪报头共12字节
				   
				   0x04,0x00,//源端口号1024
	               0x04,0x00,//目标端口号1024
				   0x00,0x00,//UDP报长度
				   0x00,0x00,//UDP校验和//UDP报头共8字节
				   
 				   };//数据部分
uchar Rec_packet[255]={0x00};//接收到的帧,考虑到M16只有1KRAM,所以这里设定,最大帧不能超过255
uchar Rec232[255]={0x00};//串口接收到的数据
uchar usart_number=0;	
//#######################IP报头校验和计算#######################//
void CreateCrc(uchar *p,uchar num,uchar CRCH,uchar CRCL)
//必需先附IpHead值后再校验,CRCH表示数组存放校验和的位置高8位,CRCL表示数组存放校验和的位置低8位
//num表示数组中元数的个数,如IP包头数组个数为20个
{uchar i=0;
 uchar temp=0,L=0,H=0;
 p[CRCH]=0x00;p[CRCL]=0x00;//先将存放校验和的位置那位清0
 for(i=1;i<num+1;i=i+2){temp=temp+p[i];
		             if(temp<p[i])L++;}//如果temp<p[i]表示前面相加结果大于0XFF,则进1
 for(i=0;i<num;i=i+2){L=L+p[i];
		             if(L<p[i])H++;}//如果temp<p[i]表示前面相加结果大于0XFF,则进1   
 temp=temp+H;//把高出16位的结果与低16位相加
 if(temp<H){L++;//把高出16位的结果与低16位相加,如果有溢出,则再向高位进位
            if(L==0)temp++;}//如果高位再溢出,再加到低位
 p[CRCH]=0xff-L;//结果取反
 p[CRCL]=0xff-temp;//结果取反
}

//##########################发送UDP数据包##########################//
void Transmit_Packets(void)
{uchar i=0;
 enc28j60SetBank(0x00);//通过ECON1先选中当前控制寄存器组是Bank0
 
 Write_Control_Register(0x02,0x00);//EWRPTL
 Write_Control_Register(0x03,0x00);//EWRPTH
 Write_Control_Register(0x04,0x00);//ETXSTL
 Write_Control_Register(0x05,0x00);//ETXSTH
  
 Bit_Field_Set(0x1e,0x80);//ECON2寄存器中的AUTOINC位置1,

 for(i=0;i<8;i++)UDPpacket[i]=IpHead[i+12];//给UDP伪报头部分附IP值
 IpHead[3]=DateLen+28;//IP包长度
 UDPpacket[11]=DateLen+8;//UDP包长度,伪报头,不发送部分
 UDPpacket[17]=DateLen+8;//UDP包长度,UDP报头
 CreateCrc(IpHead,20,10,11);//校验前要对数组中其它元素先附好值
 CreateCrc(UDPpacket,DateLen+20,18,19);//UDP校验
Set_CS(0);//使能SPI器件
 Write_Buffer_Memory_date(0x7A);//送命令,28J60中写缓冲存储器操作前3位为011后5位为常量11010
 Write_Buffer_Memory_date(0x0e);//28J60要求在待发送的数据包前添加一个包控制字节
 
 for(i=0;i<14;i++)Write_Buffer_Memory_date(MACHead[i]);//MAC首部14字节  
 for(i=0;i<20;i++)Write_Buffer_Memory_date(IpHead[i]);//IP首部20字节
 for(i=12;i<DateLen+20;i++)Write_Buffer_Memory_date(UDPpacket[i]);//UDP层去掉伪报头 
   
Set_CS(1);//写缓冲寄存器结束
 
 Write_Control_Register(0x06,DateLen+42);//ETXNDL,6+6+2+20+8+DateLen
 Write_Control_Register(0x07,0x00);//ETXNDH,即从0x0000开始写入数据
 
 Bit_Field_Clear(0x1c,0x08);//将EIR.TXIF位清零
 //Bit_Field_Set(0x1b,0x88);//将EIE.TXIE位和EIE.INTIE位置1允许在发送完成后产生中断。
 Bit_Field_Set(0x1f,0x08);//将ECON1.TXRTS 位置1开始发送
 }
//########从当前接收到的数据包中判断是不是本地ARP请求帧,是则返回1,否返回0#########//
uchar ARP_request_or_answer(void)
{uchar ARPflag=0;//
if(Rec_packet[12]==0x08 && Rec_packet[13]==0x06)//如果符合则表示当前数据包是ARP帧
if(Rec_packet[20]==0x00 && Rec_packet[21]==0x01)//如果符合则表示当前数据包是ARP请求帧
if(Rec_packet[38]==IpHead[12] && Rec_packet[39]==IpHead[13] && Rec_packet[40]==IpHead[14]&& Rec_packet[41]==IpHead[15])ARPflag=0x01;
		 //请求方希望获得MAC地址的IP地址是不是和本地IP地址一致,如果一致,则说明是要本地回答
else ARPflag=0x00;
return ARPflag;
}  
//##########################发送ARP数据包##########################//
void Transmit_ARP_Packets(void)
{uchar i=0;
 enc28j60SetBank(0x00);//通过ECON1先选中当前控制寄存器组是Bank0
 Write_Control_Register(0x02,0x00);//EWRPTL
 Write_Control_Register(0x03,0x00);//EWRPTH
 Write_Control_Register(0x04,0x00);//ETXSTL
 Write_Control_Register(0x05,0x00);//ETXSTH
 Bit_Field_Set(0x1e,0x80);//ECON2寄存器中的AUTOINC位置1,
Set_CS(0);//使能SPI器件
 Write_Buffer_Memory_date(0x7A);//送命令,28J60中写缓冲存储器操作前3位为011后5位为常量11010
 Write_Buffer_Memory_date(0x0e);//28J60要求在待发送的数据包前添加一个包控制字节

for(i=6;i<12;i++)Write_Buffer_Memory_date(Rec_packet[i]);//目标MAC地址6字节
for(i=6;i<12;i++)Write_Buffer_Memory_date(MACHead[i]);    //源MAC地址6字节
for(i=12;i<20;i++)Write_Buffer_Memory_date(Rec_packet[i]);//0x08,0x06,0x00,0x01,0x08,0x00,0x06,0x04
Write_Buffer_Memory_date(0x00);
Write_Buffer_Memory_date(0x02);//0x0002表示是应答帧
for(i=6;i<12;i++)Write_Buffer_Memory_date(MACHead[i]);    //源MAC地址6字节
for(i=38;i<42;i++)Write_Buffer_Memory_date(Rec_packet[i]);//源IP地址
for(i=22;i<32;i++)Write_Buffer_Memory_date(Rec_packet[i]);//目标MAC地址6字节,目标IP地址
Set_CS(1);//写缓冲寄存器结束
 Write_Control_Register(0x06,42);//ETXNDL,6+6+2+20+8
 Write_Control_Register(0x07,0x00);//ETXNDH,即从0x0000开始写入数据
 
 Bit_Field_Clear(0x1c,0x08);//将EIR.TXIF位清零
 Bit_Field_Set(0x1f,0x08);//将ECON1.TXRTS 位置1开始发送
}
//##########################接收数据包处理##########################//
void Receive_Packets(void)//
{uchar i=0;
 uint Receive_Byte_Number=0;
 enc28j60SetBank(0x00);//通过ECON1先选中当前控制寄存器组是Bank0
 Receive_Status[0]=Read_Buffer_Memory();//存放下一个数据包的起始位置低8位
 Receive_Status[1]=Read_Buffer_Memory();//存放下一个数据包的起始位置高8位
 Receive_Status[2]=Read_Buffer_Memory();//存放当前接收到的数据包的字节数低8位
 Receive_Status[3]=Read_Buffer_Memory();//存放当前接收到的数据包的字节数高8位
 Receive_Status[4]=Read_Buffer_Memory();//其它,参看数据手册
 Receive_Status[5]=Read_Buffer_Memory();//其它,参看数据手册
  
 Receive_Byte_Number +=Receive_Status[3];
 Receive_Byte_Number =Receive_Byte_Number<<8;
 Receive_Byte_Number +=Receive_Status[2];
 //得到接收到的数据包长度包括目标地址,源地址,类型/长度,数据,填充,CRC字段
 for(i=0;i<Receive_Byte_Number;i++)Rec_packet[i]=Read_Buffer_Memory();//将接收到的当前数据包存放在Rec_packet[255]中等待处理
 i=ARP_request_or_answer();
 if(i==0x01)Transmit_ARP_Packets();//如果是本地ARP请求帧,则响应请求,发送ARP应答帧

 putchar(0x4C);
 putchar(0x48);
 putchar(0x46);//发送"LHF"通知上位机,紧接着要发送刚接收到的数据帧给上位机
 for(i=0;i<Receive_Byte_Number;i++)putchar(Rec_packet[i]);
  //将接收到的数据发送到上位机软件,包括目标地址,源地址,类型/长度,数据,填充,CRC字段。

 Bit_Field_Set(0x1e,0x40);//数据处理完后,然后清零待处理中断标志位PKTIF
 //只能通过将ECON2中的PKTDEC置1时才能清PKTIF
  Write_Control_Register(0x00,Receive_Status[0]);//ERDPTL
  Write_Control_Register(0x01,Receive_Status[1]);//ERDPTH,读数据包指针起始位置,准备处理下一数据帧
 
 enc28j60SetBank(0x01);//因为EPKTCNT寄存器在Bank1.
 EPKTCNT=Read_Control_Register(ETH,0x19);//读取EPKTCNT值
 }

⌨️ 快捷键说明

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