✔零知开源(零知IDE)是一个专为电子初学者/电子兴趣爱好者设计的开源软硬件平台,在硬件上提供超高性价比STM32系列开发板、物联网控制板。取消了Bootloader程序烧录,让开发重心从“配置环境”转移到“创意实现”,极大降低了技术门槛。零知IDE编程软件,内置上千个覆盖多场景的示例代码,支持项目源码一键下载,项目文章在线浏览。零知开源(零知IDE)平台通过软硬件协同创新,让你的创意快速转化为实物,来动手试试吧!
✔访问零知实验室,获取更多实战项目和教程资源吧!
www.lingzhilab.com
项目概述
本项目基于零知增强板(主控STM32F407VET6)结合W5500以太网模块,实现了一套完整的UDP通信温湿度监控系统。系统通过DHT11传感器实时采集环境温湿度数据,通过W5500以太网模块建立UDP通信链路,将数据发送至PC上位机。同时,上位机可通过UDP协议发送控制指令,远程控制开发板上的LED灯开关状态
项目难点及解决方案
问题描述:多网卡路由冲突导致路由表混乱,UDP包丢失
解决方案:网段隔离与静态配置,将网络拓扑从混合网段改为独立网段;代码中禁用DHCP功能,网关和DNS强制指向PC的以太网IP;同时网段检测逻辑
一、系统硬件部分
1.1 元件清单
| 硬件名称 | 数量 | 备注 |
|---|---|---|
| 零知增强板(STM32F407VET6) | 1 | 主控核心板 |
| W5500 以太网模块 | 1 | 带 SPI 接口的以太网模块 |
| DHT11 温湿度传感器 | 1 | 数字型温湿度传感器 |
| LED 发光二极管 | 1 | 用于远程控制演示 |
| 10K 上拉电阻 | 1 | DHT11 数据脚需接 |
| 杜邦线 | 若干 | 连接各模块 |
| 网线 | 1 | PC 与 W5500 直连 |
| PC(带以太网口) | 1 | 运行 Python 上位机 |
1.2 接线方案表
请务必严格按照代码中的定义进行连接,否则会导致初始化失败。
| 零知增强板引脚 | 外接设备 | 设备引脚 | 功能说明 |
|---|---|---|---|
| 7 | DHT11 | DATA | 温湿度数据传输 |
| 8 | LED | 正极 | LED 控制引脚(低电平熄灭) |
| GND | DHT11/LED/W5500 | GND | 公共接地 |
| 5V | W5500/DHT11 | 5V / + | 供电(W5500 需 5V) |
| 3.3V | 可选 | DHT11 (+) | DHT11 也可接 3.3V |
| A5 (SCLK) | W5500 | SCLK | SPI 时钟线 |
| A6 (MISO) | W5500 | MISO | SPI 主机输入 / 从机输出 |
| A7 (MOSI) | W5500 | MOSI | SPI 主机输出 / 从机输入 |
| A4 (SCS) | W5500 | CS | W5500 片选引脚 |
1.3 接线示意图

W5500 的 SPI 接线必须严格对应零知增强板 的 SPI 引脚(SCK/MISO/MOSI/CS)
1.4 实物连接图

二、安装与使用部分
2.1 开源平台-输入"W5500的UDP通信"并搜索-代码下载自动打开

2.2 连接-验证-上传

2.3 调试-串口监视器

三、核心代码讲解
本项目的代码设计体现了模块化和健壮性的特点,以下将对核心的四个部分进行详细剖析
3.1网络初始化与配置
网络初始化是本项目的核心,采用PC直连静态IP模式,确保通信稳定
// ==================== 网络配置 - PC直连模式 ==================== byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // 静态IP配置 IPAddress staticIP(192, 168, 10, 22); // W5500的IP IPAddress gateway(192, 168, 10, 1); // 设为PC的以太网卡IP IPAddress subnet(255, 255, 255, 0); IPAddress dnsip(192, 168, 10, 1); // DNS指向PC // PC的以太网卡IP IPAddress pcIP(192, 168, 10, 17); // 网络初始化函数 void initNetwork() { // 静态IP配置 Ethernet.begin(mac, staticIP, dnsip, gateway, subnet); // 验证网络配置 IPAddress ip = Ethernet.localIP(); if (ip == IPAddress(0, 0, 0, 0)) { Serial.println("✗✗✗ 错误: 以太网初始化失败! ✗✗✗"); // 错误处理... } // 启动UDP服务 Udp.begin(localPort); }
PC以太网卡不提供DHCP服务,必须使用静态IP;网关设置指向PC,点对点直连网络
3.2DHT11数据采集与处理
DHT11传感器数据采集需要精确的时序控制,并处理可能的读取失败情况
// DHT11初始化 DHT dht(DHTPIN, DHTTYPE); // 读取DHT数据函数 void readDHTData() { unsigned long currentTime = millis(); // 每10秒读取一次 if (currentTime - lastDHTReadTime >= 10000) { lastDHTReadTime = currentTime; float h = dht.readHumidity(); float t = dht.readTemperature(); if (isnan(h) || isnan(t)) { Serial.println("✗ DHT11读取失败!"); dhtValid = false; } else { humidity = h; temperature = t; dhtValid = true; // 发送数据 sendDHTData(); } } } // 发送DHT数据函数 void sendDHTData() { if (dhtValid) { messageCount++; char tempStr[10]; char humiStr[10]; floatToString(tempStr, temperature, 2); // 2位小数精度 floatToString(humiStr, humidity, 2); // 构建JSON格式数据 snprintf(sendBuffer, sizeof(sendBuffer), "{"type":"dht","count":%lu,"temp":%s,"humi":%s,"time":%lu}", messageCount, tempStr, humiStr, millis() / 1000); sendUDP(sendBuffer); } }
DHT11设置为10秒的读取间隔,使用自定义floatToString()函数处理浮点数
3.3 UDP通信协议解析
实现简单的命令解析机制,支持多种控制指令
// 协议解析函数 void parseCommand(const char* cmd, IPAddress remoteIP, int remotePort) { // LED_ON命令 if (strcmp(cmd, "LED_ON") == 0) { digitalWrite(LED_CONTROL_PIN, HIGH); ledControlState = true; snprintf(sendBuffer, sizeof(sendBuffer), "{"type":"response","cmd":"LED_ON","status":"success","led_state":true}"); Udp.beginPacket(remoteIP, remotePort); Udp.write((uint8_t*)sendBuffer, strlen(sendBuffer)); Udp.endPacket(); } // GET_DHT命令 else if (strcmp(cmd, "GET_DHT") == 0) { float h = dht.readHumidity(); float t = dht.readTemperature(); if (isnan(h) || isnan(t)) { snprintf(sendBuffer, sizeof(sendBuffer), "{"type":"response","cmd":"GET_DHT","status":"error","error":"read_failed"}"); } else { char tempStr[10]; char humiStr[10]; floatToString(tempStr, t, 2); floatToString(humiStr, h, 2); snprintf(sendBuffer, sizeof(sendBuffer), "{"type":"response","cmd":"GET_DHT","status":"success","temp":%s,"humi":%s}", tempStr, humiStr); } Udp.beginPacket(remoteIP, remotePort); Udp.write((uint8_t*)sendBuffer, strlen(sendBuffer)); Udp.endPacket(); } // 其他命令处理... }
支持的命令列表
| 指令 | 功能说明 | 返回信息 |
|---|---|---|
| LED_ON | 点亮LED | 返回成功状态和LED状态 |
| LED_OFF | 熄灭LED | 返回成功状态和LED状态 |
| GET_DHT | 读取实时温湿度 | 返回数据或错误信息 |
| STATUS | 获取设备完整状态信息 | 返回设备状态 |
每个命令都有明确的成功/失败状态返回,接收到命令后立即处理并返回结果
3.4系统状态维护与心跳机制
系统需要维护多个状态变量,并实现心跳机制确保连接正常
// 全局状态变量 unsigned long lastDHTReadTime = 0; // 上次DHT读取时间 unsigned long lastSendTime = 0; // 上次发送时间 unsigned long messageCount = 0; // 消息计数器 unsigned long lastHeartbeat = 0; // 上次心跳时间 bool dhtValid = false; // DHT数据有效性 bool ledControlState = false; // LED控制状态 bool networkInitialized = false; // 网络初始化状态 unsigned long packetsSent = 0; // 发送数据包计数 unsigned long packetsReceived = 0; // 接收数据包计数 // 心跳包发送函数 void sendHeartbeat() { unsigned long currentTime = millis(); if (currentTime - lastHeartbeat >= 30000) { // 每30秒 lastHeartbeat = currentTime; snprintf(sendBuffer, sizeof(sendBuffer), "{"type":"heartbeat","uptime":%lu,"packets_sent":%lu,"packets_received":%lu}", millis() / 1000, packetsSent, packetsReceived); sendUDP(sendBuffer); } } // 状态LED指示函数 void updateStatusLED() { unsigned long currentTime = millis(); if (currentTime - lastBlinkTime >= 500) { // 每500ms闪烁一次 lastBlinkTime = currentTime; ledBlinkState = !ledBlinkState; digitalWrite(LED_BUILTIN, ledBlinkState ? LOW : HIGH); } }
统计发送和接收的数据包数量,用于监控通信质量;定期发送心跳包,让上位机知道设备在线状态
3.5 系统完整代码
/************************************************************************************** * 文件: W5500_UDP_DHT11_Control.ino * 作者:零知实验室(深圳市在芯间科技有限公司) * -^^- 零知实验室,让电子制作变得更简单! -^^- * 时间: 2026-02-09 * 网络拓扑: * 路由器(192.168.3.1) ←WiFi→ PC(WiFi: 192.168.3.17, 以太网: 192.168.10.1) * ↓ 直连网线 * W5500(192.168.10.22) * * 功能说明: * W5500以太网模块UDP通信、DHT11温湿度传感器数据采集和上报、远程LED控制功能、简单协议解析和响应、修复JSON浮点数格式化问题(snprintf不支持%f) ************************************************************************************/ #include < SPI.h > #include < Ethernet_STM.h > #include < EthernetUdp.h > #include "DHT.h" // ==================== 硬件配置 ==================== #define DHTPIN 7 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); #define LED_CONTROL_PIN 8 // ==================== 网络配置 - PC直连模式 ==================== #if defined(WIZ550io_WITH_MACADDRESS) // WIZ550io有内置MAC地址 #else byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; #endif // PC直连模式 - 必须使用静态IP! // PC的以太网卡不提供DHCP服务,所以DHCP无法工作 #define USE_DHCP false // ==================== 重要: 网段配置说明 ==================== // 使用 192.168.10.x 网段,与PC的WiFi网段(192.168.3.x)分开 // 避免IP冲突和路由混乱 // 静态IP配置 IPAddress staticIP(192, 168, 10, 22); // W5500的IP IPAddress gateway(192, 168, 10, 1); // 设为PC的以太网卡IP IPAddress subnet(255, 255, 255, 0); IPAddress dnsip(192, 168, 10, 1); // DNS指向PC // PC的以太网卡IP (连接W5500的那个网卡) // 不是WiFi的IP (192.168.3.17)! IPAddress pcIP(192, 168, 10, 17); // UDP端口 unsigned int localPort = 8888; unsigned int pcPort = 9003; // ==================== 如果您的PC以太网卡IP是其他值 ==================== // 请相应修改上面的配置,例如: // // 如果PC以太网卡是 192.168.137.1 (启用了ICS): // IPAddress staticIP(192, 168, 137, 22); // IPAddress gateway(192, 168, 137, 1); // IPAddress dnsip(192, 168, 137, 1); // IPAddress pcIP(192, 168, 137, 1); // // 如果PC以太网卡是 192.168.3.215 (不推荐,会与WiFi冲突): // IPAddress staticIP(192, 168, 3, 22); // IPAddress gateway(192, 168, 3, 215); // 指向PC,不是路由器! // IPAddress dnsip(192, 168, 3, 215); // IPAddress pcIP(192, 168, 3, 215); // ==================== 全局变量 ==================== EthernetUDP Udp; char receiveBuffer[256]; char sendBuffer[512]; // 定时器 unsigned long lastDHTReadTime = 0; unsigned long lastSendTime = 0; unsigned long messageCount = 0; unsigned long lastHeartbeat = 0; // DHT数据 float temperature = 0.0; float humidity = 0.0; bool dhtValid = false; // LED状态 bool ledControlState = false; unsigned long lastBlinkTime = 0; bool ledBlinkState = false; // 网络状态 bool networkInitialized = false; unsigned long lastSuccessTime = 0; unsigned long packetsSent = 0; unsigned long packetsReceived = 0; // ==================== 函数声明 ==================== void floatToString(char* buffer, float value, int decimalPlaces); // ==================== 浮点数转字符串 ==================== void floatToString(char* buffer, float value, int decimalPlaces) { int intPart = (int)value; int decPart = (int)((value - intPart) * pow(10, decimalPlaces)); if (decPart < 0) decPart = -decPart; if (decimalPlaces == 1) { sprintf(buffer, "%d.%01d", intPart, decPart); } else if (decimalPlaces == 2) { sprintf(buffer, "%d.%02d", intPart, decPart); } } // ==================== 初始化 ==================== void setup() { Serial.begin(115200); delay(100); Serial.println("nn"); Serial.println("========================================"); Serial.println(" W5500 UDP + DHT11温湿度监控系统"); Serial.println(" 零知实验室"); Serial.println(" 版本: v3.1 (PC直连专用版)"); Serial.println("========================================n"); Serial.println(" 网络模式: PC直连(静态IP)"); Serial.println(" 请确保PC的以太网卡已配置静态IP!n"); initHardware(); initNetwork(); initDHT(); Serial.println("n========================================"); Serial.println("系统启动完成!"); Serial.println("========================================n"); printSystemInfo(); sendStartupMessage(); Serial.println("n开始工作...n"); Serial.println("----------------------------------------n"); } // ==================== 硬件初始化 ==================== void initHardware() { Serial.println("[1/3] 初始化硬件..."); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); pinMode(LED_CONTROL_PIN, OUTPUT); digitalWrite(LED_CONTROL_PIN, LOW); ledControlState = false; // 启动提示 - LED快闪3次 for(int i = 0; i < 3; i++) { digitalWrite(LED_BUILTIN, LOW); delay(100); digitalWrite(LED_BUILTIN, HIGH); delay(100); } Serial.println("✓ 硬件初始化完成!"); } // ==================== 网络初始化 ==================== void initNetwork() { Serial.println("n[2/3] 初始化W5500以太网模块..."); Serial.println(" 模式: 静态IP (PC直连)"); delay(500); // 静态IP配置 #if defined(WIZ550io_WITH_MACADDRESS) Ethernet.begin(staticIP, dnsip, gateway, subnet); #else Ethernet.begin(mac, staticIP, dnsip, gateway, subnet); #endif delay(1000); // 验证网络配置 IPAddress ip = Ethernet.localIP(); if (ip == IPAddress(0, 0, 0, 0)) { Serial.println("n✗✗✗ 错误: 以太网初始化失败! ✗✗✗"); Serial.println("n请检查:"); Serial.println(" 1. W5500模块SPI接线是否正确"); Serial.println(" 2. 网线是否连接到PC的以太网口"); Serial.println(" 3. PC的以太网卡是否已配置静态IP"); Serial.println("n设备将进入错误指示模式"); while(1) { digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); delay(100); } } Serial.println("n✓ W5500初始化成功!"); Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); Serial.print(" 本机IP: "); Serial.println(ip); Serial.print(" 子网掩码: "); Serial.println(Ethernet.subnetMask()); Serial.print(" 网关: "); Serial.println(Ethernet.gatewayIP()); Serial.print(" DNS: "); Serial.println(Ethernet.dnsServerIP()); Serial.println(" 模式: 静态IP (PC直连)"); Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); // 显示PC配置提示 Serial.println("n 审核编辑 黄宇
-
STM32
+关注
关注
2313文章
11195浏览量
374673 -
UDP
+关注
关注
0文章
335浏览量
35529 -
湿度监控
+关注
关注
0文章
5浏览量
5330
发布评论请先 登录
模块化扩展:多机房以太网 POE 温湿度监控部署方案
冷库温湿度监控系统物联网解决方案
科研实验室以太网POE供电温湿度监控系统方案
STM32驱动W5500作为客户端进行通讯
零知IDE——基于STM32与W5500的UDP通信实现温湿度监控
评论