STM32 控制 W5500 以太网传输程序

STM32 控制 W5500 以太网模块的程序,包含 TCP 服务器/客户端、UDP 通信、HTTP 服务器、DHCP 客户端 等功能,支持以太网数据传输。

一、系统架构

复制代码
STM32 + W5500 以太网系统架构:
├── 硬件层
│   ├── STM32F103/F407 微控制器
│   ├── W5500 以太网模块
│   ├── RJ45 网口连接器
│   └── 网络变压器
├── 驱动层
│   ├── SPI 通信驱动
│   ├── W5500 寄存器配置
│   ├── Socket 管理
│   └── 中断处理
├── 协议层
│   ├── TCP/IP 协议栈
│   ├── DHCP 客户端
│   ├── DNS 解析
│   ├── HTTP 服务器
│   └── MQTT 客户端
├── 应用层
│   ├── 数据透传
│   ├── Web 服务器
│   ├── 远程控制
│   └── 固件升级
└── 工具层
    ├── 网络调试
    ├── 性能测试
    └── 故障诊断

二、硬件连接

2.1 W5500 引脚连接

复制代码
W5500模块    STM32F103   功能说明
SCS          PA4         SPI片选
SCLK         PA5         SPI时钟
MOSI         PA6         SPI主出从入
MISO         PA7         SPI主入从出
RST          PA8         复位引脚
INT          PA9         中断引脚
VCC          3.3V        电源
GND          GND         地

2.2 硬件配置

c 复制代码
// 硬件配置宏定义
#define W5500_SPI_PORT        SPI1
#define W5500_CS_PORT         GPIOA
#define W5500_CS_PIN          GPIO_Pin_4
#define W5500_RST_PORT        GPIOA
#define W5500_RST_PIN         GPIO_Pin_8
#define W5500_INT_PORT        GPIOA
#define W5500_INT_PIN         GPIO_Pin_9

// SPI配置
#define W5500_SPI_SPEED       42000000  // 42MHz
#define W5500_SPI_DATASIZE    SPI_DataSize_8b
#define W5500_SPI_MODE         SPI_Mode_0

三、核心代码实现

3.1 W5500 寄存器定义 (w5500_reg.h)

c 复制代码
#ifndef W5500_REG_H
#define W5500_REG_H

#include <stdint.h>

// W5500 通用寄存器地址
#define MR          0x0000      // 模式寄存器
#define GAR0        0x0001      // 网关地址寄存器 0
#define GAR1        0x0002      // 网关地址寄存器 1
#define GAR2        0x0003      // 网关地址寄存器 2
#define GAR3        0x0004      // 网关地址寄存器 3
#define SUBR0       0x0005      // 子网掩码寄存器 0
#define SUBR1       0x0006      // 子网掩码寄存器 1
#define SUBR2       0x0007      // 子网掩码寄存器 2
#define SUBR3       0x0008      // 子网掩码寄存器 3
#define SHAR0       0x0009      // 源硬件地址寄存器 0
#define SHAR1       0x000A      // 源硬件地址寄存器 1
#define SHAR2       0x000B      // 源硬件地址寄存器 2
#define SHAR3       0x000C      // 源硬件地址寄存器 3
#define SHAR4       0x000D      // 源硬件地址寄存器 4
#define SHAR5       0x000E      // 源硬件地址寄存器 5
#define SIPR0       0x000F      // 源IP地址寄存器 0
#define SIPR1       0x0010      // 源IP地址寄存器 1
#define SIPR2       0x0011      // 源IP地址寄存器 2
#define SIPR3       0x0012      // 源IP地址寄存器 3

// W5500 Socket 寄存器基地址
#define Sn_MR(n)    (0x0400 + (n) * 0x0100)  // Socket n 模式寄存器
#define Sn_CR(n)    (0x0401 + (n) * 0x0100)  // Socket n 命令寄存器
#define Sn_IR(n)    (0x0402 + (n) * 0x0100)  // Socket n 中断寄存器
#define Sn_SR(n)    (0x0403 + (n) * 0x0100)  // Socket n 状态寄存器
#define Sn_PORT(n)  (0x0404 + (n) * 0x0100)  // Socket n 源端口寄存器
#define Sn_DHAR(n)  (0x0406 + (n) * 0x0100)  // Socket n 目的硬件地址寄存器
#define Sn_DIPR(n)  (0x040C + (n) * 0x0100)  // Socket n 目的IP地址寄存器
#define Sn_DPORTR(n)(0x0410 + (n) * 0x0100)  // Socket n 目的端口寄存器
#define Sn_TX_FSR(n)(0x0420 + (n) * 0x0100)  // Socket n 发送空闲大小寄存器
#define Sn_TX_RD(n) (0x0422 + (n) * 0x0100)  // Socket n 发送读指针寄存器
#define Sn_TX_WR(n) (0x0424 + (n) * 0x0100)  // Socket n 发送写指针寄存器
#define Sn_RX_RSR(n)(0x0426 + (n) * 0x0100)  // Socket n 接收大小寄存器
#define Sn_RX_RD(n) (0x0428 + (n) * 0x0100)  // Socket n 接收读指针寄存器
#define Sn_RX_WR(n) (0x042A + (n) * 0x0100)  // Socket n 接收写指针寄存器

// Socket 模式寄存器定义
#define Sn_MR_CLOSE    0x00    // 关闭模式
#define Sn_MR_TCP      0x01    // TCP模式
#define Sn_MR_UDP      0x02    // UDP模式
#define Sn_MR_MACRAW   0x04    // MACRAW模式
#define Sn_MR_ND       0x20    // 无延迟确认
#define Sn_MR_MC       0x80    // 多播模式

// Socket 命令寄存器定义
#define Sn_CR_OPEN     0x01    // 打开Socket
#define Sn_CR_LISTEN   0x02    // 监听(TCP服务器)
#define Sn_CR_CONNECT  0x04    // 连接(TCP客户端)
#define Sn_CR_DISCON   0x08    // 断开连接
#define Sn_CR_CLOSE    0x10    // 关闭Socket
#define Sn_CR_SEND     0x20    // 发送数据
#define Sn_CR_SEND_MAC 0x21    // 发送MAC帧
#define Sn_CR_SEND_KEEP 0x22   // 发送保活包
#define Sn_CR_RECV     0x40    // 接收数据

// Socket 状态寄存器定义
#define Sn_SR_CLOSED   0x00    // 关闭
#define Sn_SR_INIT     0x13    // 初始化
#define Sn_SR_LISTEN   0x14    // 监听
#define Sn_SR_SYNSENT  0x15    // SYN发送
#define Sn_SR_SYNRECV  0x16    // SYN接收
#define Sn_SR_ESTABLISHED 0x17 // 建立连接
#define Sn_SR_FIN_WAIT 0x18    // FIN等待
#define Sn_SR_CLOSING  0x1A    // 关闭中
#define Sn_SR_TIME_WAIT 0x1B   // 时间等待
#define Sn_SR_CLOSE_WAIT 0x1C  // 关闭等待
#define Sn_SR_LAST_ACK 0x1D    // 最后ACK
#define Sn_SR_UDP      0x22    // UDP模式
#define Sn_SR_MACRAW   0x42    // MACRAW模式

// Socket 中断寄存器定义
#define Sn_IR_CON      0x01    // 连接中断
#define Sn_IR_DISCON   0x02    // 断开连接中断
#define Sn_IR_RECV     0x04    // 接收中断
#define Sn_IR_TIMEOUT  0x08    // 超时中断
#define Sn_IR_SENDOK   0x10    // 发送完成中断

// W5500 操作码
#define W5500_WRITE_OPCODE  0xF0
#define W5500_READ_OPCODE   0x0F

// Socket 数量
#define MAX_SOCKET_NUM      8
#define SOCKET_INVALID      -1

#endif // W5500_REG_H

3.2 W5500 SPI 驱动 (w5500_spi.c)

c 复制代码
#include "w5500_spi.h"
#include "stm32f10x_spi.h"
#include "stm32f10x_gpio.h"
#include "delay.h"

// SPI 初始化
void W5500_SPI_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;
    
    // 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
    
    // 配置 SPI 引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置 CS 引脚
    GPIO_InitStructure.GPIO_Pin = W5500_CS_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(W5500_CS_PORT, &GPIO_InitStructure);
    
    // 配置 RST 引脚
    GPIO_InitStructure.GPIO_Pin = W5500_RST_PIN;
    GPIO_Init(W5500_RST_PORT, &GPIO_InitStructure);
    
    // 配置 INT 引脚
    GPIO_InitStructure.GPIO_Pin = W5500_INT_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(W5500_INT_PORT, &GPIO_InitStructure);
    
    // SPI 配置
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);
    
    // 使能 SPI
    SPI_Cmd(SPI1, ENABLE);
    
    // 初始状态
    W5500_CS_HIGH();
    W5500_RST_HIGH();
}

// SPI 发送接收字节
uint8_t W5500_SPI_ReadWriteByte(uint8_t data)
{
    // 等待发送缓冲区为空
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    
    // 发送数据
    SPI_I2S_SendData(SPI1, data);
    
    // 等待接收完成
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    
    // 返回接收的数据
    return SPI_I2S_ReceiveData(SPI1);
}

// 写寄存器
void W5500_WriteReg(uint32_t addr, uint8_t data)
{
    W5500_CS_LOW();
    
    // 发送操作码和地址
    W5500_SPI_ReadWriteByte(W5500_WRITE_OPCODE);
    W5500_SPI_ReadWriteByte((addr >> 8) & 0xFF);
    W5500_SPI_ReadWriteByte(addr & 0xFF);
    W5500_SPI_ReadWriteByte(0x04);  // 写操作
    
    // 发送数据
    W5500_SPI_ReadWriteByte(data);
    
    W5500_CS_HIGH();
}

// 读寄存器
uint8_t W5500_ReadReg(uint32_t addr)
{
    uint8_t data;
    
    W5500_CS_LOW();
    
    // 发送操作码和地址
    W5500_SPI_ReadWriteByte(W5500_READ_OPCODE);
    W5500_SPI_ReadWriteByte((addr >> 8) & 0xFF);
    W5500_SPI_ReadWriteByte(addr & 0xFF);
    W5500_SPI_ReadWriteByte(0x01);  // 读操作
    
    // 读取数据
    data = W5500_SPI_ReadWriteByte(0x00);
    
    W5500_CS_HIGH();
    
    return data;
}

// 写缓冲区
void W5500_WriteBuffer(uint32_t addr, uint8_t *buf, uint16_t len)
{
    uint16_t i;
    
    W5500_CS_LOW();
    
    // 发送操作码和地址
    W5500_SPI_ReadWriteByte(W5500_WRITE_OPCODE);
    W5500_SPI_ReadWriteByte((addr >> 8) & 0xFF);
    W5500_SPI_ReadWriteByte(addr & 0xFF);
    W5500_SPI_ReadWriteByte(0x04);  // 写操作
    
    // 发送数据
    for (i = 0; i < len; i++) {
        W5500_SPI_ReadWriteByte(buf[i]);
    }
    
    W5500_CS_HIGH();
}

// 读缓冲区
void W5500_ReadBuffer(uint32_t addr, uint8_t *buf, uint16_t len)
{
    uint16_t i;
    
    W5500_CS_LOW();
    
    // 发送操作码和地址
    W5500_SPI_ReadWriteByte(W5500_READ_OPCODE);
    W5500_SPI_ReadWriteByte((addr >> 8) & 0xFF);
    W5500_SPI_ReadWriteByte(addr & 0xFF);
    W5500_SPI_ReadWriteByte(0x01);  // 读操作
    
    // 读取数据
    for (i = 0; i < len; i++) {
        buf[i] = W5500_SPI_ReadWriteByte(0x00);
    }
    
    W5500_CS_HIGH();
}

// 硬件复位
void W5500_HardwareReset(void)
{
    W5500_RST_LOW();
    Delay_ms(10);
    W5500_RST_HIGH();
    Delay_ms(100);
}

3.3 W5500 驱动 (w5500_driver.c)

c 复制代码
#include "w5500_driver.h"
#include "w5500_spi.h"
#include "w5500_reg.h"

// 网络配置
static Net_Config net_config = {
    .mac_addr = {0x00, 0x08, 0xDC, 0x11, 0x22, 0x33},
    .ip_addr = {192, 168, 1, 100},
    .sub_mask = {255, 255, 255, 0},
    .gw_addr = {192, 168, 1, 1},
    .dns_addr = {8, 8, 8, 8}
};

// Socket 状态
static Socket_Status socket_status[MAX_SOCKET_NUM];

// 初始化 W5500
uint8_t W5500_Init(void)
{
    uint8_t i;
    uint8_t chip_id[4];
    
    // 硬件复位
    W5500_HardwareReset();
    
    // 软件复位
    W5500_WriteReg(MR, 0x80);
    Delay_ms(10);
    
    // 读取芯片ID
    chip_id[0] = W5500_ReadReg(0x0000);
    chip_id[1] = W5500_ReadReg(0x0001);
    chip_id[2] = W5500_ReadReg(0x0002);
    chip_id[3] = W5500_ReadReg(0x0003);
    
    // 检查芯片ID
    if (chip_id[0] != 0x55 || chip_id[1] != 0x55 || 
        chip_id[2] != 0x55 || chip_id[3] != 0x55) {
        return W5500_ERR_INIT_FAILED;
    }
    
    // 设置MAC地址
    W5500_WriteBuffer(SHAR0, net_config.mac_addr, 6);
    
    // 设置IP地址
    W5500_WriteBuffer(SIPR0, net_config.ip_addr, 4);
    
    // 设置子网掩码
    W5500_WriteBuffer(SUBR0, net_config.sub_mask, 4);
    
    // 设置网关
    W5500_WriteBuffer(GAR0, net_config.gw_addr, 4);
    
    // 初始化Socket状态
    for (i = 0; i < MAX_SOCKET_NUM; i++) {
        socket_status[i].socket_num = i;
        socket_status[i].state = SOCKET_STATE_CLOSED;
        socket_status[i].protocol = PROTOCOL_TCP;
        socket_status[i].local_port = 0;
        socket_status[i].remote_port = 0;
        memset(socket_status[i].remote_ip, 0, 4);
        socket_status[i].rx_size = 0;
        socket_status[i].tx_size = 0;
    }
    
    return W5500_OK;
}

// 打开Socket
uint8_t W5500_SocketOpen(uint8_t socket_num, Protocol_Type protocol, uint16_t local_port)
{
    uint8_t ret;
    
    if (socket_num >= MAX_SOCKET_NUM) {
        return W5500_ERR_INVALID_SOCKET;
    }
    
    // 设置协议类型
    switch (protocol) {
        case PROTOCOL_TCP:
            W5500_WriteReg(Sn_MR(socket_num), Sn_MR_TCP);
            break;
        case PROTOCOL_UDP:
            W5500_WriteReg(Sn_MR(socket_num), Sn_MR_UDP);
            break;
        case PROTOCOL_MACRAW:
            W5500_WriteReg(Sn_MR(socket_num), Sn_MR_MACRAW);
            break;
        default:
            return W5500_ERR_INVALID_PROTOCOL;
    }
    
    // 设置本地端口
    W5500_WriteReg(Sn_PORT(socket_num), (local_port >> 8) & 0xFF);
    W5500_WriteReg(Sn_PORT(socket_num) + 1, local_port & 0xFF);
    
    // 打开Socket
    W5500_WriteReg(Sn_CR(socket_num), Sn_CR_OPEN);
    Delay_ms(5);
    
    // 检查状态
    ret = W5500_ReadReg(Sn_SR(socket_num));
    if (ret != Sn_SR_INIT && ret != Sn_SR_UDP && ret != Sn_SR_MACRAW) {
        return W5500_ERR_SOCKET_OPEN_FAILED;
    }
    
    socket_status[socket_num].state = SOCKET_STATE_OPEN;
    socket_status[socket_num].protocol = protocol;
    socket_status[socket_num].local_port = local_port;
    
    return W5500_OK;
}

// 关闭Socket
uint8_t W5500_SocketClose(uint8_t socket_num)
{
    if (socket_num >= MAX_SOCKET_NUM) {
        return W5500_ERR_INVALID_SOCKET;
    }
    
    // 关闭Socket
    W5500_WriteReg(Sn_CR(socket_num), Sn_CR_CLOSE);
    Delay_ms(5);
    
    socket_status[socket_num].state = SOCKET_STATE_CLOSED;
    
    return W5500_OK;
}

// TCP 服务器监听
uint8_t W5500_TcpServerListen(uint8_t socket_num, uint16_t local_port)
{
    uint8_t ret;
    
    // 打开Socket
    ret = W5500_SocketOpen(socket_num, PROTOCOL_TCP, local_port);
    if (ret != W5500_OK) {
        return ret;
    }
    
    // 开始监听
    W5500_WriteReg(Sn_CR(socket_num), Sn_CR_LISTEN);
    Delay_ms(5);
    
    // 检查状态
    ret = W5500_ReadReg(Sn_SR(socket_num));
    if (ret != Sn_SR_LISTEN) {
        return W5500_ERR_TCP_LISTEN_FAILED;
    }
    
    socket_status[socket_num].state = SOCKET_STATE_LISTEN;
    
    return W5500_OK;
}

// TCP 客户端连接
uint8_t W5500_TcpClientConnect(uint8_t socket_num, uint16_t local_port, 
                             uint8_t *remote_ip, uint16_t remote_port)
{
    uint8_t ret;
    
    // 打开Socket
    ret = W5500_SocketOpen(socket_num, PROTOCOL_TCP, local_port);
    if (ret != W5500_OK) {
        return ret;
    }
    
    // 设置远程IP和端口
    W5500_WriteBuffer(Sn_DIPR(socket_num), remote_ip, 4);
    W5500_WriteReg(Sn_DPORTR(socket_num), (remote_port >> 8) & 0xFF);
    W5500_WriteReg(Sn_DPORTR(socket_num) + 1, remote_port & 0xFF);
    
    // 发起连接
    W5500_WriteReg(Sn_CR(socket_num), Sn_CR_CONNECT);
    Delay_ms(100);
    
    // 检查连接状态
    ret = W5500_ReadReg(Sn_SR(socket_num));
    if (ret != Sn_SR_ESTABLISHED) {
        return W5500_ERR_TCP_CONNECT_FAILED;
    }
    
    socket_status[socket_num].state = SOCKET_STATE_CONNECTED;
    memcpy(socket_status[socket_num].remote_ip, remote_ip, 4);
    socket_status[socket_num].remote_port = remote_port;
    
    return W5500_OK;
}

// 发送数据
uint16_t W5500_SendData(uint8_t socket_num, uint8_t *data, uint16_t len)
{
    uint16_t free_size;
    uint16_t tx_wr;
    uint16_t i;
    
    if (socket_num >= MAX_SOCKET_NUM || data == NULL || len == 0) {
        return 0;
    }
    
    // 检查Socket状态
    if (socket_status[socket_num].state != SOCKET_STATE_CONNECTED &&
        socket_status[socket_num].protocol != PROTOCOL_UDP) {
        return 0;
    }
    
    // 获取发送空闲大小
    free_size = (W5500_ReadReg(Sn_TX_FSR(socket_num)) << 8) | 
                W5500_ReadReg(Sn_TX_FSR(socket_num) + 1);
    
    if (free_size < len) {
        return 0;  // 缓冲区不足
    }
    
    // 获取发送写指针
    tx_wr = (W5500_ReadReg(Sn_TX_WR(socket_num)) << 8) | 
            W5500_ReadReg(Sn_TX_WR(socket_num) + 1);
    
    // 写入数据到发送缓冲区
    for (i = 0; i < len; i++) {
        W5500_WriteReg(tx_wr + i, data[i]);
    }
    
    // 更新发送写指针
    tx_wr += len;
    W5500_WriteReg(Sn_TX_WR(socket_num), (tx_wr >> 8) & 0xFF);
    W5500_WriteReg(Sn_TX_WR(socket_num) + 1, tx_wr & 0xFF);
    
    // 发送数据
    W5500_WriteReg(Sn_CR(socket_num), Sn_CR_SEND);
    Delay_ms(1);
    
    return len;
}

// 接收数据
uint16_t W5500_ReceiveData(uint8_t socket_num, uint8_t *buffer, uint16_t buffer_size)
{
    uint16_t rx_size;
    uint16_t rx_rd;
    uint16_t i;
    
    if (socket_num >= MAX_SOCKET_NUM || buffer == NULL || buffer_size == 0) {
        return 0;
    }
    
    // 获取接收数据大小
    rx_size = (W5500_ReadReg(Sn_RX_RSR(socket_num)) << 8) | 
              W5500_ReadReg(Sn_RX_RSR(socket_num) + 1);
    
    if (rx_size == 0) {
        return 0;  // 没有数据
    }
    
    // 限制接收大小
    if (rx_size > buffer_size) {
        rx_size = buffer_size;
    }
    
    // 获取接收读指针
    rx_rd = (W5500_ReadReg(Sn_RX_RD(socket_num)) << 8) | 
            W5500_ReadReg(Sn_RX_RD(socket_num) + 1);
    
    // 从接收缓冲区读取数据
    for (i = 0; i < rx_size; i++) {
        buffer[i] = W5500_ReadReg(rx_rd + i);
    }
    
    // 更新接收读指针
    rx_rd += rx_size;
    W5500_WriteReg(Sn_RX_RD(socket_num), (rx_rd >> 8) & 0xFF);
    W5500_WriteReg(Sn_RX_RD(socket_num) + 1, rx_rd & 0xFF);
    
    // 接收数据
    W5500_WriteReg(Sn_CR(socket_num), Sn_CR_RECV);
    Delay_ms(1);
    
    return rx_size;
}

// 获取Socket状态
Socket_Status* W5500_GetSocketStatus(uint8_t socket_num)
{
    if (socket_num >= MAX_SOCKET_NUM) {
        return NULL;
    }
    
    return &socket_status[socket_num];
}

3.4 TCP/UDP 应用层 (network_app.c)

c 复制代码
#include "network_app.h"
#include "w5500_driver.h"
#include "w5500_reg.h"

// 应用配置
static App_Config app_config = {
    .tcp_server_port = 8080,
    .udp_local_port = 8081,
    .udp_remote_port = 8082,
    .http_port = 80,
    .dhcp_enabled = 1
};

// TCP 服务器处理
void TCP_ServerTask(void)
{
    static uint8_t socket_num = 0;
    static uint8_t buffer[1024];
    uint16_t rx_len;
    
    // 初始化TCP服务器
    if (W5500_TcpServerListen(socket_num, app_config.tcp_server_port) != W5500_OK) {
        return;
    }
    
    while (1) {
        Socket_Status *status = W5500_GetSocketStatus(socket_num);
        
        if (status == NULL) {
            break;
        }
        
        switch (status->state) {
            case SOCKET_STATE_LISTEN:
                // 等待客户端连接
                break;
                
            case SOCKET_STATE_CONNECTED:
                // 接收数据
                rx_len = W5500_ReceiveData(socket_num, buffer, sizeof(buffer));
                if (rx_len > 0) {
                    // 处理接收到的数据
                    Process_TCP_Data(buffer, rx_len);
                    
                    // 回显数据
                    W5500_SendData(socket_num, buffer, rx_len);
                }
                break;
                
            case SOCKET_STATE_CLOSED:
                // 重新打开Socket
                W5500_TcpServerListen(socket_num, app_config.tcp_server_port);
                break;
                
            default:
                break;
        }
        
        Delay_ms(10);
    }
}

// TCP 客户端处理
void TCP_ClientTask(void)
{
    static uint8_t socket_num = 1;
    static uint8_t buffer[1024];
    uint8_t remote_ip[4] = {192, 168, 1, 50};
    uint16_t remote_port = 8080;
    
    // 连接到TCP服务器
    if (W5500_TcpClientConnect(socket_num, 5000, remote_ip, remote_port) != W5500_OK) {
        return;
    }
    
    while (1) {
        Socket_Status *status = W5500_GetSocketStatus(socket_num);
        
        if (status == NULL) {
            break;
        }
        
        if (status->state == SOCKET_STATE_CONNECTED) {
            // 发送数据
            char *message = "Hello from STM32!\r\n";
            W5500_SendData(socket_num, (uint8_t*)message, strlen(message));
            
            // 接收响应
            uint16_t rx_len = W5500_ReceiveData(socket_num, buffer, sizeof(buffer));
            if (rx_len > 0) {
                Process_TCP_Data(buffer, rx_len);
            }
        }
        
        Delay_ms(1000);
    }
}

// UDP 通信处理
void UDP_Task(void)
{
    static uint8_t socket_num = 2;
    static uint8_t buffer[1024];
    uint8_t remote_ip[4] = {192, 168, 1, 255};  // 广播地址
    uint16_t remote_port = 8082;
    
    // 打开UDP Socket
    if (W5500_SocketOpen(socket_num, PROTOCOL_UDP, app_config.udp_local_port) != W5500_OK) {
        return;
    }
    
    while (1) {
        // 发送UDP数据
        char *message = "UDP Broadcast from STM32!\r\n";
        W5500_SendData(socket_num, (uint8_t*)message, strlen(message));
        
        // 接收UDP数据
        uint16_t rx_len = W5500_ReceiveData(socket_num, buffer, sizeof(buffer));
        if (rx_len > 0) {
            Process_UDP_Data(buffer, rx_len);
        }
        
        Delay_ms(2000);
    }
}

// HTTP 服务器处理
void HTTP_ServerTask(void)
{
    static uint8_t socket_num = 3;
    static uint8_t buffer[1024];
    uint16_t rx_len;
    
    // 启动HTTP服务器
    if (W5500_TcpServerListen(socket_num, app_config.http_port) != W5500_OK) {
        return;
    }
    
    while (1) {
        Socket_Status *status = W5500_GetSocketStatus(socket_num);
        
        if (status == NULL) {
            break;
        }
        
        if (status->state == SOCKET_STATE_CONNECTED) {
            rx_len = W5500_ReceiveData(socket_num, buffer, sizeof(buffer));
            if (rx_len > 0) {
                // 解析HTTP请求
                if (strstr((char*)buffer, "GET /")) {
                    // 发送HTTP响应
                    char http_response[] = 
                        "HTTP/1.1 200 OK\r\n"
                        "Content-Type: text/html\r\n"
                        "Connection: close\r\n"
                        "\r\n"
                        "<html><body>"
                        "<h1>STM32 W5500 Web Server</h1>"
                        "<p>System Status: Running</p>"
                        "<p>IP Address: 192.168.1.100</p>"
                        "</body></html>";
                    
                    W5500_SendData(socket_num, (uint8_t*)http_response, strlen(http_response));
                }
            }
        }
        
        Delay_ms(10);
    }
}

// DHCP 客户端处理
void DHCP_ClientTask(void)
{
    static uint8_t socket_num = 4;
    static uint8_t buffer[1024];
    
    if (!app_config.dhcp_enabled) {
        return;
    }
    
    // DHCP 发现
    // 这里需要实现完整的DHCP协议,包括:
    // 1. DHCP Discover
    // 2. DHCP Offer
    // 3. DHCP Request
    // 4. DHCP ACK
    
    // 简化版本:发送DHCP Discover
    uint8_t dhcp_discover[] = {
        0x01, 0x01, 0x06, 0x00,  // 操作码,硬件类型,跳数
        0x00, 0x00, 0x00, 0x00,  // 事务ID
        // ... 更多DHCP字段
    };
    
    if (W5500_SocketOpen(socket_num, PROTOCOL_UDP, 68) == W5500_OK) {
        W5500_SendData(socket_num, dhcp_discover, sizeof(dhcp_discover));
    }
}

// 数据处理函数
void Process_TCP_Data(uint8_t *data, uint16_t len)
{
    // 处理TCP数据
    printf("Received TCP data: %s\n", data);
    
    // 根据数据内容执行相应操作
    if (strstr((char*)data, "LED_ON")) {
        // 打开LED
        GPIO_SetBits(GPIOC, GPIO_Pin_13);
    } else if (strstr((char*)data, "LED_OFF")) {
        // 关闭LED
        GPIO_ResetBits(GPIOC, GPIO_Pin_13);
    }
}

void Process_UDP_Data(uint8_t *data, uint16_t len)
{
    // 处理UDP数据
    printf("Received UDP data: %s\n", data);
}

// 网络初始化
uint8_t Network_Init(void)
{
    uint8_t ret;
    
    // 初始化W5500
    ret = W5500_Init();
    if (ret != W5500_OK) {
        printf("W5500 init failed: %d\n", ret);
        return ret;
    }
    
    printf("W5500 initialized successfully\n");
    printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", 
           net_config.mac_addr[0], net_config.mac_addr[1], net_config.mac_addr[2],
           net_config.mac_addr[3], net_config.mac_addr[4], net_config.mac_addr[5]);
    printf("IP: %d.%d.%d.%d\n", 
           net_config.ip_addr[0], net_config.ip_addr[1], 
           net_config.ip_addr[2], net_config.ip_addr[3]);
    
    return W5500_OK;
}

3.5 主程序 (main.c)

c 复制代码
#include "stm32f10x.h"
#include "w5500_spi.h"
#include "w5500_driver.h"
#include "network_app.h"
#include "delay.h"
#include "usart.h"

// 系统状态
typedef enum {
    SYS_INIT = 0,
    SYS_NETWORK_INIT,
    SYS_RUNNING,
    SYS_ERROR
} System_State;

System_State system_state = SYS_INIT;

// 任务标志
uint8_t tcp_server_task_running = 0;
uint8_t tcp_client_task_running = 0;
uint8_t udp_task_running = 0;
uint8_t http_server_task_running = 0;

int main(void)
{
    // 系统初始化
    System_Init();
    
    // 延时初始化
    Delay_Init();
    
    // 串口初始化
    USART_Init(115200);
    printf("STM32 W5500 Ethernet System Starting...\n");
    
    // GPIO 初始化
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
    system_state = SYS_NETWORK_INIT;
    
    while (1) {
        switch (system_state) {
            case SYS_NETWORK_INIT:
                // 初始化网络
                if (Network_Init() == W5500_OK) {
                    system_state = SYS_RUNNING;
                    printf("System running...\n");
                } else {
                    system_state = SYS_ERROR;
                    printf("Network initialization failed!\n");
                }
                break;
                
            case SYS_RUNNING:
                // 启动TCP服务器任务
                if (!tcp_server_task_running) {
                    tcp_server_task_running = 1;
                    printf("Starting TCP Server...\n");
                    TCP_ServerTask();
                }
                
                // 启动UDP任务
                if (!udp_task_running) {
                    udp_task_running = 1;
                    printf("Starting UDP Task...\n");
                    UDP_Task();
                }
                
                // 启动HTTP服务器任务
                if (!http_server_task_running) {
                    http_server_task_running = 1;
                    printf("Starting HTTP Server...\n");
                    HTTP_ServerTask();
                }
                
                // 主循环处理
                GPIO_SetBits(GPIOC, GPIO_Pin_13);  // LED亮
                Delay_ms(500);
                GPIO_ResetBits(GPIOC, GPIO_Pin_13); // LED灭
                Delay_ms(500);
                
                break;
                
            case SYS_ERROR:
                printf("System error!\n");
                Delay_ms(1000);
                break;
                
            default:
                break;
        }
    }
}

四、编译与部署

4.1 Keil 工程配置

makefile 复制代码
# Keil 工程配置
Target: STM32F103C8T6
Device: STM32F103C8
C/C++:
  Include Paths: 
    .\
    .\inc
    .\User
    .\Hardware
  Define: STM32F10X_MD, USE_STDPERIPH_DRIVER
Linker:
  Scatter File: STM32_FLASH.sct
Debug:
  Debugger: ST-Link Debugger

4.2 网络测试工具

python 复制代码
# Python 网络测试脚本
import socket
import time

def test_tcp_client():
    """测试TCP客户端"""
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect(('192.168.1.100', 8080))
    
    for i in range(10):
        message = f"Hello STM32 {i}\r\n"
        client_socket.send(message.encode())
        response = client_socket.recv(1024)
        print(f"Response: {response.decode()}")
        time.sleep(1)
    
    client_socket.close()

def test_udp():
    """测试UDP通信"""
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    for i in range(5):
        message = f"UDP Message {i}"
        udp_socket.sendto(message.encode(), ('192.168.1.100', 8081))
        time.sleep(1)
    
    udp_socket.close()

def test_http():
    """测试HTTP服务器"""
    import requests
    response = requests.get('http://192.168.1.100')
    print(f"HTTP Response: {response.text}")

if __name__ == "__main__":
    test_tcp_client()
    # test_udp()
    # test_http()

参考代码 STM32控制W5500模块实现以太网传输 www.youwenfan.com/contentcsv/72214.html

五、性能优化与调试

5.1 性能优化建议

  1. SPI 速度优化:使用最高 42MHz SPI 时钟
  2. 中断处理:使用 W5500 中断引脚减少轮询
  3. DMA 传输:使用 DMA 进行大数据传输
  4. 内存管理:优化缓冲区分配

5.2 调试技巧

c 复制代码
// 调试输出宏
#define NET_DEBUG(fmt, ...) printf("[NET] " fmt, ##__VA_ARGS__)

// 网络状态监控
void Net_StatusMonitor(void)
{
    uint8_t i;
    for (i = 0; i < MAX_SOCKET_NUM; i++) {
        Socket_Status *status = W5500_GetSocketStatus(i);
        if (status) {
            NET_DEBUG("Socket %d: State=%d, RX=%d, TX=%d\n", 
                     i, status->state, status->rx_size, status->tx_size);
        }
    }
}

5.3 常见问题解决

问题 原因 解决方法
无法ping通 IP配置错误 检查IP、子网掩码、网关设置
连接失败 防火墙阻挡 关闭防火墙或添加例外
数据传输慢 SPI速度低 提高SPI时钟频率
经常断线 网络不稳定 增加心跳包机制

这个STM32 + W5500 以太网程序支持多种网络协议和应用场景,可以直接用于工业控制、物联网设备、远程监控系统等项目开发。

相关推荐
念一不念二1 小时前
【SSD】三维闪存 异步时序 同步时序
嵌入式硬件
LCG元1 小时前
STM32实战:基于STM32F103的车内防窒息系统(红外检测+GSM报警)
stm32·单片机·嵌入式硬件
XTIOT6661 小时前
俄罗斯诚信标签Chestny ZNAK技术约束分析与智能化应对思路
大数据·人工智能·嵌入式硬件·物联网
崇山峻岭之间1 小时前
单片机串口实验
单片机·嵌入式硬件
爱的si念1 小时前
Zephyr 在 Nucleo G474RE 的完整编译与模块提取指南
stm32·单片机·嵌入式硬件
深圳市九鼎创展科技1 小时前
九鼎创展 X7110 开发板(JH7110):国产 RISC-V 多媒体平台全解析
大数据·linux·人工智能·嵌入式硬件·ubuntu·risc-v
Jason_zhao_MR2 小时前
RK3506工业网关:如何打通现场采集、无线传输与行业规约接入?
linux·嵌入式硬件·物联网·系统架构·嵌入式
m0_377108142 小时前
stm32--I2C
stm32·单片机·嵌入式硬件
发光小北2 小时前
单通道串口服务器如何应用?
运维·服务器·单片机