目前的整车电子电器架构中,Ethernet的应用已经非常普遍,可以说,到了整车标配的程度。所以,汽车嵌入式工程师掌握Ethernet,也愈发的必要。如果想透彻的理解Ethernet,不能仅仅停留在协议层面,结合实例"跑"起来,才能对问题有更深刻的理解。
本文,基于TC375 Demo+Lwip,对UDP(User Datagram Protocol,用户数据报协议)、TCP(Transmission Control Protocol,传输控制协议)示例进行了二次开发。对于移植过程中的注意点进行说明,最后,给出工程源码。 对于Lwip,本文不做过多说明,对于入门的同学,可以参考:https://doc./net/lwip/zh/latest/index.html。本文使用的开发板是TC375,使用的Phy型号为DP83825I,结合手册,确认使用的Pin脚,如下所示:对应的软件实现位置如下(...\Ethernet\lwip\port\src\netif.c):Server端IP Address配置(IP4),需要修改Ifx_Lwip.c文件的Ifx_Lwip_init()接口,本文IP4设置如下:struct udp_pcb* g_UDPPcb; /****************************************************************************** * 描述 : 初始化UDP Server * 参数 : 无 * 返回 : 无 ******************************************************************************/ static void UDP_server_init(void) { ip_addr_t rmtipaddr;
IP4_ADDR(&rmtipaddr, 192,168,0,10); /* 创建UDP协议控制块 */ g_UDPPcb = udp_new();
if (g_UDPPcb != NULL) { #define UDP_LOCAL_PORT 90 /* pcb:指定一个连接(pcb) ipaddr:绑定的本地IP地址。如果为IP_ADDR_ANY,则将连接绑定到所有的本地IP地址上 port:绑定的本地端口号。 注意:千万不要和其它的应用程序产生冲突 */ err_t err = udp_bind(g_UDPPcb, IP_ADDR_ANY, UDP_LOCAL_PORT); if (err == ERR_OK) { /* ipaddr:设置连接的远程主机IP地址 port:设置连接的远程主机端口号 */ udp_connect(g_UDPPcb, &rmtipaddr, UDP_LOCAL_PORT); /* 注册接收回调函数 */ udp_recv(g_UDPPcb, UDP_server_receive_callback, NULL); } else{ /* 删除控制块 */ udp_remove(g_UDPPcb); } } }
static void UDP_server_receive_callback(void *arg, struct udp_pcb *upcb,\ struct pbuf *p, const ip_addr_t *addr, u16_t port) { /* 数据回传 */ udp_sendto(upcb, p, addr, port);
/* 释放缓冲区数据 */ pbuf_free(p); }
提示:UDP绑定的Port Number = 90。 (四)TCP Server代码实现 相对于UDP,TCP稍微复杂一些,对应实现代码如下:
struct tcp_pcb* g_TCPPcb; void TCP_server_init(void) { g_TCPPcb = tcp_new(); if (g_TCPPcb != NULL) { err_t err = tcp_bind(g_TCPPcb, IP_ADDR_ANY, TCP_LOCAL_PORT); if (err == ERR_OK) { g_TCPPcb = tcp_listen(g_TCPPcb); tcp_accept(g_TCPPcb, tcp_server_accept); } else { memp_free(MEMP_TCP_PCB, g_TCPPcb); } }
}
/****************************************************************************** * 描述 : 客户端接收回调函数 ******************************************************************************/ static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { /* 注册接收回调函数 */ tcp_recv(newpcb, tcp_server_recv);
return ERR_OK; }
/****************************************************************************** * 描述 : 接收回调函数 ******************************************************************************/ static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { #define TCP_SEND_DATA_LEN 20 uint32_t i; if (p != NULL) { struct pbuf *ptmp = p; while(ptmp != NULL) { for (i = 0; i < TCP_SEND_DATA_LEN; i++) { TCP_RecData[i] = *((char *)p->payload + i) + 2; } ptmp = p->next; } tcp_recved(tpcb, p->tot_len); /* 释放缓冲区数据 */ pbuf_free(p);
/* 发送数据 */ tcp_write(tpcb, TCP_RecData, TCP_SEND_DATA_LEN, TCP_WRITE_FLAG_COPY); } else if (err == ERR_OK) { tcp_recved(tpcb, p->tot_len); return tcp_close(tpcb); }
return ERR_OK; } 提示:TCP绑定的Port Number = 8088。提示:接收到的信息递交给上层由端口号(Port Number)唯一标识,即:传输层将信息发送给目标应用层,由Port Number决定。而某些端口号已经使用,eg:53(DNS协议)、80(HTTP协议)、13400(DOIP协议)等。所以,实现过程中,如果没有使用这些协议,避免使用这些端口号。 https://github.com/Kaixinguo2021/TC375_Tasking_Ethernet.git(一)待优化
本文的示例中,TCP的发送不稳定(发送一段时间挂掉),还需要优化。
|