打印
[研电赛技术支持]

GD32H759I-EVAL 以太网通信

[复制链接]
142|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
评估板:GD32H759I-EVAL

连接方式:网线连接评估板网线接口(银色方块)和电脑



工程文件:在评估板配套资料的26

跳线帽配置:



代码需要修改main.h中参数的配置

Windows 系统查看 IP 地址、子网掩码、网关
按下 Win + R,输入 cmd 打开命令提示符。
输入 ipconfig 并回车
将结果复制给ai让它给出修改建议(让它按照以太网那个数据给,不是wifi那个)。
我还人工设置了一下以太网的地址(好像他除了最后一小段都要和板子的IP一样,所以需要手动改一下)我评估板的 172.16.179.150 同所以那个以太网就设置成172.16.179.131





这里可以问问ai都设置成什么

5.验证以太网接口的 IP 配置是否生效

再次执行 ipconfig,确认 “以太网 2” 的 IP 已变为手动配置的地址





之后下载网络调试助手,我是在CSDN上找了个网盘资源的NetAssist。

然后分别让电脑为服务端(TCP),客户端(TCP),和进行UDP通信。

这个过程中主机地址主机端口都要看好才设置(按照配套资料的代码中的数据去设置)

并且这个网络调试助手上的地址和端口都可以手动修改(即使它的下拉菜单没有,也可以手动改)

最终结果:

电脑为服务端:



电脑为客户端:



进行UDP通信(不需要三次握手建立通信,直接通信,记得修改“远程主机”的端口1025):



统计以太网通信的帧速率:

修改资料给的工程文件:

在文件夹inc中添加一个h头文件comm_stats.h(让所有文件使用完全相同的枚举类型,避免因各文件单独定义枚举导致的 “类型不兼容” 或 “枚举值冲突”):

#ifndef __COMM_STATS_H
#define __COMM_STATS_H

#include <stdint.h>

/* 通信类型枚举(补充COMM_TYPE_UNKNOWN) */
typedef enum {
    COMM_TYPE_TCP_SERVER,    // 评估板作为TCP服务端
    COMM_TYPE_TCP_CLIENT,    // 评估板作为TCP客户端
    COMM_TYPE_UDP,           // UDP通信
    COMM_TYPE_UNKNOWN        // 新增:未知类型
} comm_type_t;

/* 声明统计函数 */
void comm_stats_on_receive(comm_type_t type);

#endif /* __COMM_STATS_H */



之后修改文件夹src中的hello_gigadevice.c

/*!
    \file    hello_gigadevice.c
    \brief   TCP server demo program with communication statistics
*/

#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "FreeRTOS.h"
#include "hello_gigadevice.h"
#include <string.h>
#include <stdio.h>
#include "gd32h7xx.h"
#include "lwip/api.h"
#include "task.h"
#include "main.h"  
#include "comm_stats.h"

#define HELLO_TASK_PRIO  ( tskIDLE_PRIORITY + 5 )
#define MAX_NAME_SIZE      32

#define GREETING           "\n\r======= HelloGigaDevice =======\
                            \n\r== GD32 ==\
                            \n\r== Telnet SUCCESS==\
                            \n\rHello. What is your name?\r\n"
#define HELLO              "\n\rGigaDevice PORT Hello "



#if ((LWIP_SOCKET == 0) && (LWIP_NETCONN == 1))

static err_t hello_gigadevice_recv(struct netconn *conn, void *data, u16_t len);
static err_t hello_gigadevice_accept(struct netconn *conn);

/*!
    \brief      called when a data is received on the telnet connection
    \param[in]  conn: the TCP netconn over which to send data
    \param[in]  data: pointer to the data received
    \param[in]  len: size of the data
    \param[out] none
    \retval     err_t: error value
*/
static err_t hello_gigadevice_recv(struct netconn *conn, void *data, u16_t len)
{
    int done;
    char *c;
    int i;

    done = 0;
    c = (char *)data;
    /* a telnet communication packet is ended with an enter key */
    for(i = 0; i < len && !done; i++) {
        done = ((c == '\r') || (c == '\n'));
    }

    if(done) {
        if(c[len - 2] != '\r' || c[len - 1] != '\n') {
            /* limit the received data length to MAX_NAME_SIZE - 2('\r' and '\n' will be put into the buffer) */
            if((c[len - 1] == '\r' || c[len - 1] == '\n') && (len + 1 <= MAX_NAME_SIZE)) {
                /* calculate the buffer size to be sent(including '\r' and '\n') */
                len += 1;
            } else if(len + 2 <= MAX_NAME_SIZE) {
                len += 2;
            } else {
                len = MAX_NAME_SIZE;
            }
            /* save the received data to a new buffer */
            c[len - 2] = '\r';
            c[len - 1] = '\n';
        }
        netconn_write(conn, (void *)&HELLO, sizeof(HELLO), NETCONN_COPY);
        netconn_write(conn, data, len, NETCONN_COPY);
    }

    // 新增:收到数据后通知统计系统(TCP服务端通信)
    comm_stats_on_receive(COMM_TYPE_TCP_SERVER);
    return ERR_OK;
}

/*!
    \brief      called when the telnet connection is established
    \param[in]  conn: the TCP netconn over which to send data
    \param[out] none
    \retval     err_t: error value
*/
static err_t hello_gigadevice_accept(struct netconn *conn)
{
    u32_t ipaddress;
    u8_t iptxt[50];
    volatile u8_t iptab[4];
    struct tcp_pcb *pcb;

    pcb = conn->pcb.tcp;
    ipaddress = pcb->remote_ip.addr;

    /* read its IP address */
    iptab[0] = (u8_t)(ipaddress >> 24);
    iptab[1] = (u8_t)(ipaddress >> 16);
    iptab[2] = (u8_t)(ipaddress >> 8);
    iptab[3] = (u8_t)(ipaddress);

    sprintf((char *)iptxt, "Telnet:%d.%d.%d.%d   ", iptab[3], iptab[2], iptab[1], iptab[0]);

    /* send out the first message */
    netconn_write(conn, (void *)&iptxt, sizeof(iptxt), NETCONN_COPY);
    netconn_write(conn, (void *)&GREETING, sizeof(GREETING), NETCONN_COPY);

    return ERR_OK;
}

/*!
    \brief      hello task
    \param[in]  arg: user supplied argument
    \param[out] none
    \retval     none
*/
static void hello_task(void *arg)
{
    struct netconn *conn, *newconn;
    err_t err, accept_err;
    struct netbuf *buf;
    void *data;
    u16_t len;
    err_t recv_err;

    LWIP_UNUSED_ARG(arg);

    conn = netconn_new(NETCONN_TCP);

    if(NULL != conn) {
        /* bind connection to well known port number 8000 */
        err = netconn_bind(conn, NULL, 8000);

        if(ERR_OK == err) {

            netconn_listen(conn);

            while(1) {
                /* grab new connection */
                accept_err = netconn_accept(conn, &newconn);

                /* process the new connection */
                if(ERR_OK == accept_err) {
                    hello_gigadevice_accept(newconn);

                    recv_err = netconn_recv(newconn, &buf);
                    while(ERR_OK == recv_err) {

                        do {
                            netbuf_data(buf, &data, &len);
                        } while(netbuf_next(buf) >= 0);
                        hello_gigadevice_recv(newconn, data, len);
                        netbuf_delete(buf);

                        recv_err = netconn_recv(newconn, &buf);
                    }

                    /* close connection and discard connection identifier */
                    netconn_close(newconn);
                    netconn_delete(newconn);
                }
            }
        } else {
            netconn_delete(newconn);
            printf(" can not bind TCP netconn");
        }
    } else {
        printf("can not create TCP netconn");
    }
}

#endif /* ((LWIP_SOCKET == 0) && (LWIP_NETCONN == 1)) */



#if LWIP_SOCKET
#include "lwip/sockets.h"

struct recev_packet {
    int length;
    char bytes[MAX_NAME_SIZE];
    int done;
} name_recv;

static err_t hello_gigadevice_recv(int fd, void *data, int len);

/*!
    \brief      called when a data is received on the telnet connection
    \param[in]  fd: the socket id which to send data
    \param[in]  data: pointer to the data received
    \param[in]  len: size of the data
    \param[out] none
    \retval     err_t: error value
*/
static err_t hello_gigadevice_recv(int fd, void *data, int len)
{
    char *c;
    int i;
    int done;

    done = 0;
    c = (char *)data;

    /* a telnet communication packet is ended with an enter key,
       in socket, here is to check whether the last packet is complete */
    for(i = 0; i < len && !done; i++) {
        done = ((c == '\r') || (c == '\n'));
    }

    /* when the packet length received is no larger than MAX_NAME_SIZE */
    if(0 == name_recv.done) {
        /* havn't received the end of the packet, so the received data length
           is the configured socket reception limit--MAX_NAME_SIZE */
        if(0 == done) {
            memcpy(name_recv.bytes, data, MAX_NAME_SIZE);
            name_recv.length = MAX_NAME_SIZE;
            name_recv.done = 1;
            /* have received the end of the packet */
        } else {
            memcpy(name_recv.bytes, data, len);
            name_recv.length = len;
        }
    }
    if(1 == done) {
        if(c[len - 2] != '\r' || c[len - 1] != '\n') {
            /* limit the received data length to MAX_NAME_SIZE - 2('\r' and '\n' will be put into the buffer) */
            if((c[len - 1] == '\r' || c[len - 1] == '\n') && (len + 1 <= MAX_NAME_SIZE)) {
                /* calculate the buffer size to be sent(including '\r' and '\n') */
                name_recv.length += 1;
            } else if(len + 2 <= MAX_NAME_SIZE) {
                name_recv.length += 2;
            } else {
                name_recv.length = MAX_NAME_SIZE;
            }
            /* save the received data to name_recv.bytes */
            name_recv.bytes[name_recv.length - 2] = '\r';
            name_recv.bytes[name_recv.length - 1] = '\n';
        }
        send(fd, (void *)&HELLO, sizeof(HELLO), 0);
        send(fd, name_recv.bytes, name_recv.length, 0);
        name_recv.done = 0;
        name_recv.length = 0;
    }
    // 新增:收到数据后通知统计系统(TCP服务端通信)
    comm_stats_on_receive(COMM_TYPE_TCP_SERVER);
    return ERR_OK;
}
/*!
    \brief      hello task
    \param[in]  arg: user supplied argument
    \param[out] none
    \retval     none
*/
static void hello_task(void *arg)
{
    int ret;
    int sockfd = -1, newfd = -1;
    uint32_t len;
    int tcp_port = 8000;
    int recvnum;
    struct sockaddr_in svr_addr, clt_addr;
    char buf[50];
    /* bind to port 8000 at any interface */
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(tcp_port);
    svr_addr.sin_addr.s_addr = htons(INADDR_ANY);
    name_recv.length = 0;
    name_recv.done = 0;
    while(1) {
        /* create a TCP socket */
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(sockfd < 0) {
            continue;
        }
        ret = bind(sockfd, (struct sockaddr *)&svr_addr, sizeof(svr_addr));
        if(ret < 0) {
            lwip_close(sockfd);
            sockfd = -1;
            continue;
        }
        /* listen for incoming connections (TCP listen backlog = 1) */
        ret = listen(sockfd, 1);
        if(ret < 0) {
            lwip_close(sockfd);
            continue;
        }
        len = sizeof(clt_addr);
        /* grab new connection */
        newfd = accept(sockfd, (struct sockaddr *)&clt_addr, (socklen_t *)&len);
        if(-1 != newfd) {
            send(newfd, (void *)&GREETING, sizeof(GREETING), 0);
        }
        while(-1 != newfd) {
            /* reveive packets, and limit a reception to MAX_NAME_SIZE bytes */
            recvnum = recv(newfd, buf, MAX_NAME_SIZE, 0);
            if(recvnum <= 0) {
                lwip_close(newfd);
                newfd = -1;
                break;
            }
            hello_gigadevice_recv(newfd, buf, recvnum);
        }
        lwip_close(sockfd);
        sockfd = -1;
    }
}
#endif /* LWIP_SOCKET */
/*!
    \brief      initialize the hello application
    \param[in]  none
    \param[out] none
    \retval     none
*/
void hello_gigadevice_init(void)
{
    xTaskCreate(hello_task, "HELLO", DEFAULT_THREAD_STACKSIZE, NULL, HELLO_TASK_PRIO, NULL);
}



之后修改文件夹src中的tcp_client.c

/*!
    \file    tcp_client.c
    \brief   TCP client demo program with communication statistics
*/

#include "lwip/opt.h"
#include "lwip/sys.h"
#include "tcp_client.h"
#include <string.h>
#include <stdio.h>
#include "gd32h7xx.h"
#include "main.h"  // 用于调用统计函数
#include "lwip/tcp.h"
#include "lwip/memp.h"
#include "lwip/api.h"
#include "comm_stats.h"

#define TCP_CLIENT_TASK_PRIO            ( tskIDLE_PRIORITY + 5)
#define MAX_BUF_SIZE                    50
#define TIME_WAITING_FOR_CONNECT        ( ( portTickType ) 500 )

#if ((LWIP_SOCKET == 0) && (LWIP_NETCONN == 1))

struct recev_packet {
    int length;
    char bytes[MAX_BUF_SIZE];
};

static err_t tcp_client_recv(struct netconn *conn, struct netbuf *buf);

/*!
    \brief      收到数据时调用(TCP客户端模式)
    \param[in]  conn: 网络连接对象
    \param[in]  buf: 接收的数据缓冲区
    \param[out] none
    \retval     err_t: 错误码
*/
static err_t tcp_client_recv(struct netconn *conn, struct netbuf *buf)
{
    struct pbuf *q;
    struct recev_packet recev_packet;
    uint32_t data_len = 0;

    if(NULL != buf) {
        for(q = buf->p; q != NULL; q = q->next) {
            if(q->len > (MAX_BUF_SIZE - data_len)) {
                memcpy((recev_packet.bytes + data_len), q->payload, (MAX_BUF_SIZE - data_len));
                data_len = MAX_BUF_SIZE;
            } else {
                memcpy((recev_packet.bytes + data_len), q->payload, q->len);
                data_len += q->len;
            }
            if(data_len >= MAX_BUF_SIZE) break;
        }

        recev_packet.length = data_len;
        netconn_write(conn, (void *)&(recev_packet.bytes), recev_packet.length, NETCONN_COPY);
    }

    // 新增:通知统计系统(TCP客户端通信)
    comm_stats_on_receive(COMM_TYPE_TCP_CLIENT);
    return ERR_OK;
}

/*!
    \brief      TCP客户端任务
    \param[in]  arg: 未使用
    \param[out] none
    \retval     none
*/
static void tcp_client_task(void *arg)
{
    struct netconn *conn;
    ip_addr_t ipaddr;
    struct netbuf *buf;
    err_t ret, recv_err;

    IP4_ADDR(&ipaddr, IP_S_ADDR0, IP_S_ADDR1, IP_S_ADDR2, IP_S_ADDR3);

    while(1) {
        conn = netconn_new(NETCONN_TCP);
        recv_err = netconn_bind(conn, IP_ADDR_ANY, 10260);

        if((ERR_USE != recv_err) && (ERR_ISCONN != recv_err)) {
            ret = netconn_connect(conn, &ipaddr, 10260);
            if(ERR_OK == ret) {
                recv_err = netconn_recv(conn, &buf);
                while(ERR_OK == recv_err) {
                    tcp_client_recv(conn, buf);
                    netbuf_delete(buf);
                    recv_err = netconn_recv(conn, &buf);
                }
            }
        }

        netconn_close(conn);
        netconn_delete(conn);
    }
}

#endif /* ((LWIP_SOCKET == 0) && (LWIP_NETCONN == 1)) */



#if LWIP_SOCKET
#include "lwip/sockets.h"

/*!
    \brief      TCP客户端任务(Socket模式)
    \param[in]  arg: 未使用
    \param[out] none
    \retval     none
*/
static void tcp_client_task(void *arg)
{
    int  ret, recvnum, sockfd = -1;
    int tcp_port = 10260;
    struct sockaddr_in svr_addr, clt_addr;
    char buf[100];
    ip_addr_t ipaddr;

    IP4_ADDR(&ipaddr, IP_S_ADDR0, IP_S_ADDR1, IP_S_ADDR2, IP_S_ADDR3);

    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(tcp_port);
    svr_addr.sin_addr.s_addr = ipaddr.addr;

    clt_addr.sin_family = AF_INET;
    clt_addr.sin_port = htons(tcp_port);
    clt_addr.sin_addr.s_addr = htons(INADDR_ANY);

    while(1) {
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(sockfd < 0) continue;

        ret = bind(sockfd, (struct sockaddr *)&clt_addr, sizeof(clt_addr));
        if(ret < 0) {
            lwip_close(sockfd);
            sockfd = -1;
            continue;
        }

        ret = connect(sockfd, (struct sockaddr *)&svr_addr, sizeof(svr_addr));
        if(ret < 0) {
            lwip_close(sockfd);
            sockfd = -1;
            continue;
        }

        while(-1 != sockfd) {
            recvnum = recv(sockfd, buf, MAX_BUF_SIZE, 0);
            if(recvnum <= 0) {
                lwip_close(sockfd);
                sockfd = -1;
                break;
            }
            send(sockfd, buf, recvnum, 0);

            // 新增:通知统计系统(TCP客户端通信)
            comm_stats_on_receive(COMM_TYPE_TCP_CLIENT);
        }

        lwip_close(sockfd);
        sockfd = -1;
    }
}

#endif /* LWIP_SOCKET */


/*!
    \brief      初始化TCP客户端
    \param[in]  none
    \param[out] none
    \retval     none
*/
void tcp_client_init(void)
{
    xTaskCreate(tcp_client_task, "TCP_CLIENT", DEFAULT_THREAD_STACKSIZE, NULL, TCP_CLIENT_TASK_PRIO, NULL);
}



之后修改文件夹src中的udp_echo.c

/*!
    \file    udp_echo.c
    \brief   UDP demo program with communication statistics
*/

#include "main.h"
#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "udp_echo.h"
#include <string.h>
#include <stdio.h>
#include "gd32h7xx.h"
#include "lwip/memp.h"
#include "lwip/api.h"
#include "comm_stats.h"

#define UDP_TASK_PRIO       ( tskIDLE_PRIORITY + 5)
#define MAX_BUF_SIZE        50


#if ((LWIP_SOCKET == 0) && (LWIP_NETCONN == 1))

struct recev_packet {
    int length;
    char bytes[MAX_BUF_SIZE];
};

static err_t udp_echo_recv(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port);

/*!
    \brief      收到UDP数据时调用
    \param[in]  conn: UDP连接对象
    \param[in]  buf: 接收的数据缓冲区
    \param[in]  addr: 发送方IP地址
    \param[in]  port: 发送方端口
    \param[out] none
    \retval     err_t: 错误码
*/
static err_t udp_echo_recv(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
{
    struct pbuf *q;
    struct recev_packet recev_packet;
    uint32_t data_len = 0;
    struct netbuf *udpbuf;

    if(NULL != buf) {
        for(q = buf->p; q != NULL; q = q->next) {
            if(q->len > (MAX_BUF_SIZE - data_len)) {
                memcpy((recev_packet.bytes + data_len), q->payload, (MAX_BUF_SIZE - data_len));
                data_len = MAX_BUF_SIZE;
            } else {
                memcpy((recev_packet.bytes + data_len), q->payload, q->len);
                data_len += q->len;
            }
            if(data_len >= MAX_BUF_SIZE) break;
        }

        recev_packet.length = data_len;
        udpbuf = netbuf_new();
        netbuf_ref(udpbuf, recev_packet.bytes, recev_packet.length);
        netconn_sendto(conn, udpbuf, addr, port);
        netbuf_delete(udpbuf);
    }

    // 新增:通知统计系统(UDP通信)
    comm_stats_on_receive(COMM_TYPE_UDP);
    return ERR_OK;
}

/*!
    \brief      UDP回显任务
    \param[in]  arg: 未使用
    \param[out] none
    \retval     none
*/
static void udp_task(void *arg)
{
    struct netconn *conn;
    ip_addr_t ipaddr;
    struct netbuf *buf;
    err_t recv_err;

    IP4_ADDR(&ipaddr, IP_S_ADDR0, IP_S_ADDR1, IP_S_ADDR2, IP_S_ADDR3);

    conn = netconn_new(NETCONN_UDP);
    netconn_bind(conn, IP_ADDR_ANY, 1025);  // 绑定1025端口

    while(1) {
        recv_err = netconn_recv(conn, &buf);
        while(ERR_OK == recv_err) {
            udp_echo_recv(conn, buf, &ipaddr, 1025);
            netbuf_delete(buf);
            recv_err = netconn_recv(conn, &buf);
        }

        netconn_close(conn);
        netconn_delete(conn);
    }
}

#endif /* ((LWIP_SOCKET == 0) && (LWIP_NETCONN == 1)) */



#if LWIP_SOCKET
#include "lwip/sockets.h"

/*!
    \brief      UDP回显任务(Socket模式)
    \param[in]  arg: 未使用
    \param[out] none
    \retval     none
*/
static void udp_task(void *arg)
{
    int  ret, recvnum, sockfd = -1;
    int udp_port = 1025;
    struct sockaddr_in rmt_addr, bod_addr;
    char buf[100];
    u32_t len;
    ip_addr_t ipaddr;

    IP4_ADDR(&ipaddr, IP_S_ADDR0, IP_S_ADDR1, IP_S_ADDR2, IP_S_ADDR3);

    rmt_addr.sin_family = AF_INET;
    rmt_addr.sin_port = htons(udp_port);
    rmt_addr.sin_addr.s_addr = ipaddr.addr;

    bod_addr.sin_family = AF_INET;
    bod_addr.sin_port = htons(udp_port);
    bod_addr.sin_addr.s_addr = htons(INADDR_ANY);

    while(1) {
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfd < 0) continue;

        ret = bind(sockfd, (struct sockaddr *)&bod_addr, sizeof(bod_addr));
        if(ret < 0) {
            lwip_close(sockfd);
            sockfd = -1;
            continue;
        }

        len = sizeof(rmt_addr);
        recvnum = recvfrom(sockfd, buf, MAX_BUF_SIZE, 0, (struct sockaddr *)&rmt_addr, &len);

        while(-1 != sockfd) {
            if(recvnum > 0) {
                sendto(sockfd, buf, recvnum, 0, (struct sockaddr *)&rmt_addr, sizeof(rmt_addr));

                // 新增:通知统计系统(UDP通信)
                comm_stats_on_receive(COMM_TYPE_UDP);
            }
            recvnum = recvfrom(sockfd, buf, MAX_BUF_SIZE, 0, (struct sockaddr *)&rmt_addr, &len);
        }

        lwip_close(sockfd);
    }
}

#endif /* LWIP_SOCKET */


/*!
    \brief      初始化UDP回显功能
    \param[in]  none
    \param[out] none
    \retval     none
*/
void udp_echo_init(void)
{
    xTaskCreate(udp_task, "UDP", DEFAULT_THREAD_STACKSIZE, NULL, UDP_TASK_PRIO, NULL);
}



最终修改main.c

/*!
    \file    main.c
    \brief   enet demo with communication statistics
*/

#include "gd32h7xx.h"
#include "netconf.h"
#include "main.h"
#include "lwip/tcp.h"
#include "lwip/timeouts.h"
#include "gd32h759i_eval.h"
#include "hello_gigadevice.h"
#include "tcp_client.h"
#include "udp_echo.h"
#include <string.h>
#include <inttypes.h>
#include "comm_stats.h"  // 包含公共头文件,使用其中的枚举定义

/* 任务优先级 */
#define INIT_TASK_PRIO     (tskIDLE_PRIORITY + 1)
#define DHCP_TASK_PRIO     (tskIDLE_PRIORITY + 4)
#define LED_TASK_PRIO      (tskIDLE_PRIORITY + 2)
#define STATS_TASK_PRIO    (tskIDLE_PRIORITY + 5)

/* 超时时间(3秒) */
#define COMM_TIMEOUT_MS    3000

/* 网络接口对象(定义以解决链接错误) */
struct netif g_mynetif;
extern struct netif g_mynetif;  // 声明为外部变量供其他文件使用

/* 通信统计结构体 */
typedef struct {
    uint32_t total_frames;         // 总帧数
    uint32_t max_fps;              // 最大帧率(帧/秒)
    uint32_t current_second_frames;// 当前1秒内帧数
    uint32_t start_time;           // 统计开始时间(毫秒)
    uint32_t last_frame_time;      // 最后一帧时间(毫秒)
    uint32_t first_frame_time;     // 第一帧时间(毫秒)
    comm_type_t comm_type;         // 通信类型(使用comm_stats.h中的枚举)
    uint8_t stats_active;          // 统计激活标志
} comm_stats_t;

/* 全局统计变量 */
static comm_stats_t g_comm_stats;

/* 函数声明 */
void cache_enable(void);
void mpu_config(void);
void led_task(void *pvParameters);
void init_task(void *pvParameters);
void stats_monitor_task(void *pvParameters);
static void comm_stats_reset(void);
void comm_stats_on_receive(comm_type_t type);  // 使用comm_stats.h中的枚举
static void comm_stats_print_result(void);
void lwip_netif_status_callback(struct netif *netif);  // 实现网络接口回调


/*!
    \brief  系统启动时打印初始信息
*/
static void print_initial_message(void)
{
    printf("\n\n=== 以太网通信测试 ===\n");  // 一运行就打印
}


/*!
    \brief  重置统计信息
*/
static void comm_stats_reset(void)
{
    memset(&g_comm_stats, 0, sizeof(comm_stats_t));
    g_comm_stats.comm_type = COMM_TYPE_UNKNOWN;  // 使用comm_stats.h中的枚举值
    g_comm_stats.stats_active = 0;
}


/*!
    \brief  收到数据时调用,更新统计并打印"开始通信"
*/
void comm_stats_on_receive(comm_type_t type)  // 参数类型来自comm_stats.h
{
    uint32_t current_time = xTaskGetTickCount();

    if (!g_comm_stats.stats_active) {
        // 首次收到数据,打印"开始通信"
        g_comm_stats.stats_active = 1;
        g_comm_stats.comm_type = type;  // 记录通信类型(来自comm_stats.h)
        g_comm_stats.first_frame_time = current_time;
        g_comm_stats.start_time = current_time;
        g_comm_stats.current_second_frames = 1;
        g_comm_stats.max_fps = 1;
        g_comm_stats.total_frames = 1;
        g_comm_stats.last_frame_time = current_time;

        printf("===== 开始通信 =====\n");  // 开始通信时打印
        return;
    }

    // 非首次收到数据,更新统计
    g_comm_stats.total_frames++;
    g_comm_stats.last_frame_time = current_time;

    // 计算每秒帧数并更新最大帧率
    uint32_t time_since_start = current_time - g_comm_stats.start_time;
    uint32_t current_second = time_since_start / 1000;
    uint32_t prev_second = (time_since_start - 1000) / 1000;

    if (current_second > prev_second) {
        g_comm_stats.max_fps = g_comm_stats.current_second_frames > g_comm_stats.max_fps ?
                              g_comm_stats.current_second_frames : g_comm_stats.max_fps;
        g_comm_stats.current_second_frames = 1;
    } else {
        g_comm_stats.current_second_frames++;
    }
}


/*!
    \brief  打印最终统计结果
*/
static void comm_stats_print_result(void)
{
    if (!g_comm_stats.stats_active) return;

    uint32_t total_ms = g_comm_stats.last_frame_time - g_comm_stats.first_frame_time;

    printf("\n===== 通信统计结果 =====\n");
    // 打印通信类型(使用comm_stats.h中的枚举值判断)
    switch(g_comm_stats.comm_type) {
        case COMM_TYPE_TCP_SERVER:
            printf("通信类型:TCP(电脑作为客户端,评估板作为服务端)\n");
            break;
        case COMM_TYPE_TCP_CLIENT:
            printf("通信类型:TCP(电脑作为服务端,评估板作为客户端)\n");
            break;
        case COMM_TYPE_UDP:
            printf("通信类型:UDP\n");
            break;
        default:
            printf("通信类型:未知\n");
            break;
    }
    // 打印持续时间、总帧数、最大帧率
    printf("通信持续时间:%" PRIu32 ".%03" PRIu32 " 秒\n", total_ms / 1000, total_ms % 1000);
    printf("总帧数:%" PRIu32 " 帧\n", g_comm_stats.total_frames);
    printf("最大帧速率:%" PRIu32 " 帧/秒\n", g_comm_stats.max_fps);
    printf("========================\n\n");

    comm_stats_reset();  // 重置统计
}


/*!
    \brief  统计监控任务:检测3秒无数据后打印结果
*/
void stats_monitor_task(void *pvParameters)
{
    TickType_t xLastWakeTime = xTaskGetTickCount();
    const TickType_t xCheckInterval = pdMS_TO_TICKS(100);  // 每100ms检查一次

    for(;;) {
        vTaskDelayUntil(&xLastWakeTime, xCheckInterval);

        if (g_comm_stats.stats_active) {
            uint32_t current_time = xTaskGetTickCount();
            uint32_t idle_time = current_time - g_comm_stats.last_frame_time;

            if (idle_time >= COMM_TIMEOUT_MS) {
                comm_stats_print_result();  // 3秒无数据,打印结果
            }
        }
    }
}


/*!
    \brief  网络接口状态回调(解决链接错误)
*/
void lwip_netif_status_callback(struct netif *netif)
{
    if ((netif->flags & NETIF_FLAG_UP) && netif->ip_addr.addr) {
        // 初始化TCP/UDP服务
        hello_gigadevice_init();  // TCP服务端
        tcp_client_init();        // TCP客户端
        udp_echo_init();          // UDP
    }
}


/*!
    \brief  主函数
*/
int main(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
    comm_stats_reset();
    xTaskCreate(init_task, "INIT", configMINIMAL_STACK_SIZE * 2, NULL, INIT_TASK_PRIO, NULL);
    vTaskStartScheduler();
    while(1);
}


/*!
    \brief  初始化任务
*/
void init_task(void *pvParameters)
{
    mpu_config();
    cache_enable();

    // 初始化串口并打印启动信息
    gd_eval_com_init(EVAL_COM);
    print_initial_message();  // 打印"以太网测试"

    gd_eval_led_init(LED1);
    enet_system_setup();      // 配置以太网
    lwip_stack_init();        // 初始化LwIP

#ifdef USE_DHCP
    // 启动DHCP客户端
    xTaskCreate(dhcp_task, "DHCP", configMINIMAL_STACK_SIZE * 2, NULL, DHCP_TASK_PRIO, NULL);
#else
    // 静态IP配置(根据实际网络修改)
    ip_addr_t ipaddr, netmask, gw;
    IP4_ADDR(&ipaddr, 172, 16, 179, 150);   // 评估板IP
    IP4_ADDR(&netmask, 255, 255, 255, 0);  // 子网掩码
    IP4_ADDR(&gw, 172, 16, 179, 1);        // 网关
    netif_set_addr(&g_mynetif, &ipaddr, &netmask, &gw);
#endif

    // 创建LED任务和统计任务
    xTaskCreate(led_task, "LED", configMINIMAL_STACK_SIZE, NULL, LED_TASK_PRIO, NULL);
    xTaskCreate(stats_monitor_task, "STATS", configMINIMAL_STACK_SIZE * 2, NULL, STATS_TASK_PRIO, NULL);

    vTaskDelete(NULL);
}


/*!
    \brief  LED闪烁任务
*/
void led_task(void *pvParameters)
{
    for(;;) {
        gd_eval_led_toggle(LED1);
        vTaskDelay(250);
    }
}


/*!
    \brief  使能CPU缓存
*/
void cache_enable(void)
{
    SCB_EnableICache();
    SCB_EnableDCache();
}


/*!
    \brief  配置MPU
*/
void mpu_config(void)
{
    mpu_region_init_struct mpu_init_struct;
    mpu_region_struct_para_init(&mpu_init_struct);
    ARM_MPU_SetRegion(0U, 0U);

    // 配置DMA和缓冲区
    mpu_init_struct.region_base_address = 0x30000000;
    mpu_init_struct.region_size = MPU_REGION_SIZE_16KB;
    mpu_init_struct.access_permission = MPU_AP_FULL_ACCESS;
    mpu_init_struct.access_bufferable = MPU_ACCESS_BUFFERABLE;
    mpu_init_struct.access_cacheable = MPU_ACCESS_NON_CACHEABLE;
    mpu_init_struct.access_shareable = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number = MPU_REGION_NUMBER0;
    mpu_init_struct.subregion_disable = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec = MPU_INSTRUCTION_EXEC_PERMIT;
    mpu_init_struct.tex_type = MPU_TEX_TYPE0;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();

    // 配置LwIP堆内存
    mpu_init_struct.region_base_address = 0x30004000;
    mpu_init_struct.region_size = MPU_REGION_SIZE_16KB;
    mpu_init_struct.access_bufferable = MPU_ACCESS_NON_BUFFERABLE;
    mpu_init_struct.access_shareable = MPU_ACCESS_SHAREABLE;
    mpu_init_struct.region_number = MPU_REGION_NUMBER1;
    mpu_init_struct.tex_type = MPU_TEX_TYPE1;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();

    ARM_MPU_Enable(MPU_MODE_PRIV_DEFAULT);
}


/*!
    \brief  串口重定向
*/
#ifdef GD_ECLIPSE_GCC
int __io_putchar(int ch)
{
    usart_data_transmit(EVAL_COM, (uint8_t)ch);
    while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
    return ch;
}
#else
int fputc(int ch, FILE *f)
{
    usart_data_transmit(EVAL_COM, (uint8_t)ch);
    while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
    return ch;
}
#endif



实现功能,统计打印各个通信过程中的帧速率:







————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_59104195/article/details/149708792

使用特权

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

本版积分规则

70

主题

213

帖子

0

粉丝