测试W5500的第5步_使用ioLibrary库创建UDP组播

UDP组播是用来向特定的几个设备发送数据。
1、UDP组播的基本步骤:
1).设置本地网络参数
本地物理地址:00 08 DC 11 11 11
本地IP地址:192.168.1.199
本地子网掩码:    255.255.255.0
本地网关:192.168.1.1
目的是让设备连接到本地的局域网。
2).为SOCKET通道设置一个目标主机MAC地址
3).为SOCKET通道设置具有相同组播组的IP地址
4).为SOCKET通道设置具有相同的端口
就可以接收到组内的任何用户的消息。

2、发送组播消息时,需要将数据发送到组播组的IP地址和端口上。

3、组播地址
在IPv4中,组播地址的范围从224.0.0.0到239.255.255.255。
224.0.0.0 ~ 224.0.0.255: 局部链接多播地址:是为路由协议和其它用途保留的地址,只能用于局域网中。
路由器是不会转发的地址224.0.0.0,是保留地址
224.0.1.0 ~ 224.0.1.255: 为用户可用的组播地址(临时组地址),可以用于Internet上的。
224.0.2.0 ~ 238.255.255.255: 用户可用的组播地址(临时组地址),全网范围内有效。
239.0.0.0 ~ 239.255.255.255: 为本地管理组播地址,仅在特定的本地范围内有效。

4、ioLibrary库下载地址

文件下载地址:https://gitee.com/wiznet-hk/STM32F10x_W5500_Examples
源文件下载地址:https://gitee.com/wiznet-hk

5、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的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外设
}

//函数功能:初始化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发送给W5500
	while (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);
	}
}

6\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表示网速为10M
	printf("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 register

	wiz_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地址,DHCP
	if (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模式,然后从串口输出
}

7、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地址
wiz_NetInfo net_info;

char Local_Net_Message_Buffer[Local_Net_Message_Buffer_Size]="[192.168.1.199]:[6000]: ";

uint8_t Multicast_mac[6] = {0x01, 0x00, 0x5e, 0x01, 0x01, 0x0b}; //组播MAC地址
uint8_t Multicast_IP[4] = {224, 1, 1, 11};//组播IP地址 
uint16_t Multicast_port = 6000;//组播端口


//uint16_t local_port=4000;//W5500的本地端口

uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};

8、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;
#define Local_Net_Message_Buffer_Size 30
extern char Local_Net_Message_Buffer[Local_Net_Message_Buffer_Size];

extern uint8_t Multicast_mac[6]; //组播MAC地址
extern uint8_t Multicast_IP[4];  //组播
extern uint16_t Multicast_port;  //组播端口

#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
extern uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE];

#endif

9、UDP_MULTICAST.c

#include "UDP_MULTICAST.h"
#include <stdio.h>
#include "socket.h"
#include "wizchip_conf.h"
#include "W5500_Variable.h"
#include <string.h>

//函数功能:
//1.将W5500的SOCKET通道sn添加到组播中
//2.设置W5500在组播中的MAC地址,IP地址和端口
void Join_W5500_Multicast(uint8_t sn)
{
	setSn_DHAR(sn, Multicast_mac);//设置W5500的SOCKET通道sn的MAC地址
	setSn_DIPR(sn, Multicast_IP); //设置W5500的SOCKET通道sn的IP地址
	setSn_DPORT(sn, Multicast_port);//设置W5500的SOCKET通道sn的端口值
	socket(sn, Sn_MR_UDP, Multicast_port, Sn_MR_MULTI);
	//将SOCKET通道sn配置为UDP组播模式
	printf("%d:Opened, UDP Multicast Socket\r\n", sn);
	printf("%d:Multicast Group IP - %d.%d.%d.%d\r\n", sn, Multicast_IP[0], Multicast_IP[1], Multicast_IP[2], Multicast_IP[3]);
	printf("%d:Multicast Group Port - %d\r\n", sn, Multicast_port);
}

//函数功能:将buf[]中的字符串通过SOCKET通道sn,发送给IP地址为destip和端口为destport的UDP设备
void Send_UDP_Message(uint8_t sn,char* buf,uint8_t* destip,uint16_t destport)
{
	int16_t len;

	len=strlen(buf);
	sendto(sn,(uint8_t* )buf, len, destip, destport);
	//将ethernet_buf为首地址的存储区中的前len个字节
	//通过端口sn发送给远程IP地址为destip,并指定远程端口为destport
	printf("%d: %s\r\n",sn,buf);
}

/**
 * @brief Multicast receive data
 * @param sn socket number
 * @param buf buffer pointer
 * @param multicast_mac Multicast MAC address
 * @param multicast_ip Multicast IP address
 * @param multicast_port Multicast port number
 * @return The size of the data received, which returns a negative number if the reception fails
 */
int32_t udp_multicast(uint8_t sn, uint8_t* buf, uint8_t* multicast_mac, uint8_t* multicast_ip, uint16_t multicast_port)
{
	int32_t  ret;
	uint16_t size, sentsize;
	uint8_t destip[4];//用来保存接收到的IP地址
	uint16_t destport;//用来保存接收到的端口
	uint8_t Sn_SR_Value;
	uint8_t len;

	Sn_SR_Value=getSn_SR(sn);//Sn_SR_Value为0x22
	switch(Sn_SR_Value)
	{
		case SOCK_UDP :
			if((size = getSn_RX_RSR(sn)) > 0)
			{
				if(size > ETHERNET_BUF_MAX_SIZE) size = ETHERNET_BUF_MAX_SIZE;
				ret = recvfrom(sn, buf, size, destip, (uint16_t*)&destport);
				//接收数据,并将发送放的IP地址保存到destip[],将发送方的端口保存到destport[]
				buf[ret]='\0';//添加字符串结束符
				printf("recv from [%d.%d.%d.%d][%d]: %s\r\n",destip[0],destip[1],destip[2],destip[3],destport,buf);
				if(ret <= 0)
				{
#ifdef _MULTICAST_DEBUG_
					printf("%d: recvfrom error. %d\r\n",sn,ret);
#endif
					return ret;
				}

				len=strlen(Local_Net_Message_Buffer);//求Local_Net_Message_Buffer[]中字符串传毒
				memmove(&buf[len], &buf[0],ret);//将buf[]中的数据整体右移len个字节
				for(;len>0;len--)//装载应答头信息
				{
					buf[len-1]=Local_Net_Message_Buffer[len-1];
				}
				ret=strlen((char*)buf);//设置发送数据的字节数量
				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,并指定远程端口为destport
					printf("%s\r\n",buf);
					if(ret < 0)
					{
#ifdef _MULTICAST_DEBUG_
						printf("%d: sendto error. %d\r\n",sn,ret);
#endif
						return ret;
					}
					sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
				}
			}
			break;

		case SOCK_CLOSED:
#ifdef _MULTICAST_DEBUG_
		  printf("%d:Multicast Loopback start\r\n",sn);
#endif
		  setSn_DIPR(sn, multicast_ip);
		  setSn_DPORT(sn, multicast_port);
		  setSn_DHAR(sn, multicast_mac);
		  if((ret = socket(sn, Sn_MR_UDP, Multicast_port, Sn_MR_MULTI)) != sn)
				//令SOCKET端口sn工作在UDP模式,并设置UDP端口为Multicast_port
			  return ret;
#ifdef _MULTICAST_DEBUG_
			printf("%d:Opened, UDP Multicast Socket\r\n", sn);
			printf("%d:Multicast Group IP - %d.%d.%d.%d\r\n", sn, multicast_ip[0], multicast_ip[1], multicast_ip[2], multicast_ip[3]);
			printf("%d:Multicast Group Port - %d\r\n", sn, multicast_port);
#endif
			break;
		default :
			break;
	}

	return 1;
}

10、UDP_MULTICAST.h

#ifndef _UDP_MULTICAST_H_
#define _UDP_MULTICAST_H_

#include <stdint.h>

#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 _MULTICAST_DEBUG_  //使能串口打印输出

void Join_W5500_Multicast(uint8_t sn);
void Send_UDP_Message(uint8_t sn,char* buf,uint8_t* destip,uint16_t destport);
int32_t udp_multicast(uint8_t sn, uint8_t* buf, uint8_t* multicast_mac, uint8_t* multicast_ip, uint16_t multicast_port);

#endif

11、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"


//文件下载地址: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 "UDP_MULTICAST.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"
	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模式,然后从串口输出

  Join_W5500_Multicast(UDP_SOCKET0);

	Send_UDP_Message(UDP_SOCKET0,"I am W5500_Multicast", Multicast_IP,Multicast_port);
	//将"I am W5500_1"通过SOCKET通道0,发送给IP地址为Multicast_IP和端口为Multicast_port的UDP设备
	
	while(1)
	{
		udp_multicast(UDP_SOCKET0, ethernet_buf, Multicast_mac, Multicast_IP, Multicast_port);
		//接收组播中其它成员的消息,并回传。
		LED0=!LED0;
		delay_ms(1000);
	}
}

12、如何配置网络调试助手加入组播

13、测试结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值