当前位置: 首页 > news >正文

测试W5500的第4步_使用ioLibrary库创建UDP客户端和服务器端

从下载网络测试工具,经常会区分UDP客户端和UDP服务器端。其实这么区分,是不正确的。它区分,是因为担心使用的人不会配置,这是它这么设计的原因。

UDP(User Datagram Protocol,用户数据报协议)是一种简单的,无连接的传输层协议,用于在网络中传输数据。它不需要建立连接,就可以发送数据。但不保证数据包能否到达、包的顺序,以及数据包的完整性。传输低延迟。一般用于VoIP(语音通话),视频会议,在线游戏。

W5500芯片最多可以创建8个UDP客户端。是因为它内部集成了8个socket通道,每个通道都可以独立进行UDP通信。这意味着W5500可以同时与8个不同的服务器进行通信,W5500的每个socket通道都可以作为一个独立的UDP客户端。如果将W5500用作服务器端,它也只能连接8个UDP客户端,这是由于其socket通道数量决定的。

如果W5500会收到IP地址[192.168.1.7]和端口[49283]发送来的数据,则将W5500的本地端口修改掉其它值,就可以了。

ioLibraryDriver下面的程序,见下图:

1、wiz_platform.c

#include "wiz_platform.h"
#include <stdio.h>
#include <stdint.h>
#include "wizchip_conf.h"
#include "wiz_interface.h"
#include "stm32f10x.h"
#include "delay.h"//函数功能:SPI1初始化
void wiz_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的SCLGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	  //选择引脚为复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA5引脚	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;         //选择PIN6,是SPI1的MISOGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	  //选择引脚为输入悬浮GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA6引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;         //选择PIN7,是SPI1的MOSIGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	  //选择引脚为复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA7引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;         //选择PIN3,是W5500的片选脚CSGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //选择引脚为推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的最高工作速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);  //根据GPIO_InitStructure结构指针所指向的参数配置PA3引脚//设置SPI1的工作模式SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;     //设置为主SPISPI_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;//设置波特率预分频值为2SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  //设置数据传输先从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;            //使用CRC7校验SPI_Init(SPI1, &SPI_InitStructure);SPI_Cmd(SPI1, ENABLE); //使能SPI外设
}//函数功能:初始化W5500的RST引脚和INT引脚
void wiz_rst_int_init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOC, ENABLE ); //使能GPIOC外设的高速时钟/* W5500_RST引脚初始化配置(PC5) */GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;	//选择PC5为W5500的RST引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_ResetBits(GPIOC, GPIO_Pin_5);RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOC, ENABLE ); //使能GPIOC外设的高速时钟/* W5500_INT引脚初始化配置(PC4) */	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	//选择PC4为W5500的INT引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOC, &GPIO_InitStructure);
}//函数功能:使能SPI片选
void wizchip_select(void)
{GPIO_ResetBits(GPIOA,GPIO_Pin_4);//输出低电平表示选择W5500
}//函数功能:不使能SPI片选
void wizchip_deselect(void)
{GPIO_SetBits(GPIOA,GPIO_Pin_4);//输出高电平表示不选择W5500
}//函数功能:通过SPI,将dat的值发送给W5500
void wizchip_write_byte(uint8_t dat)
{while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){//检查SPI1的发送完成标志是否建立}SPI_I2S_SendData(SPI1, dat);//通过SPI,将dat发送给W5500while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){//检查SPI1的接收完成标志是否建立}SPI_I2S_ReceiveData(SPI1);//读SPI接收数据寄存器
}//函数功能:通过SPI读取1个字节,并返回
uint8_t wizchip_read_byte(void)
{while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){//检查SPI1的发送完成标志是否建立}SPI_I2S_SendData(SPI1,0xffff);//发送16个移位时钟,为接收数据作准备while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){//检查SPI1的接收完成标志是否建立}return SPI_I2S_ReceiveData(SPI1);//读SPI接收数据寄存器
}//函数功能:通过SPI,将buf[]中的前len个字节发送给W5500
void wizchip_write_buff(uint8_t *buf, uint16_t len)
{uint16_t idx = 0;for (idx = 0; idx < len; idx++){wizchip_write_byte(buf[idx]);//通过SPI,将buf[idx]的值发送给W5500}
}//函数功能:通过SPI读取len个字节,保存到buf[]中
void wizchip_read_buff(uint8_t *buf, uint16_t len)
{uint16_t idx = 0;for (idx = 0; idx < len; idx++){buf[idx] = wizchip_read_byte();//通过SPI读取1个字节,保存到buf[idx]中}
}//函数功能:W5500使用RST引脚复位
void wizchip_reset(void)
{GPIO_SetBits(GPIOC, GPIO_Pin_5);//复位引脚拉高delay_ms(10);GPIO_ResetBits(GPIOC, GPIO_Pin_5);//复位引脚拉低delay_ms(10);GPIO_SetBits(GPIOC, GPIO_Pin_5);//复位引脚拉高delay_ms(10);
}//函数功能:注册SPI片选函数,单字节读写函数和多字节读写函数
//1.注册SPI片选信号函数
//2.注册SPI读写单一字节函数
//3.注册SPI读写多字节函数
void wizchip_spi_cb_reg(void)
{reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);//注册SPI片选信号函数reg_wizchip_spi_cbfunc(wizchip_read_byte, wizchip_write_byte);//注册SPI读写单一字节函数reg_wizchip_spiburst_cbfunc(wizchip_read_buff, wizchip_write_buff);//注册SPI读写多字节函数
}//函数功能:配置TIM2每毫秒中断一次
void wiz_timer_init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_TimeBaseStructure.TIM_Period = 1000 - 1;TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);TIM_ClearFlag(TIM2, TIM_FLAG_Update);TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);TIM_Cmd(TIM2, ENABLE);
}//函数功能:使能TIM2中断
void wiz_tim_irq_enable(void)
{TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}//函数功能:不使能TIM2中断
void wiz_tim_irq_disable(void)
{TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
}//函数功能:TIM2每毫秒中断一次
void TIM2_IRQHandler(void)
{static uint32_t wiz_timer_1ms_count = 0;if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){wiz_timer_1ms_count++;if (wiz_timer_1ms_count >= 1000){wiz_timer_1ms_count = 0;}TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}

 2、wiz_platform.h头文件

#ifndef __WIZ_PLATFORM_H__
#define __WIZ_PLATFORM_H__#include <stdint.h>/*** @brief   wiz spi init* @param   none* @return  none*/
void wiz_spi_init(void);/*** @brief   wiz rst and int pin init* @param   none* @return  none*/
void wiz_rst_int_init(void);/*** @brief   hardware reset wizchip* @param   none* @return  none*/
void wizchip_reset(void);/*** @brief   Register the WIZCHIP SPI callback function* @param   none* @return  none*/
void wizchip_spi_cb_reg(void);/*** @brief   wiz timer init* @param   none* @return  none*/
void wiz_timer_init(void);/*** @brief   Turn on wiz timer interrupt* @param   none* @return  none*/
void wiz_tim_irq_enable(void);/*** @brief   Turn off wiz timer interrupt* @param   none* @return  none*/
void wiz_tim_irq_disable(void);
#endif

3、wiz_interface.c

#include "wiz_interface.h"
#include "wiz_platform.h"
#include "wizchip_conf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "delay.h"
#include "W5500_Variable.h"
#include "socket.h"void wizchip_initialize(void);
void UDP_network_init(uint8_t *ethernet_buff, wiz_NetInfo *conf_info);void wizchip_version_check(void);
void print_network_information(void);
void wiz_phy_link_check(void);
void wiz_print_phy_info(void);#define W5500_VERSION 0x04
//函数功能:读取芯片版本号码,并检查是否正确
void wizchip_version_check(void)
{uint8_t error_count = 0;while (1){delay_ms(1000);if (getVERSIONR() != W5500_VERSION){//读取芯片版本号码error_count++;if (error_count > 5){printf("error, %s version is 0x%02x, but read %s version value = 0x%02x\r\n", _WIZCHIP_ID_, W5500_VERSION, _WIZCHIP_ID_, getVERSIONR());while (1);}}else{break;}}
}/*** @brief Print PHY information*/
//函数功能:
//1.读PHY配置寄存器的bit1和bit2
//2.串口输出当前网速为100M/10M
//3.串口输出当前以太网采用全双工通讯/半双工通讯
void wiz_print_phy_info(void)
{uint8_t get_phy_conf;get_phy_conf = getPHYCFGR();//读PHY配置寄存器printf("The current Mbtis speed : %dMbps\r\n", get_phy_conf & 0x02 ? 100 : 10);//PHY配置寄存器,bit1=1表示网速为100M,bit1=0表示网速为10Mprintf("The current Duplex Mode : %s\r\n", get_phy_conf & 0x04 ? "Full-Duplex" : "Half-Duplex");//PHY配置寄存器,bit2=1表示以太网采用全双工通讯,bit2=0表示以太网采用半双工通讯
}//函数功能:
//读PHY配置寄存器的bit[2:0]
//bit0=1表示W5500连接到局域网
//bit1=1表示当前网速为100M,否则为10M
//bit2=1表示当前以太网采用全双工通讯,否则为半双工通讯
void wiz_phy_link_check(void)
{uint8_t phy_link_status;do{delay_ms(1000);ctlwizchip(CW_GET_PHYLINK, (void *)&phy_link_status);//读PH配置寄存器的bit0,保存到phy_link_status中,为1表示连接到局域网if (phy_link_status == PHY_LINK_ON){//W5500连接到局域网printf("PHY link\r\n");wiz_print_phy_info();//1.读PHY配置寄存器的bit1和bit2//2.串口输出当前网速为100M/10M//3.串口输出当前以太网采用全双工通讯/半双工通讯}else{printf("PHY no link\r\n");}} while (phy_link_status == PHY_LINK_OFF);
}//1.注册SPI片选函数,单字节读写函数和多字节读写函数
//2.W5500使用RST引脚复位
//3.读取芯片版本号码,并检查是否正确
//4.读PHY配置寄存器的bit[2:0],bit0=1表示W5500连接到局域网
//bit1=1表示当前网速为100M,否则为10M
//bit2=1表示当前以太网采用全双工通讯,否则为半双工通讯
void wizchip_initialize(void)
{wizchip_spi_cb_reg();//注册SPI片选函数,单字节读写函数和多字节读写函数wizchip_reset();//W5500使用RST引脚复位wizchip_version_check();//读取芯片版本号码,并检查是否正确//Read version registerwiz_phy_link_check();//读PHY配置寄存器的bit[2:0]//bit0=1表示W5500连接到局域网//bit1=1表示当前网速为100M,否则为10M//bit2=1表示当前以太网采用全双工通讯,否则为半双工通讯
}//函数功能:读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP,然后从串口输出
void print_network_information(void)
{wiz_NetInfo net_info;wizchip_getnetinfo(&net_info);// Get chip configuration information//读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCPif (net_info.dhcp == NETINFO_DHCP){printf("====================================================================================================\r\n");printf(" %s network configuration : DHCP\r\n\r\n", _WIZCHIP_ID_);}else{printf("====================================================================================================\r\n");printf(" %s network configuration : static\r\n\r\n", _WIZCHIP_ID_);}printf(" MAC         : %02X:%02X:%02X:%02X:%02X:%02X\r\n", net_info.mac[0], net_info.mac[1], net_info.mac[2], net_info.mac[3], net_info.mac[4], net_info.mac[5]);printf(" IP          : %d.%d.%d.%d\r\n", net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3]);printf(" Subnet Mask : %d.%d.%d.%d\r\n", net_info.sn[0], net_info.sn[1], net_info.sn[2], net_info.sn[3]);printf(" Gateway     : %d.%d.%d.%d\r\n", net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3]);printf(" DNS         : %d.%d.%d.%d\r\n", net_info.dns[0], net_info.dns[1], net_info.dns[2], net_info.dns[3]);printf("====================================================================================================\r\n\r\n");
}//函数功能:设置本地网络信息
//1.使用"默认网络参数"设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP
//2.读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP,然后从串口输出
void UDP_network_init(uint8_t *ethernet_buff, wiz_NetInfo *conf_info)
{wizchip_setnetinfo(conf_info);//设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP模式print_network_information();//读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP模式,然后从串口输出
}

4、wiz_interface.h

#ifndef __WIZ_INTERFACE_H__
#define __WIZ_INTERFACE_H__#include "wizchip_conf.h"extern void wizchip_initialize(void);
extern void UDP_network_init(uint8_t *ethernet_buff, wiz_NetInfo *conf_info);
#endif

5、W5500_Variable.c

#include "W5500_Variable.h"
#include "socket.h"	// Just include one header for WIZCHIP
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "string.h" //使能strcpy(),strlen(),memset()//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地址
/* network information */
wiz_NetInfo net_info = {{0x00, 0x08, 0xdc,0x11, 0x11, 0x11},{192, 168, 1, 199},{255,255,255,0},{192, 168, 1, 1},{8,8,8,8},NETINFO_STATIC}; //静态IP,程序固化IP地址uint16_t local_port[8] = {5000,5001,5002,5003,5004,5005,5006,5007};//W5500的本地端口uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};uint8_t  dest_ip[4]={192,168,1,190}; //端口0的远程IP地址:192.168.1.190
uint16_t dest_port[8]={6000,6001,6002,6003,6004,6005,6006,6007}; 

6、W5500_Variable.h头文件

#ifndef _W5500_Variable_H
#define _W5500_Variable_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 net_info;
extern uint16_t local_port[8];//W5500的本地端口#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
extern uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE];extern uint8_t  dest_ip[4]; //端口0的远程IP地址:192.168.1.190
extern uint16_t dest_port[8];#endif

7、TestUDPClient.c

#include "TestUDPClient.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "w5500.h"
#include "W5500_Variable.h"
#include "socket.h"
#include <string.h>void Send_UDP_Message(uint8_t sn);
int32_t loop_TestUDPClient(uint8_t sn, uint8_t* buf, uint8_t* destip, uint16_t destport);//在计算机的UDP服务器打开后,会看到这个信息
void Send_UDP_Message(uint8_t sn)
{int16_t len;sprintf( (char*)ethernet_buf," IP: %d.%d.%d.%d:%d connect\r\n",\net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3],local_port[sn] );len=strlen((char*)ethernet_buf);sendto(sn, ethernet_buf, len, dest_ip, dest_port[sn]);//将ethernet_buf为首地址的存储区中的前len个字节//通过端口sn发送给远程IP地址为dest_ip,并指定远程端口为dest_portprintf("%d: %s\r\n",sn,ethernet_buf);
}/*** @brief   udp client loopback test* @param   sn:         socket number* @param   buf:        Data sending and receiving cache* @param   destip:     Destination IP address* @param   destport:   Destination port* @return  value for SOCK_ERRORs,return 1:no error
*/
int32_t loop_TestUDPClient(uint8_t sn, uint8_t* buf, uint8_t* destip, uint16_t destport)
{int32_t ret;uint16_t size = 0, sentsize=0;uint8_t Sn_SR_Value;Sn_SR_Value=getSn_SR(sn);//Sn_SR_Value为0x22switch(Sn_SR_Value){case SOCK_UDP ://W5500的端口sn处于UDP模式中if((size = getSn_RX_RSR(sn)) > 0)//读端口sn的Sn_RX_RSR寄存器,获取该端口的接收缓冲区的数据长度{if(size > ETHERNET_BUF_MAX_SIZE) size = ETHERNET_BUF_MAX_SIZE;ret = recvfrom(sn, buf, size, destip, (uint16_t*)&destport);buf[ret]='\0';//添加字符串结束符printf("SOCKET%d recv form[%d.%d.%d.%d][%d]: %s\n",sn, destip[0],destip[1],destip[2],destip[3],destport,buf);if(ret <= 0){
#ifdef _LOOP_TestUDPClient_DEBUG_printf("%d: recvfrom error. %d\r\n",sn,ret);
#endifreturn ret;}size = (uint16_t) ret;sentsize = 0;while(sentsize != size)//循环发送数据{ret = sendto(sn, buf+sentsize, size-sentsize, destip, destport);//将(buf+sentsize)为首地址的存储区中的前size-sentsize个字节//通过端口sn发送给远程IP地址为destip,并指定远程端口为destportif(ret < 0){
#ifdef _LOOP_TestUDPClient_DEBUG_printf("%d: sendto error. %d\r\n",sn,ret);
#endifreturn ret;}sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.}}break;case SOCK_CLOSED://W5500端口sn处于关闭状态
#ifdef _LOOP_TestUDPClient_DEBUG_printf("%d:UDP loopback start\r\n",sn);
#endifif((ret = socket(sn, Sn_MR_UDP, local_port[sn], 0x00)) != sn)//令SOCKET端口sn工作在UDP模式,并设置UDP端口为local_portreturn ret;
#ifdef _LOOP_TestUDPClient_DEBUG_printf("%d:Opened, UDP loopback, port [%d]\r\n", sn, local_port[sn]);
#endifbreak;default :break;}return 1;}

8、TestUDPClient.h头文件

#ifndef _TestUDPClient_H
#define _TestUDPClient_H#include "stm32f10x.h"//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t#define UDP_SOCKET0        0     //W5500使用端口0作为UDP
#define UDP_SOCKET1        1     //W5500使用端口1作为UDP
#define UDP_SOCKET2        2     //W5500使用端口2作为UDP
#define UDP_SOCKET3        3     //W5500使用端口3作为UDP
#define UDP_SOCKET4        4     //W5500使用端口4作为UDP
#define UDP_SOCKET5        5     //W5500使用端口5作为UDP
#define UDP_SOCKET6        6     //W5500使用端口6作为UDP
#define UDP_SOCKET7        7     //W5500使用端口7作为UDP#define	_LOOP_TestUDPClient_DEBUG_  //允许串口跟踪extern void Send_UDP_Message(uint8_t sn);
extern int32_t loop_TestUDPClient(uint8_t sn, uint8_t* buf, uint8_t* destip, uint16_t destport);#endif

 9、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 "socket.h"/*
从下载网络测试工具,经常会区分UDP客户端和UDP服务器端。其实这么区分,是不正确的。
UDP(User Datagram Protocol,用户数据报协议)是一种简单的,无连接的传输层协议,用于
在网络中传输数据。它不需要建立连接,就可以发送数据。但不保证数据包能否到达、包的
顺序,以及数据包的完整性。传输低延迟。一般用于VoIP(语音通话),视频会议,在线游戏。W5500芯片最多可以创建8个UDP客户端。是因为它内部集成了8个socket通道,每个通道都可
以独立进行UDP通信。这意味着W5500可以同时与8个不同的服务器进行通信,W5500的每个
socket通道都可以作为一个独立的UDP客户端。如果将W5500的某个socket用作服务器端,它
可以连接8个UDP客户端。
*///文件下载地址:https://gitee.com/wiznet-hk/STM32F10x_W5500_Examples
//源文件下载地址:https://gitee.com/wiznet-hk
#include "wiz_platform.h"
#include "wizchip_conf.h"
#include "wiz_interface.h"
#include "W5500_Variable.h"
#include "TestUDPClient.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);//设置系统中断优先级分组4USART4_Serial_Interface_Enable(115200);printf("%s",CPU_Reset_REG);//调试串口输出"\r\nCPU reset!\r\n"LED_Init();LED0_ON();wiz_timer_init();  //配置TIM2每毫秒中断一次wiz_spi_init();    //SPI1初始化wiz_rst_int_init();//初始化W5500的RST引脚和INT引脚printf("%s network install example\r\n",_WIZCHIP_ID_);wizchip_initialize();//1.注册SPI片选函数,单字节读写函数和多字节读写函数//2.W5500使用RST引脚复位//3.读取芯片版本号码,并检查是否正确//4.读PHY配置寄存器的bit[2:0],bit0=1表示W5500连接到局域网//bit1=1表示当前网速为100M,否则为10M//bit2=1表示当前以太网采用全双工通讯,否则为半双工通讯UDP_network_init(ethernet_buf, &net_info);
//设置本地网络信息
//1.使用"默认网络参数"设置本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP模式
//2.读本地网络参数:MAC地址,GW网关,SN子网掩码,本地IP地址,DNS服务器IP地址,DHCP模式,然后从串口输出socket(UDP_SOCKET0, Sn_MR_UDP, local_port[UDP_SOCKET0], 0x00);//令SOCKET端口0工作在UDP模式,并设置UDP端口为local_portSend_UDP_Message(UDP_SOCKET0);//SOCKET端口0发送UDP数据;socket(UDP_SOCKET1, Sn_MR_UDP, local_port[UDP_SOCKET1], 0x00);//令SOCKET端口1工作在UDP模式,并设置UDP端口为local_portSend_UDP_Message(UDP_SOCKET1);//SOCKET端口1发送UDP数据;socket(UDP_SOCKET2, Sn_MR_UDP, local_port[UDP_SOCKET2], 0x00);//令SOCKET端口1工作在UDP模式,并设置UDP端口为local_portSend_UDP_Message(UDP_SOCKET2);//SOCKET端口2发送UDP数据;socket(UDP_SOCKET3, Sn_MR_UDP, local_port[UDP_SOCKET3], 0x00);//令SOCKET端口1工作在UDP模式,并设置UDP端口为local_portSend_UDP_Message(UDP_SOCKET3);//SOCKET端口3发送UDP数据;socket(UDP_SOCKET4, Sn_MR_UDP, local_port[UDP_SOCKET4], 0x00);//令SOCKET端口0工作在UDP模式,并设置UDP端口为local_portSend_UDP_Message(UDP_SOCKET4);//SOCKET端口4发送UDP数据;socket(UDP_SOCKET5, Sn_MR_UDP, local_port[UDP_SOCKET5], 0x00);//令SOCKET端口1工作在UDP模式,并设置UDP端口为local_portSend_UDP_Message(UDP_SOCKET5);//SOCKET端口5发送UDP数据;socket(UDP_SOCKET6, Sn_MR_UDP, local_port[UDP_SOCKET6], 0x00);//令SOCKET端口1工作在UDP模式,并设置UDP端口为local_portSend_UDP_Message(UDP_SOCKET6);//SOCKET端口6发送UDP数据;socket(UDP_SOCKET7, Sn_MR_UDP, local_port[UDP_SOCKET7], 0x00);//令SOCKET端口1工作在UDP模式,并设置UDP端口为local_portSend_UDP_Message(UDP_SOCKET7);//SOCKET端口7发送UDP数据;while(1){loop_TestUDPClient(UDP_SOCKET0, ethernet_buf, dest_ip,dest_port[UDP_SOCKET0]);loop_TestUDPClient(UDP_SOCKET1, ethernet_buf, dest_ip,dest_port[UDP_SOCKET1]);loop_TestUDPClient(UDP_SOCKET2, ethernet_buf, dest_ip,dest_port[UDP_SOCKET2]);loop_TestUDPClient(UDP_SOCKET3, ethernet_buf, dest_ip,dest_port[UDP_SOCKET3]);loop_TestUDPClient(UDP_SOCKET4, ethernet_buf, dest_ip,dest_port[UDP_SOCKET4]);loop_TestUDPClient(UDP_SOCKET5, ethernet_buf, dest_ip,dest_port[UDP_SOCKET5]);loop_TestUDPClient(UDP_SOCKET6, ethernet_buf, dest_ip,dest_port[UDP_SOCKET6]);loop_TestUDPClient(UDP_SOCKET7, ethernet_buf, dest_ip,dest_port[UDP_SOCKET7]);LED0=!LED0;delay_ms(1000);}
}

10、W5500作为UDP客户端,串口跟踪结果

 11、W5500作为UDP客户端,网络调试助手用作UDP服务器

服务器端口为6000

服务器端口为6001 

服务器端口为6002

 服务器端口为6003

 服务器端口为6004

服务器端口为6005

服务器端口为6006

 

服务器端口为6007

 12、W5500_UDP作为服务器

 

13、当W5500配置8个SOCKET后,会发现SOCKET1端口总是收到IP地址[192.168.1.7]和端口[49283]发送来的数据。我不知道,这个IP地址和端口是怎么知道SOCKET1的端口数值是5001的,有点纳闷。

14、将W5500的端口修改为4000,4001,4002,4003,4004,4005,4006,4007,可能是网络调试助手,或是串口调试助手,他们都喜欢5001这个数值吧。

测试后,就不会有收到IP地址[192.168.1.7]和端口[49283]发送来的数据。可能是串口调试助手发送的UDP信息。

 修改后,就不会收到IP地址[192.168.1.7]和端口[49283]发送来的数据

网络调试助手作为服务器,配置时,需要发送前,要选择IP地址和端口。若忘记选择,可能导致W5500收不到数据,还以为自己的程序有问题。

 

我在测试中遇到这个问题,写出来,大家不要踩坑。 

相关文章:

测试W5500的第4步_使用ioLibrary库创建UDP客户端和服务器端

从下载网络测试工具&#xff0c;经常会区分UDP客户端和UDP服务器端。其实这么区分&#xff0c;是不正确的。它区分&#xff0c;是因为担心使用的人不会配置&#xff0c;这是它这么设计的原因。 UDP(User Datagram Protocol&#xff0c;用户数据报协议)是一种简单的,无连接的传…...

六台升降台完整的限位保护逻辑

一、限位保护的核心逻辑 以下是实现限位保护功能的关键代码&#xff0c;集成在主控制程序中&#xff1a; // // 限位保护处理 - 集成在主程序中 // FOR i : 1 TO 6 DO// 读取限位状态&#xff08;从变频器状态字获取&#xff09;Lifts[i].UpperLimit : (Lifts[i].StatusWord …...

腾讯位置服务地点搜索开发指南

概述 提供多种搜索功能&#xff1a; 指定城市/区域搜索&#xff1a;如在北京搜索景点。新增高级参数&#xff1a;支持获取车站、机场、园区等较大范围地点的子点和出入口热度&#xff0c;辅助用户选择准确目的地。周边搜索&#xff1a;如&#xff0c;搜索颐和园附近半径500米内…...

101个α因子#12

(sign(delta(volume, 1)) * (-1 * delta(close, 1)))worldquant brain平台上调整后的语法&#xff1a; (sign(ts_delta(volume, 1)) * (-1 * ts_delta(close, 1)))这个alpha因子的逻辑可以分为以下几个步骤&#xff1a; 1. 计算成交量的变化方向&#xff1a;sign(ts_delta(vol…...

opencv_version_win32

很多人发了opencv的编译方法&#xff0c;很少见到启动和关闭了那些模块&#xff0c;现在发个WIN64 opencv编译后的信息。 执行opencv_version_win32.exe 因为显卡较老 2060 super, NVIDIA GPU arch: 75 80 86 87 89 90。至于更高的反本没有显卡因此不知道。 BLAS库使用效率较高…...

Flask 路由装饰器:从 URL 到视图函数的优雅映射

前置知识&#xff0c;关于Python装饰器的语法&#xff0c;链接&#xff1a;Python 装饰器&#xff1a;从“语法糖”到“代码神器”的深度解析 1、路由装饰器的功能&#xff1a;给 URL 贴 “功能标签” 在 Flask 开发中&#xff0c;你一定见过这样的代码&#xff1a; from fla…...

动态规划3、悟到核心

题目引入&#xff1a; #include <iostream> #include <queue> #include <vector> #include <tuple> #include <algorithm> #include <cstring> using namespace std;// dp[i]考虑前i家店能收获的最大价值 // 面对第i家店铺&#xff0c;你可…...

VLM-MPC:自动驾驶中模型预测控制器增强视觉-语言模型

《VLM-MPC: Model Predictive Controller Augmented Vision Language Model for Autonomous Driving》2024年8月发表&#xff0c;来自威斯康星大学的论文。 受视觉语言模型&#xff08;VLM&#xff09;的紧急推理能力及其提高自动驾驶系统可理解性的潜力的启发&#xff0c;本文…...

HTTP/HTTPS 协议浅解

文章目录 一、HTTP 协议&#xff08;一&#xff09;定义&#xff08;二&#xff09;特点&#xff08;三&#xff09;应用场景&#xff08;四&#xff09;优势&#xff08;五&#xff09;劣势 二、HTTPS 协议&#xff08;一&#xff09;定义&#xff08;二&#xff09;特点&…...

Ajax快速入门教程

输入java时&#xff0c;页面并没有刷新但是下面自动联想出了跟java有关的东西&#xff0c;像这种就叫异步交互 它不会妨碍你的输入&#xff0c;同时还能够同步进行对于java相关联想词的推送 发送异步请求需要借助工具axios 引入axios&#xff0c;可以直接在scripts中引入 get和…...

如何在Java中处理PDF文档(教程)

在开发文档管理系统、自动化工具或商业应用程序时&#xff0c;Java开发者常需处理PDF文档的编辑需求。无论是添加页面、调整内容尺寸、插入水印还是添加注释&#xff0c;选择一套可靠易用的Java PDF开发工具包至关重要。 JPedal&#xff08;Java PDF开发工具包&#xff09;的新…...

springcloud集成seata报错Error creating bean with name ‘globalTransactionScanner‘

1. pom文件引入依赖 <!-- seata --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId></dependency> 2. 报错 3. 在启动配置中添加一行配置: --add-opensjava.base/j…...

使用 OpenCV 实现哈哈镜效果:让图像“扭曲起来”!

在计算机视觉和图像处理领域&#xff0c;OpenCV 提供了非常强大的图像几何变换能力&#xff0c;不仅可以用于纠正图像&#xff0c;还能制造各种“有趣”的视觉效果。今天&#xff0c;我们就来实现一个经典的“哈哈镜”效果&#xff0c;让图像像在游乐园里一样被拉伸、压缩、扭曲…...

pikachu靶场 暴力破解

学习中参考的博客如下 pikachu靶场暴力破解专题-CSDN博客 1&#xff0c;基于表单的暴力破解 出现了一个登录页面 解题步骤&#xff1a;抓包&#xff0c;发到bp里&#xff0c;右键发到Intruder&#xff0c;因为有两个位置要爆破&#xff0c;所以选择集群炸弹攻击&#xff…...

鸿蒙开发:应用上架第三篇,配置签名信息打出上架包

前言 本文基于Api13 经过前面两篇文章&#xff0c;我们获取到了密钥和证书请求文件以及最终的发布证书和发布证书Profile文件&#xff0c;可以说&#xff0c;所有的签名信息文件&#xff0c;我们都已经完成了&#xff0c;正所谓&#xff0c;万事俱备只欠东风&#xff0c;这篇文…...

基于R语言的贝叶斯网络模型实践技术应用:开启科研新视角

在现代科研领域&#xff0c;变量间的因果关系推断是生态学、环境科学、医学等多学科研究的核心问题。然而&#xff0c;传统的统计学方法往往只能揭示变量间的相关关系&#xff0c;而非因果关系。贝叶斯网络作为一种结合图论与统计学理论的新型模型&#xff0c;不仅能够统合多种…...

第五章 GPT模块配置

由于GPT配置需要和Irq和Mcu进行配合设置(GPT可以由芯片外设中的GTM和GPT12实现,这次是以GTM为实现)。 1 GTM外设时钟配置 首先需要对MCU组件进行配置,配置GTM的时钟,需要参照GTM的CMU时钟树。 下图时钟树的CLS0_CLK为MCU(McuClockSettingConfig_0中的 McuSTMFrequency )f…...

虚拟机NAT模式获取不到ip

虚拟机NAT模式获取不到ip 如图所示 解决方案&#xff1a; 先查看NetworkManager是否启动 systemctl status NetworkManager如果没启动就启动一遍 使用DHCP手动获取一遍ip sudo dhclient ens33成功得到ip 这是后遇到了另一个问题&#xff0c;ip释放后&#xff0c;不能自动…...

Docker的网络介绍

网络简单介绍 在介绍 Docker 的网络模式之前&#xff0c;先简单说下我们在使用 Vmware 虚拟机中的网络模式&#xff0c;形成对比&#xff0c;更好理解。 1、Vmware 中的网络模式 1.1、VMnet0&#xff08;桥接模式&#xff09; 虚拟机通过宿主机的物理网卡直接连接到外部网络…...

Nginx负载均衡配置详解

在Nginx中配置负载均衡主要通过 upstream 模块实现,结合反向代理将请求分发到多个后端服务器。以下是详细配置步骤和案例解析: 一、基础配置 1. 配置语法 http {upstream backend_servers {# 负载均衡策略server backend1.example.com;server backend2.example.com;server …...

关于 Web 漏洞原理与利用:4. 文件上传漏洞

定义&#xff1a;文件上传漏洞是指应用程序允许用户上传文件&#xff0c;但没有严格校验上传文件的类型、内容、路径等属性&#xff0c;导致攻击者可以上传并执行恶意代码。 绕过方式&#xff1a; 前端绕过 1. 前端限制的原理 前端限制上传文件类型的常见方式有三种&#xf…...

(6)python爬虫--selenium

文章目录 前言一、初识selenium二、安装selenium2.1 查看chrome版本并禁止chrome自动更新2.1.1 查看chrome版本2.1.2 禁止chrome更新自动更新 2.2 安装对应版本的驱动程序2.3安装selenium包 三、selenium关于浏览器的使用3.1 创建浏览器、设置、打开3.2 打开/关闭网页及浏览器3…...

MCU 上电不启动的常见原因分析与排查思路

在开发过程中&#xff0c;“MCU 上电不运行”是我们经常遇到的问题之一。但客户对此类问题的描述往往较为模糊&#xff0c;仅简单表示“产品不工作”或“怀疑 MCU 没有运行”&#xff0c;这给我们现场排查带来了较大的挑战。即便工程师到达现场&#xff0c;往往也无法迅速定位问…...

Spark Core 源码关键环节的深度解析

以下是对 Spark Core 源码关键环节的深度解析&#xff0c;包括核心组件启动与调度机制、Shuffle与调度系统、RDD高级机制。每个环节都细化到具体方法、逻辑、源码片段&#xff0c;附有流程图思路与速记口诀&#xff0c;便于记忆和理解。 一、核心组件启动与调度机制 1. RpcEnv…...

net Core》》包与库 LibMan、NPM

LibMan 资料 NPM 资料 在 Visual Studio 中使用 npm package.json 保存之后 vs会自动下载的。 注意&#xff1a;如果您没有看到 node_modules 文件夹&#xff0c;请确保在 Visual Studio 解决方案资源管理器中启用了“显示所有文件”选项 要卸载该库&#xff0c;您只需从 …...

数学建模,机器决策人建模

目录 数学建模 微分方程 动态系统建模 时间序列分析 概述 指数衰减 随机漂移 总结 曲线拟合 最优化方法 梯度下降法 概率建模&#xff08;如贝叶斯建模、马尔可夫过程、MDP/POMDP&#xff09; 等 贝叶斯建模 贝叶斯定理 优势 马尔可夫过程 马尔可夫过程的分类…...

FFmpeg中使用Android Content协议打开文件设备

引言 随着Android 10引入的Scoped Storage&#xff08;分区存储&#xff09;机制&#xff0c;传统的文件访问方式发生了重大变化。FFmpeg作为强大的多媒体处理工具&#xff0c;也在不断适应Android平台的演进。本文将介绍如何在FFmpeg 7.0版本中使用Android content协议直接访…...

SQL查询, 响应体临时字段报: Unknown column ‘data_json_map‘ in ‘field list‘

Overridepublic AjaxResult list(AgentPageReqVO pageReqVO, Integer pageNo, Integer pageSize) {// 1. 查询数据库获取代理列表List<AgentDO> list agentMapper.selectPage(pageReqVO).getList();// 如果结果为空&#xff0c;直接返回空分页结果if (CollectionUtils.i…...

OpenCv高阶(十四)——LBPH人脸识别

文章目录 前言一、LBPH原理1. LBP&#xff08;局部二值模式&#xff09;特征提取2. 图像分块处理3. 生成直方图4. 人脸识别&#xff08;匹配阶段&#xff09;5. LBPH的特点6. 变种与优化 二、LBPH人脸识别简单实现&#xff08;一&#xff09;LBPH人脸识别1、图像读取&#xff0…...

C#开发利器:SharpBoxesCore全解析

SharpBoxesCore 是一个基于 C# 的开源开发工具库&#xff0c;旨在为开发者提供一系列常用功能模块和辅助类&#xff0c;以提高开发效率、减少重复代码编写&#xff0c;并增强项目的可维护性和扩展性。该库集成了多种实用工具类和通用扩展方法&#xff0c;适用于桌面应用、Web 项…...

回表是数据库概念,还是mysql的概念?

主键索引没有列&#xff0c;根据耳机索引去查主键索引&#xff0c;又没有查表&#xff0c;为啥叫回表呢&#xff1f; “回表”这个词&#xff0c;其实算是数据库里的一个通用概念&#xff0c;不过它最常见的应用场景是在 MySQL 的 InnoDB 引擎里&#xff0c;所以很多人一提起回…...

49、c# 能⽤foreach 遍历访问的对象需满足什么条件?

在 C# 中&#xff0c;要使用 foreach 循环遍历一个对象&#xff0c;该对象必须满足以下条件之一&#xff1a; 1. 实现 IEnumerable 或 IEnumerable 接口 非泛型版本&#xff1a;System.Collections.IEnumerable public class MyCollection : IEnumerable {private int[] _da…...

DL00987-基于深度学习YOLOv11的红外鸟类目标检测含完整数据集

提升科研能力&#xff0c;精准识别红外鸟类目标&#xff01; 完整代码数据集见文末 针对科研人员&#xff0c;尤其是研究生们&#xff0c;是否在鸟类目标检测中遇到过数据不够精准、处理困难等问题&#xff1f;现在&#xff0c;我们为你提供一款基于深度学习YOLOv11的红外鸟类…...

07 接口自动化-用例管理框架之pytest单元测试框架

文章目录 一、pytest用例管理框架&#xff08;单元测试框架&#xff09;二、pytest简介三、pytest的最基本的测试用例的规则四、运行方式1.主函数方式2.命令行方式3.通过pytest.ini的配置文件运行 五、pytest 默认执行测试用例的顺序六、跳过测试用例1.无条件跳过 pytest.mark.…...

Flutter 中 build 方法为何写在 StatefulWidget 的 State 类中

Flutter 中 build 方法为何写在 StatefulWidget 的 State 类中 在 Flutter 中&#xff0c;build 方法被设计在 StatefulWidget 的 State 类中而非 StatefulWidget 类本身&#xff0c;这种设计基于几个重要的架构原则和实际考量&#xff1a; 1. 核心设计原因 1.1 生命周期管理…...

多技术栈 iOS 项目的性能调试实战:从 Flutter 到 Unity(含 KeyMob 工具实测)

多技术栈 iOS 项目的性能调试实战&#xff1a;从 Flutter 到 Unity 随着移动端开发日趋多元化&#xff0c;iOS 项目中纯 Objective-C/Swift 已不再是唯一选择。越来越多团队采用 Flutter、React Native、Unity、WebView 混合等方案构建 App。这种“技术栈混合”带来灵活性的同…...

Base64加密解密

Base64 是一种基于 64 个可打印字符来表示二进制数据的编码方式&#xff0c;常用于需要通过文本协议传输二进制数据的场景&#xff08;如 URL、邮件&#xff09;。以下是不同场景下生成 Base64 编码的方法&#xff1a; 一、编程语言实现 Python import base64# 字符串转Base…...

程序设计基础----排序(2)

1、冒泡排序 #include <stdio.h>#define N 1000 int arr[N];/* 对长度为n的数组arr执行冒泡排序 */ void bubbleSort(int arr[], int n);/* 打印长度为n的数组arr */ void printArray(int arr[], int n);void swap(int *xp, int *yp) {int temp *xp;*xp *yp;*yp temp…...

C++:vector容器

vector容器与array容器相似&#xff0c;但vector容器是动态的&#xff0c;可以自动扩容。 使用方法和一些注意如下&#xff1a; #include<iostream> #include<vector> using namespace std;int main() {vector<char> vec { a,b,c,d };vec[4] e;//不能以此…...

十四、Hive 视图 Lateral View

作者&#xff1a;IvanCodes 日期&#xff1a;2025年5月20日 专栏&#xff1a;Hive教程 在Hive中&#xff0c;我们经常需要以不同于原始表结构的方式查看或处理数据。为了简化复杂查询、提供数据抽象&#xff0c;以及处理复杂数据类型&#xff08;如数组或Map&#xff09;&#…...

Frp Dockr Mysql内网映射

用 FRP 远程暴露 Mac mini 上的 Docker-MySQL&#xff08;含 Ubuntu frps 安装和 macOS 客户端配置&#xff09; 一、环境说明 服务器&#xff08;公网&#xff09;&#xff1a;Ubuntu 22.04 frps内网设备&#xff1a;macOS (Mac mini) frpc Docker MySQL目标&#xff1a;…...

PHP 扇形的面积(Area of a Circular Sector)

圆形扇区或圆形扇区是圆盘上由两个半径和一个圆弧围成的部分&#xff0c;其中较小的区域称为小扇区&#xff0c;较大的区域称为大扇区。让我们看看这个图&#xff0c;试着找出扇区&#xff1a; 在该图中&#xff0c;绿色阴影部分是扇形&#xff0c;“r”是半径&#xff0c;“th…...

物业后勤小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的物业后勤小程序源码&#xff0c;它为物业管理提供了高效便捷的解决方案。 该源码功能丰富&#xff0c;涵盖房屋认证、家人认证&#xff0c;保障社区居住安全&#xff1b;支持报事报修、装修申请&#xff0c;方便业主与物业沟通&#xff1b;还…...

git基础操作

当远程仓库迁移到一个新的组下面时&#xff0c;你需要在本地仓库中更新远程仓库的URL&#xff0c;以便与新的远程仓库关联。以下是详细步骤&#xff1a; 获取新的远程仓库URL&#xff1a; 首先&#xff0c;你需要从GitLab或相关平台获取新组下的仓库的新URL。通常&#xff0c;仓…...

鸿蒙HarmonyOS 【ArkTS组件】通用属性-背景设置

&#x1f4d1;往期推文全新看点&#xff08;附带最新鸿蒙全栈学习笔记&#xff09; 嵌入式开发适不适合做鸿蒙南向开发&#xff1f;看完这篇你就了解了~ 鸿蒙岗位需求突增&#xff01;移动端、PC端、IoT到底该怎么选&#xff1f; 分享一场鸿蒙开发面试经验记录&#xff08;三面…...

java 在用redis 的时候,如何合理的处理分页问题? redis应当如何存储性能最佳

在 Java 中使用 Redis 处理用户表分页时&#xff0c;需结合其数据结构特性优化存储和查询 1. 数据结构设计 场景需求 用户表字段&#xff1a;id, name, age, register_time&#xff08;注册时间&#xff09;分页要求&#xff1a;按注册时间倒序分页展示&#xff0c;每页 10 条…...

分类预测 | Matlab实现PNN概率神经网络多特征分类预测

分类预测 | Matlab实现PNN概率神经网络多特征分类预测 目录 分类预测 | Matlab实现PNN概率神经网络多特征分类预测分类效果代码功能算法流程程序设计参考资料分类效果 代码功能 该代码实现了一个基于**概率神经网络(PNN)**的多分类任务,核心功能如下: 数据预处理 读取Exce…...

spring-retry

学习链接 【SpringBoot】spring-retry(重试机制) 【Spring】Spring Retry CSDN有点可恶啊&#xff0c;拿着别人的文章&#xff0c;要开VIP才能看...

RTMP协议解析【二】

文章目录 RTMP协议解析【二】RTMP消息消息的格式Basic HeaderMessage HeaderExtended Timestamp RTMP协议解析【二】 本专栏重点负责介绍RTMP协议的理论部分&#xff0c; 跳过定义&#xff0c;协议与其他协议的优缺点对比&#xff0c;协议的拓展与改进&#xff0c;协议的历史发…...

WebGL2混合与雾

混合技术 一、混合基本技术 混合技术就是将两个片元调和&#xff0c;主要通过各种测试将准备进入帧缓冲&#xff08;源片元&#xff09;与帧缓冲中原有片元&#xff08;目标片元&#xff09;按照设定的比例加权计算出最终片元的颜色值 。 两种常用 组合 &#xff1a; 源因子…...