W55MH32 RTThread+UDP通信测试
目录
UDP 协议简介
UDP 的基本原理
UDP 的优势
RT-Thread简介
RT-Thread特点
注意事项
应用场景
编辑总结
本篇文章,我们将详细介绍如何在W55MH32 以太网芯片与 RT-Thread 实时操作系统,实现一款同时支持 UDP 服务器 + UDP 客户端双模式并行运行的回环测试程序。 通过两个独立线程分别处理 UDP 监听与主动发送逻辑,结合 W55MH32 硬件协议栈特性,完成双向数据收发验证,为嵌入式多角色网络通信提供直接可复用的实践方案。
该例程用到的其他网络协议,例如 DHCP , 请参考相关章节。有关 W55MH32 的初始化过程,请参考 Network install ,这里将不再赘述。
UDP 协议简介
UDP是一种无连接、不可靠的轻量级传输层通信协议,基于 IP 协议实现数据报文传输。 UDP 不需要提前建立连接,直接将数据报文发送到目标地址,具有速度快、延迟低、资源占用小的特点,是嵌入式设备、实时通信、局域网广播场景中最常用的通信协议之一。
UDP 的基本原理
- 无连接:发送端不需要与接收端建立连接。
- 不可靠:数据可能丢失、重复、乱序。
- 支持单播、广播、组播:可一对一会话,也可一对多群发。
- 速度极快:没有握手、确认、重传机制,延迟极低。
UDP 的优势
- 轻量高效:协议头小,CPU 与内存占用极低。
- 传输速度快:无握手、无确认,适合高速数据传输。
- 支持一对多通信:可实现组播、广播,适合多设备联动。
- 实时性强:适合传感器数据、控制指令、状态上报等场景。
- 结构简单:嵌入式设备极易实现,稳定性高。
RT-Thread简介
- RT-Thread 是一款由中国社区主导开发的开源、硬实时嵌入式操作系统(RTOS)。它诞生于 2006 年,经过近 20 年的发展,已经从最初的一个小巧的内核,演变成了一个组件丰富、生态完善的物联网操作系统平台。
- 简单来说,它就像是物联网设备的“大脑”和“管家”,负责管理硬件资源、调度任务,并提供网络连接等高级功能。
RT-Thread特点
- 极致轻量与可裁剪:它的内核非常精简,Nano 版本最小仅需 3KB ROM 和 1KB RAM,可以运行在资源极其有限的芯片上(如 Cortex-M0)。同时,它采用“内核+组件”的架构,你可以像搭积木一样,通过图形化工具(Env)按需裁剪系统功能。
- 硬实时性:采用抢占式调度算法,保证高优先级任务能立即抢占低优先级任务,中断响应时间达到微秒级,非常适合对时间要求严苛的工业控制和汽车电子场景。
- 丰富的软件生态:这是 RT-Thread 最大的亮点之一。它拥有类似手机应用商店的软件包机制,内置了 TCP/IP 协议栈、文件系统、GUI 引擎以及大量的传感器驱动和云连接组件(如 MQTT、AWS、阿里云)。开发者可以直接复用这些资源,极大地加速开发。
- 开源与商业友好:遵循 Apache License 2.0 协议,这意味着你可以免费将其用于商业产品,且无需公开你自己的产品代码。
注意事项
- 数据不可靠:无重传机制,重要数据需自行加以校验。
- 无连接:无法保证对方是否在线、是否收到数据。
- 局域网为主:组播、广播通常只能在局域网内生效。
- 端口占用:同一时间一个端口只能被一个设备使用。
应用场景
- 局域网设备发现:通过广播或组播自动搜索设备。
- 高速数据采集:传感器、采集器实时上传数据到上位机。
- 多设备联动控制:一个主机控制多个从机。
- 实时指令下发:LED、继电器、电机快速控制。
- 组播同步数据:多设备同步接收相同数据。
- RT-Thread 多任务通信:同时运行 UDP + HTTP + TCP 多协议
UDP 报文结构
UDP 报文非常简单,仅包含基本头部 + 数据部分:
- 源端口:发送方的端口号;
- 目标端口:接收方的端口号;
- 数据长度:(2即整个 UDP 报文的长度,包括头部和数据,单位为字节;
- 校验和:校验和;
结构简单、处理极快,非常适合嵌入式平台。
UDP 报文实例
在W55MH32中,UDP协议已在内部硬件协议栈实现, 所以我们只需要读取和写入对应寄存器的值即可实现发送和接收数据,无需手动组包。
| 报文原文 | C0A8 0001 C0A8 0002 1F90 1F91 0021 F7DF 4865 6C6C 6F2C 2055 4450 21 | 报文解析 | 1.IP部分(前16字节): C0A8 0001: 源IP地址(192.168.0.1) C0A8 0002: 目标IP地址(192.168.0.2) 2.UDP部分(后部分): 1F90: 源端口号(8080) 1F91: 目标端口号(8081) 0021: 报文长度(33字节) F7DF: 校验和(校验数据完整性) 4865 6C6C 6F2C 2055 4450 21: 数据部分("Hello, UDP!" 的ASCII表示)RT-Thread 运行环境说明
采用多线程并发设计,UDP 服务端、客户端拆分为两个独立任务,互不阻塞、独立调度;
借助 RT-Thread 临界区接口,保护 SPI 硬件总线资源,避免多线程抢占导致硬件通信异常;
基于系统毫秒级延时与任务时间片轮转调度,保障网络通信稳定性与实时性;
原生支持动态线程创建、资源管理,代码模块化强,便于后续拓展 TCP、MQTT、HTTP 等多协议并发业务。
实现过程
请注意:
测试实例需要 PC 端和 W55MH32 处于同一网段。
- UDP Server:监听 8080 端口,接收任意数据并原样回发。
- UDP Client:主动向电脑 192.168.1.147:8080 发送数据,实现请求 - 响应式回环。
步骤 1:初始化 W55MH32 与 RT-Thread 环境
初始化网卡硬件、SPI 接口、PHY 链路、DHCP 自动获取 IP,并配置 RT-Thread 临界区保护。
wiz_toe_init(); reg_wizchip_cris_cbfunc(rt_enter_critical, rt_exit_critical); wiz_phy_link_check(); network_init(ethernet_buf, &default_net_info);步骤 2:基于 RT-Thread 创建双 UDP 任务
使用 RT-Thread 多任务,创建两个独立线程:
Task_UDPC_Handler = rt_thread_create("Task UDP Client", Task_UDPC, RT_NULL, 256, 1, 20); Task_UDPS_Handler = rt_thread_create("Task UDP Server", Task_UDPS, RT_NULL, 256, 1, 20); rt_thread_startup(Task_UDPC_Handler); rt_thread_startup(Task_UDPS_Handler);步骤 3:UDP Server 任务逻辑(RT-Thread 独立线程)
监听本地 8080 端口,收到任何数据直接回发。
void Task_UDPS(void *parameter) { printf("UDP Server loopback\r\n"); printf("Data from any source will be transmitted back.\r\n"); while (1) { loopback_udps(SOCKET_UDPS, tcps_ethernet_buf, local_port); rt_thread_mdelay(1); } }步骤 4:UDP Client 任务逻辑(RT-Thread 独立线程)
主动向电脑 192.168.1.147:8080 发送数据,收到回复后回发。
void Task_UDPC(void *parameter) { printf("UDP Client loopback\r\n"); printf("Only when the destination address and port number are consistent will it be returned.\r\n"); while (1) { loopback_udpc(SOCKET_UDPC, tcpc_ethernet_buf, dest_ip, dest_port); rt_thread_mdelay(1); } }步骤 5:网络参数配置
主动向电脑 192.168.1.147:8080 发送数据,收到回复后回发。
wiz_NetInfo default_net_info = { .mac = {0x00, 0x08, 0xdc, 0x12, 0x22, 0x12}, .ip = {192, 168, 1, 30}, .gw = {192, 168, 1, 1}, .sn = {255, 255, 255, 0}, .dns = {8, 8, 8, 8}, .dhcp = NETINFO_DHCP }; // 目标电脑 IP + 端口 uint8_t dest_ip[4] = {192, 168, 1, 147}; uint16_t dest_port = 8080; uint16_t local_port = 8080;参考代码(UDP 任务主逻辑)
通过 RT-Thread 自动初始化宏 INIT_APP_EXPORT 挂载应用,系统上电自动执行网络与任务初始化,无需手动调用。
#define DEFAULT_MAC_EN 1 #define SOCKET_UDPC 0 #define SOCKET_UDPS 1 #define ETHERNET_BUF_MAX_SIZE (1024 * 2) #define TASK_UDPC_PRIO 1 #define TASK_UDPC_STK_SIZE 256 static rt_thread_t Task_UDPC_Handler = RT_NULL; void Task_UDPC(void *pvParameters); #define TASK_UDPS_PRIO 1 #define TASK_UDPS_STK_SIZE 256 static rt_thread_t Task_UDPS_Handler = RT_NULL; void Task_UDPS(void *pvParameters); wiz_NetInfo default_net_info = { .mac = {0x00, 0x08, 0xdc, 0x12, 0x22, 0x12}, .ip = {192, 168, 1, 30}, .gw = {192, 168, 1, 1}, .sn = {255, 255, 255, 0}, .dns = {8, 8, 8, 8}, .dhcp = NETINFO_DHCP }; uint8_t dest_ip[4] = {192, 168, 1, 147}; uint16_t dest_port = 8080; uint8_t tcpc_ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0}; uint16_t local_port = 8080; uint8_t tcps_ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0}; int main(void) { while (1) { rt_thread_mdelay(1); } } int app_init(void) { rt_kprintf("%s RTThread UDP example\n",_WIZCHIP_ID_); wiz_toe_init(); reg_wizchip_cris_cbfunc(rt_enter_critical,rt_exit_critical); #if DEFAULT_MAC_EN == 1 getSHAR(default_net_info.mac); #endif wiz_phy_link_check(); network_init(tcpc_ethernet_buf, &default_net_info); setSn_KPALVTR(SOCKET_UDPC, 6); setSn_KPALVTR(SOCKET_UDPS, 6); Task_UDPC_Handler = rt_thread_create("Task UDP Client Handler", Task_UDPC, RT_NULL, TASK_UDPC_STK_SIZE, TASK_UDPC_PRIO, 20); Task_UDPS_Handler = rt_thread_create("Task UDP Server Handler", Task_UDPS, RT_NULL, TASK_UDPS_STK_SIZE, TASK_UDPS_PRIO, 20); rt_thread_startup(Task_UDPC_Handler); rt_thread_startup(Task_UDPS_Handler); return 0; } INIT_APP_EXPORT(app_init); void Task_UDPC(void *parameter) { printf("UDP Client loopback\r\n"); printf("Only when the destination address and port number are consistent will it be returned.\r\n"); while (1) { loopback_udpc(SOCKET_UDPC, tcpc_ethernet_buf, dest_ip, dest_port); rt_thread_mdelay(1); } } void Task_UDPS(void *parameter) { printf("UDP Server loopback\r\n"); printf("Data from any source will be transmitted back.\r\n"); while (1) { loopback_udps(SOCKET_UDPS, tcps_ethernet_buf,local_port); rt_thread_mdelay(1); } }烧录程序后,串口打印如下:
双模式同时运行、互不干扰
总结
本文基于 W55MH32 硬件 TCP/IP 协议栈 + RT-Thread 实时操作系统,实现了双线程 UDP 并行通信:
- UDP Server:监听 8080,接收即回传。
- UDP Client:主动连接电脑,请求 - 响应式回传。
- 完整展示了嵌入式 UDP 开发的核心流程:初始化、多线程创建、Socket 配置、数据收发、回环测试。该方案可直接用于物联网设备、数据采集、实时控制等项目。
