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

W55RP20-EVB-MKR 嵌入式 C 语言开发教程:UDP 客户端 / 服务端双模式通信

前言

上一篇教程中,我们已经完成了TCP Server 服务端通信的开发,实现了面向连接、稳定可靠的 TCP 数据交互。而在局域网设备快速通信、低延迟指令下发等场景中,UDP 协议凭借更轻量、更高效的特性,成为嵌入式开发的重要选择。

WIZnet W5500 内置硬件 TCP/IP 协议栈,搭配树莓派 Pico RP2040 主控,使用 C 语言 开发可实现极致低延迟、无阻塞、高可靠的 UDP 数据交互,完美适配传感器上报、局域网设备发现、批量指令下发等场景。

本文将基于 W55RP20-EVB-MKR 开发板,使用标准 C 语言 实现UDP 客户端UDP 服务端双模式通信,学完本文,你将掌握:

  • UDP 协议 C 语言 实现核心逻辑
  • W5500 硬件协议栈 C 语言 底层初始化流程
  • UDP 客户端定时发送数据
  • UDP 服务端非阻塞接收 + 自动回环通信
  • 网络调试助手联调 C 语言 网络程序
  • C 语言 版 UDP 通信异常一站式排查

系列教程学习路径

本专栏共 15 篇,循序渐进覆盖 W55RP20-EVB-MKR 模块 MicroPython 开发全流程:

1.第 1 篇:静态 IP 配置与网络基础

2.第 2 篇:DHCP 自动联网与网络诊断

3.第 3 篇:TCP Client 客户端通信

4.第 4 篇:TCP Server 服务端通信

5.第 5 篇:UDP 单播数据通信(本文)

6.第 6 篇:UDP 组播/广播数据通信

7.第 7 篇:DNS 域名解析

8.第 8 篇:NTP 从网络获取时间

9.第 9 篇:HTTP Client 客户端请求

10.第 10 篇:HTTP Server 服务端搭建

11.第 11 篇:HTTP 协议与 OneNET 平台数据上云

12.第 12 篇:MQTT 协议基础通信验证

13.第 13 篇:MQTT 协议与阿里云平台对接

14.第 14 篇:MQTT 协议与 OneNET 平台对接

15.第 15 篇:MQTT 协议与 ThingSpeak 平台对接

16.第 16 篇:Modbus 工业协议通信

建议收藏本专栏,跟随教程逐步学习,所有代码均会同步更新至官方 Gitee 仓库。

目录

1. 准备工作

1.1 软件准备

1.2 硬件准备

2. 开发环境配置

3. 硬件连接

4. UDP 通信核心原理

5. 核心代码解析(C 语言)

5.1 UDP 客户端代码(定时发送数据)

5.2 UDP 服务端代码(非阻塞接收 + 自动回复)

6. 代码关键步骤说明

6.1 UDP 客户端关键逻辑

6.2 UDP 服务端关键逻辑

7. 运行结果与测试验证

7.1 UDP 客户端运行日志

7.2 UDP 服务端运行日志

7.3 联调方法

8. 常见问题一站式排查指南

8.1 编译 / 烧录问题

8.2 网络不通

8.3 UDP 收发失败

9. W5500 硬件协议栈 C 语言 优势

10. 典型应用场景

11. 系列预告

1. 准备工作

1.1 软件准备

软件名称用途
Visual Studio Code + MKR SDKC 语言 开发、编译、烧录环境
网络调试助手UDP 数据收发测试
串口调试工具查看日志、打印信息

1.2 硬件准备

  • W55RP20-EVB-MKR 开发板
  • Micro USB 数据线(支持数据传输)
  • 网线
  • 路由器 / 电脑网口

W55RP20-EVB-MKR模块已集成以太网相关器件,无需额外焊接飞线,配合 RP2040 开发板可快速搭建开发环境,大幅降低接线错误和硬件故障概率。

2. 开发环境配置

  1. 安装 Raspberry Pi MKR SDK(C 语言 编译环境)
  2. 集成 WIZnet 官方 W5500 驱动库
  3. 配置 SPI、GPIO、串口底层驱动
  4. 支持一键编译生成 UF2 固件

环境配置完成后,可直接编译本文提供的 C 语言 代码。

3. 硬件连接

  1. USB 连接:Micro USB 连接开发板与电脑,用于供电、烧录、串口日志输出
  2. 以太网连接:网线连接开发板网口与路由器 LAN 口 / 电脑网口
  3. 无需额外接线:W55RP20-EVB-MKR 板载集成 W5500,自动匹配 SPI 引脚

4. UDP 通信核心原理

UDP(用户数据报协议)是无连接、轻量、低延迟的传输层协议:

  • 不需要三次握手建立连接
  • 不保证数据可靠性,但速度极快
  • 以数据报为单位收发,自带目标 IP / 端口
  • 适合:传感器上报、设备发现、短指令、局域网广播

C 语言 + W5500 工作流程硬件初始化 → 网络配置 → 创建 UDP Socket → 数据收发 → 循环运行

5. 核心代码解析(C 语言)

本文提供两套可直接编译运行的代码:

  1. UDP 客户端:定时向目标设备发送数据
  2. UDP 服务端:非阻塞监听端口,接收后自动回复

5.1 UDP 客户端代码(定时发送数据)

功能:开发板作为 UDP 客户端,每隔 1 秒向电脑发送测试数据

#include <stdio.h> #include <string.h> #include "pico/stdlib.h" #include "port_common.h" #include "wizchip_conf.h" #include "wizchip_spi.h" #include "socket.h" // 缓冲区与Socket配置 #define ETHERNET_BUF_MAX_SIZE (1024 * 2) #define SOCKET_UDP 0 #define PORT_UDP 8083 // 网络参数(静态IP) static wiz_NetInfo g_net_info = { .mac = {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56}, .ip = {192, 168, 1, 100}, .sn = {255, 255, 255, 0}, .gw = {192, 168, 1, 1}, .dns = {8, 8, 8, 8}, #if _WIZCHIP_ > W5500 .ipmode = NETINFO_STATIC_ALL #else .dhcp = NETINFO_STATIC #endif }; // 发送缓冲区 static uint8_t g_buf[ETHERNET_BUF_MAX_SIZE] = {0}; // 目标设备IP(填写你的电脑IP) static uint8_t dest_ip[4] = {192, 168, 1, 139}; int main() { // 串口初始化 stdio_init_all(); sleep_ms(100); printf("=====================================\n"); printf(" UDP Client (C Language)\n"); printf(" Board IP: 192.168.1.100\n"); printf(" Target IP: 192.168.1.139:%d\n", PORT_UDP); printf("=====================================\n"); // W5500 硬件初始化 wizchip_spi_initialize(); wizchip_cris_initialize(); wizchip_reset(); wizchip_initialize(); network_initialize(g_net_info); print_network_information(g_net_info); // 创建UDP Socket printf("UDP Socket Initializing...\n"); socket(SOCKET_UDP, Sn_MR_UDP, 0, 0); printf("UDP Socket Ready!\n"); // 加载发送数据 const char* send_data = "Hello from W5500 C Client!"; strcpy((char*)g_buf, send_data); // 主循环:定时发送 while (1) { sendto(SOCKET_UDP, g_buf, strlen(send_data), dest_ip, PORT_UDP); printf("UDP Sent: %s\n", send_data); sleep_ms(1000); } }

5.2 UDP 服务端代码(非阻塞接收 + 自动回复)

功能:开发板作为 UDP 服务端,监听本地端口,收到数据后立即原路回复(回环测试)

#include <stdio.h> #include "pico/stdlib.h" #include "port_common.h" #include "wizchip_conf.h" #include "wizchip_spi.h" #include "socket.h" #define ETHERNET_BUF_MAX_SIZE (1024 * 2) #define SOCKET_UDP 0 #define PORT_UDP 8083 // 网络配置 static wiz_NetInfo g_net_info = { .mac = {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56}, .ip = {192, 168, 1, 100}, .sn = {255, 255, 255, 0}, .gw = {192, 168, 1, 1}, .dns = {8, 8, 8, 8}, #if _WIZCHIP_ > W5500 .ipmode = NETINFO_STATIC_ALL #else .dhcp = NETINFO_STATIC #endif }; static uint8_t g_ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0}; int main() { stdio_init_all(); sleep_ms(100); printf("=====================================\n"); printf(" UDP Server (C Language)\n"); printf(" Board IP: 192.168.1.100\n"); printf(" Listen Port: %d\n", PORT_UDP); printf("=====================================\n"); // W5500 底层初始化 wizchip_spi_initialize(); wizchip_cris_initialize(); wizchip_reset(); wizchip_initialize(); network_initialize(g_net_info); print_network_information(g_net_info); // 初始化UDP服务端(绑定端口) printf("Opening UDP Socket...\n"); if(socket(SOCKET_UDP, Sn_MR_UDP, PORT_UDP, 0) < 0) { printf("Socket Init Failed!\n"); while(1); } printf("UDP Server Started!\n"); uint16_t rx_len; uint8_t remote_ip[4]; uint16_t remote_port; // 非阻塞主循环 while(1) { // 查询是否收到数据 if((rx_len = getSn_RX_RSR(SOCKET_UDP)) > 0) { // 读取数据 + 来源IP/端口 recvfrom(SOCKET_UDP, g_ethernet_buf, rx_len, remote_ip, &remote_port); // 打印接收信息 printf("Recv %d bytes from %d.%d.%d.%d:%d\n", rx_len, remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3], remote_port); // 自动回传 sendto(SOCKET_UDP, g_ethernet_buf, rx_len, remote_ip, remote_port); printf("Data Echo Back Success!\n"); } // 每秒心跳(证明程序运行正常) static uint32_t heart_tick = 0; if(to_ms_since_boot(get_absolute_time()) - heart_tick > 1000) { printf("[Heartbeat] UDP Server Running...\n"); heart_tick = to_ms_since_boot(get_absolute_time()); } } }

6. 代码关键步骤说明

6.1 UDP 客户端关键逻辑

  1. 硬件初始化:SPI + W5500 驱动加载
  2. 网络配置:静态 IP 直接入网
  3. Socket 创建socket(..., Sn_MR_UDP, ...)
  4. 发送数据sendto()指定目标 IP + 端口
  5. 定时发送:1 秒间隔上报数据

6.2 UDP 服务端关键逻辑

  1. 绑定端口:监听局域网数据
  2. 非阻塞查询getSn_RX_RSR()判断是否有数据
  3. 读取数据recvfrom()自动获取发送方 IP / 端口
  4. 自动回环sendto()原路返回数据
  5. 心跳打印:实时监控程序运行状态

7. 运行结果与测试验证

7.1 UDP 客户端运行日志

===================================== UDP Client (C Language) Board IP: 192.168.1.100 Target IP: 192.168.1.139:8083 ===================================== Network Information: IP:192.168.1.100 UDP Socket Ready! UDP Sent: Hello from W5500 C Client! UDP Sent: Hello from W5500 C Client!

7.2 UDP 服务端运行日志

===================================== UDP Server (C Language) Board IP: 192.168.1.100 Listen Port: 8083 ===================================== UDP Server Started! [Heartbeat] UDP Server Running... Recv 12 bytes from 192.168.1.139:8083 Data Echo Back Success!

7.3 联调方法

  1. 电脑打开网络调试助手
  2. 选择UDP 模式
  3. 填写开发板 IP:192.168.1.100,端口:8083
  4. 发送数据 → 开发板自动回复
  5. 查看串口日志验证通信

8. 常见问题一站式排查指南

8.1 编译 / 烧录问题

  • 提示驱动缺失:添加 WIZnet 官方驱动库
  • UF2 无法烧录:重新进入 BOOTSEL 模式

8.2 网络不通

  • 网口灯不亮:更换网线 / 网口
  • 无法 ping 通:检查静态 IP 是否在同一网段
  • 电脑无法发送:关闭电脑防火墙

8.3 UDP 收发失败

  • 收不到数据:检查端口一致、防火墙关闭
  • 发送失败:确认目标 IP 正确
  • 程序卡死:去掉wizchip_check()函数

9. W5500 硬件协议栈 C 语言 优势

对比维度

W5500 硬件协议栈方案

外接 PHY 芯片方案

BOM 成本

中(MCU + 网络模块,无需额外器件)

中高(MCU + PHY 芯片 + 外围器件)

PCB 面积

小(模块集成度高,仅需预留模块安装空间)

大(需预留芯片、布线空间及外围电路)

开发难度

低(MicroPython 固件已封装底层,少量代码实现 UDP 组播/广播)

中高(需调试协议栈、编写底层驱动,对研发能力要求高)

网络稳定性

极高(WIZnet 专注硬件 TCP/IP 协议栈 25 年,抗干扰能力强,UDP 丢包率低)

不定(依赖研发人员对协议栈和网络开发的掌握程度,UDP 易丢包)

CPU 资源占用

0%(协议栈完全由硬件处理,不占用 MCU 资源,不影响数据发送频率)

50%以上(协议栈运行在 MCU 上,占用大量 CPU 和内存,影响 UDP 发送效率)

硬件 Socket 数量

W5500 8个独立硬件 Socket,支持多组播/广播同时进行

视 MCU 能力而定,理论支持多路拓展,但实际受 CPU 资源限制

网络吞吐量

W5500 最高 15Mbps,UDP 数据传输流畅,无明显延迟

视 MCU 能力而定,普遍低于硬件协议栈方案,多设备通信易卡顿

接口易用性

SPI 接口,接线简单,适配大多数 MCU,支持高速通信

需 MCU 带有 MII/RMII 等专用接口,适配性有限

部署难度

低(MicroPython 成熟固件,应用层协议均有库文件,多设备组网可快速部署)

高(应用层协议需要手动移植开源库适配,调试成本高)

10. 典型应用场景

  • 工业传感器局域网数据上报
  • 多设备 UDP 自动发现
  • 低延迟实时指令控制
  • 量产型物联网终端
  • 工业串口转网口网关

11. 系列预告

下一篇我们将讲解C 语言 实现 UDP 组播 + 广播通信,实现局域网内一对多设备批量控制,为多节点物联网项目打下基础。

http://www.gsyq.cn/news/1429887.html

相关文章:

  • GLM-4-9B API集成教程:如何将AI模型接入现有系统的完整方案
  • MapLibre GL JS第32课:显示跨越180度经线的线
  • 110、未来展望:车载以太网与CAN混合组网对长距离通信的启示
  • 性能优化技巧:提升DeBERTa-v3-base-zeroshot-v2.0推理速度的10个方法
  • 2026大连黄金名表回收靠谱推荐榜,这3家最权威 - 资讯纵览
  • 钢丝绳的捻制工艺对电子防盗扣柔韧性的影响
  • 用Arduino与泡沫板制作五自由度线驱仿生机械手
  • Oracle EBS R12 应付 AP 模块核心架构详解
  • 58.从PBL到系统启动,全链路解析手机安全启动链与签名校验机制
  • BUCK 功率级参数计算
  • 设计模式系列文章(基础篇第 11 篇):模板方法模式——定义算法骨架,实现代码复用与流程统一
  • 2026年5月大模型选型指南:15+主流模型全维度对比(含最新Gemini 3.5 Qwen3.7)
  • MapLibre GL JS第33课:渲染世界副本
  • 保姆级教程:Win10/Win11系统下SolidWorks 2021 SP5完整安装与破解(含.NET环境检查与防火墙设置)
  • Selenium IDE导出的Python脚本跑不起来?手把手教你配置Edge驱动和Pycharm环境(避坑指南)
  • Python 进阶:函数名、闭包与迭代器
  • 069、NeRF/Gaussian Splatting 训练太慢?数据预处理、加速采样与低分辨率预热方案
  • 3PEAK思瑞浦 TP2191-TR SOT23-5 运算放大器
  • Hyperf 利用 PHP 的 反射机制的庖丁解牛
  • spi_master
  • 第八届高分子化学国际研讨会 (ICPC 2026)
  • Python类型推导协议
  • 城通网盘解析器:3分钟掌握免费高速下载的终极方案
  • OpencvSharp 算子学习教案之 - Cv2.CvtColor
  • MATLAB图论实战:除了shortestpath,自己写的Dijkstra函数如何优化与可视化?
  • 3PEAK思瑞浦 TP5551-TR SOT23-5 精密运放
  • OmenSuperHub:彻底释放惠普暗影精灵游戏本性能的终极解决方案
  • OpencvSharp 算子学习教案之 - Cv2.CvtColorTwoPlane
  • 双系统Ubuntu18.04升级22.04,安装docker进行openclaw安装
  • 【电赛保姆级教程】别在比赛时从零写代码了!电赛“祖传代码库”搭建与OLED多级菜单硬核指南