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 性能优化建议
- SPI 速度优化:使用最高 42MHz SPI 时钟
- 中断处理:使用 W5500 中断引脚减少轮询
- DMA 传输:使用 DMA 进行大数据传输
- 内存管理:优化缓冲区分配
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 以太网程序支持多种网络协议和应用场景,可以直接用于工业控制、物联网设备、远程监控系统等项目开发。