STM32U575ZIT6Q+W5300实现UDP网络通信

  while (1)
  {

		if(HAL_GPIO_ReadPin(W5300_LINK_GPIO_Port, L_LINK)==1)  // LINK——LED 为高电平
		{
			for(i=0;i<8;i++)
			{
		    close(i);
			}	
		}	
		else
		{	
					W5300_UDP_Loopback(0,1000,Dip,1000, S_Buffer);   //socket号,本机端口,目的IP,目的端口,收发缓存
		}

  }

一、硬件配置

        1.1 stm32与W5300的硬件连接

        我选择的是16位数据宽度,因此这个地方地址线需要串一位进行连接,板子的A9不需要连,W5300的A0位也不需要连接

        下面是W5300的排针引脚:需要注意的是J1和J2不要画反了

二、软件配置

        软件的话我是用的是STM32CubeMX+keil5.32配置的。由于stm32外接w5300需要用到32的FSMC总线,这个总线可以用来外扩SRAM/FLASH/LCD的,这个地方W5300是可以当成SRAM来配置的。

 1、以下是cubemx的配置过程:

        1、首先得选择好自己的芯片型号

        2、配置ICACHE

        选择1-way就好了

        3、配置RCC

        高速时钟选择晶振

        4、配置sys

        开启系统基准时钟

        5、配置FSMC总线

        STM32的FSMC有一个存储区间,我们要用的是BANK1,BANK3一般用来外扩NAND FLASH,

然后BANK1里面又分了四个小区间每块64M,说明用户自己的话可以外扩4块SRAM类似的内存。

在这里我们选择BANK1里面的第三块,也就是NE3,这个可以随意选择,我第一块用来外扩SRAM了,这个后面再说。

chip select 选择 NE3

memory type 选择SRAM

address 选择10位的地址长度

data选择16位数据长度

然后不用勾选byte enable,不用高低位字节操作

使能write oporation 因为开了这个才能写数据

使能writefifo可以进行快速读写

下面两个图来自于W5300的数据手册,描述了地址建立时间和数据建立时间还有保持时间,一般就用到Address setup time、Address hold time、data setup time以及data hold time,我看到很多文章没有说明这个怎么来的,这个地方是根据你的系统时钟计算出来的,我在cubemx里面配置了160M的时钟频率。

下图中Address setup time最大需要7ns,那就直接用7ns来计算我们需要配置的数

7ns/(1/160M)=1.12,因此cubemx里面的address setuo time hclk可以配置为0或者1,其他类似。

        6、配置串口

        7、配置供电方式

        配置为SMPS

        8、生成代码

2、以下是keil5的编写过程

        1、需要添加的文件及描述

        IO_DEFINE.h        用于定义相应的管脚信息

#ifndef __IO_DEFINE_H_
#define __IO_DEFINE_H_
/******************************W5300接口定义********************************************/
/* W5300中断输入口定义PD3 */
#define W5300_INT	GPIO_PIN_3
/* 对W5300复位信号输出口定义 PF7*/
#define W5300_RST	GPIO_PIN_7
/* 数字信号输入口定义 */
#define D_INPUT1	GPIO_PIN_6
#define D_INPUT2	GPIO_PIN_7
/* 数字信号输出口定义 */
#define D_OUTPUT1	GPIO_PIN_11
#define D_OUTPUT2	GPIO_PIN_12
/* 以太网连接状态输入口定义 */
#define L_LINK	GPIO_PIN_6
/* W5300片选定义 */
#define W5300_CS_NE3 GPIO_PIN_10//GPIO_PG10
/* W5300读使能定义 */
#define W5300_NOE PIO_PIN_4//GPIO_PD4
/* W5300写使能定义 */
#define W5300_NWE PIO_PIN_5//GPIO_PD5
/******************************SRAM接口定义********************************************/
#define SRAM_CS_NE1  GPIO_PIN_7//GPIO_PD7
#define SRAM_NBL0 	 GPIO_PIN_0//GPIO_PE0
#define SRAM_NBL1 	 GPIO_PIN_15//GPIO_PB15

/******************************其他引脚定义********************************************/
#define AMP_POWER 	 GPIO_PIN_8//GPIO_PC8
#define IMX_POWER 	 GPIO_PIN_9//GPIO_PC9
#define IMX_INT   	 GPIO_PIN_5//GPIO_PA5
#define IMX_WAKE   	 GPIO_PIN_4//GPIO_PA4


#endif

UDP_TR.H             UDP头文件

#ifndef __UDP_TR_H
#define __UDP_TR_H

#include <stdint.h>


void W5300_Config(void);
void close(unsigned char sn);
unsigned short W5300_UDP_Loopback(unsigned char sn,unsigned short port,unsigned char Dip[],unsigned short Dport, unsigned short *buf);
void Read_sn_IR(unsigned char sn);
unsigned short Udp_rx_process(unsigned char sn, unsigned short buf[]);
void Udp_tx_process(unsigned char sn,unsigned char Dip[],unsigned short Dport, unsigned short buf[],unsigned short tx_size);
unsigned char Wait_before_send(unsigned sn);
unsigned int Socket_sn_UDP(unsigned char sn,unsigned short port,unsigned char Dip[],unsigned short Dport);


#endif

wizchip_conf.h        wiznet官方的配置文件

W5300.h                官方的5300寄存器头文件

2、主函数编写

主要是进行W5300的初始化以及调用回环函数进行数据通信

  W5300_Config();
  while (1)
  {

		if(HAL_GPIO_ReadPin(W5300_LINK_GPIO_Port, L_LINK)==1)  // LINK——LED 为高电平
		{
			for(i=0;i<8;i++)
			{
		    close(i);
			}	
		}	
		else
		{	
					W5300_UDP_Loopback(0,1000,Dip,1000, S_Buffer);   //socket号,本机端口,目的IP,目的端口,收发缓存
		}

  }

 下面是main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//#include "Device.h"
#include "IO_define.h"					/* EVB IO definition */
#include "W5300.h"
#include "UDP_TR.h"
#include "wizchip_conf.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "SRAM1.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

TIM_HandleTypeDef htim2;

UART_HandleTypeDef huart1;

SRAM_HandleTypeDef hsram1;
SRAM_HandleTypeDef hsram3;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void SystemPower_Config(void);
static void MX_GPIO_Init(void);
static void MX_FMC_Init(void);
static void MX_ICACHE_Init(void);
static void MX_MEMORYMAP_Init(void);
static void MX_TIM2_Init(void);
static void MX_USART1_UART_Init(void);

/* USER CODE BEGIN PFP */
/**************************************************/
/*****************UDP使用变量********************/
unsigned int Timer2_Counter;
unsigned int S0_Recv, Sn_SendOK[8], Sn_TimeOut[8];
unsigned short S_Buffer[800];
unsigned short UDP_Preamble[4];
/**************************************************/

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
unsigned char Dip[4]={192,168,0,40};//目的地址的IP,即PC端
unsigned short Dport = 1000;
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
    int i;

  /* USER CODE END 1 */

  /* MCU Configuration------------s--------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* Configure the System Power */
  SystemPower_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_FMC_Init();
  MX_ICACHE_Init();
  MX_MEMORYMAP_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	W5300_Config();


  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */


  /* Infinite loop */
  while (1)
  {

		if(HAL_GPIO_ReadPin(W5300_LINK_GPIO_Port, L_LINK)==1)  // LINK——LED 为高电平
		{
			for(i=0;i<8;i++)
			{
		    close(i);
			}	
		}	
		else
		{	
					W5300_UDP_Loopback(0,1000,Dip,1000, S_Buffer);   //socket号,本机端口,目的IP,目的端口,收发缓存
		}

  }
  /* USER CODE END 3 */
}

3、UDP_TR.C配置

主要用于配置UDP通信的函数

1、unsigned short W5300_UDP_Loopback(unsigned char sn,unsigned short port,unsigned char Dip[],unsigned short Dport, unsigned short *buf);
unsigned short W5300_UDP_Loopback(unsigned char sn,unsigned short port,unsigned char Dip[],unsigned short Dport, unsigned short *buf)
{
  unsigned short *ptr;
	unsigned short i;
	unsigned short Recv_len;
	unsigned short sn_dport;
	unsigned char sn_dip[4];
	
	Read_sn_IR(sn);//读取套接字中断寄存器的状态,以便后续根据中断状态采取相应的操作

	ptr=(unsigned short*)Sn_SSR(sn);//看看当前socket是什么状态,已经打开还是关闭
	i=*ptr;
	i&=0x00ff;   

	switch(i)
	{
   case SOCK_UDP:  // 套接字状态为 UDP 
		 
		  Recv_len=Udp_rx_process(sn,buf);   // 接收数据
		  if(Recv_len<=0)
			  return 0;	
			 // 以确保在发送数据之前,套接字已经处于可发送状态
			if( Wait_before_send(sn)==0) //超时返回0
				return 0;
			//将目标 IP 地址和端口从 UDP_Preamble 数组中提取出来,然后调用 Udp_tx_process 函数来发送数据。
			for(i=0;i<4;i++)
			{
			sn_dip[i]=Dip[i];
			}
//			sn_dip[0]=(unsigned char)(UDP_Preamble[0]/256);  
//			sn_dip[1]=(unsigned char)(UDP_Preamble[0]%256);
//			sn_dip[2]=(unsigned char)(UDP_Preamble[1]/256);
//			sn_dip[3]=(unsigned char)(UDP_Preamble[1]%256);
			sn_dport = Dport;  
			
//			while(1)
//			{			
				Udp_tx_process(sn,sn_dip,sn_dport, zm_Buffer,sizeof(zm_Buffer));// 发送数据
//			}
			break;
			
			
	  case SOCK_CLOSED:        // SOCKET0不是UDP模式,处于关闭状态
			//调用 Socket_sn_UDP 函数以配置 UDP 套接字参数,指定本地端口和目标 IP 地址及端口。
			 Socket_sn_UDP(sn,port,Dip,Dport);
			//将套接字的已经准备好发送数据标志为 Sn_SendOK 设置为 1,同时将超时标志 Sn_TimeOut 设置为 0。
		   Sn_SendOK[sn]=1;//已经准备好发送数据标志
	     Sn_TimeOut[sn]=0;
			break;
		default: break;
	}
  return 1;
}	

通过Sn_SSR(sn)等待标志位变为SOCK_UDP,就可以进行UDP读写,如果是SOCK_CLOSED的话需要新建一个socket来进行通信。

2、void Read_sn_IR(unsigned char sn);读取Sn_IR中断寄存器,判断socket0的状态,是否已连接或者超时
void Read_sn_IR(unsigned char sn)
{
	unsigned short *ptr;
	unsigned short j;
	ptr=(unsigned short*)Sn_IR(sn);//端口中断寄存器,主要用到以下几种中断
	j=*ptr;
	*ptr=j;
	if(j&Sn_IR_CON)// 建立连接了
	{

	}	
	if(j&Sn_IR_RECV)// 接收到了数据产生中断
	{

	}
	if(j&Sn_IR_DISCON)// 未建立连接
	{
		ptr=(unsigned short*)Sn_CR(sn);//SOCKETn命令寄存器
		*ptr=Sn_CR_DISCON;// 赋予未建立连接的状态
	}
	if(j&Sn_IR_SEND_OK)// 已发送完成产生中断
		Sn_SendOK[sn]=1;//发送已完成,可以进行下一次发送了
	if(j&Sn_IR_TIMEOUT)// 已超时
		Sn_TimeOut[sn]=1;
}	
3、Udp_rx_process和Udp_tx_process用于收发数据
unsigned short Udp_rx_process(unsigned char sn, unsigned short buf[])
{
	unsigned short *ptr;
	unsigned short rx_size;
	unsigned short i,j;

	
	ptr=(unsigned short*)Sn_RX_RSR(sn);// 看一下接收了多少个字节
	rx_size=*ptr++;
	rx_size=*ptr;

	if(rx_size==0) 		/* 没有接收数据,返回0 */
		return 0;

	ptr=(unsigned short*)Sn_RX_FIFOR(sn);//检查Sn_RX_RSR之后,主机才可以通过Sn_RX_FIFOR读取Sn_RX_RSR字节长度的数据,
	//完整UDP数据包格式为;4字节IP,2字节端口,2字节数据长度,+实际数据
	UDP_Preamble[0]=*ptr;     // 收到数据的目的IP
	//ptr++;//程序这个地方得删掉ptr++,是我自作聪明了
	UDP_Preamble[1]=*ptr;// 收到数据的目的IP
	//ptr++;
	UDP_Preamble[2]=*ptr;// 收到数据的目的端口
	//ptr++;
	UDP_Preamble[3]=*ptr;// 本包数据长度
  
	rx_size= UDP_Preamble[3];
	
	if(rx_size&0x0001)
		i=(rx_size+1)/2;
	else
		i=rx_size/2;
	
	for(j=0;j<i;j++)
		buf[j]=*ptr;

	ptr=(unsigned short*)Sn_CR(sn);		/* Set RECV command */
	*ptr=Sn_CR_RECV;// 更新接收寄存器额指针,开始接收数据
	return rx_size;
}


/*函数作用:UDP发送函数
 *输入参数:
sn 套接字编号
目的ip 端口 
buf发送数据缓冲区
size数据大小
 */
void Udp_tx_process(unsigned char sn,unsigned char Dip[],unsigned short Dport, unsigned short buf[],unsigned short tx_size)
{
	unsigned short *ptr;
	unsigned short i,j;

	/* 目的地址IP寄存器 */
	ptr=(unsigned short*)Sn_DIPR(sn);
  *ptr++=(unsigned short)(Dip[0]*256)+(unsigned short)Dip[1];
	*ptr=(unsigned short)(Dip[2]*256)+(unsigned short)Dip[3];
	
	/* 目的地址端口寄存器 */
	ptr=(unsigned short*)Sn_DPORTR(sn);
	*ptr=Dport;
	
	if(tx_size&0x0001)
		i=(tx_size+1)/2;
	else
		i=tx_size/2;
	/* 发送FIFO缓冲区寄存器 */
	ptr=(unsigned short*)Sn_TX_FIFOR(sn);
	for(j=0;j<i;j++)
		*ptr=buf[j];
	//发送数据字节数寄存器
	ptr=(unsigned short*)Sn_TX_WRSR(sn);
	*ptr++=0;
	*ptr=tx_size;
	//数据已发送
	ptr=(unsigned short*)Sn_CR(sn);		
	*ptr=Sn_CR_SEND;
}
4、Socket_sn_UDP用于新建socket
unsigned int Socket_sn_UDP(unsigned char sn,unsigned short port,unsigned char Dip[],unsigned short Dport)
{
	unsigned short *ptr;
	unsigned short i;

	/* 设置板子的端口号 */
	ptr=(unsigned short*)Sn_PORTR(sn);
	*ptr=port;

	/* 设置目的地址的IP */
	ptr=(unsigned short*)Sn_DIPR(sn);
  *ptr++=(unsigned short)(Dip[0]*256)+(unsigned short)Dip[1];
	*ptr=(unsigned short)(Dip[2]*256)+(unsigned short)Dip[3];
	
	/* 设置目的地址的端口号 */
	ptr=(unsigned short*)Sn_DPORTR(sn);
	*ptr=Dport;

	/* 设置套接字对大段大小,是TCP通信重要参数 */
	ptr=(unsigned short*)Sn_MSSR(sn);
	*ptr=1472;
   	
	/* 设置socket0为udp模式 */
	ptr=(unsigned short*)Sn_MR(sn);
	*ptr=Sn_MR_UDP;

	/* 打开socket0 */
	ptr=(unsigned short*)Sn_CR(sn);
	*ptr=Sn_CR_OPEN;
	
//	Delay(20);
	HAL_Delay(20);
	ptr=(unsigned short*)Sn_SSR(sn);
	i=*ptr;
	//查看此时的状态是否是UDP模式
	if((i&0x00ff)!=SOCK_UDP)		
	{
		ptr=(unsigned short*)Sn_CR(sn);
		*ptr=Sn_CR_CLOSE;
		return FALSE;
	}
	
	Sn_SendOK[sn]=1;
	Sn_TimeOut[sn]=0;
	return TRUE;
}
5、Wait_before_send用于发送数据前等待寄存器是否准备好
unsigned char Wait_before_send(unsigned sn)
{
	//还没准备好要发送数据,没超时 则进while
  while((Sn_SendOK[sn]==0)&&(Sn_TimeOut[sn]==0))//根据Read_sn_IR函数可以知道他的状态
	{   
			Read_sn_IR(sn);
    	if(Sn_TimeOut[sn])
     	{
		    Sn_TimeOut[sn] =0;
    		return 0; 
    	}
    	else
				Sn_SendOK[sn]=0;
			
	}
	return 1;//(Sn_SendOK[sn]==1)就直接返回
		
}	
6、close用于关闭当前socket
void close(unsigned char sn)
{
  unsigned short *ptr;
	unsigned short i;
  do
	{
		ptr=(unsigned short*)Sn_CR(sn);             //关闭使用的socket  Sn_CR(0)  括号内是socket号
		*ptr=Sn_CR_CLOSE;
		ptr=(unsigned short*)Sn_SSR(sn);//SOCKETn 状态寄存器
		i=*ptr;
		i&=0x00ff;
	}while(i!=SOCK_CLOSED);
	

}	

3、下载验证

最后可以将程序下载到板子里,进行UDP通信测试

ping一下板子

用网络调试助手,PC发送1,板子回复1-10,因为数据类型是short

用wireshark抓包测试,网速大概86M,感觉还行吧

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值