STM32 W5500以太网通讯

对于内含以太网MAC部分的芯片,可以外部增加以太网PHY芯片和连接器,实现以太网通讯。对于内部没有以太网MAC部分的芯片,通过W5500 SPI转Ethernet芯片实现以太网通讯是比较好的方式, 从而STM32F0各低端系列都能实现以太网通讯。采用W5500芯片,可以不占用MCU的内存部分做buffer,对于MCU业务逻辑时序紧张的场景也有使用价值。MCU和W5500可以通过SPI的DMA方式,实现较快的收发逻辑;W5500最大支持到80Mbps的SPI接口速度,实际情况根据MCU的SPI接口速率和PCB高速布线质量进行调整。

W5500写读Buffer的要点笔记

  1. 每个SOCKET有自己的写缓冲和读缓冲操作命令/地址,如下:

  2. 每个SOCKET的写缓冲大小(Sn_TXBUF_SIZE)和读缓冲大小(Sn_RXBUF_SIZE)可调整,写缓冲和读缓冲分离。因为8个socket共享写缓冲和读缓冲,8个socket总的写缓冲大小或读缓冲大小不超过16KB。

  3. 写时可进行burst操作。因此首地址的设置,有辅助的信息寄存器:
    ⑴Sn_TX_FSR : 用于查阅写缓冲区域剩余自由空间,可为Sn_TX_WR和Sn_TX_RD的差值
    ⑵Sn_TX_WR : 写缓冲写入的数据指针,指示已经写到的地址
    ⑶Sn_TX_RD :写缓冲发送的数据指针,指示发送改到了哪个地址

  4. 读时可进行burst操作。因此首地址的设置,有辅助的信息寄存器:
    ① Sn_RX_RSR :用于查阅读缓冲剩余的未读取的数据空间大小,可为Sn_RX_WR和Sn_RX_RD的差值
    ② Sn_RX_WR :接收数据的边界指针,接收到数据时,指针自动后移,指示前面的部分为已收到的数据。
    ③ Sn_RX_RD : 接收数据读取后的边界指针,当进行了接收缓冲区读取后,该指针手动升级到已读取的缓冲区后的地址

  5. 写缓冲和读缓冲都是循环FIFO,因此越界后翻到0地址继续进行。

需要注意的情况:

  1. 是否有不断开连接方式可以将缓冲区复位? 答:不能,且Socket端口打开和连接后的初始化地址也不是0地址,且每次初始化地址还不同。
  2. 越界情况的处理?答:循环缓冲区,控制写入时序,否则会产生对还未发送数据区域的覆盖。

发送数据操作逻辑:

  1. 通过读取Sn_TX_WR寄存器获得当前的写缓冲区指针,通过读取Sn_TX_RD寄存器获得当前的写缓冲区发送数据指针,初始时二者一致表示没有未发送完成的数据。
  2. 通过从Sn_TX_WR寄存器得到的发送缓冲区地址,写入要发送的数据,发送写数据命令和写数据之间的时间间隔不能过大,否则W5500接收SPI数据失败。
  3. 向Sn_TX_WR寄存器写入后续发送要达到的发送缓冲区地址,即当前发送缓冲区地址+要发送的字节数。实际上,这个写操作后,Sn_TX_WR寄存器并未立即更新,而是要等到发送缓冲区数据指令发送后,才会更新。
  4. 发送缓冲区数据发送指令,此时Sn_TX_WR寄存器更新,W5500从Sn_TX_RD地址开始发送数据,并实时更新Sn_TX_RD地址,等到Sn_TX_RD地址与Sn_TX_WR寄存器值相同,则完成并停止发送。

读数据操作逻辑:

  1. 通过读取Sn_RX_RD寄存器得到读缓冲区可读取区域首地址
  2. 通过读取Sn_RX_RSR寄存器得到读缓冲区未读的接收到的数据长度
  3. 通过可读取区域首地址读取读缓冲区里的数据,可小于等于Sn_RX_RSR寄存器里的长度,大于则读到无效数据
  4. 向Sn_RX_RD写入新的可读取区域首地址,为之前的首地址+已读取字节数。但此时Sn_RX_RD还未更新,还需发送下述一条指令进行触发更新。
  5. 通过向Socket的命令寄存器(Command Register)发送RECV指令,触发Sn_RX_RD更新,同时Sn_RX_RSR也被更新。
  6. 如果没有更新Sn_RX_RD寄存器指针,则再次收到数据时会继续顺序放置,同时Sn_RX_WR和Sn_RX_RSR继续增加。因此前后不同次接收到的数据仍然可以都读取出来。

实际嵌入式时序控制时,需要接收中断控制和读取W5500内部状态寄存器,进行时序调度。

STM32 W5500访问逻辑设计

这里设计一个例程,采用STM32H743VIT6连接W5500, 同时实现虚拟串口(VCOM)作为测试辅助:

  1. STM32上电后实现对W5500的配置,并读取特定寄存器以判断访问是否成功
  2. 网络连通后,用TCP测试工具,发送任意数据到STM32, STM32接收到后转发到VCOM;另外STM32将预设的特定数据发送到TCP测试工具。注意这里不是TCP端口的数据简单回环。

STM32CUBEIDE配置

采用STM32CUBEIDE进行工程配置,选择SPI1作为W5500通讯接口,STM32H743VIT6的SPI1能达到80MHz的速率,但测试环境采用短杜邦线连接,达不到80MHz信号完整性传输质量,实测60MHz能够正确响应,因此相应的时钟采用120MHz的2分频实现。

使能外部8MHz晶振时钟,整体的时钟配置如下,包括了SPI和USB VCOM的部分:


SPI1配置,W5500连接所用管脚为:

  • PD1: W5500_RST
  • PD3: W5500_SCS
  • PD5: W5500_INT
  • PB3: W5500_SCK
  • PB4: W5500_MISO
  • PB5: W5500_MOSI









USB虚拟串口的配置:





然后生成基本代码:

W5500访问库函数设计

这里设计W5500开通两个SOCKET端口,测试中只用到第一个SOCKET端口。

新建w5500.h文件,代码如下:

/** PD1: W5500_RST* PD3: W5500_SCS* PD5: W5500_INT** PB3: W5500_SCK* PB4: W5500_MISO* PB5: W5500_MOSI***/
#ifndef  _W5500_H_
#define  _W5500_H_#define PY_W5500_RST {HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_RESET);HAL_Delay(5);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_SET);HAL_Delay(5);}
#define PY_W5500_CS_EN HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
#define PY_W5500_CS_DEN HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_SET);void PY_W5500_Config(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t data);
void PY_W5500_Read(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t* data, uint16_t length);
void PY_W5500_Send(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t* data, uint16_t length);
void PY_W5500_TCPSERVER_2SOCKETS(void);
void PY_W5500_SOCKET0_CLEARRECINT(void);#endif

新建w5500.c文件,代码如下:


#include "stm32h7xx_hal.h"
#include <stdio.h>
#include <string.h>
#include "w5500.h"
#include "spi.h"void PY_W5500_Config(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t data)
{extern uint8_t PY_SPIDMA__Status;extern uint8_t* PY_CMD_Seg;PY_W5500_CS_ENPY_SPIDMA__Status=1;PY_CMD_Seg[0]=ah;PY_CMD_Seg[1]=al;PY_CMD_Seg[2]=ctl|0x04;PY_CMD_Seg[3]=data;HAL_SPI_Transmit_DMA(&hspi1, PY_CMD_Seg,4);while(PY_SPIDMA__Status==1) ;PY_W5500_CS_DENHAL_Delay(1);
}void PY_W5500_Read(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t* data, uint16_t length)
{extern uint8_t PY_SPIDMA__Status;extern uint8_t* PY_CMD_Seg;PY_W5500_CS_ENPY_SPIDMA__Status=1;PY_CMD_Seg[0]=ah;PY_CMD_Seg[1]=al;PY_CMD_Seg[2]=ctl&0xfb;HAL_SPI_Transmit_DMA(&hspi1, PY_CMD_Seg,3);while(PY_SPIDMA__Status==1) ;PY_SPIDMA__Status=1;HAL_SPI_Receive_DMA(&hspi1, data, length);while(PY_SPIDMA__Status==1) ;PY_W5500_CS_DEN
}void PY_W5500_Send(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t* data, uint16_t length)
{extern uint8_t PY_SPIDMA__Status;extern uint8_t* PY_CMD_Seg;PY_W5500_CS_ENPY_SPIDMA__Status=1;PY_CMD_Seg[0]=ah;PY_CMD_Seg[1]=al;PY_CMD_Seg[2]=ctl|0x04;HAL_SPI_Transmit_DMA(&hspi1, PY_CMD_Seg,3);while(PY_SPIDMA__Status==1) ;PY_SPIDMA__Status=1;HAL_SPI_Transmit_DMA(&hspi1, data, length);while(PY_SPIDMA__Status==1) ;PY_W5500_CS_DEN
}void PY_W5500_TCPSERVER_2SOCKETS(void)
{
/** Only one socket receiving interrupt is opened for cmd recognition. Other interrupt sources are closed. To use polling for Tx status.*/
extern uint8_t PY_SPIDMA__Status;
extern uint8_t* PY_CMD_Seg;
extern uint8_t* PY_DataR_Seg;
extern uint8_t* PY_DataW_Seg;//Common register:mode registerPY_W5500_Config(0x00, 0x00, 0x04, 0x00);
//Common register:gateway IP address registerPY_W5500_Config(0x00, 0x01, 0x04, 192); //IP: 192.168.1.252PY_W5500_Config(0x00, 0x02, 0x04, 168);PY_W5500_Config(0x00, 0x03, 0x04, 1);PY_W5500_Config(0x00, 0x04, 0x04, 252);
//Common register:subnet mask registerPY_W5500_Config(0x00, 0x05, 0x04, 255);PY_W5500_Config(0x00, 0x06, 0x04, 255);PY_W5500_Config(0x00, 0x07, 0x04, 255);PY_W5500_Config(0x00, 0x08, 0x04, 0);
//Common register:source hardware address registerPY_W5500_Config(0x00, 0x09, 0x04, 0x00);PY_W5500_Config(0x00, 0x0a, 0x04, 0x08);PY_W5500_Config(0x00, 0x0b, 0x04, 0xdc);PY_W5500_Config(0x00, 0x0c, 0x04, 0x01);PY_W5500_Config(0x00, 0x0d, 0x04, 0x02);PY_W5500_Config(0x00, 0x0e, 0x04, 0x03);//Common register:source IP address registerPY_W5500_Config(0x00, 0x0f, 0x04, 192);PY_W5500_Config(0x00, 0x10, 0x04, 168);PY_W5500_Config(0x00, 0x11, 0x04, 1);PY_W5500_Config(0x00, 0x12, 0x04, 252);//Common register:interrupt low level interval registerPY_W5500_Config(0x00, 0x13, 0x04, 0x00);PY_W5500_Config(0x00, 0x14, 0x04, 0x13);//Common register:(connection) interrupt registerPY_W5500_Config(0x00, 0x15, 0x04, 0x00);//Common register:(connection) interrupt mask registerPY_W5500_Config(0x00, 0x16, 0x04, 0xf0);//Common register:(socket)interrupt registerPY_W5500_Config(0x00, 0x17, 0x04, 0x00);//Common register:(socket) interrupt mask registerPY_W5500_Config(0x00, 0x18, 0x04, 0xc0);//Common register:retry time-value registerPY_W5500_Config(0x00, 0x19, 0x04, 0x07);PY_W5500_Config(0x00, 0x1a, 0x04, 0xd0);//Common register:retry count registerPY_W5500_Config(0x00, 0x1b, 0x04, 0x07);//Socket 0 register:mode registerPY_W5500_Config(0x00, 0x00, 0x0c, 0x21);//Socket 0 register:source port number registerPY_W5500_Config(0x00, 0x04, 0x0c, 0x03); //Port:1000PY_W5500_Config(0x00, 0x05, 0x0c, 0xe8);//Socket 0 register:maxium segment size registerPY_W5500_Config(0x00, 0x12, 0x0c, 0x05);PY_W5500_Config(0x00, 0x13, 0x0c, 0xb4);//Socket 0 register:ip type of service registerPY_W5500_Config(0x00, 0x15, 0x0c, 0x5a);//Socket 0 register:time to live registerPY_W5500_Config(0x00, 0x16, 0x0c, 64);//Socket 0 register:rx buffer size registerPY_W5500_Config(0x00, 0x1e, 0x0c, 2);//Socket 0 register:tx buffer size registerPY_W5500_Config(0x00, 0x1f, 0x0c, 2);//Socket 0 register:keep alive time registerPY_W5500_Config(0x00, 0x2f, 0x0c, 0x18);//Socket 1 register:mode registerPY_W5500_Config(0x00, 0x00, 0x2c, 0x21);//Socket 1 register:source port number registerPY_W5500_Config(0x00, 0x04, 0x2c, 0x07); //Port:2000PY_W5500_Config(0x00, 0x05, 0x2c, 0xD0);//Socket 1 register:maxium segment size registerPY_W5500_Config(0x00, 0x12, 0x2c, 0x05);PY_W5500_Config(0x00, 0x13, 0x2c, 0xb4);//Socket 1 register:ip type of service registerPY_W5500_Config(0x00, 0x15, 0x2c, 0x5a);//Socket 1 register:time to live registerPY_W5500_Config(0x00, 0x16, 0x2c, 64);//Socket 1 register:rx buffer size registerPY_W5500_Config(0x00, 0x1e, 0x2c, 2);//Socket 1 register:tx buffer size registerPY_W5500_Config(0x00, 0x1f, 0x2c, 2);//Socket 1 register:keep alive time registerPY_W5500_Config(0x00, 0x2f, 0x2c, 0x18);//interrupt mask registersPY_W5500_Config(0x00, 0x16, 0x04, 0x00);PY_W5500_Config(0x00, 0x18, 0x04, 0x01);PY_W5500_Config(0x00, 0x2c, 0x0c, 0x04);//Socket 0 : openPY_W5500_Config(0x00, 0x01, 0x0c, 0x01);  //open socketHAL_Delay(10);PY_W5500_Config(0x00, 0x01, 0x0c, 0x02);  //socket server listening//PY_W5500_Config(0x00, 0x01, 0x0c, 0x40);//Socket 1 : openPY_W5500_Config(0x00, 0x01, 0x2c, 0x01);  //open socketHAL_Delay(10);PY_W5500_Config(0x00, 0x01, 0x2c, 0x02);  //socket server listening}void PY_W5500_SOCKET0_CLEARRECINT(void)
{PY_W5500_Config(0x00, 0x02, 0x0c, 0x04);
}

main.c文件设计

对于W5500,配置为只有接收数据中断发送到STM32的中断接收管脚(PD5)。STM32收到中断后,读取数据转发到虚拟串口,另外把预设的一组值发送到以太网口。

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:*                        opensource.org/licenses/BSD-3-Clause********************************************************************************/
//SPI1 DMA buffer address can't be arranged in the region of 0x20000000 ~ 0x20020000/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "spi.h"
#include "usb_device.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "w5500.h"
#include "string.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 ---------------------------------------------------------*//* USER CODE BEGIN PV */
uint8_t PY_W5500_Ver_Addr_SegH=0x00, PY_W5500_Ver_Addr_SegL=0x39;
uint8_t PY_W5500_Ver_Ctrl_Seg=0x00;uint8_t* PY_CMD_Seg;
uint8_t* PY_DataR_Seg;
uint8_t* PY_DataW_Seg;uint8_t PY_SPIDMA__Status = 0;uint8_t cmd=0;uint8_t rx_addr_h, rx_addr_l;
uint16_t rx_len;/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 */PY_CMD_Seg = 0x38000000;PY_DataR_Seg = 0x38000004;PY_DataW_Seg = 0x30000000;/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* 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();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_USB_DEVICE_Init();MX_SPI1_Init();/* USER CODE BEGIN 2 */PY_W5500_RSTPY_CMD_Seg[0]=PY_W5500_Ver_Addr_SegH;PY_CMD_Seg[1]=PY_W5500_Ver_Addr_SegL;PY_CMD_Seg[2]=PY_W5500_Ver_Ctrl_Seg;PY_DataR_Seg[0]=0; PY_DataR_Seg[1]=0;PY_W5500_CS_ENPY_SPIDMA__Status=1;HAL_SPI_Transmit_DMA(&hspi1, PY_CMD_Seg, 3);while(PY_SPIDMA__Status==1) ;PY_SPIDMA__Status=1;HAL_SPI_Receive_DMA(&hspi1, PY_DataR_Seg, 1);while(PY_SPIDMA__Status==1) ;PY_W5500_CS_DENif(PY_DataR_Seg[0]!=0x04){while(1){CDC_Transmit_FS(PY_DataR_Seg, 1);HAL_Delay(1000);}}PY_W5500_TCPSERVER_2SOCKETS();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){//CDC_Transmit_FS(PY_DataR_Seg, 2);HAL_Delay(1000);if(cmd==1){cmd=0;PY_W5500_SOCKET0_CLEARRECINT();/** Receiving*/PY_W5500_Read(0x00, 0x28, 0x08, PY_DataR_Seg, 2);rx_addr_h=PY_DataR_Seg[0];rx_addr_l=PY_DataR_Seg[1];PY_W5500_Read(0x00, 0x26, 0x08, PY_DataR_Seg, 2);rx_len=(((uint16_t)PY_DataR_Seg[0])<<8)|((uint16_t)PY_DataR_Seg[1]);HAL_Delay(200);PY_W5500_Read(rx_addr_h, rx_addr_l, 0x18, PY_DataR_Seg, rx_len);CDC_Transmit_FS(PY_DataR_Seg, rx_len);PY_W5500_Config(0x00, 0x28, 0x0c, ((((uint16_t)(rx_addr_h))<<8)|((uint16_t)(rx_addr_l))+rx_len)>>8);PY_W5500_Config(0x00, 0x29, 0x0c, ((((uint16_t)(rx_addr_h))<<8)|((uint16_t)(rx_addr_l))+rx_len));PY_W5500_Config(0x00, 0x01, 0x0c, 0x40);HAL_Delay(200);/** Sending*/PY_DataW_Seg[0]=0;PY_DataW_Seg[1]=1;PY_DataW_Seg[2]=2;PY_DataW_Seg[3]=3;PY_DataW_Seg[4]=4;PY_DataW_Seg[5]=5;PY_DataW_Seg[6]=6;PY_DataW_Seg[7]=7;PY_W5500_Read(0x00, 0x22, 0x08, PY_DataR_Seg, 2);PY_W5500_Read(0x00, 0x24, 0x08, PY_DataR_Seg, 2);PY_W5500_Send(PY_DataR_Seg[0], PY_DataR_Seg[1], 0x14, PY_DataW_Seg, 8);PY_W5500_Config(0x00, 0x24, 0x0c, ((((uint16_t)(PY_DataR_Seg[0]))<<8)|((uint16_t)(PY_DataR_Seg[1]))+8)>>8);PY_W5500_Config(0x00, 0x25, 0x0c, ((((uint16_t)(PY_DataR_Seg[0]))<<8)|((uint16_t)(PY_DataR_Seg[1]))+8));HAL_Delay(1);PY_W5500_Read(0x00, 0x22, 0x08, PY_DataR_Seg, 2);PY_W5500_Read(0x00, 0x24, 0x08, PY_DataR_Seg, 2);HAL_Delay(1);PY_W5500_Config(0x00, 0x01, 0x0c, 0x20);HAL_Delay(1);PY_W5500_Read(0x00, 0x22, 0x08, PY_DataR_Seg, 2);PY_W5500_Read(0x00, 0x24, 0x08, PY_DataR_Seg, 2);}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Supply configuration update enable*/HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);/** Configure the main internal regulator output voltage*/__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}/** Macro to configure the PLL clock source*/__HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSE);/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 4;RCC_OscInitStruct.PLL.PLLN = 480;RCC_OscInitStruct.PLL.PLLP = 2;RCC_OscInitStruct.PLL.PLLQ = 2;RCC_OscInitStruct.PLL.PLLR = 2;RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;RCC_OscInitStruct.PLL.PLLFRACN = 0;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{extern uint8_t PY_SPIDMA__Status;PY_SPIDMA__Status = 0;
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{extern uint8_t PY_SPIDMA__Status;PY_SPIDMA__Status = 0;
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{extern uint8_t PY_SPIDMA__Status;PY_SPIDMA__Status = 0;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{extern uint8_t cmd;if(GPIO_Pin==GPIO_PIN_5){cmd=1;}}
/* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

编译并完成下载程序。

通讯测试

连接网线,并将本地IP做静态指定:

芯片重启跑起来后,网络接通,然后打开TCP测试工具,STM32是以太网Server角色,这里电脑端则设置为Client角色:


打开一个串口工具并连接:

TCP工具端连接STM32, 并发送“GOOD", 接收端设置为16进制接收:

这样,从电脑TCP发送端发送出去的"GOOD"被STM32收到后,转发到串口;STM32另外将十六进制00 01 02 03 04 05 06 07发送到电脑TCP接收端。

参考例程

上述设计的例程下载:
https://download.csdn.net/download/hwytree/22007730

–End–

STM32 W5500以太网通讯相关推荐

  1. 基于stm32之w5500以太网应用

    基于stm32之w5500以太网应用 强调一下前半段为基础知识普及(这段还是很重要的.不管用什么工具开发精通协议才是王道),后半段为实战代码干货. 如上图所示,最底下的一层叫做"物理层&qu ...

  2. STM32+W5500以太网模块

    一:w5500以太网模块介绍: W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方 案.W5500 集成了 TCP/IP 协议栈,10/100M 以太 ...

  3. 使用Aruino Ethernet使ESP32具有以太网通讯能力

    ESP32的Ethernet通讯 Arduino的Ethernet库 Ethernet库 库函数介绍 总结 Arduino的Ethernet库 Arduino很早就支持Ethernet通讯.硬件主要是 ...

  4. Wiznet W5500以太网控制器应用笔记

    引用数据手册的芯片介绍:"W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案.W5500 集成了TCP/IP 协议栈,10/100M 以太 ...

  5. 西门子S7以太网通讯协议

    S7以太网协议属于TCP/IP协议族的一种,下图为S7以太网协议在ISO-OSI参考模型中的位置. 通过WireShark抓包,可以看出S7以太网协议的模型: ISO-OSI参考模型.TCP/IP模型 ...

  6. 语言prodave以太网通讯_工业以太网通讯

    1. 工业以太网通讯简介 ⑴初识工业以太网 所谓工业以太网,通俗地讲就是应用于工业的以太网,指其在技 术上与商用以太网(IEEE802.3 标准)兼容,但材质的选用.产品的 强度和适用性方面应能满足工 ...

  7. PLC通讯实现-C#实现欧姆龙以太网通讯FINS(二)

    PLC通讯实现-C#实现欧姆龙以太网通讯FINS(二) 背景 抽象设计 欧姆龙以太网通讯实现FINS 背景 本人近十年的工作都与工业软件相关.其中工控系统开发过程中有一个必要环节就是跟各大厂商的PLC ...

  8. stm32+W5500+阿里物联网平台

    前提: 非物联网专业出身,网络协议一知半解(就是没学过),最近调试一块stm32+w5500开发板,为了学习知识,实现以个依靠阿里云物联网平台控制开发板上LED开关功能.(2020年4月24日) 1: ...

  9. Profinet高速协议下,PLC之间如何实现无线以太网通讯?

    本文以西门子S7-200SMART为例,介绍两台S7-200Smart PLC的无线 Profinet通信实现过程.无需更改网络参数和原有程序,也不必了解Profinet协议细节,只需要采用西门子PL ...

最新文章

  1. OpenCV(十七)边缘检测3 -- Canny算子(最优边缘检测)
  2. PHP中file_exists与is_file,is_dir的区别介绍
  3. WPF之DataGrid篇:DataGridComboBoxColumn
  4. Javascript简介
  5. html动画效果结束返回,javascript判断css3动画结束 css3动画结束的回调函数
  6. 大数据技术之 Kafka (第 3 章 Kafka 架构深入 ) Log存储解析
  7. Ken Block 漂移大叔,程序实现精准漂移算法。
  8. linux下如何查看某个容器的详细信息?
  9. CSDN 发布开源代码托管平台 GitCode
  10. 职教高中计算机专业知识,新课改背景下计算机专业教学(职教)三维目标设计初探...
  11. 嵌入式学习之QT学习---6 QT上位机开发之串口助手(下)
  12. java分页之页面分页—@易小川
  13. 经纬度转化为xy坐标系_Arcgis添加经纬度矢量点
  14. android代码禁用软键盘,Android 禁用软键盘
  15. laravel查询指定的一列数据 pluck
  16. 星转二手交易平台/二手交易系统/二手网站
  17. 商汤研究院基础视觉组正式员工(校招/社招)实习生长期招聘
  18. STM32的串口传输文件和点阵汉字的字模读取与显示
  19. git add . 报错‘xxx/’does not have a commit checked out,fatal: adding files failed
  20. 面试系列 -- 常见面试问题回答思路

热门文章

  1. 系综理论(Ensemble Theory)
  2. 使用U盘安装Archlinux
  3. Spring Boot(二): 集成Mybatis
  4. 什么是Ninja -
  5. 后台服务启动前台Service(跨进程)
  6. python二级练习和考试复习(分别格式化输出0.002178对应的科学表示法形式)
  7. LNMP部署应用——架设Discuz论坛——实验过程超详细!快来跟做!
  8. 【server2019】refs数据恢复/打捞
  9. 一文了解半导体的过去、现在和未来
  10. 非因解读 | DSP空间转录组技术揭示食管鳞状细胞癌三级淋巴样结构的预后价值及分子特征