打印
[应用方案]

以太网通信初探:基于APM32F407实现TCP/IP协议栈

[复制链接]
266|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
a976209770|  楼主 | 2024-11-28 15:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 a976209770 于 2024-11-28 15:05 编辑

lwIP 是一个轻量级的 TCP/IP 协议栈,适用于嵌入式系统,支持 TCP、UDP、DNS 和 DHCP 等常用网络协议。本文将以 APM32 系列为例,介绍如何移植 lwIP 并实现完整的网络通信流程,包括发送和接收数据的详细代码示例。


1. lwIP 的基础配置lwIP 的配置通过 lwipopts.h 文件完成,该文件定义了协议栈的功能模块和资源分配。以下是推荐的配置:
1.1 配置文件:lwipopts.h#ifndef LWIPOPTS_H
#define LWIPOPTS_H

// 基本功能启用
#define LWIP_TCP                1  // 启用TCP
#define LWIP_UDP                1  // 启用UDP
#define LWIP_DNS                1  // 启用DNS
#define LWIP_DHCP               1  // 启用DHCP

// 内存配置
#define MEM_SIZE                1600  // 内存池大小
#define MEMP_NUM_PBUF           16    // PBUF内存块数量
#define PBUF_POOL_SIZE          16    // PBUF池大小
#define PBUF_POOL_BUFSIZE       512   // 单个PBUF大小

// TCP配置
#define TCP_MSS                 1460  // 最大报文段长度
#define TCP_SND_BUF             (4 * TCP_MSS)  // 发送缓冲区
#define TCP_WND                 (4 * TCP_MSS)  // 接收窗口

// 系统配置
#define NO_SYS                  0  // 使用操作系统
#define SYS_LIGHTWEIGHT_PROT    1  // 启用轻量级保护

// 网络接口
#define LWIP_NETIF_STATUS_CALLBACK 1  // 启用网络接口状态回调

#endif // LWIPOPTS_H

2. lwIP 的移植
实现网络接口是 lwIP 移植的核心。以下代码示例展示了基本的以太网初始化、数据接收和发送。
以太网接口初始化

#include "lwip/err.h"
#include "lwip/netif.h"
#include "ethernetif.h"
#include "apm32f4xx_eth.h"

static uint8_t rx_buffer[1536];
static uint8_t tx_buffer[1536];

err_t ethernetif_init(struct netif *netif)
{
    netif->hwaddr_len = ETH_HWADDR_LEN;
    netif->hwaddr[0] = 0x02;  // 示例MAC地址
    netif->hwaddr[1] = 0x00;
    netif->hwaddr[2] = 0x00;
    netif->hwaddr[3] = 0x00;
    netif->hwaddr[4] = 0x00;
    netif->hwaddr[5] = 0x01;
    netif->mtu = 1500;
    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;

    ETH_Config();  // 硬件以太网初始化
    return ERR_OK;
}
以太网数据接收
void ethernetif_input(struct netif *netif)
{
    struct pbuf *p = NULL;

    if (ETH_CheckFrameReceived())
    {
        uint16_t len = ETH_GetReceivedFrame(rx_buffer, sizeof(rx_buffer));
        if (len > 0)
        {
            p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
            if (p != NULL)
            {
                memcpy(p->payload, rx_buffer, len);
                if (netif->input(p, netif) != ERR_OK)
                {
                    pbuf_free(p);
                }
            }
        }
    }
}
以太网数据发送
err_t ethernetif_output(struct netif *netif, struct pbuf *p)
{
    struct pbuf *q;
    uint16_t offset = 0;

    for (q = p; q != NULL; q = q->next)
    {
        memcpy(&tx_buffer[offset], q->payload, q->len);
        offset += q->len;
    }

    ETH_SendFrame(tx_buffer, offset);
    return ERR_OK;
}

3. 主程序初始化
以下代码展示如何基于 lwIP 实现 TCP 数据的发送和接收。
3.1 数据发送

static void tcp_send_data(struct tcp_pcb *pcb, const char *data, uint16_t len)
{
    err_t err = tcp_write(pcb, data, len, TCP_WRITE_FLAG_COPY);
    if (err == ERR_OK)
    {
        tcp_output(pcb);
    }
}
3.2 数据接收
static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
    if (p != NULL)
    {
        printf("Received: %s\n", (char *)p->payload);
        tcp_send_data(tpcb, (char *)p->payload, p->tot_len);
        tcp_recved(tpcb, p->tot_len);
        pbuf_free(p);
    }
    else if (err == ERR_OK)
    {
        tcp_close(tpcb);
    }
    return ERR_OK;
}
3.3 TCP 服务器
void tcp_server_init(void)
{
    struct tcp_pcb *pcb = tcp_new();
    tcp_bind(pcb, IP_ADDR_ANY, 12345);
    pcb = tcp_listen(pcb);
    tcp_accept(pcb, tcp_server_accept);
}

static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
    tcp_recv(newpcb, tcp_server_recv);
    return ERR_OK;
}


4. 测试和调试
  • 测试方法:
    • 启动 lwIP TCP 服务器。
    • 使用客户端工具(如 telnet 或自定义工具)连接到服务器并发送数据。
  • 调试要点:
    • 确认网络初始化是否成功。
    • 确保 lwIP 的内存配置足够。
    • 检查接收数据的完整性。

5.主要模块分析

1. 核心协议栈(src/core)
  • core/ipv4 和 core/ipv6:实现 IP 协议栈的核心逻辑。
  • TCP、UDP 协议
    • tcp.c:TCP 协议的实现,包括连接管理、数据传输和状态机。
    • udp.c:UDP 协议的实现,提供无连接的轻量级数据传输功能。
  • 内存管理
    • mem.c:lwIP 的动态内存分配。
    • memp.c:提供固定大小内存池的管理。
  • 计时器
    • sys.c:实现 lwIP 的定时器和延时机制。
2. 应用接口层(src/api)
  • 提供标准的 BSD Sockets API,便于用户开发:
    • sockets.c:BSD 套接字实现。
    • tcpip.c:实现协议栈与应用接口之间的线程同步。
3. 网络接口(src/netif)
  • ethernetif.c:以太网接口的实现。
  • 提供硬件抽象层,负责接收和发送数据帧。
4. 系统架构(doc/sys_arch.txt)
  • 描述了与操作系统的接口,主要定义线程、信号量和消息队列的使用方式。


6. 总结
以上内容适用于 APM32 平台的网络开发,能够快速实现基于 lwIP 的网络通信功能。

附件为基于APM32F407的 lwIP 的示例代码,供参考














lwip-1.4.1.zip

621.71 KB

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

37

主题

40

帖子

0

粉丝