评估板: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
|
 共1人点赞
|