news 2026/6/25 3:08:23

SeanLib系列函数库-W5500

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SeanLib系列函数库-W5500


查看其它库函数说明,请点击此处跳转到SeanLib主页

1. 本篇内容

本篇介绍W5500函数库的用法,本库包含两个文件:W5500.h和W5500.lib,提供了W5500芯片和其Socket操作的设备结构和方法。

2. 函数库用法

本函数库依赖的外部函数进行SPI接口的数据收发、获取系统滴答计数器,需要在SeanLic.c中实现,然后可以创建W5500芯片设备指针,在该设备中再进行创建Socket通讯接口

2.1 编写外部函数

头文件中列出了需要在SeanLib.c中实现的函数,如下:

/* 外部函数声明,根据需要在SeanLib.c中实现 *************************************///数据发送函数externvoidSean_Send(void*Dev,unsignedchar*Data,unsignedshortLen);//SPI设备需要使用的发送接收函数externvoidSean_SendRecv(void*Dev,unsignedchar*Send,unsignedchar*Recv,unsignedshortLen);//获取系统滴答计数器,单位ms,裸机程序中用HAL_GetTick, 其它系统中可自定义externunsignedintSean_GetTick(void);/* 以下两个函数可选 ************************************************************///开始使用SPI接口通讯时会调用该函数,可在此函数中关中断以保护通讯过程不被打断externvoidW5500_Communication_Start(void);//SPI通讯结束时会调用该函数,可以此函数中恢复中断externvoidW5500_Communication_End(void);

打开SeanLib.c文件,找到 #ifdef USE_SENDRECV 语句的位置,编写如下代码:

/* 当某些库需要使用外部数据发送和接收函数时,需要实现下面的函数 ******************/#ifdefUSE_SENDRECV//数据发送函数//参数:// Dev: 调用该函数的设备,函数中可根据该指针判断要将数据发送到哪个通讯端口// Data: 要发送的数据指针// Len: 要发送的数据长度//返回值:无voidSean_Send(void*Dev,unsignedchar*Data,unsignedshortLen){if(Dev==EtherNet){HAL_SPI_Transmit(SPI_W5500,Data,Len,Len);}}//数据接收和发送函数,适用于SPI通讯的设备//参数:// Dev: 调用该函数的设备,可根据该指针判断要将数据发送到哪个通讯端口// Send: 要发送的数据的存放指针// Recv: 接收到的数据的存放指针// Len: 传输的数据长度//返回值: 无voidSean_SendRecv(void*Dev,unsignedchar*Send,unsignedchar*Recv,unsignedshortLen){if(Dev==EtherNet){HAL_SPI_TransmitReceive(SPI_W5500,Send,Recv,Len,Len);}}#endif

再找到 #ifdefW5500_H语句的位置,编写如下代码(可选):

/* 当使用W5500库时,根据需要实现下面的函数 ************************************/#ifdef_W5500_H_//开始使用SPI接口通讯时会调用该函数,可在此函数中关中断以保护通讯过程不被打断voidW5500_Communication_Start(void){taskENTER_CRITICAL();}//SPI通讯结束时会调用该函数,可以此函数中恢复中断voidW5500_Communication_End(void){taskEXIT_CRITICAL();}#endif

再找到 #ifdef USE_GETTICK 语句,编写如下代码:

/* 有些库会调用该函数获取系统滴答计数器,请在此处实现 *************************/#ifdefUSE_GETTICK//获取系统滴答计数器,单位ms,裸机程序中用HAL_GetTick, 其它系统中可自定义unsignedintSean_GetTick(void){returnHAL_GetTick();}#endif

外部函数编写完成,关于W5500的中断引脚及SPI的配置,本篇中不做介绍,请自行完成。

2.2 创建芯片设备指针

头文件中提供了两个结构体,和一个创建W5500芯片设备的函数,首先需要创建W5500芯片设备,这是一切通讯的基础,步骤如下:

//函数原型:/******************************************************************************* * 功 能: 创建以太网设备指针 * 参 数: * PinAddr_CS : 片选引脚的位带区地址,如 BITBAND_ADDR(GPIOD->ODR, 5) * PinAddr_RST : 复位引脚的位带区地址,如不使用,可设置为0 * 返回值:创建成功返回设备指针,否则返回空指针NULL ********************************************************************************/W5500_t*NewW5500(unsignedintPinAddr_CS,unsignedintPinAddr_RST);//定义W5500_CS和W5500_RST引脚的位带区地址:#defineW5500_CSBITBAND_ADDR(GPIOE->ODR,10)#defineW5500_RSTBITBAND_ADDR(GPIOE->ODR,15)//创建芯片设备指针W5500_t*EtherNet=NewW5500(W5500_CS,W5500_RST);//或使用如下方法直接在创建的时候传入位带区地址:W5500_t*EtherNet=NewW5500(BITBAND_ADDR(GPIOE->ODR,10),BITBAND_ADDR(GPIOE->ODR,15));//创建的过程中会进行动态内存申请,因此请务必检查返回值,确认创建成功

创建了芯片设备指针,现在可以在该指针的基础上创建Socket接口指针:

//调用 W5500_t 中提供的方法创建Socket,本例中创建一个在线下载固件的socket,作为client使用MySocket_t*Socket_IAP=EtherNet->CreatSocket();

2.3 参数配置

首先配置W5500的通用寄存器,在W5500_t的结构体中已经进行了抽象化封装,下面是结构体中支持的配置参数:

struct{unsignedWakeOnLAN:1;//是否启用网络唤醒功能unsignedUsePing:1;//是否启用ping命令unsignedPPPoE:1;//是否启用PPPoE模式unsignedFARP:1;//是否启用强制ARP模式unsignedPHY_Mode:3;//PHY工作模式unsignedCFG_Mode:1;//配置PHY工作模式的方式,设置为1时配置字生效,设置为0硬件引脚设置生效unsignedcharIMR;//中断屏蔽unsignedcharSIMR;//Socket中断屏蔽unsignedcharDeviceID;//器件ID,应为0x04,不可修改unsignedshortIntLevel;//中断延时void(*Get)(void);void(*Set)(void);}Config;struct{unsignedcharDefaultGateway[4];//默认网关unsignedcharSubnetMask[4];//子网掩码unsignedcharIP[4];//本机IPunsignedcharMAC[6];//本机MAC地址void(*Get)(void);void(*Set)(void);}Local;

主要提供了两个配置参数结构Config、Local,每个结构体中都提供了Get、Set方法,Get用于从芯片的寄存器中读出配置参数到结构体中,Set用于将结构体中配置的参数更新到芯片的寄存器。在正常使用中若要更新配置参数,建议先用Get获取最新的参数,再修改参数,然后再调用Set方法写入参数,当然,如果不调用Get方法,直接更新全部参数再调用Set,也是可以的。
参数配置步骤示例如下:

EtherNet->Config.WakeOnLAN=0;EtherNet->Config.UsePing=1;EtherNet->Config.PPPoE=0;EtherNet->Config.FARP=0;EtherNet->Config.PHY_Mode=0x07;EtherNet->Config.CFG_Mode=1;EtherNet->Config.IMR=0xFF;EtherNet->Config.SIMR=0xFF;EtherNet->Config.IntLevel=5;EtherNet->Config.Set();EtherNet->Local.MAC[0]=Config.MAC[0];EtherNet->Local.MAC[1]=Config.MAC[1];EtherNet->Local.MAC[2]=Config.MAC[2];EtherNet->Local.MAC[3]=Config.MAC[3];EtherNet->Local.MAC[4]=Config.MAC[4];EtherNet->Local.MAC[5]=Config.MAC[5];EtherNet->Local.Set();Socket_IAP->Config.Get();Socket_IAP->Config.Mode.Bit.Protocol=W5500_SOC_MR_PR_TCP;Socket_IAP->Config.IMR=0xFF;Socket_IAP->Config.Set();Socket_IAP->Remote.IP[0]=Config.IP_IAP[0];//设置服务器IP和PortSocket_IAP->Remote.IP[1]=Config.IP_IAP[1];Socket_IAP->Remote.IP[2]=Config.IP_IAP[2];Socket_IAP->Remote.IP[3]=Config.IP_IAP[3];Socket_IAP->Remote.Port=80;//端口固定为80Socket_IAP->Remote.Set();

到此,Socket 也创建完成了,并配置了通讯所必要的参数,后面是步骤就是连接服务器进行通讯了。
如果还有其它参数需要设置,而结构体中没有,则可以调用 W5500_t 和 Socket_t 结构体中的 Read 和 Write 方法,实现对通用寄存器组以及 Socket 寄存器组的读写操作,寄存器的地址都已在头文件中列出。

2.3 连接服务器

Socket 结构体中提供了如下函数,可以实现完整的通讯步骤:

void(*Open)(void);//函数指针,开启Socketvoid(*Listen)(void);//函数指针,服务器模式时开启侦听void(*Connect)(void);//函数指针,客户端模式时请求连接void(*DisConnect)(void);//函数指针,断开连接void(*Close)(void);//函数指针,关闭Socketvoid(*Send_MAC)(void);//函数指针,UDP时发送MAC地址void(*Send_Keep)(void);//函数指针,发送心跳包//数据发送Sean_Result_t(*Send)(unsignedchar*Data,unsignedintLen);//数据接收Sean_Result_t(*Recv)(unsignedchar*Data,unsignedshortLen);

连接服务器的完整流程如下:

Sean_Result_tIAP_Connect(void){unsignedchartimeout;xEventGroupClearBits(Events_IAP,EVENT_IAP_ALL);//先清除所有事件位Socket_IAP->Status.Get();if(Socket_IAP->Status.SR==W5500_SOC_SR_ESTABLISHED)//已经处于连接状态,直接返回{returnSean_PASS;}Socket_IAP->Close();//不处于连接状态时,先关闭,再打开timeout=10;while(1){osDelay(pdMS_TO_TICKS(10));Socket_IAP->Status.Get();if(Socket_IAP->Status.SR==W5500_SOC_SR_CLOSED){break;}if(--timeout==0){Printf_To_PC("Socket close timeout!\r\n");returnSean_FAIL;}}Socket_IAP->Open();timeout=10;while(1){osDelay(pdMS_TO_TICKS(10));Socket_IAP->Status.Get();if(Socket_IAP->Status.SR==W5500_SOC_SR_INIT){break;}if(--timeout==0){Printf_To_PC("Socket open timeout!\r\n");returnSean_FAIL;}}Socket_IAP->Connect();if(WaitForEventbits(W5500_SOC_IR_CON,3000)!=Sean_PASS)//在3秒内等待连接成功{Printf_To_PC("Socket connect timeout!\r\n");returnSean_FAIL;}Socket_IAP->Status.Get();if(Socket_IAP->Status.SR!=W5500_SOC_SR_ESTABLISHED)//确保状态正确{Printf_To_PC("Socket status is not connected!\r\n");returnSean_FAIL;}returnSean_PASS;}//连接服务器的核心流程为:Socket_IAP->Open();osDelay(pdMS_TO_TICKS(10));Socket_IAP->Connect();

2.4 通讯示例代码

与服务器连接成功后,可以直接调用Send方法发送数据:

charBuffer[1024];intLength=snprintf(Buffer,sizeof(Buffer),//生成http请求"GET %s HTTP/1.1\r\n""Host: %hhu.%hhu.%hhu.%hhu\r\n""Accept: text/plain\r\n"// 明确指定接收纯文本"Connection: close\r\n"// 请求后关闭连接"User-Agent: STM32F429/1.0\r\n"// 自定义设备标识"\r\n",// 空行标记请求头结束Path,Socket_IAP->Remote.IP[0],Socket_IAP->Remote.IP[1],Socket_IAP->Remote.IP[2],Socket_IAP->Remote.IP[3]);if(Socket_IAP->Send((unsignedchar*)Buffer,Length)!=Sean_PASS)//发送Get请求{Printf_To_PC("Send fail!\r\n");gotoErr;}

当W5500发生中断时,需要检查中断标志,进行相应的处理:

//任务被中断唤醒,开始处理W5500的中断EtherNet->Status.Get();//获取所有中断标志EtherNet->Status.ClrIR(EtherNet->Status.IR);//清除中断标志//处理4个基础中断if(EtherNet->Status.IR&W5500_REG_IR_CONFLICT){Printf_To_PC("Base IR: IP地址冲突\r\n");}if(EtherNet->Status.IR&W5500_REG_IR_UNREACH){Printf_To_PC("Base IR: 无法抵达目标\r\n");}if(EtherNet->Status.IR&W5500_REG_IR_PPPoE){Printf_To_PC("Base IR: PPPoE连接关闭\r\n");}if(EtherNet->Status.IR&W5500_REG_IR_MP){Printf_To_PC("Base IR: 网络被唤醒\r\n");}//处理Socket中断if(EtherNet->Status.SIR&(1<<Socket_IAP->Channel))//判断Socket_IAP是否有中断发生{Socket_IAP->Status.Get();//获取中断标志Socket_IAP->Status.ClrIR(Socket_IAP->Status.IR);//清除所有中断标志Socket_IAP->Recv(Buffer,Socket_IAP->Status.BytesToRead);//接收服务器应答//处理数据}

以上代码仅为参考,实际使用中需要考虑任务阻塞、任务同步、中断响应等问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 5:40:39

苹果近场磁共振无线充电技术:原理、挑战与生态影响

1. 无线充电技术演进与近场磁共振的定位无线充电这个概念&#xff0c;从最早的电动牙刷接触式充电&#xff0c;到后来的Qi标准电磁感应&#xff0c;再到今天大家讨论的磁共振&#xff0c;其实是一个不断追求“自由度”和“效率”的过程。作为一名在消费电子硬件领域摸爬滚打了十…

作者头像 李华
网站建设 2026/6/14 5:40:41

从零搭建红外遥控系统:基于555与LM567的频分制通信全解析

1. 项目概述&#xff1a;从“黑盒子”到亲手搭建红外遥控&#xff0c;这个技术听起来像是上个世纪的产物&#xff0c;但时至今日&#xff0c;它依然是我们身边最“隐形”却又最无处不在的通信方式之一。从客厅电视的遥控器&#xff0c;到空调、风扇&#xff0c;再到一些工业设备…

作者头像 李华
网站建设 2026/6/19 4:57:18

基于FM1702SL的13.56MHz RFID读卡器开发全解析:从硬件设计到软件驱动

1. 项目概述&#xff1a;从零构建一个13.56MHz RFID读卡器最近在做一个智能储物柜的项目&#xff0c;需要用到非接触式IC卡作为用户身份识别介质。市面上现成的读卡模块虽然方便&#xff0c;但要么尺寸不合适&#xff0c;要么接口不灵活&#xff0c;要么成本偏高。于是决定自己…

作者头像 李华
网站建设 2026/6/14 5:40:40

分贝(dB)完全指南:从对数原理到射频工程实战应用

1. 从“挠人”的dB说起&#xff1a;一个电子工程师的实用指南干了十几年硬件和射频&#xff0c;回头看看&#xff0c;最基础、最常用&#xff0c;但也最容易让人犯迷糊的&#xff0c;恐怕就是“分贝”&#xff08;dB&#xff09;这个单位了。新手工程师看到电路图上的“增益20d…

作者头像 李华
网站建设 2026/6/18 4:35:23

利用快马平台与codex网页版登录入口快速构建用户登录页面原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 请基于codex网页版登录入口的功能&#xff0c;生成一个用户登录页面的前端原型代码&#xff0c;要求包含以下核心功能&#xff1a;一个简洁美观的登录表单&#xff0c;包含用户名输…

作者头像 李华