W55MH32 RTThread+UDP通信测试

目录

[UDP 协议简介](#UDP 协议简介)

[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协议已在内部硬件协议栈实现, 所以我们只需要读取和写入对应寄存器的值即可实现发送和接收数据,无需手动组包。

cpp 复制代码
| 报文原文 |
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 临界区保护。

cpp 复制代码
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 多任务,创建两个独立线程:

cpp 复制代码
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 端口,收到任何数据直接回发。

cpp 复制代码
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 发送数据,收到回复后回发。

cpp 复制代码
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 发送数据,收到回复后回发。

cpp 复制代码
                
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 挂载应用,系统上电自动执行网络与任务初始化,无需手动调用。

cpp 复制代码
  
#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 配置、数据收发、回环测试。该方案可直接用于物联网设备、数据采集、实时控制等项目。
相关推荐
skilllite作者1 小时前
LangChain-SkillLite 快速入门
网络·人工智能·安全·langchain·openclaw·agentskills
人道领域1 小时前
从零实现一个轻量级 RPC 框架:通信协议与动态代理的核心原理
开发语言·网络·qt
灰子学技术1 小时前
Envoy HTTP 协议实现技术文档
网络·网络协议·http
牛大兵1 小时前
IP扫描,局域网内扫描IP地址,找出有用,未使用的。正在使用的信息
服务器·网络·tcp/ip
CDN3602 小时前
告别“慢”与“不安全”:360CDN动态API加速与HTTPS配置实战
网络协议·安全·https
minji...2 小时前
Linux 网络套接字编程(七)TCP服务端和客户端的实现——网络版本计算器
linux·运维·服务器·网络·c++·tcp/ip·udp
aodunsoft2 小时前
安全月报 | 傲盾DDoS攻击防御2026年4月简报
网络·安全·ddos
Lucis__2 小时前
HTTP协议深度解析—从HTTP原理到手写实现服务器
服务器·网络协议·http
S1998_1997111609•X2 小时前
iOS栈被恶意篡改变成开发者模式漏洞裸露内核系统核心功能栈被泄露于政府黑客集团泄漏安全系统置门的犯罪行为原理
数据库·网络协议·百度·ssh·开闭原则