STM32 + uIP协议栈实现TCP/UDP功能指南

基于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通信的全套解决方案。

相关推荐
sdm0704275 小时前
TCP--面向字节流
网络·网络协议·tcp/ip
山木嵌入式15 小时前
【STM32实战】轻量级任务调度器实现
stm32·单片机·rtos·任务调度器·裸机开发
ytttr87315 小时前
DSP 28335 CAN总线通信程序
开发语言·stm32·单片机
缪懿17 小时前
应用层中的UDP协议原理
网络·网络协议·udp·javaee
田甲19 小时前
STM32开发环境迁移实践:从 CubeMX 生成 CMake 工程到 VS Code 编译与调试
stm32·单片机·嵌入式硬件
hoiii18719 小时前
在 STM32F1上读取 BMX055 三轴加速度
stm32·单片机·嵌入式硬件
satadriver19 小时前
ip-guard网络通信加解密
linux·网络·tcp/ip
IpdataCloud19 小时前
如何用Python和IP离线库查询IP归属地?获取国家、城市、经纬度的完整代码
开发语言·python·tcp/ip
嵌入式小站19 小时前
STM32 零基础可移植教程 04:按键输入,为什么按下去读到的是 0 或 1
chrome·stm32·嵌入式硬件