51单片机驱动W5100以太网接口芯片

51单片机驱动W5100以太网接口芯片

2023年7月15日发(作者:)

51单⽚机驱动W5100以太⽹接⼝芯⽚51单⽚机驱动W5100以太⽹接⼝芯⽚****************************************************************************** * @file W5100.c* 本⽂件包括5个部分:* 1. W5100初始化* 2. W5100的Socket初始化* 3. Socket连接* 如果Socket设置为TCP服务器模式,则调⽤Socket_Listen()函数,W5100处于侦听状态,直到远程客户端与它连接。* 如果Socket设置为TCP客户端模式,则调⽤Socket_Connect()函数,* 每调⽤⼀次Socket_Connect(s)函数,产⽣⼀次连接,* 如果连接不成功,则产⽣超时中断,然后可以再调⽤该函数进⾏连接。* 如果Socket设置为UDP模式,则调⽤Socket_UDP函数* 4. Socket数据接收和发送* 5. W5100中断处理** 置W5100为服务器模式的调⽤过程:W5100_Init()-->Socket_Init(s)-->Socket_Listen(s),设置过程即完成,等待客户端的连接。* 置W5100为客户端模式的调⽤过程:W5100_Init()-->Socket_Init(s)-->Socket_Connect(s),设置过程即完成,并与远程服务器连接。* 置W5100为UDP模式的调⽤过程:W5100_Init()-->Socket_Init(s)-->Socket_UDP(s),设置过程即完成,可以与远程主机UDP通信。** W5100产⽣的连接成功、终⽌连接、接收数据、发送数据、超时等事件,都可以从中断状态中获得。****************************************************************************** */#include"W5100.h" /* 定义W5100的寄存器地址、状态*/#include"REG51.h"typedef unsigned char SOCKET;sbit SPI_CS= P1^0;sbit SPI_SCK= P1^1;sbit SPI_SO= P1^2;sbit SPI_SI= P1^3;sbit SPI_EN= P1^4;sbit KEY= P1^5;/* 端⼝数据缓冲区*/unsigned char Rx_Buffer[20]; /* 端⼝接收数据缓冲区*/unsigned char Tx_Buffer[20]; /* 端⼝发送数据缓冲区*//* ⽹络参数寄存器*/unsigned char Gateway_IP[4]={192,168,2,254}; /* Gateway IP Address */unsigned char Sub_Mask[4]={255,255,255,0}; /* Subnet Mask */unsigned char Phy_Addr[6]={0x00,0x08,0xDC,0x01,0x02,0x03}; /* Physical Address */ unsigned char IP_Addr[4]={192,168,2,1}; /* Loacal IP Address */unsigned char S0_Port[2]={0x13,0x88}; /* Socket0 Port number 5000 */unsigned char S0_DIP[4]={192,168,2,43}; /* Socket0 Destination IP Address */ unsigned char S0_DPort[2]={0x13,0x88}; /*Socket0 Destination Port number 5000*/ unsigned char S0_State=0; /* Socket0 state recorder */unsigned char S0_Data; /* Socket0 receive data and transmit OK */unsigned char W5100_Interrupt;/* UDP Destionation IP address and Port number */unsigned char UDP_DIPR[4];unsigned char UDP_DPORT[2];void Delay(unsigned int x){unsigned int i;for(i=0;iSPI_EN=1;}}unsigned char SPI_ReadByte(void){unsigned char i,rByte=0;for(i=0;i<8;i++){rByte<<=1;rByte|=SPI_SO;SPI_SCK=0;Delay(10);SPI_SCK=1;SPI_SCK=0;}return rByte;}void SPI_SendByte(unsigned char dt){unsigned char i;for(i=0;i<8;i++){if((dt<{SPI_SI=1;}else{SPI_SI=0;}SPI_SCK=0;Delay(10);SPI_SCK=1;SPI_SCK=0;}}unsigned char Read_W5100(unsigned short addr){unsigned char i;/* 置W5100的CS为低电平*/SPI_CS=0;/* 发送读命令*/SPI_SendByte(0x0f);/* 发送地址*/SPI_SendByte(addr/256);SPI_SendByte(addr);/* 读取数据*/i=SPI_ReadByte();/* 置W5100的CS为⾼电平*/SPI_CS=1;return i;}void Write_W5100(unsigned short addr, unsigned char dat){/* 置W5100的CS为低电平*/SPI_CS=0;Delay(100);/* 发送写命令*/SPI_SendByte(0xf0);/* 发送地址*/SPI_SendByte(addr/256);SPI_SendByte(addr);/* 写⼊数据*/SPI_SendByte(dat);Delay(100);/* 置W5100的CS为⾼电平*/SPI_CS=1;}void W5100_Init(void){unsigned char i;SPI_EN=1;SPI_SCK=0;SPI_CS=1;SPI_SO=1;Write_W5100(W5100_MODE,MODE_RST); /*软复位W5100*/ Delay(100);///Write_W5100(W5100_MODE,0); /*软复位W5100*/Delay(100); /*延时100ms,⾃⼰定义该函数*//*设置⽹关(Gateway)的IP地址,4字节*//*使⽤⽹关可以使通信突破⼦⽹的局限,通过⽹关可以访问到其它⼦⽹或进⼊Internet*/ for(i=0;i<4;i++)Write_W5100(W5100_GAR+i,Gateway_IP); /*Gateway_IP为4字节unsigned char数组,⾃⼰定义*/for(i=0;i<4;i++)Gateway_IP=Read_W5100(W5100_GAR+i);/*设置⼦⽹掩码(MASK)值,4字节。⼦⽹掩码⽤于⼦⽹运算*/for(i=0;i<4;i++)Write_W5100(W5100_SUBR+i,Sub_Mask); /*SUB_MASK为4字节unsigned char数组,⾃⼰定义*//*设置物理地址,6字节,⽤于唯⼀标识⽹络设备的物理地址值该地址值需要到IEEE申请,按照OUI的规定,前3个字节为⼚商代码,后三个字节为产品序号如果⾃⼰定义物理地址,注意第⼀个字节必须为偶数*/for(i=0;i<6;i++)Write_W5100(W5100_SHAR+i,Phy_Addr); /*PHY_ADDR6字节unsigned char数组,⾃⼰定义*//*设置本机的IP地址,4个字节注意,⽹关IP必须与本机IP属于同⼀个⼦⽹,否则本机将⽆法找到⽹关*/for(i=0;i<4;i++)Write_W5100(W5100_SIPR+i,IP_Addr); /*IP_ADDR为4字节unsigned char数组,⾃⼰定义*/ /*设置发送缓冲区和接收缓冲区的⼤⼩,参考W5100数据⼿册*/Write_W5100(W5100_RMSR,0x55); /*Socket Rx memory size=2k*/Write_W5100(W5100_TMSR,0x55); /*Socket Tx mempry size=2k*//* 设置重试时间,默认为2000(200ms) */Write_W5100(W5100_RTR,0x07);Write_W5100(W5100_RTR+1,0xd0);/* 设置重试次数,默认为8次*/Write_W5100(W5100_RCR,8);/* 启动中断,参考W5100数据⼿册确定⾃⼰需要的中断类型IMR_CONFLICT是IP地址冲突异常中断IMR_UNREACH是UDP通信时,地址⽆法到达的异常中断其它是Socket事件中断,根据需要添加*/Write_W5100(W5100_IMR,(IMR_CONFLICT|IMR_UNREACH|IMR_S0_INT));}unsigned char Detect_Gateway(void){unsigned char i;Write_W5100((W5100_S0_MR),S_MR_TCP); /*设置socket0为TCP模式*/Write_W5100((W5100_S0_CR),S_CR_OPEN); /*打开socket0*/if(Read_W5100(W5100_S0_SSR)!=S_SSR_INIT){Write_W5100((W5100_S0_CR),S_CR_CLOSE); /*打开不成功,关闭Socket,然后返回*/ return FALSE;/*检查⽹关及获取⽹关的物理地址*/for(i=0;i<4;i++)Write_W5100((W5100_S0_DIPR+i),IP_Addr+1); /*向⽬的地址寄存器写⼊与本机IP不同的IP 值*/Write_W5100((W5100_S0_CR),S_CR_CONNECT); /*打开socket0的TCP连接*/Delay(20); /* 延时20ms */i=Read_W5100(W5100_S0_DHAR); /*读取⽬的主机的物理地址,该地址就是⽹关地址*/Write_W5100((W5100_S0_CR),S_CR_CLOSE); /*关闭socket0*/if(i==0xff){/**********没有找到⽹关服务器,或没有与⽹关服务器成功连接***********//********** ⾃⼰添加处理代码***********/return FALSE;}return TRUE;}void Socket_Init(SOCKET s){unsigned int i;/*设置分⽚长度,参考W5100数据⼿册,该值可以不修改*/Write_W5100((W5100_S0_MSS+s*0x100),0x00); /*最⼤分⽚字节数=16*/Write_W5100((W5100_S0_MSS+s*0x100+1),0x10);/* Set Socket Port number */switch(s){case 0:Write_W5100(W5100_S0_PORT,S0_Port[0]); /* Set Local Socket Port number */Write_W5100(W5100_S0_PORT+1,S0_Port[1]);Write_W5100(W5100_S0_DPORT,S0_DPort[0]); /* Set Destination port number */Write_W5100(W5100_S0_DPORT+1,S0_DPort[1]);for(i=0;i<4;i++)Write_W5100(W5100_S0_DIPR+i,S0_DIP); /* Set Destination IP Address */break;case 1:break;case 2:break;case 3:break;default:break;}}* @brief 设置Socket为客户端与远程服务器连接*当本机Socket⼯作在客户端模式时,引⽤该程序,与远程服务器建⽴连接**如果启动连接后出现超时中断,则与服务器连接失败,需要重新调⽤该程序连接*该程序每调⽤⼀次,就与服务器产⽣⼀次连接**/unsigned char Socket_Connect(SOCKET s){Write_W5100((W5100_S0_MR+s*0x100), S_MR_TCP); /*设置socket为TCP模式*/Write_W5100((W5100_S0_CR+s*0x100), S_CR_OPEN); /*打开Socket*/if(Read_W5100(W5100_S0_SSR+s*0x100)!=S_SSR_INIT){Write_W5100(W5100_S0_CR+s*0x100,S_CR_CLOSE); /*打开不成功,关闭Socket,然后返回*/return FALSE;}Write_W5100((W5100_S0_CR+s*0x100),S_CR_CONNECT); /*设置Socket为Connect模式*/ return TRUE;/*⾄此完成了Socket的打开连接⼯作,⾄于它是否与远程服务器建⽴连接,则需要等待Socket中断,以判断Socket的连接是否成功。参考W5100数据⼿册的Socket中断状态*/}/*** @brief 设置Socket作为服务器等待远程主机的连接*当本机Socket⼯作在服务器模式时,引⽤该程序,等等远程主机的连接**该程序只调⽤⼀次,就使W5100设置为服务器模式* @return 如果设置成功则返回true, 否则返回false**/unsigned char Socket_Listen(SOCKET s){Write_W5100((W5100_S0_MR+s*0x100), S_MR_TCP); /*设置socket为TCP模式*/Write_W5100(W5100_S0_PORT,S0_Port[0]); /* Set source Socket Port number */Write_W5100(W5100_S0_PORT+1,S0_Port[1]);Write_W5100((W5100_S0_CR+s*0x100), S_CR_OPEN); /*打开Socket*/if(Read_W5100(W5100_S0_SSR+s*0x100)!=S_SSR_INIT){Write_W5100((W5100_S0_CR+s*0x100),S_CR_CLOSE); /*打开不成功,关闭Socket,然后返回*/return FALSE;}Write_W5100((W5100_S0_CR+s*0x100), S_CR_LISTEN); /*设置Socket为侦听模式*/if(Read_W5100(W5100_S0_SSR+s*0x100)!=S_SSR_LISTEN)Write_W5100((W5100_S0_CR+s*0x100), S_CR_CLOSE); /*设置不成功,关闭Socket,然后返回*/return FALSE;}return TRUE;/*⾄此完成了Socket的打开和设置侦听⼯作,⾄于远程客户端是否与它建⽴连接,则需要等待Socket中断,以判断Socket的连接是否成功。参考W5100数据⼿册的Socket中断状态在服务器侦听模式不需要设置⽬的IP和⽬的端⼝号*/}/*** @brief 设置Socket为UDP模式*如果Socket⼯作在UDP模式,引⽤该程序。在UDP模式下,Socket通信不需要建⽴连接*该程序只调⽤⼀次,就使W5100设置为UDP模式* @return 如果设置成功则返回true, 否则返回false**/unsigned char Socket_UDP(SOCKET s){Write_W5100((W5100_S0_MR+s*0x100), S_MR_UDP); /*设置Socket为UDP模式*/Write_W5100((W5100_S0_CR+s*0x100), S_CR_OPEN); /*打开Socket*/if(Read_W5100(W5100_S0_SSR+s*0x100)!=S_SSR_UDP){Write_W5100((W5100_S0_CR+s*0x100), S_CR_CLOSE); /*打开不成功,关闭Socket,然后返回*/return FALSE;}elsereturn TRUE;/*⾄此完成了Socket的打开和UDP模式设置,在这种模式下它不需要与远程主机建⽴连接因为Socket不需要建⽴连接,所以在发送数据前都可以设置⽬的主机IP和⽬的Socket的端⼝号如果⽬的主机IP和⽬的Socket的端⼝号是固定的,在运⾏过程中没有改变,那么也可以在这⾥设置*/}/*** @brief 处理Socket接收和发送的数据*如果Socket产⽣接收数据的中断,则引⽤该程序进⾏处理*该程序将Socket的接收到的数据缓存到Rx_buffer数组中,并返回接收的数据字节数* @return 数据长度**/unsigned short S_rx_process(SOCKET s){unsigned short i,j;unsigned short rx_size,rx_offset;/*读取接收数据的字节数*/rx_size=Read_W5100(W5100_S0_RX_RSR+s*0x100);rx_size*=256;rx_size+=Read_W5100(W5100_S0_RX_RSR+s*0x100+1);/*读取接收缓冲区的偏移量*/rx_offset=Read_W5100(W5100_S0_RX_RR+s*0x100);rx_offset*=256;rx_offset+=Read_W5100(W5100_S0_RX_RR+s*0x100+1);i=rx_offset/S_RX_SIZE; /*计算实际的物理偏移量,S0_RX_SIZE需要在前⾯#define中定义*//*注意S_RX_SIZE的值在W5100_Init()函数的W5100_RMSR中确定*/rx_offset=rx_offset-i*S_RX_SIZE;j=W5100_RX+s*S_RX_SIZE+rx_offset; /*实际物理地址为W5100_RX+rx_offset*/for(i=0;i{if(rx_offset>=S_RX_SIZE){j=W5100_RX+s*S_RX_SIZE;rx_offset=0;}Rx_Buffer=Read_W5100(j); /*将数据缓存到Rx_buffer数组中*/j++;rx_offset++;}/*计算下⼀次偏移量*/rx_offset=Read_W5100(W5100_S0_RX_RR+s*0x100);rx_offset*=256;rx_offset+=Read_W5100(W5100_S0_RX_RR+s*0x100+1);rx_offset+=rx_size;Write_W5100((W5100_S0_RX_RR+s*0x100), (rx_offset/256));Write_W5100((W5100_S0_RX_RR+s*0x100+1), rx_offset);Write_W5100((W5100_S0_CR+s*0x100), S_CR_RECV); /*设置RECV命令,等等下⼀次接收*/return rx_size; /*返回接收的数据字节数*/}/*** @brief 如果要通过Socket发送数据,则引⽤该程序*要发送的数据缓存在Tx_buffer中, size则是要发送的字节长度* @author stmsky* @param[in] socket nummber* @param[out] none* @return* @note**/unsigned char S_tx_process(SOCKET s, unsigned int size){unsigned short i,j;unsigned short tx_free_size,tx_offset;/*如果是UDP模式,可以在此设置⽬的主机的IP和端⼝号*/if((Read_W5100(W5100_S0_MR+s*0x100)&0x0f)==0x02){for(i=0;i<4;i++) /* 设置⽬的主机IP*/Write_W5100((W5100_S0_DIPR+s*0x100+i), UDP_DIPR);Write_W5100((W5100_S0_DPORT+s*0x100), UDP_DPORT[0]);Write_W5100((W5100_S0_DPORT+s*0x100+1), UDP_DPORT[1]);}/*读取缓冲区剩余的长度*/tx_free_size=Read_W5100(W5100_S0_TX_FSR+s*0x100);tx_free_size*=256;tx_free_size+=Read_W5100(W5100_S0_TX_FSR+s*0x100+1);if(tx_free_sizereturn FALSE;/*读取发送缓冲区的偏移量*/tx_offset=Read_W5100(W5100_S0_TX_WR+s*0x100);tx_offset*=256;tx_offset+=Read_W5100(W5100_S0_TX_WR+s*0x100+1);i=tx_offset/S_TX_SIZE; /*计算实际的物理偏移量,S0_TX_SIZE需要在前⾯#define中定义*/ /*注意S0_TX_SIZE的值在W5100_Init()函数的W5100_TMSR中确定*/tx_offset=tx_offset-i*S_TX_SIZE;j=W5100_TX+s*S_TX_SIZE+tx_offset; /*实际物理地址为W5100_TX+tx_offset*/for(i=0;i{if(tx_offset>=S_TX_SIZE){j=W5100_TX+s*S_TX_SIZE;tx_offset=0;}Write_W5100(j,Tx_Buffer); /*将Tx_buffer缓冲区中的数据写⼊到发送缓冲区*/j++;tx_offset++;}/*计算下⼀次的偏移量*/tx_offset=Read_W5100(W5100_S0_TX_WR+s*0x100);tx_offset*=256;tx_offset+=Read_W5100(W5100_S0_TX_WR+s*0x100+1);tx_offset+=size;Write_W5100((W5100_S0_TX_WR+s*0x100),(tx_offset/256));Write_W5100((W5100_S0_TX_WR+s*0x100+1),tx_offset);Write_W5100((W5100_S0_CR+s*0x100), S_CR_SEND); /*设置SEND命令,启动发送*/ return TRUE; /*返回成功*/}/*** @brief W5100中断处理程序框架* @note**/void W5100_Interrupt_Process(void){unsigned char i,j;W5100_Interrupt=0;i=Read_W5100(W5100_IR);Write_W5100(W5100_IR, (i&0xf0)); /*回写清除中断标志*///GPIO_SetBits(GPIOB, GPIO_Pin_0);if((i & IR_CONFLICT) == IR_CONFLICT) /*IP地址冲突异常处理,⾃⼰添加代码*/{}if((i & IR_UNREACH) == IR_UNREACH) /*UDP模式下地址⽆法到达异常处理,⾃⼰添加代码*/{}/* Socket事件处理*/if((i & IR_S0_INT) == IR_S0_INT){j=Read_W5100(W5100_S0_IR);Write_W5100(W5100_S0_IR, j); /* 回写清中断标志*/if(j&S_IR_CON) /* 在TCP模式下,Socket0成功连接*/{S0_State|=S_CONN;}if(j&S_IR_DISCON) /* 在TCP模式下Socket断开连接处理,⾃⼰添加代码*/{Write_W5100(W5100_S0_CR, S_CR_CLOSE); /* 关闭端⼝,等待重新打开连接*/S0_State=0;}if(j&S_IR_SENDOK) /* Socket0数据发送完成,可以再次启动S_tx_process()函数发送数据*/ {S0_Data|=S_TRANSMITOK;}if(j&S_IR_RECV) /* Socket接收到数据,可以启动S_rx_process()函数*/{S0_Data|=S_RECEIVE;}if(j&S_IR_TIMEOUT) /* Socket连接或数据传输超时处理*/{Write_W5100(W5100_S0_CR, S_CR_CLOSE); /* 关闭端⼝,等待重新打开连接*/ S0_State=0;}}/* Socket1事件处理*/if((i&IR_S1_INT)==IR_S1_INT){j=Read_W5100(W5100_S1_IR);Write_W5100(W5100_S1_IR, j); /* 回写清中断标志*/}/* Socket2事件处理*/if((i&IR_S2_INT)==IR_S2_INT){j=Read_W5100(W5100_S2_IR);Write_W5100(W5100_S2_IR, j); /*回写清中断标志*/}/* Socket3事件处理*/if((i&IR_S3_INT)==IR_S3_INT){j=Read_W5100(W5100_S3_IR);Write_W5100(W5100_S3_IR, j); /* 回写清中断标志*/}}void main(void){W5100_Init();Socket_Init(0);Socket_Listen(0);while(1){W5100_Interrupt_Process();if(S0_State==S_CONN) break;}while(1){}}

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1689407669a243146.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信