W5500

关于使用W5500的介绍

一.关于5500的介绍及使用

相关资料连接: w5500数据手册.

注意
  1. MCU与W5500通讯使用 SPI协议
  2. W5500发送函数int32_t send(uint8_t sn, uint8_t * buf, uint16_t len);
  3. W5500接收数据函int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len);
  4. 本案例用的是STM32H743,同时是使用HAL库进行相关配置。

二.数据手册分析

W5500
上图是接线方式,该芯片内部已经有TCP/IP协议,不需要使用者去移植lwpi,只需要确保SPI通讯没问题即可。

三.代码分析

模块一:
使能初始化SPI

SPI_HandleTypeDef SPI4_Handler;     //SPI4句柄

void SPI4Init()
{
  SPI4_Handler.Instance=SPI4;                      //SP4
  SPI4_Handler.Init.Mode=SPI_MODE_MASTER;          //设置SPI工作模式,设置为主模式
  SPI4_Handler.Init.Direction=SPI_DIRECTION_2LINES;//设置SPI单向或者双向的数据模式:SPI设置为双线模式
  SPI4_Handler.Init.DataSize=SPI_DATASIZE_8BIT;    //设置SPI的数据大小:SPI发送接收8位帧结构
  SPI4_Handler.Init.CLKPolarity=SPI_POLARITY_HIGH; //串行同步时钟的空闲状态为高电平
  SPI4_Handler.Init.CLKPhase=SPI_PHASE_2EDGE;      //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
  SPI4_Handler.Init.NSS=SPI_NSS_SOFT;              //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
  SPI4_Handler.Init.NSSPMode=SPI_NSS_PULSE_DISABLE;//NSS信号脉冲失能
  SPI4_Handler.Init.MasterKeepIOState=SPI_MASTER_KEEP_IO_STATE_ENABLE;  //SPI主模式IO状态保持使能
	SPI4_Handler.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_4;
  SPI4_Handler.Init.FirstBit=SPI_FIRSTBIT_MSB;     //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
  SPI4_Handler.Init.TIMode=SPI_TIMODE_DISABLE;     //关闭TI模式
  SPI4_Handler.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
  SPI4_Handler.Init.CRCPolynomial=0x00;//7;               //CRC值计算的多项式
	HAL_SPI_Init( &SPI4_Handler);//初始化
	__HAL_SPI_ENABLE(&SPI4_Handler);                 //使能SPI4
}



void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
	//SPI4引脚初始化
    if(hspi->Instance==SPI4)
	{
		GPIO_InitTypeDef GPIO_Initure;
		RCC_PeriphCLKInitTypeDef SPI4ClkInit;
	
		__HAL_RCC_SPI4_CLK_ENABLE();
		__HAL_RCC_GPIOE_CLK_ENABLE();
		__HAL_RCC_GPIOI_CLK_ENABLE();
		
     //设置SPI4的时钟源 
		SPI4ClkInit.PeriphClockSelection=RCC_PERIPHCLK_SPI4;	
		SPI4ClkInit.Spi45ClockSelection=RCC_SPI45CLKSOURCE_D2PCLK1;
		if(HAL_OK != HAL_RCCEx_PeriphCLKConfig(&SPI4ClkInit))
		{
		  printf("SPI4 CLK init error!\n");
		}
		
		GPIO_Initure.Pin=GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_6;
	    GPIO_Initure.Mode=GPIO_MODE_AF_PP;              //复用推挽输出
	    GPIO_Initure.Pull=GPIO_PULLUP;                  //上拉
	    GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;   //快速    
	    GPIO_Initure.Alternate=GPIO_AF5_SPI4;           //复用为SPI4
	    HAL_GPIO_Init(GPIOE,&GPIO_Initure);             //初始化
			
		/*定义片选引脚*/
		GPIO_Initure.Pin = GPIO_PIN_4;		 
		GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;		
		GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
		HAL_GPIO_Init(GPIOE, &GPIO_Initure);
		HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_SET);

		/*定义RESET引脚*/	
		GPIO_Initure.Pin = GPIO_PIN_3; 
		GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
		GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
		HAL_GPIO_Init(GPIOE, &GPIO_Initure);
		HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
		
		/*定义INT引脚*///外部中断引脚-无效
		GPIO_Initure.Pin = GPIO_PIN_8;
		GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;	
		GPIO_Initure.Mode = GPIO_MODE_IT_RISING;
		HAL_GPIO_Init(GPIOI, &GPIO_Initure);
		HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_RESET);
	}
}



//进入临界区
void SPI4_CrisEnter()
{
   // __set_PRIMASK(1);//可用可不用
}
//退出临界区
void SPI4_CrisExit()
{
   // __set_PRIMASK(0);//可用可不用
}

//片选拉低
void SPI4_NSS_Select()
{
	HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_RESET);
}

//片选拉高
void SPI4_NSS_Deselect()
{
	HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_SET);
}

//w5500复位
void w5500_SPI_reset()
{
	HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
  	delay_ms(500);
	HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
  	delay_ms(500);
}


//从SPI总线读取1字节数据
u8 SPI4_ReadByte(void)
{	
	u8 Rxdata, TxData;
	TxData = 0xFF;
	HAL_SPI_TransmitReceive(&SPI4_Handler, &TxData, &Rxdata, 1, 1000);
	return Rxdata;
}

//写1字节数据到SPI总线
void SPI4_WriteByte(u8 TxData)
{
	u8 Rxdata;
	HAL_SPI_TransmitReceive(&SPI4_Handler, &TxData, &Rxdata, 1, 1000);
}

模块二:
注册W5500函数

//******************************外部网口注册配置初始化******************************//
void ExternalNetworkInit()
{
	uint8_t tmp;
	uint8_t memsize[2][8] = {{2, 2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2, 2}};//设置接收端和发送端的芯片内部缓冲区大小,一个有8个socket,每个socket的接收端和发送端缓存设置为2(2KB大小);
	do
	{
		SPI4Init();													  //初始化spi
		reg_wizchip_cris_cbfunc(SPI4_CrisEnter, SPI4_CrisExit);	  //注册临界区函数
		reg_wizchip_cs_cbfunc(SPI4_NSS_Select, SPI4_NSS_Deselect); //注册SPI片选信号函数
		reg_wizchip_spi_cbfunc(SPI4_ReadByte, SPI4_WriteByte);	  //注册读写函数

		w5500_SPI_reset();
		/* WIZCHIP SOCKET Buffer initialize */
		if (ctlwizchip(CW_INIT_WIZCHIP, (void *)memsize) == -1)
		{
			printf("WIZCHIP Initialized fail.\r\n");
		}
		/* PHY link status check */
		do
		{
			if (ctlwizchip(CW_GET_PHYLINK, (void *)&tmp) == -1)
			{
				printf("Unknown PHY Link stauts.\r\n");
			}
			if (tmp == PHY_LINK_OFF)
			{
				printf("PHY Link off\n");
			}
		} while (0); //tmp == PHY_LINK_OFF);

		//设置和读取网络配置
		ctlnetwork(CN_SET_NETINFO, (void *)&gWIZNETINFO2);
		ctlnetwork(CN_GET_NETINFO, (void *)&gWIZNETINFO_temp);
	}

	while (memcmp((const char *)&gWIZNETINFO2, (char *)&gWIZNETINFO_temp, sizeof(gWIZNETINFO2)) != 0);//因为可能会初始化失败,所以在初始化后重新把寄存器的配置参数读出来进行比较,判断初始化W5500是否成功!!!
	// Display Network Information
	//	ctlwizchip(1,CW_GET_ID,(void*)tmpstr);//获取芯片ID
	//	printf("\r\n=== %s NET CONF ===\r\n",(char*)tmpstr);
	//	printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",gWIZNETINFO2.mac[0],gWIZNETINFO2.mac[1],gWIZNETINFO2.mac[2],gWIZNETINFO2.mac[3],gWIZNETINFO2.mac[4],gWIZNETINFO2.mac[5]);
	//	printf("SIP: %d.%d.%d.%d\r\n", gWIZNETINFO2.ip[0],gWIZNETINFO2.ip[1],gWIZNETINFO2.ip[2],gWIZNETINFO2.ip[3]);
	//	printf("GAR: %d.%d.%d.%d\r\n", gWIZNETINFO2.gw[0],gWIZNETINFO2.gw[1],gWIZNETINFO2.gw[2],gWIZNETINFO2.gw[3]);
	//	printf("SUB: %d.%d.%d.%d\r\n", gWIZNETINFO2.sn[0],gWIZNETINFO2.sn[1],gWIZNETINFO2.sn[2],gWIZNETINFO2.sn[3]);
	//	printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO2.dns[0],gWIZNETINFO2.dns[1],gWIZNETINFO2.dns[2],gWIZNETINFO2.dns[3]);
	//printf("Port: %d\r\n",network.port);
	//printf("======================\r\n");
	
	printf("finish restart network\n");
}

模块三:
W5500轮询检测


#define SOCK_TCPS_Server             0 //通道0-7都可以用
//W5500作为服务端的轮询:
u32 local_port=8080;//设置该通道的port端口号
void do_tcp_server(void)
{	
	uint16 len=0;
	W5500_Use_Flag = 1;
	switch(getSn_SR(SOCK_TCPS_Server))		/*获取socket的状态*/
	{
		case SOCK_CLOSED:	/*socket处于关闭状态*/
		     socket(SOCK_TCPS_Server,Sn_MR_TCP,local_port,Sn_MR_ND);/*打开socket*/
		     break;     
		case SOCK_INIT:	/*socket已初始化状态*/
			 printf("处于监听状态\r\n");
			 listen(SOCK_TCPS_Server);	/*socket建立监听*/	
             break;
		case SOCK_ESTABLISHED:	/*socket处于连接建立状态*/
			 printf("处于建立连接状态\r\n");
			 if(getSn_IR(SOCK_TCPS_Server) & Sn_IR_CON)
			 {
			 	setSn_IR(SOCK_TCPS_Server, Sn_IR_CON);	/*清除接收中断标志位*/
			 }
			 len=getSn_RX_RSR(SOCK_TCPS_Server);/*定义len为已接收数据的长度*/
			 if(len>0)
			 {
				recv(SOCK_TCPS_Server,buff,len);/*接收来自Client的数据*/
				buff[len]=0x00; /*添加字符串结束符*/
				printf("%s\r\n",buff);
				send(SOCK_TCPS_Server,buff,len);	/*向Client发送数据*/
		     }
		     break;
	   case SOCK_CLOSE_WAIT:/*socket处于等待关闭状态*/
			close(SOCK_TCPS_Server);
		    break;
	}
}

#define SOCK_TCPS_Client             1 //通道0-7都可以用
//W5500作为客户端的轮询:

void do_tcp_client(void)
{	
    uint16 len=0;	
	switch(getSn_SR(SOCK_TCPS_Client))		/*获取socket的状态*/
	{
		case SOCK_CLOSED:	/*socket处于关闭状态*/
			socket(SOCK_TCPS_Client,Sn_MR_TCP,local_port++,Sn_MR_ND);
			break;
		case SOCK_INIT:		/*socket处于初始化状态*/
			connect(SOCK_TCPS_Client,serverip,serverport);   /*socket连接服务器*/ 
			//serverip为服务器的IP,serverport服务器的端口号
		    break;
	   case SOCK_ESTABLISHED:  /*socket处于连接建立状态*/
			if(getSn_IR(SOCK_TCPS_Client) & Sn_IR_CON)
			{
				setSn_IR(SOCK_TCPS_Client, Sn_IR_CON);  /*清除接收中断标志位*/
			}
			len=getSn_RX_RSR(SOCK_TCPS_Client); 	/*定义len为已接收数据的长度*/
			if(len>0)
			{
				recv(SOCK_TCPS_Client,buff,len);  /*接收来自Server的数据*/
				buff[len]=0x00;   /*添加字符串结束符*/
				printf("%s\r\n",buff);
				send(SOCK_TCPS_Client,buff,len);	/*向Server发送数据*/
			}		  
		    break;
		case SOCK_CLOSE_WAIT: 	/*socket处于等待关闭状态*/
			close(SOCK_TCPS_Client);
		    break;
	}
}


注意点:

W5500一共提供8个socket(通道),分别为0-7。
在TCP/IP模式下,每个socket工作时候只能客户端或者服务端,不能同时使用。

上一篇:ERROR 2002 (HY000): Cant connect to local MySQL server through socket的解决方法


下一篇:音视频通话的方案记录