文章目录
-
- 一、前言
-
- [1.1 技术背景](#1.1 技术背景)
- [1.2 本文目标](#1.2 本文目标)
- [1.3 技术栈](#1.3 技术栈)
- 二、环境准备
-
- [2.1 硬件准备](#2.1 硬件准备)
- [2.2 软件安装](#2.2 软件安装)
-
- [2.2.1 安装STM32CubeIDE](#2.2.1 安装STM32CubeIDE)
- [2.2.2 下载LWIP源码](#2.2.2 下载LWIP源码)
- 三、项目创建与配置
-
- [3.1 创建STM32CubeIDE工程](#3.1 创建STM32CubeIDE工程)
- [3.2 配置以太网外设](#3.2 配置以太网外设)
- [3.3 配置LWIP](#3.3 配置LWIP)
- [3.4 生成代码](#3.4 生成代码)
- 四、LWIP移植与配置
-
- [4.1 工程结构](#4.1 工程结构)
- [4.2 配置lwipopts.h](#4.2 配置lwipopts.h)
- [4.3 实现TCP Server](#4.3 实现TCP Server)
- [4.4 主程序实现](#4.4 主程序实现)
- [4.5 系统架构流程图](#4.5 系统架构流程图)
- 五、编译与下载
-
- [5.1 编译工程](#5.1 编译工程)
- [5.2 网络配置](#5.2 网络配置)
- [5.3 测试连接](#5.3 测试连接)
- 六、故障排查与问题解决
-
- [6.1 网络连接问题](#6.1 网络连接问题)
- [6.2 内存问题](#6.2 内存问题)
- 七、总结
-
- [7.1 核心知识点回顾](#7.1 核心知识点回顾)
- [7.2 扩展学习方向](#7.2 扩展学习方向)
- [7.3 学习资源](#7.3 学习资源)
一、前言
1.1 技术背景
在物联网和工业控制领域,以太网通信是实现设备互联的重要手段。STM32F407系列微控制器集成了MAC(媒体访问控制器),配合外部PHY芯片可以实现以太网通信。LWIP(Lightweight IP)是一个开源的TCP/IP协议栈,专为嵌入式系统设计,具有资源占用少、功能完善等特点。
本文将介绍如何在STM32F407上移植LWIP协议栈,实现TCP Server功能,用于接收客户端连接、处理数据请求。
1.2 本文目标
通过本教程,你将学会:
- STM32F407以太网外设的配置
- LWIP协议栈的移植与配置
- TCP Server的实现
- 网络数据包的收发处理
- 多客户端连接管理
1.3 技术栈
硬件平台:
- STM32F407VET6(主控芯片)
- LAN8720(以太网PHY芯片)
- RJ45网络接口
软件环境:
- STM32CubeIDE v1.10.0+
- LWIP v2.1.2+
- HAL库
二、环境准备
2.1 硬件准备
| 设备 | 数量 | 说明 |
|---|---|---|
| STM32F407VET6开发板 | 1块 | 主控芯片,168MHz |
| LAN8720模块 | 1个 | 以太网PHY |
| 网线 | 1根 | 连接路由器或PC |
| ST-Link V2 | 1个 | 程序下载与调试 |
硬件连接图:
STM32F407VET6 LAN8720
PA1 ─────────── ETH_RMII_REF_CLK
PA2 ─────────── ETH_MDIO
PA7 ─────────── ETH_RMII_CRS_DV
PB11 ─────────── ETH_RMII_TX_EN
PB12 ─────────── ETH_RMII_TXD0
PB13 ─────────── ETH_RMII_TXD1
PC1 ─────────── ETH_MDC
PC4 ─────────── ETH_RMII_RXD0
PC5 ─────────── ETH_RMII_RXD1
3.3V ─────────── VCC
GND ─────────── GND
PA0 ─────────── ETH_RST (PHY复位)
2.2 软件安装
2.2.1 安装STM32CubeIDE
- 访问ST官网下载STM32CubeIDE
- 安装并配置HAL库
2.2.2 下载LWIP源码
LWIP已集成在STM32CubeMX中,无需单独下载。
三、项目创建与配置
3.1 创建STM32CubeIDE工程
- 打开STM32CubeIDE
- 创建新工程,选择STM32F407VET6
- 工程名称:STM32_LWIP_TCP_Server
3.2 配置以太网外设
-
打开
.ioc文件 -
配置ETH外设:
- 选择
ETH->Mode->RMII
- 选择
-
配置引脚:
PA1 - ETH_RMII_REF_CLK
PA2 - ETH_MDIO
PA7 - ETH_RMII_CRS_DV
PB11 - ETH_RMII_TX_EN
PB12 - ETH_RMII_TXD0
PB13 - ETH_RMII_TXD1
PC1 - ETH_MDC
PC4 - ETH_RMII_RXD0
PC5 - ETH_RMII_RXD1
PA0 - GPIO_Output (PHY复位)
3.3 配置LWIP
- 在CubeMX中,点击
Middleware -> LWIP - 启用LWIP
- 配置参数:
General Settings:
LWIP_DHCP: Enabled
LWIP_DNS: Enabled
MEM_SIZE: 16000
MEMP_NUM_PBUF: 16
MEMP_NUM_UDP_PCB: 4
MEMP_NUM_TCP_PCB: 5
MEMP_NUM_TCP_PCB_LISTEN: 8
MEMP_NUM_TCP_SEG: 16
IP配置:
IP_ADDR: 192.168.1.100
NETMASK: 255.255.255.0
GATEWAY: 192.168.1.1
3.4 生成代码
- 点击
Project -> Generate Code - 等待代码生成完成
四、LWIP移植与配置
4.1 工程结构
STM32_LWIP_TCP_Server/
├── Core/
│ ├── Inc/
│ │ └── main.h
│ └── Src/
│ └── main.c
├── LWIP/
│ ├── App/
│ │ └── lwip.c/.h
│ └── Target/
│ └── ethernetif.c/.h
└── Middlewares/
└── Third_Party/
└── LwIP/
└── ...
4.2 配置lwipopts.h
📝 修改文件:
LWIP/Target/lwipopts.h
c
/*
* lwipopts.h - LWIP配置文件
*/
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
/* 平台相关配置 */
#define LWIP_PLATFORM_BYTESWAP 0
#define SYS_LIGHTWEIGHT_PROT 1
/* 内存配置 */
#define MEM_SIZE (16 * 1024)
#define MEMP_NUM_PBUF 16
#define MEMP_NUM_UDP_PCB 4
#define MEMP_NUM_TCP_PCB 5
#define MEMP_NUM_TCP_PCB_LISTEN 8
#define MEMP_NUM_TCP_SEG 16
#define MEMP_NUM_SYS_TIMEOUT 8
#define MEMP_NUM_NETBUF 8
#define MEMP_NUM_NETCONN 8
/* Pbuf配置 */
#define PBUF_POOL_SIZE 16
#define PBUF_POOL_BUFSIZE 1524
/* TCP配置 */
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN (4 * TCP_SND_QUEUELEN)
#define TCP_WND (8 * TCP_MSS)
#define TCP_OVERSIZE TCP_MSS
/* IP配置 */
#define LWIP_IPV4 1
#define IP_REASSEMBLY 0
#define IP_FRAG 0
/* ARP配置 */
#define ARP_TABLE_SIZE 10
#define ARP_QUEUEING 0
/* DHCP配置 */
#define LWIP_DHCP 1
#define LWIP_AUTOIP 0
#define LWIP_DHCP_AUTOIP_COOP 0
/* DNS配置 */
#define LWIP_DNS 1
/* UDP配置 */
#define LWIP_UDP 1
#define UDP_TTL 255
/* TCP配置 */
#define LWIP_TCP 1
#define TCP_TTL 255
#define TCP_QUEUE_OOSEQ 0
/* 统计 */
#define LWIP_STATS 0
#define LWIP_PROVIDE_ERRNO 1
/* 检查 */
#define LWIP_CHECKSUM_ON_COPY 0
/* 钩子函数 */
#define LWIP_CALLBACK_API 1
/* 线程配置 */
#define TCPIP_THREAD_STACK_SIZE 1024
#define TCPIP_THREAD_PRIO 3
#define TCPIP_MBOX_SIZE 16
/* 底层接口 */
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
/* Socket API */
#define LWIP_SOCKET 0
#define LWIP_NETCONN 1
/* 调试 */
#define LWIP_DEBUG 0
#endif /* __LWIPOPTS_H__ */
4.3 实现TCP Server
📄 创建文件:
Core/Src/tcp_server.c
c
/*
* tcp_server.c - TCP Server实现
*
* 功能:
* - TCP服务器初始化
* - 多客户端连接管理
* - 数据接收与发送
* - 连接状态监控
*/
#include "tcp_server.h"
#include "lwip/tcp.h"
#include "lwip/api.h"
#include <string.h>
#include <stdio.h>
/* 服务器配置 */
#define TCP_SERVER_PORT 8080
#define TCP_MAX_CLIENTS 5
#define TCP_RX_BUFFER_SIZE 1024
/* 客户端状态 */
typedef enum {
CLIENT_STATE_IDLE = 0,
CLIENT_STATE_CONNECTED,
CLIENT_STATE_CLOSING
} client_state_t;
/* 客户端结构体 */
typedef struct {
struct tcp_pcb *pcb;
client_state_t state;
uint8_t rx_buffer[TCP_RX_BUFFER_SIZE];
uint16_t rx_len;
uint32_t rx_count;
uint32_t tx_count;
} tcp_client_t;
/* 服务器状态 */
static struct tcp_pcb *server_pcb = NULL;
static tcp_client_t clients[TCP_MAX_CLIENTS];
static uint8_t client_count = 0;
/* 统计信息 */
static uint32_t total_connections = 0;
static uint32_t total_rx_bytes = 0;
static uint32_t total_tx_bytes = 0;
/* 函数声明 */
static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err);
static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
static void tcp_server_error(void *arg, err_t err);
static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb);
static err_t tcp_server_process(tcp_client_t *client, struct tcp_pcb *tpcb);
static void tcp_server_close(tcp_client_t *client, struct tcp_pcb *tpcb);
/* 查找空闲客户端槽 */
static tcp_client_t* find_free_client_slot(void)
{
for (int i = 0; i < TCP_MAX_CLIENTS; i++) {
if (clients[i].state == CLIENT_STATE_IDLE) {
return &clients[i];
}
}
return NULL;
}
/* 根据PCB查找客户端 */
static tcp_client_t* find_client_by_pcb(struct tcp_pcb *pcb)
{
for (int i = 0; i < TCP_MAX_CLIENTS; i++) {
if (clients[i].pcb == pcb) {
return &clients[i];
}
}
return NULL;
}
/* TCP Server初始化 */
err_t tcp_server_init(void)
{
err_t err;
/* 初始化客户端数组 */
memset(clients, 0, sizeof(clients));
/* 创建TCP控制块 */
server_pcb = tcp_new();
if (server_pcb == NULL) {
printf("[TCP] Failed to create PCB\\n");
return ERR_MEM;
}
/* 绑定端口 */
err = tcp_bind(server_pcb, IP_ADDR_ANY, TCP_SERVER_PORT);
if (err != ERR_OK) {
printf("[TCP] Failed to bind port %d, err=%d\\n", TCP_SERVER_PORT, err);
tcp_close(server_pcb);
return err;
}
/* 开始监听 */
server_pcb = tcp_listen(server_pcb);
if (server_pcb == NULL) {
printf("[TCP] Failed to listen\\n");
return ERR_MEM;
}
/* 设置接受回调 */
tcp_accept(server_pcb, tcp_server_accept);
printf("[TCP] Server started on port %d\\n", TCP_SERVER_PORT);
printf("[TCP] Max clients: %d\\n", TCP_MAX_CLIENTS);
return ERR_OK;
}
/* 接受连接回调 */
static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
(void)arg;
if (err != ERR_OK || newpcb == NULL) {
return ERR_VAL;
}
/* 查找空闲客户端槽 */
tcp_client_t *client = find_free_client_slot();
if (client == NULL) {
printf("[TCP] Max clients reached, rejecting connection\\n");
tcp_close(newpcb);
return ERR_MEM;
}
/* 初始化客户端 */
memset(client, 0, sizeof(tcp_client_t));
client->pcb = newpcb;
client->state = CLIENT_STATE_CONNECTED;
client_count++;
total_connections++;
/* 设置回调函数 */
tcp_arg(newpcb, client);
tcp_recv(newpcb, tcp_server_recv);
tcp_sent(newpcb, tcp_server_sent);
tcp_err(newpcb, tcp_server_error);
tcp_poll(newpcb, tcp_server_poll, 2); /* 每1秒轮询 */
/* 设置接收缓冲区 */
tcp_nagle_disable(newpcb);
/* 获取客户端IP */
ip_addr_t client_ip = newpcb->remote_ip;
printf("[TCP] Client connected from %d.%d.%d.%d:%d\\n",
ip4_addr1(&client_ip), ip4_addr2(&client_ip),
ip4_addr3(&client_ip), ip4_addr4(&client_ip),
newpcb->remote_port);
printf("[TCP] Active clients: %d/%d\\n", client_count, TCP_MAX_CLIENTS);
/* 发送欢迎消息 */
const char *welcome = "Welcome to STM32 TCP Server!\\r\\n";
tcp_write(newpcb, welcome, strlen(welcome), TCP_WRITE_FLAG_COPY);
return ERR_OK;
}
/* 接收数据回调 */
static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
tcp_client_t *client = (tcp_client_t *)arg;
if (p == NULL) {
/* 连接关闭 */
printf("[TCP] Client disconnected\\n");
tcp_server_close(client, tpcb);
return ERR_OK;
}
if (err != ERR_OK) {
pbuf_free(p);
return err;
}
/* 接收数据 */
uint16_t len = p->tot_len;
if (client->rx_len + len > TCP_RX_BUFFER_SIZE) {
printf("[TCP] RX buffer overflow\\n");
pbuf_free(p);
return ERR_MEM;
}
pbuf_copy_partial(p, &client->rx_buffer[client->rx_len], len, 0);
client->rx_len += len;
client->rx_count += len;
total_rx_bytes += len;
/* 确认接收 */
tcp_recved(tpcb, len);
pbuf_free(p);
/* 处理数据 */
return tcp_server_process(client, tpcb);
}
/* 数据处理 */
static err_t tcp_server_process(tcp_client_t *client, struct tcp_pcb *tpcb)
{
/* 查找换行符 */
char *newline = memchr(client->rx_buffer, '\\n', client->rx_len);
if (newline == NULL) {
/* 等待更多数据 */
return ERR_OK;
}
/* 计算命令长度 */
uint16_t cmd_len = newline - (char *)client->rx_buffer + 1;
/* 提取命令 */
char cmd[64];
uint16_t copy_len = cmd_len < sizeof(cmd) - 1 ? cmd_len : sizeof(cmd) - 1;
memcpy(cmd, client->rx_buffer, copy_len);
cmd[copy_len] = '\\0';
/* 移除末尾的换行符 */
char *cr = strchr(cmd, '\\r');
if (cr) *cr = '\\0';
char *lf = strchr(cmd, '\\n');
if (lf) *lf = '\\0';
printf("[TCP] Received: %s\\n", cmd);
/* 处理命令 */
char response[256];
if (strcasecmp(cmd, "help") == 0) {
snprintf(response, sizeof(response),
"Commands:\\r\\n"
" help - Show this help\\r\\n"
" status - Show server status\\r\\n"
" info - Show system info\\r\\n"
" led on - Turn LED on\\r\\n"
" led off - Turn LED off\\r\\n"
" time - Get current time\\r\\n"
" echo - Echo test\\r\\n"
" quit - Disconnect\\r\\n");
}
else if (strcasecmp(cmd, "status") == 0) {
snprintf(response, sizeof(response),
"Server Status:\\r\\n"
" Active clients: %d/%d\\r\\n"
" Total connections: %lu\\r\\n"
" RX bytes: %lu\\r\\n"
" TX bytes: %lu\\r\\n",
client_count, TCP_MAX_CLIENTS,
total_connections, total_rx_bytes, total_tx_bytes);
}
else if (strcasecmp(cmd, "info") == 0) {
snprintf(response, sizeof(response),
"System Info:\\r\\n"
" MCU: STM32F407VET6\\r\\n"
" Clock: 168MHz\\r\\n"
" LWIP Version: %s\\r\\n",
LWIP_VERSION_STRING);
}
else if (strcasecmp(cmd, "led on") == 0) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
snprintf(response, sizeof(response), "LED is ON\\r\\n");
}
else if (strcasecmp(cmd, "led off") == 0) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
snprintf(response, sizeof(response), "LED is OFF\\r\\n");
}
else if (strcasecmp(cmd, "time") == 0) {
uint32_t tick = HAL_GetTick();
snprintf(response, sizeof(response), "Uptime: %lu ms\\r\\n", tick);
}
else if (strcasecmp(cmd, "echo") == 0) {
snprintf(response, sizeof(response), "Echo test OK\\r\\n");
}
else if (strcasecmp(cmd, "quit") == 0) {
snprintf(response, sizeof(response), "Goodbye!\\r\\n");
tcp_write(tpcb, response, strlen(response), TCP_WRITE_FLAG_COPY);
tcp_server_close(client, tpcb);
/* 移动缓冲区 */
memmove(client->rx_buffer, &client->rx_buffer[cmd_len],
client->rx_len - cmd_len);
client->rx_len -= cmd_len;
return ERR_OK;
}
else {
snprintf(response, sizeof(response), "Unknown command: %s\\r\\n", cmd);
}
/* 发送响应 */
err_t err = tcp_write(tpcb, response, strlen(response), TCP_WRITE_FLAG_COPY);
if (err == ERR_OK) {
client->tx_count += strlen(response);
total_tx_bytes += strlen(response);
tcp_output(tpcb);
}
/* 移动缓冲区 */
memmove(client->rx_buffer, &client->rx_buffer[cmd_len],
client->rx_len - cmd_len);
client->rx_len -= cmd_len;
return ERR_OK;
}
/* 发送完成回调 */
static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
(void)arg;
(void)tpcb;
(void)len;
return ERR_OK;
}
/* 错误回调 */
static void tcp_server_error(void *arg, err_t err)
{
tcp_client_t *client = (tcp_client_t *)arg;
printf("[TCP] Error: %d\\n", err);
if (client != NULL) {
client->pcb = NULL;
client->state = CLIENT_STATE_IDLE;
if (client_count > 0) client_count--;
}
}
/* 轮询回调 */
static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb)
{
(void)tpcb;
tcp_client_t *client = (tcp_client_t *)arg;
if (client != NULL && client->state == CLIENT_STATE_CLOSING) {
tcp_server_close(client, tpcb);
}
return ERR_OK;
}
/* 关闭连接 */
static void tcp_server_close(tcp_client_t *client, struct tcp_pcb *tpcb)
{
if (tpcb == NULL) {
return;
}
/* 清除回调 */
tcp_arg(tpcb, NULL);
tcp_sent(tpcb, NULL);
tcp_recv(tpcb, NULL);
tcp_err(tpcb, NULL);
tcp_poll(tpcb, NULL, 0);
/* 关闭连接 */
if (tcp_close(tpcb) != ERR_OK) {
tcp_abort(tpcb);
}
/* 清除客户端 */
if (client != NULL) {
client->pcb = NULL;
client->state = CLIENT_STATE_IDLE;
client->rx_len = 0;
}
if (client_count > 0) client_count--;
printf("[TCP] Connection closed, active clients: %d\\n", client_count);
}
/* 获取统计信息 */
void tcp_server_get_stats(uint32_t *connections, uint32_t *rx, uint32_t *tx)
{
if (connections) *connections = total_connections;
if (rx) *rx = total_rx_bytes;
if (tx) *tx = total_tx_bytes;
}
/* 获取客户端数量 */
uint8_t tcp_server_get_client_count(void)
{
return client_count;
}
📄 创建文件:
Core/Inc/tcp_server.h
c
/*
* tcp_server.h - TCP Server头文件
*/
#ifndef __TCP_SERVER_H__
#define __TCP_SERVER_H__
#include "lwip/err.h"
#include <stdint.h>
/* TCP Server初始化 */
err_t tcp_server_init(void);
/* 获取统计信息 */
void tcp_server_get_stats(uint32_t *connections, uint32_t *rx, uint32_t *tx);
/* 获取客户端数量 */
uint8_t tcp_server_get_client_count(void);
#endif /* __TCP_SERVER_H__ */
4.4 主程序实现
📝 修改文件:
Core/Src/main.c
c
/*
* main.c - 主程序入口
*/
#include "main.h"
#include "lwip.h"
#include "tcp_server.h"
#include <stdio.h>
/* 私有函数声明 */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* 主函数 */
int main(void)
{
/* MCU配置 */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
/* 初始化LWIP */
MX_LWIP_Init();
/* 初始化TCP Server */
tcp_server_init();
printf("\\n");
printf("========================================\\n");
printf(" STM32F407 TCP Server\\n");
printf(" IP: 192.168.1.100\\n");
printf(" Port: 8080\\n");
printf("========================================\\n");
printf("\\n");
/* 主循环 */
while (1)
{
/* 处理LWIP任务 */
MX_LWIP_Process();
/* 周期性打印状态 */
static uint32_t last_print = 0;
if (HAL_GetTick() - last_print > 10000) {
last_print = HAL_GetTick();
uint32_t connections, rx, tx;
tcp_server_get_stats(&connections, &rx, &tx);
printf("[Status] Clients: %d, Connections: %lu, RX: %lu, TX: %lu\\n",
tcp_server_get_client_count(), connections, rx, tx);
}
HAL_Delay(1);
}
}
/* GPIO初始化 */
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO时钟使能 */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/* 配置LED引脚(PC13) */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
/* 系统时钟配置 */
void SystemClock_Config(void)
{
/* 由CubeMX生成 */
}
/* 错误处理 */
void Error_Handler(void)
{
__disable_irq();
while (1) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(100);
}
}
4.5 系统架构流程图
应用层
LWIP协议栈
驱动层
硬件层
STM32F407
168MHz
LAN8720
PHY芯片
RJ45接口
ETH外设驱动
HAL库
DMA传输
GPIO控制
网络接口层
ethernetif.c
IP层
TCP层
内存管理
TCP Server
tcp_server.c
客户端1
客户端2
客户端3
五、编译与下载
5.1 编译工程
- 在STM32CubeIDE中,点击
Project -> Build All - 等待编译完成
5.2 网络配置
- 将开发板通过网线连接到路由器
- 确保PC与开发板在同一网段
- 配置PC的IP地址为
192.168.1.x
5.3 测试连接
使用telnet或netcat测试:
bash
# 使用telnet连接
telnet 192.168.1.100 8080
# 或使用nc
nc 192.168.1.100 8080
测试命令:
help - 显示帮助
status - 显示服务器状态
info - 显示系统信息
led on - 点亮LED
led off - 熄灭LED
time - 获取运行时间
echo - 回声测试
quit - 断开连接
六、故障排查与问题解决
6.1 网络连接问题
问题1:无法连接服务器
错误现象:
- telnet连接超时
- ping不通开发板
原因分析:
- IP地址配置错误
- 网线连接问题
- PHY芯片未初始化
解决方案:
方案1:检查网络配置
c
// 确认IP配置
#define IP_ADDR0 192
#define IP_ADDR1 168
#define IP_ADDR2 1
#define IP_ADDR3 100
// 检查DHCP是否启用
#define LWIP_DHCP 1 // 如果启用DHCP,IP可能不同
方案2:检查PHY初始化
c
// 在ethernetif.c中添加调试输出
printf("PHY Address: %d\\n", PHY_ADDRESS);
printf("PHY ID: 0x%04X\\n", phy_id);
问题2:数据接收异常
错误现象:
- 数据丢失
- 接收不完整
原因分析:
- 接收缓冲区太小
- DMA配置错误
- 中断处理不及时
解决方案:
c
// 增大接收缓冲区
#define TCP_RX_BUFFER_SIZE 2048
// 在lwipopts.h中配置
#define PBUF_POOL_SIZE 32
#define PBUF_POOL_BUFSIZE 1524
6.2 内存问题
问题3:内存不足
错误现象:
- 无法建立新连接
- 系统崩溃
解决方案:
c
// 增加内存池大小
#define MEM_SIZE (32 * 1024)
#define MEMP_NUM_TCP_PCB 10
七、总结
7.1 核心知识点回顾
- 以太网配置:掌握STM32 ETH外设和PHY芯片的配置
- LWIP移植:理解LWIP协议栈的架构和配置方法
- TCP编程:掌握TCP Server的实现和多客户端管理
- 网络调试:学会使用网络工具进行调试
7.2 扩展学习方向
- UDP通信:实现UDP Server/Client
- HTTP服务器:在TCP基础上实现HTTP协议
- MQTT客户端:接入物联网平台
- 网络安全性:实现TLS/SSL加密
7.3 学习资源
官方文档: