
查看其它库函数说明请点击此处跳转到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(DevEtherNet){HAL_SPI_Transmit(SPI_W5500,Data,Len,Len);}}//数据接收和发送函数适用于SPI通讯的设备//参数:// Dev: 调用该函数的设备可根据该指针判断要将数据发送到哪个通讯端口// Send: 要发送的数据的存放指针// Recv: 接收到的数据的存放指针// Len: 传输的数据长度//返回值: 无voidSean_SendRecv(void*Dev,unsignedchar*Send,unsignedchar*Recv,unsignedshortLen){if(DevEtherNet){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*EtherNetNewW5500(W5500_CS,W5500_RST);//或使用如下方法直接在创建的时候传入位带区地址W5500_t*EtherNetNewW5500(BITBAND_ADDR(GPIOE-ODR,10),BITBAND_ADDR(GPIOE-ODR,15));//创建的过程中会进行动态内存申请因此请务必检查返回值确认创建成功创建了芯片设备指针现在可以在该指针的基础上创建Socket接口指针//调用 W5500_t 中提供的方法创建Socket本例中创建一个在线下载固件的socket作为client使用MySocket_t*Socket_IAPEtherNet-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.WakeOnLAN0;EtherNet-Config.UsePing1;EtherNet-Config.PPPoE0;EtherNet-Config.FARP0;EtherNet-Config.PHY_Mode0x07;EtherNet-Config.CFG_Mode1;EtherNet-Config.IMR0xFF;EtherNet-Config.SIMR0xFF;EtherNet-Config.IntLevel5;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.ProtocolW5500_SOC_MR_PR_TCP;Socket_IAP-Config.IMR0xFF;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.Port80;//端口固定为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.SRW5500_SOC_SR_ESTABLISHED)//已经处于连接状态直接返回{returnSean_PASS;}Socket_IAP-Close();//不处于连接状态时先关闭再打开timeout10;while(1){osDelay(pdMS_TO_TICKS(10));Socket_IAP-Status.Get();if(Socket_IAP-Status.SRW5500_SOC_SR_CLOSED){break;}if(--timeout0){Printf_To_PC(Socket close timeout!\r\n);returnSean_FAIL;}}Socket_IAP-Open();timeout10;while(1){osDelay(pdMS_TO_TICKS(10));Socket_IAP-Status.Get();if(Socket_IAP-Status.SRW5500_SOC_SR_INIT){break;}if(--timeout0){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];intLengthsnprintf(Buffer,sizeof(Buffer),//生成http请求GET %s HTTP/1.1\r\nHost: %hhu.%hhu.%hhu.%hhu\r\nAccept: 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.IRW5500_REG_IR_CONFLICT){Printf_To_PC(Base IR: IP地址冲突\r\n);}if(EtherNet-Status.IRW5500_REG_IR_UNREACH){Printf_To_PC(Base IR: 无法抵达目标\r\n);}if(EtherNet-Status.IRW5500_REG_IR_PPPoE){Printf_To_PC(Base IR: PPPoE连接关闭\r\n);}if(EtherNet-Status.IRW5500_REG_IR_MP){Printf_To_PC(Base IR: 网络被唤醒\r\n);}//处理Socket中断if(EtherNet-Status.SIR(1Socket_IAP-Channel))//判断Socket_IAP是否有中断发生{Socket_IAP-Status.Get();//获取中断标志Socket_IAP-Status.ClrIR(Socket_IAP-Status.IR);//清除所有中断标志Socket_IAP-Recv(Buffer,Socket_IAP-Status.BytesToRead);//接收服务器应答//处理数据}以上代码仅为参考实际使用中需要考虑任务阻塞、任务同步、中断响应等问题。