📄 main.c
字号:
/*##############################################################################
功能: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 + -