基于STM32F407与LAN8720A实现以太网通信

一、硬件连接方案(RMII模式)

graph LR A[STM32F407] -->|RMII接口| B[LAN8720A] A -->|GPIO| B subgraph STM32F407 ETH_MDC --> GPIOC1 ETH_MDIO --> GPIOA2 ETH_RMII_REF_CLK --> GPIOA1 ETH_RMII_CRS_DV --> GPIOA7 ETH_RMII_RXD0 --> GPIOC4 ETH_RMII_RXD1 --> GPIOC5 ETH_RMII_TX_EN --> GPIOG11 ETH_RMII_TXD0 --> GPIOG13 ETH_RMII_TXD1 --> GPIOG14 ETH_RESET --> GPIOD3 end subgraph LAN8720A MDC --> ETH_MDC MDIO --> ETH_MDIO RX_CLK --> ETH_RMII_REF_CLK RX_DV --> ETH_RMII_CRS_DV RX_ER --> NC RXD0 --> ETH_RMII_RXD0 RXD1 --> ETH_RMII_RXD1 TX_CLK --> ETH_RMII_TX_CLK TX_EN --> ETH_RMII_TX_EN TXD0 --> ETH_RMII_TXD0 TXD1 --> ETH_RMII_TXD1 nRST --> ETH_RESET end

二、软件实现流程

2.1 CubeMX配置(关键参数)

  1. 时钟配置

    • HSE设置为外部8MHz晶振
    • PLL配置:PLL_SRC=HSE, PLLM=8, PLLN=336, PLLP=2, PLLQ=7
    • ETH时钟源选择PLL2(需启用PLL2)
  2. 以太网配置

    • 模式选择:RMII
    • PHY地址:0x01(根据实际电路调整)
    • 自动协商:启用
    • 接收缓冲区:20个(ETH_RXBUFNB=20)
  3. LWIP配置

    #define LWIP_DHCP 1
    #define LWIP_NETIF_HOSTNAME 1
    #define MEM_SIZE (16 * 1024)
    #define PBUF_POOL_SIZE 16
    #define TCPIP_THREAD_STACKSIZE 1024
    

2.2 PHY驱动代码(HAL库实现)

// PHY复位函数
void PHY_Reset(void) {
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
    HAL_Delay(50);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_SET);
    HAL_Delay(100);
}

// PHY状态检测
uint8_t PHY_LinkStatus(void) {
    uint16_t regval = ETH_ReadPHYRegister(0x01, 0x0001);
    return (regval & 0x0004) ? 1 : 0; // Link status bit
}

// 初始化流程
void MX_ETH_Init(void) {
    __HAL_RCC_ETH_CLK_ENABLE();
    
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    // 配置RMII引脚(代码参考CubeMX生成)
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    
    PHY_Reset();
    HAL_Delay(200);
    
    // 配置自动协商
    ETH_ConfigPhy(ETH_AUTONEGOTIATION_ENABLE);
}

2.3 LWIP协议栈集成

// 网络接口初始化
struct netif gnetif;
void lwip_init_system(void) {
    IP4_ADDR(&ipaddr, 192,168,1,100);
    IP4_ADDR(&netmask, 255,255,255,0);
    IP4_ADDR(&gw, 192,168,1,1);
    
    netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, eth_init, ethernet_input);
    netif_set_default(&gnetif);
    netif_set_up(&gnetif);
}

// 低层接口实现
err_t eth_init(struct netif *netif) {
    netif->linkoutput = eth_linkoutput;
    netif->output = eth_output;
    netif->state = (void*)&mac_address;
    return ERR_OK;
}

// 数据包发送
err_t eth_linkoutput(struct netif *netif, struct pbuf *p) {
    return HAL_ETH_TransmitFrame(&heth, p->payload, p->len);
}

三、关键功能实现

3.1 TCP服务器

void tcp_server_task(void *arg) {
    struct tcp_pcb *pcb = tcp_new();
    tcp_bind(pcb, IP_ADDR_ANY, 8080);
    tcp_listen(pcb);
    
    while(1) {
        struct tcp_pcb *newpcb = tcp_accept(pcb, tcp_accept_cb);
        if(newpcb) {
            tcp_arg(newpcb, newpcb);
            tcp_recv(newpcb, tcp_recv_cb);
            tcp_err(newpcb, tcp_err_cb);
        }
    }
}

// 接收回调
err_t tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
    if(p) {
        // 处理接收数据
        tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY);
        pbuf_free(p);
    }
    return ERR_OK;
}

3.2 UDP广播

void udp_broadcast_task(void) {
    struct udp_pcb *upcb = udp_new();
    udp_bind(upcb, IP_ADDR_ANY, 0);
    
    while(1) {
        uint8_t msg[] = "Hello World";
        udp_sendto(upcb, msg, sizeof(msg), IP_ADDR_BROADCAST, 1234);
        HAL_Delay(1000);
    }
}

四、完整工程结构

STM32F407_ETH_Driver/
├── Core/
│   ├── Inc/
│   │   ├── main.h
│   │   ├── lwipopts.h
│   │   └── lan8720.h
│   └── Src/
│       ├── main.c
│       ├── lwip.c
│       └── lan8720.c
├── Drivers/
│   ├── CMSIS/
│   └── STM32F4xx_HAL_Driver/
└── Middlewares/
    └── lwIP/

五、扩展功能实现

5.1 MQTT协议集成

#include "mqtt_client.h"

void mqtt_connect() {
    mqtt_client_connect("broker.hivemq.com", 1883, "STM32_Client");
}

void mqtt_publish() {
    mqtt_publish("topic/sensor", "Hello MQTT", strlen("Hello MQTT"));
}

5.2 Web服务器实现

void web_server_init() {
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.uri_match_fn = httpd_uri_match_wildcard;
    
    httpd_uri_t uri_get = {
        .uri       = "/status",
        .method    = HTTP_GET,
        .handler   = status_handler,
        .user_ctx  = NULL
    };
    
    httpd_register_uri_handler(server, &uri_get);
}

参考代码 通过STM32F407来驱动LAN8720A实现网络通信 www.youwenfan.com/contentcnl/57058.html

六、测试验证

  1. 基础测试

    ping 192.168.1.100
    # 预期结果:Reply from 192.168.1.100: bytes=32 time<1ms TTL=64
    
  2. 流量测试

    // 使用iperf3测试带宽
    iperf3 -s  # 服务端
    iperf3 -c 192.168.1.100  # 客户端
    
  3. 压力测试

    // 持续发送1000个TCP连接
    for(i=0; i<1000; i++) {
        tcp_client_connect("192.168.1.100", 8080);
    }
    
posted @ 2025-11-10 15:50  别说我的眼泪有点咸  阅读(0)  评论(0)    收藏  举报