当前位置: 首页 > news >正文

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 配置、数据收发、回环测试。该方案可直接用于物联网设备、数据采集、实时控制等项目。
http://www.jsqmd.com/news/728743/

相关文章:

  • 告别VSCode卡顿与插件冲突:一份详细的缓存与插件数据清理指南(附一键清理脚本)
  • ModStart:基于 Laravel 的模块化开发框架,V11.0.0 版本新增 15 个特性!
  • 联创 DelBug:AI Agents 驱动,项目 + 缺陷 + 测试一站式管理,让交付更省心。
  • 2026年海牙认证服务机构名录:北京企业境外投资、吉尔吉斯斯坦海牙认证、境外投资备案审批流程、大使馆公证认证代办选择指南 - 优质品牌商家
  • 开源对话大模型MOSS:从架构解析到微调部署实战指南
  • 期货量化模拟转实盘检查清单:延迟、成交偏差与异常处理
  • 机器学习实验跟踪工具Neptune:从原理到实战的完整指南
  • 2026超高频工器具标签技术解析:耐高温电子标签/超高频4通道读写器/超高频8通道读写器/超高频工器具标签/超高频耐高温抗金属标签/选择指南 - 优质品牌商家
  • 深度学习图像描述生成技术解析与应用实践
  • 8devices Maca 2超远距离无线数据电台技术解析与应用
  • Transformer库实战:从原理到NLP应用部署
  • 数据库主键选型终极指南:从自增ID到分布式雪花
  • 构建AI智能体驱动的个人操作系统:从工作流自动化到认知增强
  • 告别枯燥调试!用CANoe Panel的CAPL Output View组件实时显示报文(附报文更新避坑指南)
  • 申博择导认知纠偏:打破固有误区,建立底层择导逻辑
  • 2026年4月全屋定制大揭秘,究竟哪家才是行业最强?
  • 深入AutoSar CAN通信栈:图解CAN IF模块如何桥接CAN Driver与上层
  • SERA代码代理训练框架:低成本高效AI辅助编程方案
  • 仅限前500名R工程师获取:Tidyverse 2.0自动化报告模板库(含FDA/ISO/金融监管合规元数据框架)
  • TSX07311628扩展模块
  • BeagleBone开发板:嵌入式系统开发与实时控制实战指南
  • 2026年小程序商城如何上架商品?
  • 激光成形技术:无模具金属加工的革命性方法
  • 通过环境变量为Hermes Agent配置Taotoken自定义模型提供方的详细方法
  • 别再硬编码了!用Simulink.Parameter对象管理模型参数的保姆级教程
  • 对比体验在 Taotoken 上切换不同模型生成代码片段的差异
  • Node.js统一LLM接口开发指南:多模型切换与生产实践
  • Red-emissive Oil-soluble Perovskite QDs,红光油溶性钙钛矿量子点的结构特征
  • 深度详解 GitHub Copilot:从入门安装、核心功能、实战技巧到避坑指南,程序员必备 AI 编程神器
  • 手把手教你用STM32驱动AD9910 DDS模块:从原理图到生成1GHz正弦波(附完整代码)