[研电赛技术支持] 基于 GD32F450 的以太网 ENC28J60 驱动开发:TCP 通信建立与数据传输

[复制链接]
134|0
Haizangwang 发表于 2025-11-5 16:59 | 显示全部楼层 |阅读模式
基于 GD32F450 与 ENC28J60 的 TCP 通信实现
一、系统架构
graph TD
    A[GD32F450] -->|SPI| B(ENC28J60)
    B -->|RJ45| C[以太网]
    D[TCP客户端] -->|IP:192.168.1.100| B
    A --> E[应用程序]


二、关键开发步骤
硬件接口配置

SPI 时钟配置:

48498690b11e20b3ea.png

引脚映射:
SCK: PA5
MISO: PA6
MOSI: PA7
CS: PA4
INT: PA3
ENC28J60 驱动层

// ENC28J60 初始化
void ENC28J60_Init(void) {
    SPI_Config();  // SPI 初始化
    ETH_Reset();   // 硬件复位
    // 设置接收缓冲区
    ENC28J60_WriteReg(ERXSTL, RX_BUF_START & 0xFF);
    ENC28J60_WriteReg(ERXSTH, RX_BUF_START >> 8);
    // 启用接收功能
    ENC28J60_BitSet(ECON1, ECON1_RXEN);
}



TCP/IP 协议栈实现

ARP 协议处理
IP 分片重组
TCP 状态机:

98435690b11f45db73.png

TCP 连接建立代码

// TCP 三次握手处理
void TCP_Handshake(tcp_pcb* pcb) {
    // 发送 SYN
    tcp_send_syn(pcb);
    // 等待 SYN-ACK
    while(pcb->state != SYN_RCVD);
    // 发送 ACK
    tcp_send_ack(pcb);
}


三、数据传输实现
数据发送流程
void TCP_SendData(uint8_t* data, uint16_t len) {
    // 创建TCP段
    tcp_seg* seg = tcp_create_seg(pcb, data, len);
    // 添加到发送队列
    tcp_enqueue(pcb, seg);
    // 触发发送
    ENC28J60_StartTransmit();
}


数据接收处理
// 接收回调函数
err_t tcp_recv_cb(void* arg, tcp_pcb* pcb, pbuf* p, err_t err) {
    if (p != NULL) {
        // 处理接收数据
        ProcessData(p->payload, p->len);
        pbuf_free(p);  // 释放缓冲区
    }
    return ERR_OK;
}


四、关键参数配置

52492690b11bc138dc.png

五、调试要点
网络连通性测试

ping 192.168.1.50  # 测试基础连通性
telnet 192.168.1.50 8080  # 测试TCP端口


常见问题解决

丢包问题:检查 SPI 时序,确保时钟频率 ≤ 20MHz
连接超时:验证 ARP 缓存表是否正确建立
数据校验错误:启用 ENC28J60 的 CRC 校验功能
ENC28J60_BitSet(ECON1, ECON1_CRCEN);


六、性能优化
启用 DMA 传输:

45272690b117c258e5.png

2

91118690b11602bae9.png

实现 Nagle 算法减少小包传输
提示:完整实现需结合 lwIP 或 uIP 协议栈,上述代码为精简示例。实际开发中建议使用硬件定时器处理 TCP 超时重传,避免阻塞主循环。
————————————————
版权声明:本文为CSDN博主「2501_93939917」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/2501_93939917/article/details/154250653

您需要登录后才可以回帖 登录 | 注册

本版积分规则

95

主题

300

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部