• 基于STM32F1的局域网通信模块W5500驱动


    说明

    需要调整的内容为W5500.h中关于IP地址、端口号、子网掩码、网关等参数

    W5500

    #ifndef	_W5500_H_
    #define	_W5500_H_
    
    /****************** Parameter **********************/
    //网关地址
    #define GATEWAY_IP_0 125
    #define GATEWAY_IP_1 217
    #define GATEWAY_IP_2 54
    #define GATEWAY_IP_3 254
    
    #define SUB_MASK_0 255
    #define SUB_MASK_1 255
    #define SUB_MASK_2 255
    #define SUB_MASK_3 0
    
    #define PHY_ADDR_0 0x80
    #define PHY_ADDR_1 0x9E
    #define PHY_ADDR_2 0x01
    #define PHY_ADDR_3 0x56
    #define PHY_ADDR_4 0x37
    #define PHY_ADDR_5 0xC6
    
    //本机IP地址
    #define IP_ADDR_0 125
    #define IP_ADDR_1 217
    #define IP_ADDR_2 54
    #define IP_ADDR_3 55
    
    //本机端口号
    #define S0_PORT_0 0x13
    #define S0_PORT_1 0x88
    
    //UDP(广播)模式,目的主机IP地址
    #define UDP_DIR_0 125
    #define UDP_DIR_1 217
    #define UDP_DIR_2 54
    #define UDP_DIR_3 242
    
    //UDP(广播)模式,目的主机端口号
    #define UDP_DPORT_0 0x17
    #define UDP_DPORT_1 0x75
    
    //模式配置
    #define S0_MODE UDP_MODE
    
    
    
    /***************** Common Register *****************/
    #define MR		0x0000
    	#define RST		0x80
    	#define WOL		0x20
    	#define PB		0x10
    	#define PPP		0x08
    	#define FARP	0x02
    
    #define GAR		0x0001
    #define SUBR	0x0005
    #define SHAR	0x0009
    #define SIPR	0x000f
    
    #define INTLEVEL	0x0013
    #define IR		0x0015
    	#define CONFLICT	0x80
    	#define UNREACH		0x40
    	#define PPPOE		0x20
    	#define MP			0x10
    
    #define IMR		0x0016
    	#define IM_IR7		0x80
    	#define IM_IR6		0x40
    	#define IM_IR5		0x20
    	#define IM_IR4		0x10
    
    #define SIR		0x0017
    	#define S7_INT		0x80
    	#define S6_INT		0x40
    	#define S5_INT		0x20
    	#define S4_INT		0x10
    	#define S3_INT		0x08
    	#define S2_INT		0x04
    	#define S1_INT		0x02
    	#define S0_INT		0x01
    
    #define SIMR	0x0018
    	#define S7_IMR		0x80
    	#define S6_IMR		0x40
    	#define S5_IMR		0x20
    	#define S4_IMR		0x10
    	#define S3_IMR		0x08
    	#define S2_IMR		0x04
    	#define S1_IMR		0x02
    	#define S0_IMR		0x01
    
    #define RTR		0x0019
    #define RCR		0x001b
    
    #define PTIMER	0x001c
    #define PMAGIC	0x001d
    #define PHA		0x001e
    #define PSID	0x0024
    #define PMRU	0x0026
    
    #define UIPR	0x0028
    #define UPORT	0x002c
    
    #define PHYCFGR	0x002e
    	#define RST_PHY		0x80
    	#define OPMODE		0x40
    	#define DPX			0x04
    	#define SPD			0x02
    	#define LINK		0x01
    
    #define VERR	0x0039
    
    /********************* Socket Register *******************/
    #define Sn_MR		0x0000
    	#define MULTI_MFEN		0x80
    	#define BCASTB			0x40
    	#define	ND_MC_MMB		0x20
    	#define UCASTB_MIP6B	0x10
    	#define MR_CLOSE		0x00
    	#define MR_TCP		0x01
    	#define MR_UDP		0x02
    	#define MR_MACRAW		0x04
    
    #define Sn_CR		0x0001
    	#define OPEN		0x01
    	#define LISTEN		0x02
    	#define CONNECT		0x04
    	#define DISCON		0x08
    	#define CLOSE		0x10
    	#define SEND		0x20
    	#define SEND_MAC	0x21
    	#define SEND_KEEP	0x22
    	#define RECV		0x40
    
    #define Sn_IR		0x0002
    	#define IR_SEND_OK		0x10
    	#define IR_TIMEOUT		0x08
    	#define IR_RECV			0x04
    	#define IR_DISCON		0x02
    	#define IR_CON			0x01
    
    #define Sn_SR		0x0003
    	#define SOCK_CLOSED		0x00
    	#define SOCK_INIT		0x13
    	#define SOCK_LISTEN		0x14
    	#define SOCK_ESTABLISHED	0x17
    	#define SOCK_CLOSE_WAIT		0x1c
    	#define SOCK_UDP		0x22
    	#define SOCK_MACRAW		0x02
    
    	#define SOCK_SYNSEND	0x15
    	#define SOCK_SYNRECV	0x16
    	#define SOCK_FIN_WAI	0x18
    	#define SOCK_CLOSING	0x1a
    	#define SOCK_TIME_WAIT	0x1b
    	#define SOCK_LAST_ACK	0x1d
    
    #define Sn_PORT		0x0004
    #define Sn_DHAR	   	0x0006
    #define Sn_DIPR		0x000c
    #define Sn_DPORTR	0x0010
    
    #define Sn_MSSR		0x0012
    #define Sn_TOS		0x0015
    #define Sn_TTL		0x0016
    
    #define Sn_RXBUF_SIZE	0x001e
    #define Sn_TXBUF_SIZE	0x001f
    #define Sn_TX_FSR	0x0020
    #define Sn_TX_RD	0x0022
    #define Sn_TX_WR	0x0024
    #define Sn_RX_RSR	0x0026
    #define Sn_RX_RD	0x0028
    #define Sn_RX_WR	0x002a
    
    #define Sn_IMR		0x002c
    	#define IMR_SENDOK	0x10
    	#define IMR_TIMEOUT	0x08
    	#define IMR_RECV	0x04
    	#define IMR_DISCON	0x02
    	#define IMR_CON		0x01
    
    #define Sn_FRAG		0x002d
    #define Sn_KPALVTR	0x002f
    
    /*******************************************************************/
    /************************ SPI Control Byte *************************/
    /*******************************************************************/
    /* Operation mode bits */
    #define VDM		0x00
    #define FDM1	0x01
    #define	FDM2	0x02
    #define FDM4	0x03
    
    /* Read_Write control bit */
    #define RWB_READ	0x00
    #define RWB_WRITE	0x04
    
    /* Block select bits */
    #define COMMON_R	0x00
    
    /* Socket 0 */
    #define S0_REG		0x08
    #define S0_TX_BUF	0x10
    #define S0_RX_BUF	0x18
    
    /* Socket 1 */
    #define S1_REG		0x28
    #define S1_TX_BUF	0x30
    #define S1_RX_BUF	0x38
    
    /* Socket 2 */
    #define S2_REG		0x48
    #define S2_TX_BUF	0x50
    #define S2_RX_BUF	0x58
    
    /* Socket 3 */
    #define S3_REG		0x68
    #define S3_TX_BUF	0x70
    #define S3_RX_BUF	0x78
    
    /* Socket 4 */
    #define S4_REG		0x88
    #define S4_TX_BUF	0x90
    #define S4_RX_BUF	0x98
    
    /* Socket 5 */
    #define S5_REG		0xa8
    #define S5_TX_BUF	0xb0
    #define S5_RX_BUF	0xb8
    
    /* Socket 6 */
    #define S6_REG		0xc8
    #define S6_TX_BUF	0xd0
    #define S6_RX_BUF	0xd8
    
    /* Socket 7 */
    #define S7_REG		0xe8
    #define S7_TX_BUF	0xf0
    #define S7_RX_BUF	0xf8
    
    #define TRUE	0xff
    #define FALSE	0x00
    
    #define S_RX_SIZE	2048	/*定义Socket接收缓冲区的大小,可以根据W5500_RMSR的设置修改 */
    #define S_TX_SIZE	2048  	/*定义Socket发送缓冲区的大小,可以根据W5500_TMSR的设置修改 */
    
    /***************----- W5500 GPIO定义 -----***************/
    #define W5500_SCS		GPIO_Pin_4	//定义W5500的CS引脚	 
    #define W5500_SCS_PORT	GPIOA
    	
    #define W5500_RST		GPIO_Pin_0	//定义W5500的RST引脚
    #define W5500_RST_PORT	GPIOB
    
    #define W5500_INT		GPIO_Pin_1	//定义W5500的INT引脚
    #define W5500_INT_PORT	GPIOB
    
    /***************----- 网络参数变量定义 -----***************/
    extern unsigned char Gateway_IP[4];	//网关IP地址 
    extern unsigned char Sub_Mask[4];	//子网掩码 
    extern unsigned char Phy_Addr[6];	//物理地址(MAC) 
    extern unsigned char IP_Addr[4];	//本机IP地址 
    
    extern unsigned char S0_Port[2];	//端口0的端口号(5000) 
    extern unsigned char S0_DIP[4];		//端口0目的IP地址 
    extern unsigned char S0_DPort[2];	//端口0目的端口号(6000) 
    
    extern unsigned char UDP_DIPR[4];	//UDP(广播)模式,目的主机IP地址
    extern unsigned char UDP_DPORT[2];	//UDP(广播)模式,目的主机端口号
    
    /***************----- 端口的运行模式 -----***************/
    extern unsigned char S0_Mode;	//端口0的运行模式,0:TCP服务器模式,1:TCP客户端模式,2:UDP(广播)模式
    #define TCP_SERVER		0x00	//TCP服务器模式
    #define TCP_CLIENT		0x01	//TCP客户端模式 
    #define UDP_MODE		0x02	//UDP(广播)模式 
    
    /***************----- 端口的运行状态 -----***************/
    extern unsigned char S0_State;	//端口0状态记录,1:端口完成初始化,2端口完成连接(可以正常传输数据) 
    #define S_INIT			0x01	//端口完成初始化 
    #define S_CONN			0x02	//端口完成连接,可以正常传输数据 
    
    /***************----- 端口收发数据的状态 -----***************/
    extern unsigned char S0_Data;		//端口0接收和发送数据的状态,1:端口接收到数据,2:端口发送数据完成 
    #define S_RECEIVE		0x01		//端口接收到一个数据包 
    #define S_TRANSMITOK	0x02		//端口发送一个数据包完成 
    
    /***************----- 端口数据缓冲区 -----***************/
    extern unsigned char Rx_Buffer[2048];	//端口接收数据缓冲区 
    extern unsigned char Tx_Buffer[2048];	//端口发送数据缓冲区 
    
    extern unsigned char W5500_Interrupt;	//W5500中断标志(0:无中断,1:有中断)
    typedef unsigned char SOCKET;			//自定义端口号数据类型
    
    extern void Delay(unsigned int d);//延时函数(ms)
    extern void W5500_GPIO_Configuration(void);//W5500 GPIO初始化配置
    extern void W5500_NVIC_Configuration(void);//W5500 接收引脚中断优先级设置
    extern void SPI_Configuration(void);//W5500 SPI初始化配置(STM32 SPI1)
    extern void W5500_Hardware_Reset(void);//硬件复位W5500
    extern void W5500_Init(void);//初始化W5500寄存器函数
    extern unsigned char Detect_Gateway(void);//检查网关服务器
    extern void Socket_Init(SOCKET s);//指定Socket(0~7)初始化
    extern unsigned char Socket_Connect(SOCKET s);//设置指定Socket(0~7)为客户端与远程服务器连接
    extern unsigned char Socket_Listen(SOCKET s);//设置指定Socket(0~7)作为服务器等待远程主机的连接
    extern unsigned char Socket_UDP(SOCKET s);//设置指定Socket(0~7)为UDP模式
    extern unsigned short Read_SOCK_Data_Buffer(SOCKET s, unsigned char *dat_ptr);//指定Socket(0~7)接收数据处理
    extern void Write_SOCK_Data_Buffer(SOCKET s, unsigned char *dat_ptr, unsigned short size); //指定Socket(0~7)发送数据处理
    extern void W5500_Interrupt_Process(void);//W5500中断处理程序框架
    void NVIC_Configuration(void);
    void RCC_Configuration(void);
    void Timer2_Init_Config(void);
    void SendData(unsigned char* data,int length);
    void My_W5500_Init(void);
    void W5500_Socket_Set(void);
    void Process_Socket_Data(SOCKET s);
    
    #endif
    
    

    W5500.c

    /**********************************************************************************
     * 文件名  :W5500.c
     * 描述    :W5500 驱动函数库         
     * 库版本  :ST_v3.5
    **********************************************************************************/
    
    #include "stm32f10x.h"
    #include "stm32f10x_spi.h"				
    #include "W5500.h"		
    #include <string.h>
    
    /***************----- 网络参数变量定义 -----***************/
    unsigned char Gateway_IP[4];//网关IP地址 
    unsigned char Sub_Mask[4];	//子网掩码 
    unsigned char Phy_Addr[6];	//物理地址(MAC) 
    unsigned char IP_Addr[4];	//本机IP地址 
    
    unsigned char S0_Port[2];	//端口0的端口号(5000) 
    unsigned char S0_DIP[4];	//端口0目的IP地址 
    unsigned char S0_DPort[2];	//端口0目的端口号(6000) 
    
    unsigned char UDP_DIPR[4];	//UDP(广播)模式,目的主机IP地址
    unsigned char UDP_DPORT[2];	//UDP(广播)模式,目的主机端口号
    
    /***************----- 端口的运行模式 -----***************/
    unsigned char S0_Mode =3;	//端口0的运行模式,0:TCP服务器模式,1:TCP客户端模式,2:UDP(广播)模式
    #define TCP_SERVER	0x00	//TCP服务器模式
    #define TCP_CLIENT	0x01	//TCP客户端模式 
    #define UDP_MODE	0x02	//UDP(广播)模式 
    
    /***************----- 端口的运行状态 -----***************/
    unsigned char S0_State =0;	//端口0状态记录,1:端口完成初始化,2端口完成连接(可以正常传输数据) 
    #define S_INIT		0x01	//端口完成初始化 
    #define S_CONN		0x02	//端口完成连接,可以正常传输数据 
    
    /***************----- 端口收发数据的状态 -----***************/
    unsigned char S0_Data;		//端口0接收和发送数据的状态,1:端口接收到数据,2:端口发送数据完成 
    #define S_RECEIVE	 0x01	//端口接收到一个数据包 
    #define S_TRANSMITOK 0x02	//端口发送一个数据包完成 
    
    /***************----- 端口数据缓冲区 -----***************/
    unsigned char Rx_Buffer[2048];	//端口接收数据缓冲区 
    unsigned char Tx_Buffer[2048];	//端口发送数据缓冲区 
    
    unsigned char W5500_Interrupt;	//W5500中断标志(0:无中断,1:有中断)
    
    unsigned int Timer2_Counter=0; //Timer2定时器计数变量(ms)
    unsigned int W5500_Send_Delay_Counter=0; //W5500发送延时计数变量(ms)
    
    /*******************************************************************************
    * 函数名  : W5500_GPIO_Configuration
    * 描述    : W5500 GPIO初始化配置
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void W5500_GPIO_Configuration(void)
    {
    	GPIO_InitTypeDef  GPIO_InitStructure;	
    
    	/* W5500_RST引脚初始化配置(PC5) */
    	GPIO_InitStructure.GPIO_Pin  = W5500_RST;
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_Init(W5500_RST_PORT, &GPIO_InitStructure);
    	GPIO_ResetBits(W5500_RST_PORT, W5500_RST);
    }
    
    /*******************************************************************************
    * 函数名  : SPI_Configuration
    * 描述    : W5500 SPI初始化配置(STM32 SPI1)
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void SPI_Configuration(void)
    {
    	GPIO_InitTypeDef 	GPIO_InitStructure;
    	SPI_InitTypeDef   	SPI_InitStructure;	   
    
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1 | RCC_APB2Periph_AFIO, ENABLE);	
    
    	/* 初始化SCK、MISO、MOSI引脚 */
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    
    	/* 初始化CS引脚 */
    	GPIO_InitStructure.GPIO_Pin = W5500_SCS;
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    	GPIO_Init(W5500_SCS_PORT, &GPIO_InitStructure);
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS);
    
    	/* 初始化配置STM32 SPI1 */
    	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;	//SPI设置为双线双向全双工
    	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;							//设置为主SPI
    	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;						//SPI发送接收8位帧结构
    	SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low;							//时钟悬空低
    	SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;							//数据捕获于第1个时钟沿
    	SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;								//NSS由外部管脚管理
    	SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;	//波特率预分频值为2
    	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;					//数据传输从MSB位开始
    	SPI_InitStructure.SPI_CRCPolynomial=7;								//CRC多项式为7
    	SPI_Init(SPI1,&SPI_InitStructure);									//根据SPI_InitStruct中指定的参数初始化外设SPI1寄存器
    
    	SPI_Cmd(SPI1,ENABLE);	//STM32使能SPI1
    }
    
    /*******************************************************************************
    * 函数名  : SPI1_Send_Byte
    * 描述    : SPI1发送1个字节数据
    * 输入    : dat:待发送的数据
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void SPI1_Send_Byte(unsigned char dat)
    {
    	SPI_I2S_SendData(SPI1,dat);//写1个字节数据
    	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//等待数据寄存器空
    }
    
    /*******************************************************************************
    * 函数名  : SPI1_Send_Short
    * 描述    : SPI1发送2个字节数据(16位)
    * 输入    : dat:待发送的16位数据
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void SPI1_Send_Short(unsigned short dat)
    {
    	SPI1_Send_Byte(dat/256);//写数据高位
    	SPI1_Send_Byte(dat);	//写数据低位
    }
    
    /*******************************************************************************
    * 函数名  : Write_W5500_1Byte
    * 描述    : 通过SPI1向指定地址寄存器写1个字节数据
    * 输入    : reg:16位寄存器地址,dat:待写入的数据
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void Write_W5500_1Byte(unsigned short reg, unsigned char dat)
    {
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(FDM1|RWB_WRITE|COMMON_R);//通过SPI1写控制字节,1个字节数据长度,写数据,选择通用寄存器
    	SPI1_Send_Byte(dat);//写1个字节数据
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    }
    
    /*******************************************************************************
    * 函数名  : Write_W5500_2Byte
    * 描述    : 通过SPI1向指定地址寄存器写2个字节数据
    * 输入    : reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void Write_W5500_2Byte(unsigned short reg, unsigned short dat)
    {
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    		
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(FDM2|RWB_WRITE|COMMON_R);//通过SPI1写控制字节,2个字节数据长度,写数据,选择通用寄存器
    	SPI1_Send_Short(dat);//写16位数据
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    }
    
    /*******************************************************************************
    * 函数名  : Write_W5500_nByte
    * 描述    : 通过SPI1向指定地址寄存器写n个字节数据
    * 输入    : reg:16位寄存器地址,*dat_ptr:待写入数据缓冲区指针,size:待写入的数据长度
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void Write_W5500_nByte(unsigned short reg, unsigned char *dat_ptr, unsigned short size)
    {
    	unsigned short i;
    
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平	
    		
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(VDM|RWB_WRITE|COMMON_R);//通过SPI1写控制字节,N个字节数据长度,写数据,选择通用寄存器
    
    	for(i=0;i<size;i++)//循环将缓冲区的size个字节数据写入W5500
    	{
    		SPI1_Send_Byte(*dat_ptr++);//写一个字节数据
    	}
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    }
    
    /*******************************************************************************
    * 函数名  : Write_W5500_SOCK_1Byte
    * 描述    : 通过SPI1向指定端口寄存器写1个字节数据
    * 输入    : s:端口号,reg:16位寄存器地址,dat:待写入的数据
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void Write_W5500_SOCK_1Byte(SOCKET s, unsigned short reg, unsigned char dat)
    {
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平	
    		
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(FDM1|RWB_WRITE|(s*0x20+0x08));//通过SPI1写控制字节,1个字节数据长度,写数据,选择端口s的寄存器
    	SPI1_Send_Byte(dat);//写1个字节数据
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    }
    
    /*******************************************************************************
    * 函数名  : Write_W5500_SOCK_2Byte
    * 描述    : 通过SPI1向指定端口寄存器写2个字节数据
    * 输入    : s:端口号,reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void Write_W5500_SOCK_2Byte(SOCKET s, unsigned short reg, unsigned short dat)
    {
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    			
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(FDM2|RWB_WRITE|(s*0x20+0x08));//通过SPI1写控制字节,2个字节数据长度,写数据,选择端口s的寄存器
    	SPI1_Send_Short(dat);//写16位数据
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    }
    
    /*******************************************************************************
    * 函数名  : Write_W5500_SOCK_4Byte
    * 描述    : 通过SPI1向指定端口寄存器写4个字节数据
    * 输入    : s:端口号,reg:16位寄存器地址,*dat_ptr:待写入的4个字节缓冲区指针
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void Write_W5500_SOCK_4Byte(SOCKET s, unsigned short reg, unsigned char *dat_ptr)
    {
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    			
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(FDM4|RWB_WRITE|(s*0x20+0x08));//通过SPI1写控制字节,4个字节数据长度,写数据,选择端口s的寄存器
    
    	SPI1_Send_Byte(*dat_ptr++);//写第1个字节数据
    	SPI1_Send_Byte(*dat_ptr++);//写第2个字节数据
    	SPI1_Send_Byte(*dat_ptr++);//写第3个字节数据
    	SPI1_Send_Byte(*dat_ptr++);//写第4个字节数据
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    }
    
    /*******************************************************************************
    * 函数名  : Read_W5500_1Byte
    * 描述    : 读W5500指定地址寄存器的1个字节数据
    * 输入    : reg:16位寄存器地址
    * 输出    : 无
    * 返回值  : 读取到寄存器的1个字节数据
    * 说明    : 无
    *******************************************************************************/
    unsigned char Read_W5500_1Byte(unsigned short reg)
    {
    	unsigned char i;
    
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    			
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(FDM1|RWB_READ|COMMON_R);//通过SPI1写控制字节,1个字节数据长度,读数据,选择通用寄存器
    
    	i=SPI_I2S_ReceiveData(SPI1);
    	SPI1_Send_Byte(0x00);//发送一个哑数据
    	i=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为高电平
    	return i;//返回读取到的寄存器数据
    }
    
    /*******************************************************************************
    * 函数名  : Read_W5500_SOCK_1Byte
    * 描述    : 读W5500指定端口寄存器的1个字节数据
    * 输入    : s:端口号,reg:16位寄存器地址
    * 输出    : 无
    * 返回值  : 读取到寄存器的1个字节数据
    * 说明    : 无
    *******************************************************************************/
    unsigned char Read_W5500_SOCK_1Byte(SOCKET s, unsigned short reg)
    {
    	unsigned char i;
    
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    			
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(FDM1|RWB_READ|(s*0x20+0x08));//通过SPI1写控制字节,1个字节数据长度,读数据,选择端口s的寄存器
    
    	i=SPI_I2S_ReceiveData(SPI1);
    	SPI1_Send_Byte(0x00);//发送一个哑数据
    	i=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为高电平
    	return i;//返回读取到的寄存器数据
    }
    
    /*******************************************************************************
    * 函数名  : Read_W5500_SOCK_2Byte
    * 描述    : 读W5500指定端口寄存器的2个字节数据
    * 输入    : s:端口号,reg:16位寄存器地址
    * 输出    : 无
    * 返回值  : 读取到寄存器的2个字节数据(16位)
    * 说明    : 无
    *******************************************************************************/
    unsigned short Read_W5500_SOCK_2Byte(SOCKET s, unsigned short reg)
    {
    	unsigned short i;
    
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    			
    	SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
    	SPI1_Send_Byte(FDM2|RWB_READ|(s*0x20+0x08));//通过SPI1写控制字节,2个字节数据长度,读数据,选择端口s的寄存器
    
    	i=SPI_I2S_ReceiveData(SPI1);
    	SPI1_Send_Byte(0x00);//发送一个哑数据
    	i=SPI_I2S_ReceiveData(SPI1);//读取高位数据
    	SPI1_Send_Byte(0x00);//发送一个哑数据
    	i*=256;
    	i+=SPI_I2S_ReceiveData(SPI1);//读取低位数据
    
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为高电平
    	return i;//返回读取到的寄存器数据
    }
    
    /*******************************************************************************
    * 函数名  : Read_SOCK_Data_Buffer
    * 描述    : 从W5500接收数据缓冲区中读取数据
    * 输入    : s:端口号,*dat_ptr:数据保存缓冲区指针
    * 输出    : 无
    * 返回值  : 读取到的数据长度,rx_size个字节
    * 说明    : 无
    *******************************************************************************/
    unsigned short Read_SOCK_Data_Buffer(SOCKET s, unsigned char *dat_ptr)
    {
    	unsigned short rx_size;
    	unsigned short offset, offset1;
    	unsigned short i;
    	unsigned char j;
    
    	rx_size=Read_W5500_SOCK_2Byte(s,Sn_RX_RSR);
    	if(rx_size==0) return 0;//没接收到数据则返回
    	if(rx_size>1460) rx_size=1460;
    
    	offset=Read_W5500_SOCK_2Byte(s,Sn_RX_RD);
    	offset1=offset;
    	offset&=(S_RX_SIZE-1);//计算实际的物理地址
    
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    
    	SPI1_Send_Short(offset);//写16位地址
    	SPI1_Send_Byte(VDM|RWB_READ|(s*0x20+0x18));//写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
    	j=SPI_I2S_ReceiveData(SPI1);
    	
    	if((offset+rx_size)<S_RX_SIZE)//如果最大地址未超过W5500接收缓冲区寄存器的最大地址
    	{
    		for(i=0;i<rx_size;i++)//循环读取rx_size个字节数据
    		{
    			SPI1_Send_Byte(0x00);//发送一个哑数据
    			j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
    			*dat_ptr=j;//将读取到的数据保存到数据保存缓冲区
    			dat_ptr++;//数据保存缓冲区指针地址自增1
    		}
    	}
    	else//如果最大地址超过W5500接收缓冲区寄存器的最大地址
    	{
    		offset=S_RX_SIZE-offset;
    		for(i=0;i<offset;i++)//循环读取出前offset个字节数据
    		{
    			SPI1_Send_Byte(0x00);//发送一个哑数据
    			j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
    			*dat_ptr=j;//将读取到的数据保存到数据保存缓冲区
    			dat_ptr++;//数据保存缓冲区指针地址自增1
    		}
    		GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    
    		GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    
    		SPI1_Send_Short(0x00);//写16位地址
    		SPI1_Send_Byte(VDM|RWB_READ|(s*0x20+0x18));//写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
    		j=SPI_I2S_ReceiveData(SPI1);
    
    		for(;i<rx_size;i++)//循环读取后rx_size-offset个字节数据
    		{
    			SPI1_Send_Byte(0x00);//发送一个哑数据
    			j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
    			*dat_ptr=j;//将读取到的数据保存到数据保存缓冲区
    			dat_ptr++;//数据保存缓冲区指针地址自增1
    		}
    	}
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    
    	offset1+=rx_size;//更新实际物理地址,即下次读取接收到的数据的起始地址
    	Write_W5500_SOCK_2Byte(s, Sn_RX_RD, offset1);
    	Write_W5500_SOCK_1Byte(s, Sn_CR, RECV);//发送启动接收命令
    	return rx_size;//返回接收到数据的长度
    }
    
    /*******************************************************************************
    * 函数名  : Write_SOCK_Data_Buffer
    * 描述    : 将数据写入W5500的数据发送缓冲区
    * 输入    : s:端口号,*dat_ptr:数据保存缓冲区指针,size:待写入数据的长度
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void Write_SOCK_Data_Buffer(SOCKET s, unsigned char *dat_ptr, unsigned short size)
    {
    	unsigned short offset,offset1;
    	unsigned short i;
    
    	//如果是UDP模式,可以在此设置目的主机的IP和端口号
    	if((Read_W5500_SOCK_1Byte(s,Sn_MR)&0x0f) != SOCK_UDP)//如果Socket打开失败
    	{		
    		Write_W5500_SOCK_4Byte(s, Sn_DIPR, UDP_DIPR);//设置目的主机IP  		
    		Write_W5500_SOCK_2Byte(s, Sn_DPORTR, UDP_DPORT[0]*256+UDP_DPORT[1]);//设置目的主机端口号				
    	}
    
    	offset=Read_W5500_SOCK_2Byte(s,Sn_TX_WR);
    	offset1=offset;
    	offset&=(S_TX_SIZE-1);//计算实际的物理地址
    
    	GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    
    	SPI1_Send_Short(offset);//写16位地址
    	SPI1_Send_Byte(VDM|RWB_WRITE|(s*0x20+0x10));//写控制字节,N个字节数据长度,写数据,选择端口s的寄存器
    
    	if((offset+size)<S_TX_SIZE)//如果最大地址未超过W5500发送缓冲区寄存器的最大地址
    	{
    		for(i=0;i<size;i++)//循环写入size个字节数据
    		{
    			SPI1_Send_Byte(*dat_ptr++);//写入一个字节的数据		
    		}
    	}
    	else//如果最大地址超过W5500发送缓冲区寄存器的最大地址
    	{
    		offset=S_TX_SIZE-offset;
    		for(i=0;i<offset;i++)//循环写入前offset个字节数据
    		{
    			SPI1_Send_Byte(*dat_ptr++);//写入一个字节的数据
    		}
    		GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    
    		GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    
    		SPI1_Send_Short(0x00);//写16位地址
    		SPI1_Send_Byte(VDM|RWB_WRITE|(s*0x20+0x10));//写控制字节,N个字节数据长度,写数据,选择端口s的寄存器
    
    		for(;i<size;i++)//循环写入size-offset个字节数据
    		{
    			SPI1_Send_Byte(*dat_ptr++);//写入一个字节的数据
    		}
    	}
    	GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    
    	offset1+=size;//更新实际物理地址,即下次写待发送数据到发送数据缓冲区的起始地址
    	Write_W5500_SOCK_2Byte(s, Sn_TX_WR, offset1);
    	Write_W5500_SOCK_1Byte(s, Sn_CR, SEND);//发送启动发送命令				
    }
    
    /*******************************************************************************
    * 函数名  : W5500_Hardware_Reset
    * 描述    : 硬件复位W5500
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 无
    * 说明    : W5500的复位引脚保持低电平至少500us以上,才能重围W5500
    *******************************************************************************/
    void W5500_Hardware_Reset(void)
    {
    	GPIO_ResetBits(W5500_RST_PORT, W5500_RST);//复位引脚拉低
    	Delay(50);
    	GPIO_SetBits(W5500_RST_PORT, W5500_RST);//复位引脚拉高
    	Delay(200);
    	while((Read_W5500_1Byte(PHYCFGR)&LINK)==0);//等待以太网连接完成
    }
    
    /*******************************************************************************
    * 函数名  : W5500_Init
    * 描述    : 初始化W5500寄存器函数
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 在使用W5500之前,先对W5500初始化
    *******************************************************************************/
    void W5500_Init(void)
    {
    	u8 i=0;
    
    	Write_W5500_1Byte(MR, RST);//软件复位W5500,置1有效,复位后自动清0
    	Delay(10);//延时10ms,自己定义该函数
    
    	//设置网关(Gateway)的IP地址,Gateway_IP为4字节unsigned char数组,自己定义 
    	//使用网关可以使通信突破子网的局限,通过网关可以访问到其它子网或进入Internet
    	Write_W5500_nByte(GAR, Gateway_IP, 4);
    			
    	//设置子网掩码(MASK)值,SUB_MASK为4字节unsigned char数组,自己定义
    	//子网掩码用于子网运算
    	Write_W5500_nByte(SUBR,Sub_Mask,4);		
    	
    	//设置物理地址,PHY_ADDR为6字节unsigned char数组,自己定义,用于唯一标识网络设备的物理地址值
    	//该地址值需要到IEEE申请,按照OUI的规定,前3个字节为厂商代码,后三个字节为产品序号
    	//如果自己定义物理地址,注意第一个字节必须为偶数
    	Write_W5500_nByte(SHAR,Phy_Addr,6);		
    
    	//设置本机的IP地址,IP_ADDR为4字节unsigned char数组,自己定义
    	//注意,网关IP必须与本机IP属于同一个子网,否则本机将无法找到网关
    	Write_W5500_nByte(SIPR,IP_Addr,4);		
    	
    	//设置发送缓冲区和接收缓冲区的大小,参考W5500数据手册
    	for(i=0;i<8;i++)
    	{
    		Write_W5500_SOCK_1Byte(i,Sn_RXBUF_SIZE, 0x02);//Socket Rx memory size=2k
    		Write_W5500_SOCK_1Byte(i,Sn_TXBUF_SIZE, 0x02);//Socket Tx mempry size=2k
    	}
    
    	//设置重试时间,默认为2000(200ms) 
    	//每一单位数值为100微秒,初始化时值设为2000(0x07D0),等于200毫秒
    	Write_W5500_2Byte(RTR, 0x07d0);
    
    	//设置重试次数,默认为8次 
    	//如果重发的次数超过设定值,则产生超时中断(相关的端口中断寄存器中的Sn_IR 超时位(TIMEOUT)置“1”)
    	Write_W5500_1Byte(RCR,8);
    }
    
    /*******************************************************************************
    * 函数名  : Detect_Gateway
    * 描述    : 检查网关服务器
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
    * 说明    : 无
    *******************************************************************************/
    unsigned char Detect_Gateway(void)
    {
    	unsigned char ip_adde[4];
    	ip_adde[0]=IP_Addr[0]+1;
    	ip_adde[1]=IP_Addr[1]+1;
    	ip_adde[2]=IP_Addr[2]+1;
    	ip_adde[3]=IP_Addr[3]+1;
    
    	//检查网关及获取网关的物理地址
    	Write_W5500_SOCK_4Byte(0,Sn_DIPR,ip_adde);//向目的地址寄存器写入与本机IP不同的IP值
    	Write_W5500_SOCK_1Byte(0,Sn_MR,MR_TCP);//设置socket为TCP模式
    	Write_W5500_SOCK_1Byte(0,Sn_CR,OPEN);//打开Socket	
    	Delay(5);//延时5ms 	
    	
    	if(Read_W5500_SOCK_1Byte(0,Sn_SR) != SOCK_INIT)//如果socket打开失败
    	{
    		Write_W5500_SOCK_1Byte(0,Sn_CR,CLOSE);//打开不成功,关闭Socket
    		return FALSE;//返回FALSE(0x00)
    	}
    
    	Write_W5500_SOCK_1Byte(0,Sn_CR,CONNECT);//设置Socket为Connect模式						
    
    	do
    	{
    		u8 j=0;
    		j=Read_W5500_SOCK_1Byte(0,Sn_IR);//读取Socket0中断标志寄存器
    		if(j!=0)
    		Write_W5500_SOCK_1Byte(0,Sn_IR,j);
    		Delay(5);//延时5ms 
    		if((j&IR_TIMEOUT) == IR_TIMEOUT)
    		{
    			return FALSE;	
    		}
    		else if(Read_W5500_SOCK_1Byte(0,Sn_DHAR) != 0xff)
    		{
    			Write_W5500_SOCK_1Byte(0,Sn_CR,CLOSE);//关闭Socket
    			return TRUE;							
    		}
    	}while(1);
    }
    
    /*******************************************************************************
    * 函数名  : Socket_Init
    * 描述    : 指定Socket(0~7)初始化
    * 输入    : s:待初始化的端口
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void Socket_Init(SOCKET s)
    {
    	//设置分片长度,参考W5500数据手册,该值可以不修改	
    	Write_W5500_SOCK_2Byte(0, Sn_MSSR, 1460);//最大分片字节数=1460(0x5b4)
    	//设置指定端口
    	switch(s)
    	{
    		case 0:
    			//设置端口0的端口号
    			Write_W5500_SOCK_2Byte(0, Sn_PORT, S0_Port[0]*256+S0_Port[1]);
    						
    			break;
    
    		case 1:
    			break;
    
    		case 2:
    			break;
    
    		case 3:
    			break;
    
    		case 4:
    			break;
    
    		case 5:
    			break;
    
    		case 6:
    			break;
    
    		case 7:
    			break;
    
    		default:
    			break;
    	}
    }
    
    /*******************************************************************************
    * 函数名  : Socket_Connect
    * 描述    : 设置指定Socket(0~7)为客户端与远程服务器连接
    * 输入    : s:待设定的端口
    * 输出    : 无
    * 返回值  : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
    * 说明    : 当本机Socket工作在客户端模式时,引用该程序,与远程服务器建立连接
    *			如果启动连接后出现超时中断,则与服务器连接失败,需要重新调用该程序连接
    *			该程序每调用一次,就与服务器产生一次连接
    *******************************************************************************/
    unsigned char Socket_Connect(SOCKET s)
    {
    	Write_W5500_SOCK_1Byte(s,Sn_MR,MR_TCP);//设置socket为TCP模式
    	Write_W5500_SOCK_1Byte(s,Sn_CR,OPEN);//打开Socket
    	Delay(5);//延时5ms
    	if(Read_W5500_SOCK_1Byte(s,Sn_SR)!=SOCK_INIT)//如果socket打开失败
    	{
    		Write_W5500_SOCK_1Byte(s,Sn_CR,CLOSE);//打开不成功,关闭Socket
    		return FALSE;//返回FALSE(0x00)
    	}
    	Write_W5500_SOCK_1Byte(s,Sn_CR,CONNECT);//设置Socket为Connect模式
    	return TRUE;//返回TRUE,设置成功
    }
    
    /*******************************************************************************
    * 函数名  : Socket_Listen
    * 描述    : 设置指定Socket(0~7)作为服务器等待远程主机的连接
    * 输入    : s:待设定的端口
    * 输出    : 无
    * 返回值  : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
    * 说明    : 当本机Socket工作在服务器模式时,引用该程序,等等远程主机的连接
    *			该程序只调用一次,就使W5500设置为服务器模式
    *******************************************************************************/
    unsigned char Socket_Listen(SOCKET s)
    {
    	Write_W5500_SOCK_1Byte(s,Sn_MR,MR_TCP);//设置socket为TCP模式 
    	Write_W5500_SOCK_1Byte(s,Sn_CR,OPEN);//打开Socket	
    	Delay(5);//延时5ms
    	if(Read_W5500_SOCK_1Byte(s,Sn_SR)!=SOCK_INIT)//如果socket打开失败
    	{
    		Write_W5500_SOCK_1Byte(s,Sn_CR,CLOSE);//打开不成功,关闭Socket
    		return FALSE;//返回FALSE(0x00)
    	}	
    	Write_W5500_SOCK_1Byte(s,Sn_CR,LISTEN);//设置Socket为侦听模式	
    	Delay(5);//延时5ms
    	if(Read_W5500_SOCK_1Byte(s,Sn_SR)!=SOCK_LISTEN)//如果socket设置失败
    	{
    		Write_W5500_SOCK_1Byte(s,Sn_CR,CLOSE);//设置不成功,关闭Socket
    		return FALSE;//返回FALSE(0x00)
    	}
    
    	return TRUE;
    
    	//至此完成了Socket的打开和设置侦听工作,至于远程客户端是否与它建立连接,则需要等待Socket中断,
    	//以判断Socket的连接是否成功。参考W5500数据手册的Socket中断状态
    	//在服务器侦听模式不需要设置目的IP和目的端口号
    }
    
    /*******************************************************************************
    * 函数名  : Socket_UDP
    * 描述    : 设置指定Socket(0~7)为UDP模式
    * 输入    : s:待设定的端口
    * 输出    : 无
    * 返回值  : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
    * 说明    : 如果Socket工作在UDP模式,引用该程序,在UDP模式下,Socket通信不需要建立连接
    *			该程序只调用一次,就使W5500设置为UDP模式
    *******************************************************************************/
    unsigned char Socket_UDP(SOCKET s)
    {
    	Write_W5500_SOCK_1Byte(s,Sn_MR,MR_UDP);//设置Socket为UDP模式*/
    	Write_W5500_SOCK_1Byte(s,Sn_CR,OPEN);//打开Socket*/
    	Delay(5);//延时5ms
    	if(Read_W5500_SOCK_1Byte(s,Sn_SR)!=SOCK_UDP)//如果Socket打开失败
    	{
    		Write_W5500_SOCK_1Byte(s,Sn_CR,CLOSE);//打开不成功,关闭Socket
    		return FALSE;//返回FALSE(0x00)
    	}
    	else
    		return TRUE;
    
    	//至此完成了Socket的打开和UDP模式设置,在这种模式下它不需要与远程主机建立连接
    	//因为Socket不需要建立连接,所以在发送数据前都可以设置目的主机IP和目的Socket的端口号
    	//如果目的主机IP和目的Socket的端口号是固定的,在运行过程中没有改变,那么也可以在这里设置
    }
    
    /*******************************************************************************
    * 函数名  : W5500_Interrupt_Process
    * 描述    : W5500中断处理程序框架
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 无
    *******************************************************************************/
    void W5500_Interrupt_Process(void)
    {
    	unsigned char i,j;
    
    IntDispose:
    
    	i=Read_W5500_1Byte(SIR);//读取端口中断标志寄存器	
    	if((i & S0_INT) == S0_INT)//Socket0事件处理 
    	{
    		j=Read_W5500_SOCK_1Byte(0,Sn_IR);//读取Socket0中断标志寄存器
    		Write_W5500_SOCK_1Byte(0,Sn_IR,j);
    		if(j&IR_CON)//在TCP模式下,Socket0成功连接 
    		{
    			S0_State|=S_CONN;//网络连接状态0x02,端口完成连接,可以正常传输数据
    		}
    		if(j&IR_DISCON)//在TCP模式下Socket断开连接处理
    		{
    			Write_W5500_SOCK_1Byte(0,Sn_CR,CLOSE);//关闭端口,等待重新打开连接 
    			Socket_Init(0);		//指定Socket(0~7)初始化,初始化端口0
    			S0_State=0;//网络连接状态0x00,端口连接失败
    		}
    		if(j&IR_SEND_OK)//Socket0数据发送完成,可以再次启动S_tx_process()函数发送数据 
    		{
    			S0_Data|=S_TRANSMITOK;//端口发送一个数据包完成 
    		}
    		if(j&IR_RECV)//Socket接收到数据,可以启动S_rx_process()函数 
    		{
    			S0_Data|=S_RECEIVE;//端口接收到一个数据包
    		}
    		if(j&IR_TIMEOUT)//Socket连接或数据传输超时处理 
    		{
    			Write_W5500_SOCK_1Byte(0,Sn_CR,CLOSE);// 关闭端口,等待重新打开连接 			
    			S0_State=0;//网络连接状态0x00,端口连接失败
    		}
    	}
    
    	if(Read_W5500_1Byte(SIR) != 0) 
    		goto IntDispose;
    }
    
    /*******************************************************************************
    * 函数名  : NVIC_Configuration
    * 描述    : STM32中断向量表配配置
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 设置KEY1(PC11)的中断优先组
    *******************************************************************************/
    void NVIC_Configuration(void)
    {
    	NVIC_InitTypeDef NVIC_InitStructure;						//定义NVIC初始化结构体
    
      	/* Set the Vector Table base location at 0x08000000 */
      	NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
    	
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);				//设置中断优先级组为1,优先组(可设0~4位)
    	
    	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//设置中断向量号
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//设置抢先优先级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;			//设置响应优先级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//使能NVIC
    	NVIC_Init(&NVIC_InitStructure);
    }
    
    /*******************************************************************************
    * 函数名  : RCC_Configuration
    * 描述    : 设置系统时钟为72MHZ(这个可以根据需要改)
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 无
    * 说明    : STM32F107x和STM32F105x系列MCU与STM32F103x系列MCU时钟配置有所不同
    *******************************************************************************/
    void RCC_Configuration(void)
    {
      ErrorStatus HSEStartUpStatus;               //外部高速时钟(HSE)的工作状态变量
      
      RCC_DeInit();                               //将所有与时钟相关的寄存器设置为默认值
      RCC_HSEConfig(RCC_HSE_ON);                  //启动外部高速时钟HSE 
      HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部高速时钟(HSE)稳定
    
      if(SUCCESS == HSEStartUpStatus)             //如果外部高速时钟已经稳定
      {
        /* Enable Prefetch Buffer */
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Flash设置
        /* Flash 2 wait state */
        FLASH_SetLatency(FLASH_Latency_2);
        
      
        RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB时钟等于系统时钟(1分频)/72MHZ
        RCC_PCLK2Config(RCC_HCLK_Div1);  //设置APB2时钟和HCLK时钟相等/72MHz(最大为72MHz)
        RCC_PCLK1Config(RCC_HCLK_Div2);  //设置APB1时钟是HCLK时钟的2分频/36MHz(最大为36MHz)
      
    #ifndef STM32F10X_CL                 //如果使用的不是STM32F107x或STM32F105x系列MCU,PLL以下配置  
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MHz 
    #else                                //如果使用的是STM32F107x或STM32F105x系列MCU,PLL以下配置
        /***** 配置PLLx *****/
        /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
        RCC_PREDIV2Config(RCC_PREDIV2_Div5);
        RCC_PLL2Config(RCC_PLL2Mul_8);
    
        RCC_PLL2Cmd(ENABLE); //使能PLL2 
        while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET);//等待PLL2稳定
    
        /* PLL configuration: PLLCLK = (PLL2 / 5) * 9 = 72 MHz */ 
        RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
        RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
    #endif
    
        RCC_PLLCmd(ENABLE); //使能PLL
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL稳定
    
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);          //设置系统时钟的时钟源为PLL
    
        while(RCC_GetSYSCLKSource() != 0x08);               //检查系统的时钟源是否是PLL
        RCC_ClockSecuritySystemCmd(ENABLE);                 //使能系统安全时钟 
    
    	/* Enable peripheral clocks --------------------------------------------------*/
      	/* Enable I2C1 and I2C1 clock */
     	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
      	/* Enable GPIOA GPIOB SPI1 and USART1 clocks */
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB
    					| RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD
    					| RCC_APB2Periph_AFIO, ENABLE);    
      }
    }
    
    /*******************************************************************************
    * 函数名  : Timer2_Init_Config
    * 描述    : Timer2初始化配置
    * 输入    : 无
    * 输出    : 无
    * 返回    : 无 
    * 说明    : 无
    *******************************************************************************/
    void Timer2_Init_Config(void)
    {
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);		//使能Timer2时钟
    	
    	TIM_TimeBaseStructure.TIM_Period = 9;						//设置在下一个更新事件装入活动的自动重装载寄存器周期的值(计数到10为1ms)
    	TIM_TimeBaseStructure.TIM_Prescaler = 7199;					//设置用来作为TIMx时钟频率除数的预分频值(10KHz的计数频率)
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//设置时钟分割:TDTS = TIM_CKD_DIV1
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;	//TIM向上计数模式
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);				//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    	 
    	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE ); 				//使能TIM2指定的中断
    	
    	TIM_Cmd(TIM2, ENABLE);  									//使能TIMx外设
    }
    
    /*******************************************************************************
    * 函数名  : TIM2_IRQHandler
    * 描述    : 定时器2中断断服务函数
    * 输入    : 无
    * 输出    : 无
    * 返回    : 无 
    * 说明    : 无
    *******************************************************************************/
    void TIM2_IRQHandler(void)
    {
    	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    	{
    		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    		Timer2_Counter++;
    		W5500_Send_Delay_Counter++;
    	}
    }
    
    
    
    /*******************************************************************************
    * 函数名  : Delay
    * 描述    : 延时函数(ms)
    * 输入    : d:延时系数,单位为毫秒
    * 输出    : 无
    * 返回    : 无 
    * 说明    : 延时是利用Timer2定时器产生的1毫秒的计数来实现的
    *******************************************************************************/
    void Delay(unsigned int d)
    {
    	Timer2_Counter=0; 
    	while(Timer2_Counter < d);
    }
    
    
    /*******************************************************************************
    * 函数名  : Delay
    * 描述    : 延时函数(ms)
    * 输入    : *data 数据指针
    *           length 字节数
    * 输出    : 无
    * 返回    : 无 
    *******************************************************************************/
    void SendData(unsigned char *data,int length)
    {
    	if(S0_State == (S_INIT|S_CONN))
    	{
    		S0_Data&=~S_TRANSMITOK;
    		memcpy(Tx_Buffer, data, length);
    		Write_SOCK_Data_Buffer(0, Tx_Buffer, length);
    	}
    }
    
    
    /*******************************************************************************
    * 函数名  : MyW5500_Init
    * 描述    : 集成化W5500初始函数
    * 输出    : 无
    * 返回    : 无 
    *******************************************************************************/
    void My_W5500_Init(void)
    {
    	RCC_Configuration();		//设置系统时钟为72MHZ(这个可以根据需要改)
      	NVIC_Configuration();		//STM32中断向量表配配置
    	SPI_Configuration();		//W5500 SPI初始化配置(STM32 SPI1)
    	Timer2_Init_Config();		//Timer2初始化配置
    	W5500_GPIO_Configuration();	//W5500 GPIO初始化配置
    	
    	/*Load_Net_Parameters*/
    	Gateway_IP[0] = GATEWAY_IP_0;//加载网关参数
    	Gateway_IP[1] = GATEWAY_IP_1;
    	Gateway_IP[2] = GATEWAY_IP_2;
    	Gateway_IP[3] = GATEWAY_IP_3;
    
    	Sub_Mask[0]=SUB_MASK_0;//加载子网掩码
    	Sub_Mask[1]=SUB_MASK_1;
    	Sub_Mask[2]=SUB_MASK_2;
    	Sub_Mask[3]=SUB_MASK_3;
    
    	Phy_Addr[0]=PHY_ADDR_0;//加载物理地址
    	Phy_Addr[1]=PHY_ADDR_1;
    	Phy_Addr[2]=PHY_ADDR_2;
    	Phy_Addr[3]=PHY_ADDR_3;
    	Phy_Addr[4]=PHY_ADDR_4;
    	Phy_Addr[5]=PHY_ADDR_5;
    
    	IP_Addr[0]=IP_ADDR_0;//加载本机IP地址
    	IP_Addr[1]=IP_ADDR_1;
    	IP_Addr[2]=IP_ADDR_2;
    	IP_Addr[3]=IP_ADDR_3;
    
    	S0_Port[0] = S0_PORT_0;//加载端口0的端口号5000 
    	S0_Port[1] = S0_PORT_1;
    
    
    	UDP_DIPR[0] = UDP_DIR_0;	//UDP(广播)模式,目的主机IP地址
    	UDP_DIPR[1] = UDP_DIR_1;
    	UDP_DIPR[2] = UDP_DIR_2;
    	UDP_DIPR[3] = UDP_DIR_3;
    
    	UDP_DPORT[0] = UDP_DPORT_0;	//UDP(广播)模式,目的主机端口号
    	UDP_DPORT[1] = UDP_DPORT_1;
    
    	S0_Mode=UDP_MODE;//加载端口0的工作模式,UDP模式
    	
    	W5500_Hardware_Reset();
    	W5500_Init();		//初始化W5500寄存器函数
    	Detect_Gateway();	//检查网关服务器 
    	Socket_Init(0);		//指定Socket(0~7)初始化,初始化端口0
    }
    /*******************************************************************************
    * 函数名  : W5500_Socket_Set
    * 描述    : W5500端口初始化配置
    * 输入    : 无
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 分别设置4个端口,根据端口工作模式,将端口置于TCP服务器、TCP客户端或UDP模式.
    *			从端口状态字节Socket_State可以判断端口的工作情况
    *******************************************************************************/
    void W5500_Socket_Set(void)
    {
    	if(S0_State==0)//端口0初始化配置
    	{
    		if(S0_Mode==TCP_SERVER)//TCP服务器模式 
    		{
    			if(Socket_Listen(0)==TRUE)
    				S0_State=S_INIT;
    			else
    				S0_State=0;
    		}
    		else if(S0_Mode==TCP_CLIENT)//TCP客户端模式 
    		{
    			if(Socket_Connect(0)==TRUE)
    				S0_State=S_INIT;
    			else
    				S0_State=0;
    		}
    		else//UDP模式 
    		{
    			if(Socket_UDP(0)==TRUE)
    				S0_State=S_INIT|S_CONN;
    			else
    				S0_State=0;
    		}
    	}
    }
    
    /*******************************************************************************
    * 函数名  : Process_Socket_Data
    * 描述    : W5500接收并发送接收到的数据
    * 输入    : s:端口号
    * 输出    : 无
    * 返回值  : 无
    * 说明    : 本过程先调用S_rx_process()从W5500的端口接收数据缓冲区读取数据,
    *			然后将读取的数据从Rx_Buffer拷贝到Temp_Buffer缓冲区进行处理。
    *			处理完毕,将数据从Temp_Buffer拷贝到Tx_Buffer缓冲区。调用S_tx_process()
    *			发送数据。
    *******************************************************************************/
    void Process_Socket_Data(SOCKET s)
    {
    	unsigned short size;
    	size=Read_SOCK_Data_Buffer(s, Rx_Buffer);
    	memcpy(Tx_Buffer, Rx_Buffer+8, size-8);			
    	Write_SOCK_Data_Buffer(s, Tx_Buffer, size);
    }
    
    

    使用方法

    W5500_Socket_Set();                  //W5500端口初始化
    W5500_Interrupt_Process();        //W5500中断处理程序框架
    if((S0_Data & S_RECEIVE) == S_RECEIVE)     //如果Socket0接收到数据
    {					
        S0_Data&=~S_RECEIVE;
        Read_SOCK_Data_Buffer(0, Rx_Buffer); //读取数据,返回值为数据长度
    }
    

    注意Rx_Buffer[0]~Rx_Buffer[7]为地址头(具体可参照UDP协议),真正的数据从Rx_Buffer[8]开始

    如果你对本博客有任何的疑问或者建议,欢迎联系作者:QQ944273070
  • 相关阅读:
    MySql 应用语句
    MySql 存储过程 退出
    MySql 存储过程 光标只循环一次
    MySql获取两个日期间的时间差
    VM VirtualBox 全屏模式 && 自动缩放模式 相互切换
    区分不同操作系统、编译器不同版本的宏
    debian下配置网络 安装无线网卡驱动 Broadcom BCMXX系列
    YII 主题设置
    Unix线程概念、控制原语、属性
    远程IPC种植木马
  • 原文地址:https://www.cnblogs.com/velscode/p/10105475.html
Copyright © 2020-2023  润新知