W5500使用ioLibrary库创建TCP客户端

1、WIZnet全硬件TCP/IP协议栈

WIZnet全硬件TCP/IP协议栈,支持TCP,UDP,IPv4,ICMP,ARP,IGMP以及PPPoE协议。

以太网:支持BSD和WIZCHIP(W5500/W5300/W5200/W5100/W5100S)的SOCKET APIs驱动程序。

互联网:

DHCP客户端

DNS客户端

FTP客户端

FTP服务器

SNMP代理/陷阱

SNTP客户端

TFTP客户端

HTTP服务器

MQTT客户端

其他功能将陆续添加。

ioLibrary库下载地址: https://gitcode.com/gh_mirrors/io/ioLibrary_Driver?utm_source=csdn_github_accelerator\&isLogin=1

案例:项目首页 - MINISTM32移植W5500ioLiberary:MINISTM32 移植W5500 ioLiberary项目为开发者提供了在MINISTM32平台上移植W5500网络芯片的完整解决方案。该项目包含移植所需的库文件和示例代码,帮助开发者快速上手并实现网络通信功能。通过详细的移植说明和步骤,开发者可以轻松完成配置和调试,节省开发时间。无论是初学者还是有经验的工程师,都可以利用该项目在STM32F103RCT6平台上高效集成W5500,实现稳定的网络连接。项目资源丰富,文档清晰,是嵌入式网络开发的理想选择。 - GitCode

internet文件夹

W5500文件夹

2、W5500芯片

W5500是一款全硬件TCP/IP以太网控制器。W5500集成了TCP/IP协议栈,10/100M以太网数据链路

层(MAC)及物理层(PHY),使得用户使用单芯片就能够在他们的应用中拓展网络连接。

支持8个独立端口(Socket)同时通讯,每一个 Socket 的发送 缓存区都在一个 16KB 的物理发送内存中,初始化分配为 2KB。每一个 Socket 的接收缓 存区都在一个 16KB 的物理接收内存中,初始化分配为 2KB。

W5500提供了SPI接口,最大支持80MHz速率,W5500支持SPI模式0和模式3。

3、配置使能W5500驱动

添加wizchip_conf.c,w5500.c和socket.c到工程中。打开wizchip_conf.H,找到_WIZCHIP_宏定义,修改如下:

#ifndef WIZCHIP

// NOTE_LIHAN: Some sections of this code are not yet fully defined.

#define WIZCHIP W5500 // W5100, W5100S, W5200, W5300, W5500, 6300

//将_WIZCHIP_宏设置为W5500,2025年5月15日修改
#endif

4、添加SPI1驱动程序

//函数功能:
//初始化SPI1_SCL为PA5,SPI1_MISO为PA6,SPI1_MOSI为PA7,SPI1_CS为PA3;
//设置SPI1的工作模式
void W5500_SPI_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA的外设时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //使能SPI1的外设时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //选择PIN5,是SPI1的SCL

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //选择引脚为复用推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHz

GPIO_Init(GPIOA, &GPIO_InitStructure); //根据GPIO_InitStructure结构指针所指向的参数配置PA5引脚

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //选择PIN6,是SPI1的MISO

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //选择引脚为输入悬浮

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHz

GPIO_Init(GPIOA, &GPIO_InitStructure); //根据GPIO_InitStructure结构指针所指向的参数配置PA6引脚

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //选择PIN7,是SPI1的MOSI

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //选择引脚为复用推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHz

GPIO_Init(GPIOA, &GPIO_InitStructure); //根据GPIO_InitStructure结构指针所指向的参数配置PA7引脚

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //选择PIN3,是W5500的片选脚CS

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择引脚为推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHz

GPIO_Init(GPIOA, &GPIO_InitStructure); //根据GPIO_InitStructure结构指针所指向的参数配置PA3引脚

//设置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; //设置SCK空闲时钟为低电平

SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第1个时钟沿

//SCK空闲时钟为低电平,数据捕获于第1个时钟沿,这样就设置了SPI从机在下降沿采集数据了

//SPI从机在下降沿采集数据,这要求CPU必须在SCK上升沿输出位值,在SCK为高电平时达到稳定,为数据采集做好准备

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //设置NSS输出由SSI位控制

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;

//设置波特率预分频值为2

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //设置数据传输先从MSB位开始

SPI_InitStructure.SPI_CRCPolynomial = 7; //使用CRC7校验

SPI_Init(SPI1, &SPI_InitStructure);

SPI_Cmd(SPI1, ENABLE); //使能SPI外设

}

#define W5500_CS_high() GPIO_SetBits(GPIOA,GPIO_Pin_4) //W5500片选引脚
#define W5500_CS_low() GPIO_ResetBits(GPIOA,GPIO_Pin_4) //W5500片选引脚

//函数功能:选择W5500
void SPI_CS_Select(void)

{

W5500_CS_low();

}

//函数功能:不选择W5500
void SPI_CS_Deselect(void)

{

W5500_CS_high();

}

//函数功能:从W5500读取一个字节

uint8_t SPI_ReadByte(void)

{

uint8_t byte;

byte=SPI_I2S_ReceiveData(SPI1);//虚读一次

SPI_I2S_SendData(SPI1,0x00);//通过外设SPI1发送0x00为的是发送8个移位时钟

while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

//检查SPI1标志位,是否设置"发送缓存空标志位",等待数据寄存器空

byte=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据

return byte;

}

//函数功能:将byte发送给W5500
void SPI_WriteByte(uint8_t byte)

{

SPI_I2S_SendData(SPI1,byte);//通过外设SPI1发送一个数据

while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

//检查SPI1标志位,是否设置"发送缓存空标志位",等待数据寄存器空

}

//函数功能:关闭总中断
void SPI_CrisEnter(void)

{

__set_PRIMASK(1);//关闭总中断

}

//函数功能:使能总中断
void SPI_CrisExit(void)

{

__set_PRIMASK(0);//开放总中断

}

5、TCP客户端应用程序W5500_HD_Driver.c

复制代码
#include "W5500_HD_Driver.h"		
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "socket.h"	// Just include one header for WIZCHIP
#include "SPI1.h"

//下载地址: https://gitcode.com/gh_mirrors/io/ioLibrary_Driver?utm_source=csdn_github_accelerator&isLogin=1
//W5500的网络参数
//本地物理地址:00 08 DC 11 11 11
//本地IP地址:192.168.1.199
//本地子网掩码:	255.255.255.0
//本地网关:192.168.1.1
//DNS服务器IP地址:8.8.8.8
//通过手动配置静态IP地址,Static IP configuration by manually.
wiz_NetInfo gWIZNETINFO = { {0x00, 0x08, 0xdc,0x11, 0x11, 0x11},
                            {192, 168, 1, 199},
                            {255,255,255,0},
                            {192, 168, 1, 1},
                            {8,8,8,8},
                            NETINFO_STATIC };

//端口0的网络参数
uint16_t LocalPort0=5000;	               //端口0的本地端口号(5000)
uint8_t  DstIP_Port0[4]={192,168,1,190}; //端口0的远程IP地址:192.168.1.190
uint16_t DstPort_Port0=6000;             //端口0的远程端口号:6000

uint8_t gDATABUF[DATA_BUF_SIZE];//STM32接收/发送W5500的数据缓冲区

void W5500_Initialization(void);

//函数功能:装载W5500的本地网络参数和端口0的网络参数
void W5500_Load_Net_Parameters(void)
{
//本地物理地址:00 08 DC 11 11 11
	gWIZNETINFO.mac[0]=0x00;
	gWIZNETINFO.mac[1]=0x08;
	gWIZNETINFO.mac[2]=0xdc;
	gWIZNETINFO.mac[3]=0x11;
	gWIZNETINFO.mac[4]=0x11;
	gWIZNETINFO.mac[5]=0x11;

//本地IP地址:192.168.1.199
	gWIZNETINFO.ip[0]=192;
	gWIZNETINFO.ip[1]=168;
	gWIZNETINFO.ip[2]=1;
	gWIZNETINFO.ip[3]=199;

//本地子网掩码:	255.255.255.0
	gWIZNETINFO.sn[0]=255;
	gWIZNETINFO.sn[1]=255;
	gWIZNETINFO.sn[2]=255;
	gWIZNETINFO.sn[3]=0;

//本地网关:192.168.1.1
  gWIZNETINFO.gw[0]=192;
	gWIZNETINFO.gw[1]=168;
	gWIZNETINFO.gw[2]=1;
	gWIZNETINFO.gw[3]=1;

//DNS服务器IP地址:8.8.8.8
  gWIZNETINFO.dns[0]=8;
	gWIZNETINFO.dns[1]=8;
	gWIZNETINFO.dns[2]=8;
	gWIZNETINFO.dns[3]=8;

//DHCP模式
  gWIZNETINFO.dhcp=NETINFO_STATIC;
	//告诉ioLibrary库,当前使用"静态IP地址"配置
	//通过手动配置静态IP地址,Static IP configuration by manually.

//端口0的本地端口号
	LocalPort0=5000;

//端口0的远程IP地址:192.168.1.190
  DstIP_Port0[0]=192;
	DstIP_Port0[1]=168;
	DstIP_Port0[2]=1;
	DstIP_Port0[3]=190;

//端口0的远程端口号
  DstPort_Port0=6000;
}

/**
  * @brief  Intialize the network information to be used in WIZCHIP
  * @retval None
  */
//函数功能:设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
void network_init(void)
{
  uint8_t tmpstr[6];
	ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);
	//设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
	//设置MAC地址,将gWIZNETINFO.mac写入W5500;
	//设置网关,将gWIZNETINFO.gw写入W5500;
	//设置子网掩码,将gWIZNETINFO.sn写入W5500
	//设置本地IP地址,将gWIZNETINFO.ip写入W5500
	//将gWIZNETINFO.dns[]拷贝到_DNS_[]中
	//将gWIZNETINFO.dhcp保存到_DHCP_中

	ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
	//读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
	//读MAC地址,保存到gWIZNETINFO.mac
	//读网关,保存到gWIZNETINFO.gw
	//读子网掩码,保存到gWIZNETINFO.sn
	//读本地IP地址,保存到gWIZNETINFO.ip
	//将_DNS_[]拷贝到gWIZNETINFO.dns[]中
	//将_DHCP_保存到gWIZNETINFO.dhcp中

	ctlwizchip(CW_GET_ID,(void*)tmpstr);
	//读W5500的ID,保存到tmpstr[6]中,"W5500\0",这是ioLibrary驱动定义的ID;
	//在wizchip_conf.h中定义_WIZCHIP_ID_为"W5500\0"

	printf("\r\n=== %s NET CONF ===\r\n",(char*)tmpstr);
	//串口输出W5500的ID

	printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],
	gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);//串口输出W5500的MAC地址

	printf("SIP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
	//串口输出W5500的IP地址

	printf("GAR: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0],gWIZNETINFO.gw[1],gWIZNETINFO.gw[2],gWIZNETINFO.gw[3]);
	//串口输出W5500的网关地址

	printf("SUB: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0],gWIZNETINFO.sn[1],gWIZNETINFO.sn[2],gWIZNETINFO.sn[3]);
	//串口输出W5500的子网掩码

	printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
	//串口输出W5500的DNS服务器IP地址
	printf("======================\r\n");
}

//函数功能:
//1.初始化SPI接口
//2.注册相关函数
//3.设置W5500每个端口的发送缓冲区和接收缓冲区的大小均为2K字节
//4.等待"以太网"连接完成
//5.装载本地网络参数
//6.设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
void W5500_Initialization(void)
{
	uint8_t memsize[2][8] = {{2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};
	//W5500发送和接收各有8个端口,这里定义每个端口的发送缓冲区和接收缓冲区的大小均为2K字节
	uint8_t tmp;

	W5500_SPI_Init();   //W5500 SPI初始化配置

	reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);	//注册临界区函数
	reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);//注册SPI片选信号函数
	reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);	//注册读写函数

	if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1)
	{//W5500发送和接收各有8个端口,这里初始化每个端口的发送缓冲区和接收缓冲区的大小均为2K字节
		 printf("WIZCHIP Initialized fail.\r\n");
	}

	//等待"以太网"连接完成, PHY link status check
	do{
		 if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1)
		 {//读PHYCFGR寄存器bit0,若为1,则表示网络已经连接
				printf("Unknown PHY Link stauts.\r\n");
		 }
	}while(tmp == PHY_LINK_OFF);

	W5500_Load_Net_Parameters();//装载W5500的本地网络参数和端口0的网络参数
	network_init();//设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
}

//函数功能:端口0发送"I am W5500\r\n"
void SOCKET0_Send_Data(void)
{
	char buf[20];
	uint16_t len=0;

	memset(gDATABUF,'\0',sizeof(gDATABUF));
	strcpy(buf,"I am W5500\r\n");strcat((char*)gDATABUF,buf);
	len=strlen( (char*)gDATABUF );
	send(SOCK_TCPS,gDATABUF,len);//发送数据
}

void SOCKET0_Work(void)
{
	uint16_t len=0;

	switch(getSn_SR(SOCK_TCPS))//获取W5500端口0的状态寄存器
	{
		case SOCK_INIT://W5500端口0已经初始化
			connect(SOCK_TCPS,DstIP_Port0,DstPort_Port0);
		  //将W5500端口0连接到远程IP地址DstIP_Port0和远程端口DstPort_Port0上
		  break;

		case SOCK_ESTABLISHED://W5500端口0已经连接成功
			if(getSn_IR(SOCK_TCPS) & Sn_IR_CON)
			{//读端口0的Sn_IR中断标志寄存器的bit0
				setSn_IR(SOCK_TCPS, Sn_IR_CON);//回写清除中断标志
			}

			len=getSn_RX_RSR(SOCK_TCPS);
			//读端口0接收缓冲区的数据长度
			if(len)
			{
				recv(SOCK_TCPS,gDATABUF,len);//读"W5500端口0"的数据,长度为len个字节,保存到gDATABUF
				printf("%s\r\n",gDATABUF);
				send(SOCK_TCPS,gDATABUF,len);//将gDATABUF的前len个字节通过"W5500端口0"发送出去
			}
            SOCKET0_Send_Data();
			break;

		case SOCK_CLOSE_WAIT://W5500端口0处于等待关闭状态
			disconnect(SOCK_TCPS);//关闭端口0的连接
		  break;

		case SOCK_CLOSED://W5500端口0处于关闭状态
			socket(SOCK_TCPS,Sn_MR_TCP,LocalPort0,0x00);//打开Socket0,打开一个本地端口
		  break;
	}
}

6、TCP客户端应用程序W5500_HD_Driver.h头文件

复制代码
#ifndef	_W5500_HD_Driver_H_
#define	_W5500_HD_Driver_H_

#include "stm32f10x.h"//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#include "wizchip_conf.h"

extern wiz_NetInfo gWIZNETINFO;//W5500的网络参数

#define SOCK_TCPS        0     //端口0
extern uint16_t LocalPort0;	   //端口0的端口号
extern uint8_t DstIP_Port0[4]; //端口0的远程IP地址
extern uint16_t	DstPort_Port0; //端口0的远程端口号

#define DATA_BUF_SIZE   2048
extern uint8_t gDATABUF[DATA_BUF_SIZE];

#define	W5500_CS_high()   GPIO_SetBits(GPIOA,GPIO_Pin_4)   //W5500片选引脚
#define	W5500_CS_low()    GPIO_ResetBits(GPIOA,GPIO_Pin_4) //W5500片选引脚

extern void W5500_Initialization(void);
extern void SOCKET0_Work(void);
#endif

7、main.c程序

复制代码
#include "stm32f10x.h"//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "string.h" //使能strcpy(),strlen(),memset()
#include "delay.h"
#include "USART4.h"

#include "LED.h"
#include "W5500_HD_Driver.h"

//#include "W5500_Variable.h"

const char CPU_Reset_REG[]="\r\nCPU reset!\r\n";
int main(void)
{
	
//	SCB->VTOR = 0x8000000;//中断向量表重定义

//	SystemInit();
	delay_init();//延时函数初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
	USART4_Serial_Interface_Enable(115200);
	printf("%s",CPU_Reset_REG);//调试串口输出"\r\nCPU reset!\r\n"

	W5500_Initialization();
  //1.初始化SPI接口
  //2.注册相关函数
  //3.设置W5500每个端口的发送缓冲区和接收缓冲区的大小均为2K字节
  //4.等待"以太网"连接完成
  //5.装载本地网络参数
  //6.设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP

  LED_Init();
	LED0_ON();

	while(1)
	{
		LED0=!LED0;
		delay_ms(1000);
		SOCKET0_Work();//W5500端口0工作
	}
}
相关推荐
南棱笑笑生1 小时前
20250515测试飞凌的OK3588-C的核心板在Linux R4下适配以太网RTL8211F-CG时跑iperf3的极速
linux·服务器·网络
Think Spatial 空间思维1 小时前
【HTTPS基础概念与原理】TLS握手过程详解
数据库·网络协议·https
2501_915909062 小时前
开发日常中的抓包工具经验谈:Charles 抓包工具与其它选项对比
websocket·网络协议·tcp/ip·http·网络安全·https·udp
Johny_Zhao2 小时前
Vmware workstation安装部署微软SCCM服务系统
网络·人工智能·python·sql·网络安全·信息安全·微软·云计算·shell·系统运维·sccm
会员果汁2 小时前
网络实验-VRRP
网络
XiaoCCCcCCccCcccC3 小时前
Linux 的 UDP 网络编程 -- 回显服务器,翻译服务器
linux·网络·udp
獨枭3 小时前
Visual Studio 2022 跨网络远程调试
网络·ide·visual studio
深度学习04073 小时前
【网络实验】-BGP-EBGP的基本配置
网络·智能路由器
阿斯顿法国红酒快3 小时前
Windows系统安全加固
网络·windows·安全·网络安全·系统安全·ddos
qq_401700414 小时前
电容触摸按键PCB设计
stm32