基于STM32和uIP协议栈的TCP/UDP通信实现方案。uIP是一个极小的开源TCP/IP协议栈,特别适合资源有限的嵌入式系统。
一、系统架构
1.1 硬件平台
STM32F103C8T6 (72MHz, 20KB RAM, 64KB Flash)
├── 以太网模块 (ENC28J60) - SPI接口
├── 串口1 (USART1) - 调试输出
├── 按键 (GPIO) - 控制/复位
└── LED指示灯 (GPIO) - 状态指示
1.2 软件架构
c
/* 文件结构 */
uIP_Project/
├── Core/
│ ├── main.c
│ ├── stm32f1xx_hal_msp.c
│ └── system_stm32f1xx.c
├── Drivers/
│ ├── STM32F1xx_HAL_Driver/
│ └── BSP/
│ ├── enc28j60.c/.h
│ ├── uip_arch.c/.h
│ └── network.c/.h
├── Middleware/
│ └── uip-1.0/
│ ├── uip/
│ ├── uipopt.h
│ ├── tapdev.c/.h
│ └── clock-arch.c/.h
└── Application/
├── tcp_server.c/.h
├── udp_server.c/.h
├── web_server.c/.h
└── telnet_server.c/.h
二、uIP协议栈移植
2.1 uIP配置文件 (uipopt.h)
c
/**
* @file uipopt.h
* @brief uIP协议栈配置
*/
#ifndef __UIPOPT_H__
#define __UIPOPT_H__
#include <stdint.h>
/* CPU字节序 */
#define UIP_BIG_ENDIAN 0
#define UIP_LITTLE_ENDIAN 1
#define UIP_BYTE_ORDER UIP_LITTLE_ENDIAN
/* 协议栈选项 */
#define UIP_LLH_LEN 14 // 链路层头部长度
#define UIP_BUFSIZE 400 // 缓冲区大小
#define UIP_CONF_MAX_CONNECTIONS 4 // 最大TCP连接数
#define UIP_CONF_MAX_LISTENPORTS 4 // 最大监听端口数
#define UIP_CONF_UDP_CONNS 4 // 最大UDP连接数
#define UIP_CONF_STATISTICS 1 // 启用统计
/* TCP选项 */
#define UIP_CONF_TCP_SPLIT 0
#define UIP_ACTIVE_OPEN 1
#define UIP_CONF_TCP_MSS 1460
#define UIP_CONF_RECEIVE_WINDOW 2920
#define UIP_CONF_TTL 64
/* UDP选项 */
#define UIP_CONF_UDP 1
#define UIP_CONF_UDP_CHECKSUMS 1
#define UIP_CONF_BROADCAST 1
/* ICMP选项 */
#define UIP_CONF_ICMP_DEST_UNREACH 1
#define UIP_CONF_PINGADDR_CONF 1
/* 网络接口 */
#define UIP_CONF_LLH_LEN 14
#define UIP_CONF_LOGGING 0
#define UIP_CONF_IP_FORWARD 0
/* ARP选项 */
#define UIP_CONF_LL_8023 1
#define UIP_CONF_LL_80211 0
#define UIP_CONF_LL_IPCHAIN 0
#define UIP_CONF_ARP_TABLE_SIZE 8
#define UIP_CONF_ARPTAB_SIZE 8
#define UIP_CONF_ARP_QUEUEING 1
/* 时钟选项 */
#define UIP_CONF_IPV6 0
#define UIP_CONF_ICMP6 0
#define UIP_CONF_DHCP_LIGHT 0
#define UIP_CONF_DNS 0
/* 应用程序包含 */
#define UIP_APPCALL tcp_appcall
#define UIP_UDP_APPCALL udp_appcall
/* 数据类型定义 */
typedef uint8_t u8_t;
typedef uint16_t u16_t;
typedef uint32_t u32_t;
typedef unsigned short uip_stats_t;
/* 调试输出 */
#define UIP_LOGGING 1
#define UIP_DEBUG_PRINTF printf
/* 网络地址配置 */
#define UIP_FIXEDADDR 0
#if UIP_FIXEDADDR
#define UIP_IPADDR0 192
#define UIP_IPADDR1 168
#define UIP_IPADDR2 1
#define UIP_IPADDR3 100
#define UIP_NETMASK0 255
#define UIP_NETMASK1 255
#define UIP_NETMASK2 255
#define UIP_NETMASK3 0
#define UIP_DRIPADDR0 192
#define UIP_DRIPADDR1 168
#define UIP_DRIPADDR2 1
#define UIP_DRIPADDR3 1
#else
#define UIP_CONF_DHCP 1
#endif
#endif /* __UIPOPT_H__ */
2.2 网络设备驱动 (tapdev.c)
c
/**
* @file tapdev.c
* @brief 网络设备驱动 (ENC28J60)
*/
#include "tapdev.h"
#include "enc28j60.h"
#include "uip.h"
#include "uip_arp.h"
#include <string.h>
/* 全局变量 */
static struct uip_eth_addr ethaddr = {{0x00,0x11,0x22,0x33,0x44,0x55}};
static uint8_t packet_buffer[UIP_BUFSIZE];
/**
* @brief 初始化网络设备
*/
void tapdev_init(void)
{
/* 初始化ENC28J60 */
ENC28J60_Init(ethaddr.addr);
/* 设置MAC地址 */
uip_setethaddr(ethaddr);
/* 设置IP地址 (如果使用静态IP) */
#if !UIP_CONF_DHCP
uip_ipaddr_t ipaddr;
uip_ipaddr(ipaddr, 192,168,1,100);
uip_sethostaddr(ipaddr);
uip_ipaddr_t netmask;
uip_ipaddr(netmask, 255,255,255,0);
uip_setnetmask(netmask);
uip_ipaddr_t draddr;
uip_ipaddr(draddr, 192,168,1,1);
uip_setdraddr(draddr);
#endif
printf("Network Interface Initialized\n");
printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
ethaddr.addr[0], ethaddr.addr[1], ethaddr.addr[2],
ethaddr.addr[3], ethaddr.addr[4], ethaddr.addr[5]);
}
/**
* @brief 发送数据包
*/
void tapdev_send(void)
{
if(uip_len > 0)
{
/* 如果是ARP响应,更新ARP表 */
if(uip_len <= UIP_LLH_LEN + 40)
{
uip_arp_out();
}
/* 通过ENC28J60发送数据 */
ENC28J60_PacketSend(uip_len, (uint8_t*)uip_buf);
}
}
/**
* @brief 接收数据包
* @return 数据包长度,0表示无数据
*/
uint16_t tapdev_read(void)
{
uint16_t len = ENC28J60_PacketReceive(UIP_BUFSIZE, packet_buffer);
if(len > 0)
{
/* 检查最小数据包长度 */
if(len < 60)
{
len = 60;
}
/* 复制到uIP缓冲区 */
memcpy(uip_buf, packet_buffer, len);
}
return len;
}
2.3 时钟架构 (clock-arch.c)
c
/**
* @file clock-arch.c
* @brief uIP时钟架构实现
*/
#include "clock-arch.h"
#include "stm32f1xx_hal.h"
/* 时钟滴答计数 */
static clock_time_t clock_tick = 0;
/**
* @brief 获取当前时钟滴答
* @return 时钟滴答数
*/
clock_time_t clock_time(void)
{
return clock_tick;
}
/**
* @brief 时钟滴答中断 (在SysTick中断中调用)
*/
void clock_tick_isr(void)
{
clock_tick++;
/* 每秒钟调用一次周期性处理 */
if((clock_tick % CLOCK_SECOND) == 0)
{
uip_periodic_tcp();
uip_periodic_udp();
}
}
/**
* @brief 初始化系统时钟
*/
void clock_init(void)
{
/* 配置SysTick为1ms中断 */
HAL_SYSTICK_Config(SystemCoreClock / 1000);
/* 设置SysTick中断优先级 */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
printf("Clock initialized: 1ms tick\n");
}
三、TCP服务器实现
3.1 TCP服务器核心
c
/**
* @file tcp_server.h
* @brief TCP服务器实现
*/
#ifndef __TCP_SERVER_H
#define __TCP_SERVER_H
#include "uip.h"
/* TCP服务器配置 */
#define TCP_SERVER_PORT 80 // HTTP端口
#define TCP_SERVER_PORT2 23 // Telnet端口
#define TCP_SERVER_PORT3 8080 // 自定义端口
/* TCP连接状态 */
typedef enum {
TCP_STATE_CLOSED = 0,
TCP_STATE_LISTEN,
TCP_STATE_SYN_RCVD,
TCP_STATE_SYN_SENT,
TCP_STATE_ESTABLISHED,
TCP_STATE_FIN_WAIT_1,
TCP_STATE_FIN_WAIT_2,
TCP_STATE_CLOSING,
TCP_STATE_TIME_WAIT,
TCP_STATE_CLOSE_WAIT,
TCP_STATE_LAST_ACK
} tcp_state_t;
/* TCP连接结构 */
typedef struct {
struct tcp_app_state *next;
uint8_t state;
uint16_t port;
void *data;
} tcp_app_state;
/* 函数声明 */
void tcp_server_init(void);
void tcp_appcall(void);
void tcp_send_data(struct uip_conn *conn, const char *data, uint16_t len);
void tcp_close_connection(struct uip_conn *conn);
#endif /* __TCP_SERVER_H */
c
/**
* @file tcp_server.c
* @brief TCP服务器实现
*/
#include "tcp_server.h"
#include "uip.h"
#include "string.h"
#include "stdio.h"
/* TCP连接状态数组 */
static tcp_app_state tcp_states[UIP_CONF_MAX_CONNECTIONS];
/* HTTP响应头 */
static const char http_header[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
static const char http_index[] =
"<html><head><title>STM32 uIP Server</title></head>"
"<body><h1>Welcome to STM32 TCP Server</h1>"
"<p>This is a simple web server running on STM32 with uIP stack.</p>"
"<p>Free Memory: %d bytes</p>"
"<p>Connections: %d</p>"
"<p>Uptime: %lu seconds</p>"
"</body></html>";
/* Telnet欢迎信息 */
static const char telnet_welcome[] =
"\r\nSTM32 Telnet Server\r\n"
"Type 'help' for commands\r\n> ";
/* 全局变量 */
static uint32_t uptime_counter = 0;
static uint8_t active_connections = 0;
/**
* @brief 初始化TCP服务器
*/
void tcp_server_init(void)
{
struct uip_conn *conn;
/* 监听HTTP端口 (80) */
conn = uip_listen(HTONS(TCP_SERVER_PORT));
if(conn != NULL)
{
printf("TCP Server listening on port %d\n", TCP_SERVER_PORT);
}
/* 监听Telnet端口 (23) */
conn = uip_listen(HTONS(TCP_SERVER_PORT2));
if(conn != NULL)
{
printf("Telnet Server listening on port %d\n", TCP_SERVER_PORT2);
}
/* 监听自定义端口 (8080) */
conn = uip_listen(HTONS(TCP_SERVER_PORT3));
if(conn != NULL)
{
printf("Custom TCP Server listening on port %d\n", TCP_SERVER_PORT3);
}
/* 初始化连接状态 */
memset(tcp_states, 0, sizeof(tcp_states));
printf("TCP Server initialized\n");
}
/**
* @brief TCP应用程序回调
*/
void tcp_appcall(void)
{
struct tcp_app_state *s = (struct tcp_app_state *)uip_conn->appstate;
/* 根据uIP事件处理 */
if(uip_connected())
{
/* 新连接建立 */
printf("TCP Connection established from ");
printf("%d.%d.%d.%d:%d\n",
(uip_conn->ripaddr[0] >> 0) & 0xFF,
(uip_conn->ripaddr[0] >> 8) & 0xFF,
(uip_conn->ripaddr[1] >> 0) & 0xFF,
(uip_conn->ripaddr[1] >> 8) & 0xFF,
HTONS(uip_conn->rport));
/* 分配应用状态 */
s = &tcp_states[uip_conn - uip_conns];
uip_conn->appstate = s;
s->state = TCP_STATE_ESTABLISHED;
s->port = HTONS(uip_conn->lport);
active_connections++;
/* 根据端口号发送不同欢迎信息 */
if(s->port == TCP_SERVER_PORT2) // Telnet
{
uip_send(telnet_welcome, strlen(telnet_welcome));
}
}
if(s != NULL)
{
/* 数据到达 */
if(uip_newdata())
{
printf("TCP Data received: %d bytes\n", uip_datalen());
/* 处理接收到的数据 */
process_tcp_data(s, (char*)uip_appdata, uip_datalen());
}
/* 数据确认 */
if(uip_acked())
{
s->state = TCP_STATE_ESTABLISHED;
}
/* 重新发送 */
if(uip_rexmit())
{
/* 重新发送数据 */
}
/* 轮询事件 */
if(uip_poll())
{
/* 定时处理 */
}
/* 连接关闭 */
if(uip_closed())
{
printf("TCP Connection closed\n");
s->state = TCP_STATE_CLOSED;
active_connections--;
}
/* 中止连接 */
if(uip_aborted())
{
printf("TCP Connection aborted\n");
s->state = TCP_STATE_CLOSED;
active_connections--;
}
/* 超时 */
if(uip_timedout())
{
printf("TCP Connection timeout\n");
s->state = TCP_STATE_CLOSED;
active_connections--;
}
}
}
/**
* @brief 处理TCP数据
*/
void process_tcp_data(tcp_app_state *s, char *data, uint16_t len)
{
char response[512];
uint16_t response_len;
/* 根据端口处理不同协议 */
switch(s->port)
{
case TCP_SERVER_PORT: // HTTP
if(strstr(data, "GET / ") || strstr(data, "GET /index.html"))
{
/* 生成HTTP响应 */
response_len = snprintf(response, sizeof(response),
"%s%s", http_header, http_index);
uip_send(response, response_len);
}
else if(strstr(data, "GET /status"))
{
/* 返回状态信息 */
response_len = snprintf(response, sizeof(response),
"%s{\"status\":\"ok\",\"connections\":%d,\"uptime\":%lu}",
http_header, active_connections, uptime_counter);
uip_send(response, response_len);
}
else
{
/* 404错误 */
const char *not_found =
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n\r\n"
"<h1>404 Not Found</h1>";
uip_send(not_found, strlen(not_found));
}
break;
case TCP_SERVER_PORT2: // Telnet
if(len > 0)
{
/* 处理Telnet命令 */
if(strncmp(data, "help", 4) == 0)
{
const char *help =
"\r\nAvailable commands:\r\n"
" help - Show this help\r\n"
" status - Show system status\r\n"
" led on - Turn LED on\r\n"
" led off - Turn LED off\r\n"
" reboot - Reboot system\r\n"
" exit - Close connection\r\n> ";
uip_send(help, strlen(help));
}
else if(strncmp(data, "status", 6) == 0)
{
response_len = snprintf(response, sizeof(response),
"\r\nSystem Status:\r\n"
" Active Connections: %d\r\n"
" Uptime: %lu seconds\r\n"
" Free Memory: %d bytes\r\n> ",
active_connections, uptime_counter, 0);
uip_send(response, response_len);
}
else if(strncmp(data, "exit", 4) == 0)
{
const char *bye = "\r\nGoodbye!\r\n";
uip_send(bye, strlen(bye));
uip_close();
}
else
{
const char *unknown = "\r\nUnknown command. Type 'help'.\r\n> ";
uip_send(unknown, strlen(unknown));
}
}
break;
case TCP_SERVER_PORT3: // 自定义协议
/* 回显接收到的数据 */
char echo[256];
snprintf(echo, sizeof(echo), "Echo: %.*s", len, data);
uip_send(echo, strlen(echo));
break;
}
}
/**
* @brief 发送TCP数据
*/
void tcp_send_data(struct uip_conn *conn, const char *data, uint16_t len)
{
if(conn != NULL && data != NULL && len > 0)
{
uip_send(data, len);
}
}
/**
* @brief 关闭TCP连接
*/
void tcp_close_connection(struct uip_conn *conn)
{
if(conn != NULL)
{
uip_close();
}
}
四、UDP服务器实现
4.1 UDP服务器核心
c
/**
* @file udp_server.h
* @brief UDP服务器实现
*/
#ifndef __UDP_SERVER_H
#define __UDP_SERVER_H
#include "uip.h"
/* UDP服务器配置 */
#define UDP_SERVER_PORT 1234 // 自定义端口
#define UDP_CLIENT_PORT 1235
#define UDP_BROADCAST_PORT 1236
/* UDP数据包结构 */
typedef struct {
uint8_t type;
uint8_t sequence;
uint16_t length;
uint8_t data[128];
} udp_packet_t;
/* UDP连接结构 */
typedef struct {
struct uip_udp_conn *conn;
uint16_t remote_port;
uip_ipaddr_t remote_addr;
uint32_t packet_count;
} udp_app_state;
/* 函数声明 */
void udp_server_init(void);
void udp_appcall(void);
void udp_send_packet(uip_ipaddr_t *addr, uint16_t port,
const uint8_t *data, uint16_t len);
void udp_broadcast(uint16_t port, const uint8_t *data, uint16_t len);
void udp_process_packet(udp_app_state *s, uint8_t *data, uint16_t len);
#endif /* __UDP_SERVER_H */
c
/**
* @file udp_server.c
* @brief UDP服务器实现
*/
#include "udp_server.h"
#include "uip.h"
#include "string.h"
#include "stdio.h"
/* UDP连接状态 */
static udp_app_state udp_states[UIP_CONF_UDP_CONNS];
static struct uip_udp_conn *udp_conn = NULL;
static struct uip_udp_conn *udp_broadcast_conn = NULL;
/* 全局统计 */
static uint32_t udp_packets_received = 0;
static uint32_t udp_packets_sent = 0;
/**
* @brief 初始化UDP服务器
*/
void udp_server_init(void)
{
uip_ipaddr_t addr;
/* 创建UDP监听连接 */
uip_ipaddr(addr, 0,0,0,0); // 监听所有地址
udp_conn = uip_udp_new(&addr, HTONS(0));
if(udp_conn != NULL)
{
uip_udp_bind(udp_conn, HTONS(UDP_SERVER_PORT));
printf("UDP Server listening on port %d\n", UDP_SERVER_PORT);
}
/* 创建广播连接 */
uip_ipaddr(addr, 255,255,255,255); // 广播地址
udp_broadcast_conn = uip_udp_new(&addr, HTONS(UDP_BROADCAST_PORT));
if(udp_broadcast_conn != NULL)
{
printf("UDP Broadcast on port %d\n", UDP_BROADCAST_PORT);
}
/* 初始化UDP状态 */
memset(udp_states, 0, sizeof(udp_states));
printf("UDP Server initialized\n");
}
/**
* @brief UDP应用程序回调
*/
void udp_appcall(void)
{
udp_app_state *s = NULL;
/* 查找对应的UDP连接状态 */
for(int i = 0; i < UIP_CONF_UDP_CONNS; i++)
{
if(udp_states[i].conn == uip_udp_conn)
{
s = &udp_states[i];
break;
}
}
/* 如果没有找到,创建新状态 */
if(s == NULL && uip_udp_conn != NULL)
{
for(int i = 0; i < UIP_CONF_UDP_CONNS; i++)
{
if(udp_states[i].conn == NULL)
{
s = &udp_states[i];
s->conn = uip_udp_conn;
s->packet_count = 0;
/* 保存远程地址信息 */
uip_ipaddr_copy(s->remote_addr, uip_udp_conn->ripaddr);
s->remote_port = uip_udp_conn->rport;
break;
}
}
}
/* 处理新数据 */
if(uip_newdata())
{
udp_packets_received++;
printf("UDP Packet received from ");
printf("%d.%d.%d.%d:%d, Length: %d\n",
(uip_udp_conn->ripaddr[0] >> 0) & 0xFF,
(uip_udp_conn->ripaddr[0] >> 8) & 0xFF,
(uip_udp_conn->ripaddr[1] >> 0) & 0xFF,
(uip_udp_conn->ripaddr[1] >> 8) & 0xFF,
HTONS(uip_udp_conn->rport),
uip_datalen());
if(s != NULL)
{
s->packet_count++;
/* 处理UDP数据包 */
udp_process_packet(s, (uint8_t*)uip_appdata, uip_datalen());
}
}
/* 处理轮询事件 */
if(uip_poll())
{
/* 定时发送状态信息 */
static uint32_t last_broadcast = 0;
if((clock_time() - last_broadcast) > (CLOCK_SECOND * 5))
{
last_broadcast = clock_time();
/* 发送状态广播 */
char status_msg[64];
snprintf(status_msg, sizeof(status_msg),
"UDP Server Status: Packets RX=%lu TX=%lu",
udp_packets_received, udp_packets_sent);
udp_broadcast(UDP_BROADCAST_PORT,
(uint8_t*)status_msg, strlen(status_msg));
}
}
}
/**
* @brief 处理UDP数据包
*/
void udp_process_packet(udp_app_state *s, uint8_t *data, uint16_t len)
{
char response[256];
/* 回显协议 */
if(len > 0 && data[0] == 0x01) // Echo请求
{
snprintf(response, sizeof(response),
"Echo: %.*s", len-1, data+1);
udp_send_packet(&s->remote_addr, HTONS(s->remote_port),
(uint8_t*)response, strlen(response));
}
/* 状态请求 */
else if(len > 0 && data[0] == 0x02) // Status请求
{
snprintf(response, sizeof(response),
"Status: RX=%lu TX=%lu Connections=%d",
udp_packets_received, udp_packets_sent,
s->packet_count);
udp_send_packet(&s->remote_addr, HTONS(s->remote_port),
(uint8_t*)response, strlen(response));
}
/* Ping协议 */
else if(len > 0 && data[0] == 0x03) // Ping
{
uint8_t pong[] = {0x04, 'P', 'o', 'n', 'g', '!'};
udp_send_packet(&s->remote_addr, HTONS(s->remote_port),
pong, sizeof(pong));
}
/* 广播发现 */
else if(len > 0 && data[0] == 0xFF) // 发现请求
{
char discovery[] = "STM32 UDP Server v1.0";
udp_broadcast(UDP_BROADCAST_PORT,
(uint8_t*)discovery, strlen(discovery));
}
/* 默认处理:回显数据 */
else
{
snprintf(response, sizeof(response),
"Received %d bytes: %.*s", len, len, data);
udp_send_packet(&s->remote_addr, HTONS(s->remote_port),
(uint8_t*)response, strlen(response));
}
}
/**
* @brief 发送UDP数据包
*/
void udp_send_packet(uip_ipaddr_t *addr, uint16_t port,
const uint8_t *data, uint16_t len)
{
if(addr == NULL || data == NULL || len == 0)
return;
/* 设置远程地址和端口 */
uip_udp_conn->rport = port;
uip_ipaddr_copy(uip_udp_conn->ripaddr, *addr);
/* 发送数据 */
uip_udp_send(data, len);
udp_packets_sent++;
printf("UDP Packet sent to %d.%d.%d.%d:%d, Length: %d\n",
(addr->u8[0]), (addr->u8[1]),
(addr->u8[2]), (addr->u8[3]),
HTONS(port), len);
}
/**
* @brief 发送UDP广播
*/
void udp_broadcast(uint16_t port, const uint8_t *data, uint16_t len)
{
uip_ipaddr_t broadcast_addr;
uip_ipaddr(&broadcast_addr, 255,255,255,255);
udp_send_packet(&broadcast_addr, port, data, len);
}
五、主程序与网络主循环
5.1 主程序框架
c
/**
* @file main.c
* @brief 主程序 - STM32 + uIP TCP/UDP服务器
*/
#include "main.h"
#include "stm32f1xx_hal.h"
#include "uip.h"
#include "uip_arp.h"
#include "tapdev.h"
#include "clock-arch.h"
#include "tcp_server.h"
#include "udp_server.h"
#include <stdio.h>
/* 全局变量 */
UART_HandleTypeDef huart1;
SPI_HandleTypeDef hspi1;
TIM_HandleTypeDef htim2;
/* 网络相关变量 */
static uint32_t ipaddr = 0;
static uint8_t macaddr[6] = {0};
static struct timer periodic_timer, arp_timer;
/* 函数声明 */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_SPI1_Init(void);
static void MX_TIM2_Init(void);
void network_loop(void);
void network_init(void);
void print_network_info(void);
/**
* @brief 主函数
*/
int main(void)
{
/* HAL库初始化 */
HAL_Init();
/* 系统时钟配置 */
SystemClock_Config();
/* 外设初始化 */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_SPI1_Init();
MX_TIM2_Init();
printf("\r\n================================\r\n");
printf("STM32 uIP TCP/UDP Server\r\n");
printf("Version 1.0\r\n");
printf("================================\r\n");
/* 系统时钟初始化 */
clock_init();
/* 网络初始化 */
network_init();
/* TCP服务器初始化 */
tcp_server_init();
/* UDP服务器初始化 */
udp_server_init();
printf("\r\nSystem initialized successfully\r\n");
print_network_info();
/* 启动定时器 */
HAL_TIM_Base_Start_IT(&htim2);
/* 主循环 */
while(1)
{
/* 网络处理循环 */
network_loop();
/* 其他任务 */
HAL_Delay(1);
}
}
/**
* @brief 网络初始化
*/
void network_init(void)
{
/* 初始化网络设备 */
tapdev_init();
/* 初始化uIP协议栈 */
uip_init();
/* 初始化ARP表 */
uip_arp_init();
/* 设置定时器 */
timer_set(&periodic_timer, CLOCK_SECOND / 2);
timer_set(&arp_timer, CLOCK_SECOND * 10);
printf("Network stack initialized\r\n");
}
/**
* @brief 网络主循环
*/
void network_loop(void)
{
uint16_t len;
/* 检查周期性定时器 */
if(timer_expired(&periodic_timer))
{
timer_reset(&periodic_timer);
/* 处理所有TCP连接 */
for(int i = 0; i < UIP_CONNS; i++)
{
uip_periodic(i);
if(uip_len > 0)
{
uip_arp_out();
tapdev_send();
}
}
/* 处理所有UDP连接 */
for(int i = 0; i < UIP_UDP_CONNS; i++)
{
uip_udp_periodic(i);
if(uip_len > 0)
{
uip_arp_out();
tapdev_send();
}
}
/* 每2秒调用一次ARP定时器 */
if(timer_expired(&arp_timer))
{
timer_reset(&arp_timer);
uip_arp_timer();
}
}
/* 处理接收到的数据包 */
len = tapdev_read();
if(len > 0)
{
/* 检查数据包类型 */
if(BUF->type == htons(UIP_ETHTYPE_IP))
{
uip_arp_ipin();
uip_input();
if(uip_len > 0)
{
/* 处理IP数据包 */
uip_arp_out();
tapdev_send();
}
}
else if(BUF->type == htons(UIP_ETHTYPE_ARP))
{
/* 处理ARP数据包 */
uip_arp_arpin();
if(uip_len > 0)
{
tapdev_send();
}
}
}
}
/**
* @brief 打印网络信息
*/
void print_network_info(void)
{
uint8_t *ip = (uint8_t*)&uip_hostaddr;
printf("\r\n--- Network Information ---\r\n");
printf("IP Address: %d.%d.%d.%d\r\n",
ip[0], ip[1], ip[2], ip[3]);
ip = (uint8_t*)&uip_netmask;
printf("Netmask: %d.%d.%d.%d\r\n",
ip[0], ip[1], ip[2], ip[3]);
ip = (uint8_t*)&uip_draddr;
printf("Gateway: %d.%d.%d.%d\r\n",
ip[0], ip[1], ip[2], ip[3]);
printf("TCP Ports: 80(HTTP), 23(Telnet), 8080(Custom)\r\n");
printf("UDP Port: 1234\r\n");
printf("UDP Broadcast: 1236\r\n");
printf("------------------------------\r\n\r\n");
}
/**
* @brief 系统时钟配置
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* 配置HSE 8MHz外部晶振 */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; // 8MHz * 9 = 72MHz
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* 配置系统时钟 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // HCLK = 72MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // PCLK1 = 36MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // PCLK2 = 72MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}
/**
* @brief USART1初始化
*/
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);
}
/**
* @brief SPI1初始化 (ENC28J60)
*/
void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 9MHz
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
HAL_SPI_Init(&hspi1);
}
/**
* @brief TIM2初始化 (用于系统定时)
*/
void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7200 - 1; // 72MHz/7200 = 10kHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 10000 - 1; // 10kHz/10000 = 1Hz
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
}
/**
* @brief GPIO初始化
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO时钟使能 */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/* LED引脚配置 */
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);
/* ENC28J60片选引脚 */
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
/* ENC28J60复位引脚 */
GPIO_InitStruct.Pin = GPIO_PIN_3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
}
/**
* @brief 定时器2中断处理
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
static uint32_t led_counter = 0;
/* 每秒翻转LED */
if(++led_counter >= 500) // 0.5秒
{
led_counter = 0;
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
/* 更新系统时钟 */
clock_tick_isr();
}
}
/**
* @brief 重定向printf到串口
*/
int _write(int file, char *ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, 1000);
return len;
}
六、ENC28J60驱动
6.1 ENC28J60驱动头文件
c
/**
* @file enc28j60.h
* @brief ENC28J60以太网控制器驱动
*/
#ifndef __ENC28J60_H
#define __ENC28J60_H
#include "stm32f1xx_hal.h"
/* ENC28J60寄存器定义 */
#define ENC28J60_CONTROL_REG 0x1A
#define ENC28J60_BIT_FIELD_SET 0x80
#define ENC28J60_BIT_FIELD_CLR 0xA0
#define ENC28J60_SRC_REG 0x00
/* 缓冲区边界 */
#define ENC28J60_RXSTART_INIT 0x0000
#define ENC28J60_RXSTOP_INIT 0x0BFF
#define ENC28J60_TXSTART_INIT 0x0C00
#define ENC28J60_TXSTOP_INIT 0x11FF
#define ENC28J60_MAX_FRAMELEN 1500
/* 函数声明 */
void ENC28J60_Init(uint8_t* macaddr);
uint8_t ENC28J60_ReadOp(uint8_t op, uint8_t address);
void ENC28J60_WriteOp(uint8_t op, uint8_t address, uint8_t data);
void ENC28J60_ReadBuffer(uint16_t len, uint8_t* data);
void ENC28J60_WriteBuffer(uint16_t len, uint8_t* data);
void ENC28J60_SetBank(uint8_t address);
uint8_t ENC28J60_Read(uint8_t address);
void ENC28J60_Write(uint8_t address, uint8_t data);
void ENC28J60_PhyWrite(uint8_t address, uint16_t data);
uint16_t ENC28J60_PhyRead(uint8_t address);
void ENC28J60_ClkOut(uint8_t clock);
void ENC28J60_EnableBroadcast(void);
void ENC28J60_DisableBroadcast(void);
uint16_t ENC28J60_PacketReceive(uint16_t maxlen, uint8_t* packet);
void ENC28J60_PacketSend(uint16_t len, uint8_t* packet);
uint8_t ENC28J60_LinkStatus(void);
void ENC28J60_Reset(void);
/* SPI操作 */
#define ENC28J60_CS_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define ENC28J60_CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
#define ENC28J60_RESET_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET)
#define ENC28J60_RESET_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET)
#endif /* __ENC28J60_H */
6.2 ENC28J60驱动实现
c
/**
* @file enc28j60.c
* @brief ENC28J60驱动实现
*/
#include "enc28j60.h"
#include "spi.h"
#include <string.h>
/* 全局变量 */
static uint8_t Enc28j60Bank = 0;
static uint16_t NextPacketPtr = 0;
/**
* @brief 读取ENC28J60寄存器
*/
uint8_t ENC28J60_ReadOp(uint8_t op, uint8_t address)
{
uint8_t data;
uint8_t spi_tx[2], spi_rx[2];
ENC28J60_CS_LOW();
spi_tx[0] = op | (address & 0x1F);
spi_tx[1] = 0x00;
HAL_SPI_TransmitReceive(&hspi1, spi_tx, spi_rx, 2, 100);
if(address & 0x80)
{
spi_tx[0] = 0x00;
HAL_SPI_TransmitReceive(&hspi1, spi_tx, spi_rx, 1, 100);
}
data = spi_rx[1];
ENC28J60_CS_HIGH();
return data;
}
/**
* @brief 写入ENC28J60寄存器
*/
void ENC28J60_WriteOp(uint8_t op, uint8_t address, uint8_t data)
{
uint8_t spi_tx[2];
ENC28J60_CS_LOW();
spi_tx[0] = op | (address & 0x1F);
spi_tx[1] = data;
HAL_SPI_Transmit(&hspi1, spi_tx, 2, 100);
ENC28J60_CS_HIGH();
}
/**
* @brief 读取缓冲区
*/
void ENC28J60_ReadBuffer(uint16_t len, uint8_t* data)
{
ENC28J60_CS_LOW();
/* 发送读缓冲区命令 */
uint8_t cmd = 0x3A;
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
/* 读取数据 */
HAL_SPI_Receive(&hspi1, data, len, 1000);
ENC28J60_CS_HIGH();
}
/**
* @brief 写入缓冲区
*/
void ENC28J60_WriteBuffer(uint16_t len, uint8_t* data)
{
ENC28J60_CS_LOW();
/* 发送写缓冲区命令 */
uint8_t cmd = 0x7A;
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
/* 写入数据 */
HAL_SPI_Transmit(&hspi1, data, len, 1000);
ENC28J60_CS_HIGH();
}
/**
* @brief 设置寄存器组
*/
void ENC28J60_SetBank(uint8_t address)
{
if((address & 0xE0) != Enc28j60Bank)
{
ENC28J60_WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, 0x03);
Enc28j60Bank = address & 0xE0;
}
}
/**
* @brief 读取寄存器
*/
uint8_t ENC28J60_Read(uint8_t address)
{
ENC28J60_SetBank(address);
return ENC28J60_ReadOp(ENC28J60_SRC_REG, address);
}
/**
* @brief 写入寄存器
*/
void ENC28J60_Write(uint8_t address, uint8_t data)
{
ENC28J60_SetBank(address);
ENC28J60_WriteOp(ENC28J60_SRC_REG, address, data);
}
/**
* @brief PHY寄存器写入
*/
void ENC28J60_PhyWrite(uint8_t address, uint16_t data)
{
ENC28J60_Write(MIREGADR, address);
ENC28J60_Write(MIWRL, data);
ENC28J60_Write(MIWRH, data >> 8);
while(ENC28J60_Read(MISTAT) & 0x01)
{
HAL_Delay(1);
}
}
/**
* @brief 读取PHY寄存器
*/
uint16_t ENC28J60_PhyRead(uint8_t address)
{
ENC28J60_Write(MIREGADR, address);
ENC28J60_Write(MICMD, 0x01);
while(ENC28J60_Read(MISTAT) & 0x01)
{
HAL_Delay(1);
}
ENC28J60_Write(MICMD, 0x00);
return (ENC28J60_Read(MIRDH) << 8) | ENC28J60_Read(MIRDL);
}
/**
* @brief 初始化ENC28J60
*/
void ENC28J60_Init(uint8_t* macaddr)
{
/* 硬件复位 */
ENC28J60_RESET_LOW();
HAL_Delay(1);
ENC28J60_RESET_HIGH();
HAL_Delay(10);
/* 初始化接收缓冲区 */
NextPacketPtr = ENC28J60_RXSTART_INIT;
ENC28J60_Write(ERXSTL, ENC28J60_RXSTART_INIT & 0xFF);
ENC28J60_Write(ERXSTH, ENC28J60_RXSTART_INIT >> 8);
ENC28J60_Write(ERXRDPTL, ENC28J60_RXSTART_INIT & 0xFF);
ENC28J60_Write(ERXRDPTH, ENC28J60_RXSTART_INIT >> 8);
ENC28J60_Write(ERXNDL, ENC28J60_RXSTOP_INIT & 0xFF);
ENC28J60_Write(ERXNDH, ENC28J60_RXSTOP_INIT >> 8);
/* 初始化发送缓冲区 */
ENC28J60_Write(ETXSTL, ENC28J60_TXSTART_INIT & 0xFF);
ENC28J60_Write(ETXSTH, ENC28J60_TXSTART_INIT >> 8);
/* 配置接收过滤器 */
ENC28J60_Write(ERXFCON, 0x20); // 启用单播
/* 设置MAC地址 */
ENC28J60_Write(MAADR5, macaddr[0]);
ENC28J60_Write(MAADR4, macaddr[1]);
ENC28J60_Write(MAADR3, macaddr[2]);
ENC28J60_Write(MAADR2, macaddr[3]);
ENC28J60_Write(MAADR1, macaddr[4]);
ENC28J60_Write(MAADR6, macaddr[5]);
/* 配置PHY */
ENC28J60_PhyWrite(PHCON1, 0x0000);
ENC28J60_PhyWrite(PHCON2, 0x0000);
ENC28J60_PhyWrite(PHLCON, 0x0472);
/* 启用接收 */
ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, 0x01);
/* 启用中断 */
ENC28J60_Write(EIE, 0x00);
ENC28J60_Write(EIE, 0x88);
/* 启用接收和发送 */
ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, 0x04);
}
/**
* @brief 接收数据包
*/
uint16_t ENC28J60_PacketReceive(uint16_t maxlen, uint8_t* packet)
{
uint16_t rxstat;
uint16_t len;
/* 检查是否有数据包 */
if(ENC28J60_Read(EPKTCNT) == 0)
{
return 0;
}
/* 设置读取指针 */
ENC28J60_Write(ERDPTL, NextPacketPtr);
ENC28J60_Write(ERDPTH, NextPacketPtr >> 8);
NextPacketPtr = ENC28J60_ReadOp(0x00, 0x00);
NextPacketPtr |= ENC28J60_ReadOp(0x00, 0x00) << 8;
/* 读取数据包长度 */
len = ENC28J60_ReadOp(0x00, 0x00);
len |= ENC28J60_ReadOp(0x00, 0x00) << 8;
len -= 4; // 移除CRC
/* 读取接收状态 */
rxstat = ENC28J60_ReadOp(0x00, 0x00);
rxstat |= ENC28J60_ReadOp(0x00, 0x00) << 8;
/* 限制读取长度 */
if(len > maxlen - 1)
{
len = maxlen - 1;
}
/* 读取数据包 */
ENC28J60_ReadBuffer(len, packet);
/* 释放缓冲区 */
ENC28J60_Write(ERXRDPTL, NextPacketPtr);
ENC28J60_Write(ERXRDPTH, NextPacketPtr >> 8);
ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, 0x40);
return len;
}
/**
* @brief 发送数据包
*/
void ENC28J60_PacketSend(uint16_t len, uint8_t* packet)
{
/* 等待之前的发送完成 */
while(ENC28J60_Read(ECON1) & 0x08)
{
HAL_Delay(1);
}
/* 设置写指针 */
ENC28J60_Write(EWRPTL, ENC28J60_TXSTART_INIT & 0xFF);
ENC28J60_Write(EWRPTH, ENC28J60_TXSTART_INIT >> 8);
/* 写入控制字节 */
ENC28J60_WriteBuffer(1, (uint8_t[]){0x00});
/* 写入数据包长度 */
ENC28J60_WriteBuffer(2, (uint8_t[]){len & 0xFF, len >> 8});
/* 写入数据 */
ENC28J60_WriteBuffer(len, packet);
/* 启动发送 */
ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, 0x08);
}
参考代码 STM32 UIP 协议下实现 TCP UDP功能 www.youwenfan.com/contentcsv/70749.html
七、测试与调试
7.1 测试程序
c
/**
* @file test_network.c
* @brief 网络功能测试
*/
#include "main.h"
/* 测试函数 */
void test_tcp_echo_server(void)
{
printf("Testing TCP Echo Server...\n");
/* 创建TCP监听 */
struct uip_conn *conn = uip_listen(HTONS(9999));
if(conn)
{
printf("TCP Echo Server listening on port 9999\n");
}
}
void test_udp_echo_server(void)
{
printf("Testing UDP Echo Server...\n");
uip_ipaddr_t addr;
uip_ipaddr(&addr, 0,0,0,0);
struct uip_udp_conn *conn = uip_udp_new(&addr, HTONS(0));
if(conn)
{
uip_udp_bind(conn, HTONS(9998));
printf("UDP Echo Server listening on port 9998\n");
}
}
void network_test_benchmark(void)
{
static uint32_t last_report = 0;
static uint32_t packets_rx = 0;
static uint32_t packets_tx = 0;
/* 每5秒报告一次统计信息 */
if((clock_time() - last_report) > (CLOCK_SECOND * 5))
{
last_report = clock_time();
printf("\n=== Network Statistics ===\n");
printf("Uptime: %lu seconds\n", clock_time() / CLOCK_SECOND);
printf("Active TCP Connections: %d\n", 0); // 需要统计
printf("Packets Received: %lu\n", packets_rx);
printf("Packets Sent: %lu\n", packets_tx);
printf("===========================\n");
}
}
7.2 客户端测试脚本 (Python)
python
#!/usr/bin/env python3
"""
网络测试客户端脚本
"""
import socket
import time
import struct
def test_tcp_echo(host='192.168.1.100', port=9999):
"""测试TCP回显服务器"""
print(f"Testing TCP Echo Server on {host}:{port}")
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
sock.connect((host, port))
# 发送测试数据
test_data = b"Hello TCP Server!"
sock.send(test_data)
# 接收响应
response = sock.recv(1024)
print(f"Received: {response}")
sock.close()
return True
except Exception as e:
print(f"TCP Test failed: {e}")
return False
def test_udp_echo(host='192.168.1.100', port=9998):
"""测试UDP回显服务器"""
print(f"Testing UDP Echo Server on {host}:{port}")
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(5)
# 发送测试数据
test_data = b"Hello UDP Server!"
sock.sendto(test_data, (host, port))
# 接收响应
response, addr = sock.recvfrom(1024)
print(f"Received from {addr}: {response}")
sock.close()
return True
except Exception as e:
print(f"UDP Test failed: {e}")
return False
def test_http_server(host='192.168.1.100', port=80):
"""测试HTTP服务器"""
print(f"Testing HTTP Server on {host}:{port}")
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
sock.connect((host, port))
# 发送HTTP GET请求
request = b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"
sock.send(request)
# 接收响应
response = b""
while True:
chunk = sock.recv(1024)
if not chunk:
break
response += chunk
print(f"HTTP Response:\n{response[:200]}...")
sock.close()
return True
except Exception as e:
print(f"HTTP Test failed: {e}")
return False
def test_broadcast(port=1236):
"""测试广播发现"""
print(f"Testing UDP Broadcast on port {port}")
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.settimeout(5)
# 发送广播发现请求
discovery_packet = b'\xFF' # 发现命令
sock.sendto(discovery_packet, ('255.255.255.255', port))
# 接收响应
try:
response, addr = sock.recvfrom(1024)
print(f"Received broadcast response from {addr}: {response}")
except socket.timeout:
print("No broadcast response received")
sock.close()
return True
except Exception as e:
print(f"Broadcast Test failed: {e}")
return False
if __name__ == "__main__":
host = "192.168.1.100" # STM32的IP地址
print("Starting Network Tests...\n")
# 运行所有测试
tests = [
("HTTP Server", lambda: test_http_server(host, 80)),
("TCP Echo", lambda: test_tcp_echo(host, 9999)),
("UDP Echo", lambda: test_udp_echo(host, 9998)),
("Broadcast", lambda: test_broadcast(1236)),
]
results = []
for test_name, test_func in tests:
print(f"\n{'='*50}")
print(f"Test: {test_name}")
print('='*50)
result = test_func()
results.append((test_name, result))
time.sleep(1)
# 打印测试结果
print(f"\n{'='*50}")
print("Test Results:")
print('='*50)
for test_name, result in results:
status = "PASS" if result else "FAIL"
print(f"{test_name:20} {status}")
八、优化与调试技巧
8.1 内存优化
c
/* 内存池管理 */
#define MEM_POOL_SIZE 2048
static uint8_t mem_pool[MEM_POOL_SIZE];
static uint16_t mem_ptr = 0;
void* mem_alloc(uint16_t size)
{
if(mem_ptr + size > MEM_POOL_SIZE)
return NULL;
void* ptr = &mem_pool[mem_ptr];
mem_ptr += size;
return ptr;
}
void mem_free_all(void)
{
mem_ptr = 0;
}
8.2 性能监控
c
/* 网络性能统计 */
typedef struct {
uint32_t tcp_packets_rx;
uint32_t tcp_packets_tx;
uint32_t udp_packets_rx;
uint32_t udp_packets_tx;
uint32_t arp_requests;
uint32_t arp_replies;
uint32_t icmp_packets;
uint32_t errors;
} net_stats_t;
static net_stats_t network_stats = {0};
void update_network_stats(uint8_t type)
{
switch(type)
{
case 0: network_stats.tcp_packets_rx++; break;
case 1: network_stats.tcp_packets_tx++; break;
case 2: network_stats.udp_packets_rx++; break;
case 3: network_stats.udp_packets_tx++; break;
case 4: network_stats.arp_requests++; break;
case 5: network_stats.arp_replies++; break;
case 6: network_stats.icmp_packets++; break;
case 7: network_stats.errors++; break;
}
}
九、常见问题解决
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 无法ping通 | 1. IP地址配置错误 2. 网络连接问题 3. ARP表问题 | 1. 检查IP配置 2. 检查网线连接 3. 清除ARP缓存 |
| TCP连接失败 | 1. 端口被占用 2. 防火墙阻止 3. 协议栈未初始化 | 1. 使用netstat检查端口 2. 禁用防火墙 3. 检查初始化顺序 |
| 数据包丢失 | 1. 缓冲区不足 2. 网络拥堵 3. 定时器配置错误 | 1. 增大缓冲区 2. 优化网络拓扑 3. 调整定时器参数 |
| 内存泄漏 | 1. 内存分配未释放 2. 连接未正确关闭 3. 缓冲区溢出 | 1. 使用内存池 2. 确保连接关闭 3. 添加边界检查 |
这个完整的STM32 + uIP协议栈实现提供了TCP和UDP通信的全套解决方案。