STM32 + CubeMX + 硬件SPI + W5500 +TcpClient

这篇文章记录一下STM32+W5500+TCP_Client的调试过程,实现TCP客户端数据的接收与发送。

目录

一、W5500模块介绍

(后面补上)

二、Stm32CubeMx配置

1、RCC开启外部高速时钟(略)

2、配置STLink调试口(略)

3、配置串口方便调试输出(略)

4、配置工程名、生成路径,之后生成工程(略)

(1-4步的基础配置可以参考前面的文章《STM32基础工程模板创建》

5、SPI 配置,配置PA4为CS片选引脚

6、配置PB4为W5500的RST引脚,PB5为INT引脚

三、Keil代码编写

1、添加W5500驱动代码到工程(添加方法不赘述,驱动代码可以在官网找)

2、在工程中增加代码

(1)MyTcpClient.h

#ifndef MYTCPCLIENT_H
#define MYTCPCLIENT_H
#include "main.h"
#include "w5500.h"
#include "socket.h"
#include "wizchip_conf.h"
#include "spi.h"
#include <string.h>  // memcmp
#define SOCK_TCPS  0
extern  uint8_t buff[128];   //定义缓冲区   
extern uint8_t TCP_send_buff[128];   //定义UDP发送缓冲区                                            
extern uint8_t remote_ip[4]; //远程IP地址
extern uint16_t remote_port; //远程端口号

void TcpClientInit(void);
void do_tcp_client(void);
void Analysis(uint8_t *buf);
#endif // MYTCPCLIENT_H

(2)MyTcpClient.c

#include "MyTcpClient.h"
#include "main.h"
#include "w5500.h"
#include "socket.h"
#include "wizchip_conf.h"
#include "spi.h"
#include <string.h>  // memcmp

uint8_t buff[128];  
uint8_t TCP_send_buff[128]; 
                                                    
uint8_t remote_ip[4] = {192, 168, 1, 2}; //远程IP地址
uint16_t remote_port = 5002; //远程端口号

//片选
void W5500_Select(void) {
    HAL_GPIO_WritePin(W5500_CS_GPIO_Port, W5500_CS_Pin, GPIO_PIN_RESET);
}
void W5500_Unselect(void) {
    HAL_GPIO_WritePin(W5500_CS_GPIO_Port, W5500_CS_Pin, GPIO_PIN_SET);
}
void W5500_Restart(void) {
    HAL_GPIO_WritePin(W5500_RST_GPIO_Port, W5500_RST_Pin, GPIO_PIN_RESET);
    HAL_Delay(1);  // delay 1ms
    HAL_GPIO_WritePin(W5500_RST_GPIO_Port, W5500_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(1600);  // delay 1600ms
}

void W5500_ReadBuff(uint8_t* buff, uint16_t len) {
    HAL_SPI_Receive(&hspi1, buff, len, HAL_MAX_DELAY);
}

void W5500_WriteBuff(uint8_t* buff, uint16_t len) {
    HAL_SPI_Transmit(&hspi1, buff, len, HAL_MAX_DELAY);
}

uint8_t W5500_ReadByte(void) {
    uint8_t byte;
    W5500_ReadBuff(&byte, sizeof(byte));
    return byte;
}

void W5500_WriteByte(uint8_t byte) {
    W5500_WriteBuff(&byte, sizeof(byte));
}

//配置W5500网络信息
wiz_NetInfo gSetNetInfo = {
  .mac  = {0x00, 0x08, 0xdc, 0x11, 0x11, 0x11},
  .ip   = {192, 168, 1, 10},
  .sn   = {255, 255, 255, 0},
  .gw   = {192, 168, 1, 1},
  .dns  = {144, 144, 144, 144},
  .dhcp = NETINFO_STATIC};

wiz_NetInfo gGetNetInfo;

enum Status
{
  Failed = 0,
  Success = 1
};

/**
 * @brief valid the result of set net info
 * @return 1: Success
 *         0: Failed
*/
uint8_t validSetNetInfoResult(wiz_NetInfo* _set, wiz_NetInfo* _get)
{
  return (!memcmp(_set, _get, sizeof(wiz_NetInfo)));  // if same, memcmp return 0
}


void TcpClientInit(void)
{
	reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);	//注册临界区函数
  reg_wizchip_cs_cbfunc(W5500_Select, W5500_Unselect);
  reg_wizchip_spi_cbfunc(W5500_ReadByte, W5500_WriteByte);

  W5500_Restart();  // hardware restart through RESET pin

  ctlnetwork(CN_SET_NETINFO, (void*)&gSetNetInfo);  // set net info
  // maybe need delay
  ctlnetwork(CN_GET_NETINFO, (void*)&gGetNetInfo);  // get net info

  // W5500 has 8 channel, 32k buffer, 2 means 2KBytes
  uint8_t buffer_size_8channel_tx_rx[16] = {2, 2, 2, 2, 2, 2, 2, 2,  // 8 channel tx
                                            2, 2, 2, 2, 2, 2, 2, 2}; // 8 channel rx
  if(ctlwizchip(CW_INIT_WIZCHIP,(void*)buffer_size_8channel_tx_rx))
  {
    // failed
    
  }

  uint8_t sta = getSn_SR(SOCK_TCPS);
  if(sta == SOCK_CLOSED)
  {
    socket(SOCK_TCPS, Sn_MR_TCP, 5001, 0x00);
  }
  HAL_Delay(100);

}


void do_tcp_client(void)
{
	uint16_t len=0;
	switch(getSn_SR(SOCK_TCPS))														// 获取socket0的状态
	{
		case SOCK_INIT:															// Socket处于初始化完成(打开)状态	
				connect(SOCK_TCPS,remote_ip,remote_port);
		break;
		case SOCK_ESTABLISHED:											// Socket处于连接建立状态
				if(getSn_IR(SOCK_TCPS) & Sn_IR_CON)   					
				{
					setSn_IR(SOCK_TCPS, Sn_IR_CON);								// Sn_IR的CON位置1,通知W5500连接已建立
				}
				// 数据回环测试程序:数据从上位机服务器发给W5500,W5500接收到数据后再回给服务器
				len=getSn_RX_RSR(SOCK_TCPS);										// len=Socket0接收缓存中已接收和保存的数据大小					
				if(len)
				{
					recv(SOCK_TCPS,buff,len);		
					send(SOCK_TCPS,buff,len);							
				}											
		break;
		case SOCK_CLOSE_WAIT:												  // Socket处于等待关闭状态
			disconnect(SOCK_TCPS);	
		break;
		case SOCK_CLOSED:														// Socket处于关闭状态
				socket(SOCK_TCPS,Sn_MR_TCP,5001,0x00);		// 打开Socket0,打开一个本地端口
		break;
	}
}


//分析数据
void Analysis(uint8_t *buf)
{

}

3、修改CubeMx已生成的代码

(1)main.c

#include <stdio.h>
#include "MyTcpClient.h"

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_SPI1_Init();
  UDPinit();
  while (1)
  {
	do_tcp_client();
  }
}

四、硬件连接

STM32开发板 W5500模块
5V 5V
GND GND
PA4 SCS
PA6 MISO
PA5 SCK
PA7 MOSI
PB4 RST
PB5 INT

五、运行效果

(1)、将W5500和电脑通过网线直连

(2)、将电脑IP配置为192.168.1.2

(3)、ping 192.168.1.10(W5500的IP),能ping通。再使用网络调试助手给192.186.1.10的5001端口发送数据,之后网络调试助手能收到返回的数据。

相关推荐
MARIN_shen1 小时前
Marin说PCB之POC电路layout设计仿真案例---06
网络·单片机·嵌入式硬件·硬件工程·pcb工艺
Asa3191 小时前
STM32-按键扫描配置
stm32·单片机·嵌入式硬件
南城花随雪。2 小时前
单片机:实现驱动超声波(附带源码)
单片机·嵌入式硬件
嵌入式科普2 小时前
十三、从0开始卷出一个新项目之瑞萨RZN2L串口DMA接收不定长
c语言·stm32·瑞萨·e2studio·rzn2l
yutian060610 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
析木不会编程13 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉17 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名67717 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普18 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣18 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp