关于使用W5500的介绍
一.关于5500的介绍及使用
相关资料连接: w5500数据手册.
注意
- MCU与W5500通讯使用 SPI协议;
- W5500发送函数int32_t send(uint8_t sn, uint8_t * buf, uint16_t len);
- W5500接收数据函int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len);
- 本案例用的是STM32H743,同时是使用HAL库进行相关配置。
二.数据手册分析
上图是接线方式,该芯片内部已经有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工作时候只能客户端或者服务端,不能同时使用。