树莓派Pico W上LWIP UDP通信失效问题求助
排查Pico LWIP UDP无法向局域网服务器发送数据包的问题
我用树莓派Pico编写了基于LWIP UDP API的C程序,目的是检测到运动传感器触发时,向局域网内电脑的UDP服务器(用nc -u -l -p 8085启动)发送"Motion detected!"消息。程序能正常连接WiFi,且之前的UDP错误码-16问题已解决,但电脑端始终收不到数据包。程序代码如下:
#include <stdio.h> #include "pico/stdlib.h" #include "pico/cyw43_arch.h" #include "lwip/udp.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" #define SSID "MY_SSID" #define PASSWORD "MY_PASSWORD" #define SENSOR_PIN 15 // Connected to my motion sensor int main() { stdio_init_all(); gpio_init(SENSOR_PIN); gpio_set_dir(SENSOR_PIN, GPIO_IN); // Set pin as input // Initialize Wi-Fi printf("Initializing Wi-Fi... "); while (cyw43_arch_init()) { printf("Failed to initialize CYW43 Wi-Fi module "); } cyw43_arch_enable_sta_mode(); printf("Connecting to Wi-Fi: %s ", SSID); while (cyw43_arch_wifi_connect_timeout_ms(SSID, PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { printf("Failed to connect to Wi-Fi "); } printf("Connected to Wi-Fi "); // Blink LED to show successful Wi-Fi connection cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); sleep_ms(1000); cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); sleep_ms(1000); struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_V4); if (pcb == NULL) { printf("PCB Could not be allocated. "); } ip_set_option(pcb, SOF_BROADCAST); ip_addr_t ip_address; IP4_ADDR(&ip_address, 192, 168, 2, 11); // ipaddr_aton("192.168.2.11", &ip_address); const char *message = "Motion detected!"; while (true) { if (gpio_get(SENSOR_PIN)) { cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); struct pbuf *pbuf_struct = pbuf_alloc(PBUF_TRANSPORT, strlen(message), PBUF_RAM); if (!pbuf_struct) { printf("Failed to allocate pbuf "); continue; } // Copy the message to the pbuf memcpy(pbuf_struct->payload, message, strlen(message)); // Send the UDP packet err_t err = udp_sendto(pcb, pbuf_struct, &ip_address, htons(8085)); if (err != ERR_OK) { printf("Failed to send UDP packet: %d ", err); } else { printf("UDP packet sent "); } // Free the pbuf pbuf_free(pbuf_struct); cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); sleep_ms(10000); } else { sleep_ms(150); } } udp_remove(pcb); return 0; }
排查与修复步骤
1. 修正代码中的换行符错误
代码中所有printf语句的换行逻辑错误(直接换行而非使用\n),会导致编译失败或程序行为异常。将所有printf内的换行替换为\n,例如:
printf("Initializing Wi-Fi...\n");
2. 验证目标IP与端口的正确性
- 用
ipconfig(Windows)或ip a(Linux/macOS)确认电脑的局域网IP确实是192.168.2.11 - 用
netstat -ano | findstr :8085(Windows)或lsof -i :8085(Linux/macOS)检查8085端口是否被其他程序占用 - 确认
htons(8085)的网络字节序转换正确,LWIP要求端口参数使用网络字节序
3. 关闭电脑防火墙/安全软件
局域网UDP数据包常被防火墙拦截,临时关闭防火墙或添加允许UDP 8085端口的入站规则,测试是否能接收数据包。
4. 显式绑定UDP PCB的本地端口
虽然LWIP允许自动分配端口,但显式绑定可解决部分兼容性问题,在创建PCB后添加:
err_t bind_err = udp_bind(pcb, IP_ADDR_ANY, htons(0)); // 0表示自动分配端口 if (bind_err != ERR_OK) { printf("Failed to bind UDP PCB: %d\n", bind_err); udp_remove(pcb); cyw43_arch_deinit(); return -1; }
5. 检查运动传感器触发逻辑
- 添加调试输出确认传感器状态:
printf("Sensor state: %d\n", gpio_get(SENSOR_PIN)); - 确认传感器接线正确,触发时GPIO_PIN 15输出高电平(匹配代码中的检测逻辑)
- 可临时缩短
sleep_ms(10000)的时长,方便快速测试
6. 用Wireshark抓包验证
在电脑或路由器上抓取UDP 8085端口的数据包:
- 若抓不到包:问题出在Pico的发送逻辑
- 若能抓到但nc收不到:问题出在电脑端的接收规则(防火墙、nc参数等)
7. 调整nc启动参数(适配不同系统)
部分系统的netcat版本需要不同参数:
- Linux:
nc -u 0.0.0.0 8085 -l - macOS:
nc -ul 8085
修改后的完整代码示例
#include <stdio.h> #include "pico/stdlib.h" #include "pico/cyw43_arch.h" #include "lwip/udp.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" #define SSID "MY_SSID" #define PASSWORD "MY_PASSWORD" #define SENSOR_PIN 15 // Connected to my motion sensor int main() { stdio_init_all(); gpio_init(SENSOR_PIN); gpio_set_dir(SENSOR_PIN, GPIO_IN); // Set pin as input // Initialize Wi-Fi printf("Initializing Wi-Fi...\n"); while (cyw43_arch_init()) { printf("Failed to initialize CYW43 Wi-Fi module\n"); sleep_ms(1000); } cyw43_arch_enable_sta_mode(); printf("Connecting to Wi-Fi: %s\n", SSID); while (cyw43_arch_wifi_connect_timeout_ms(SSID, PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { printf("Failed to connect to Wi-Fi\n"); sleep_ms(1000); } printf("Connected to Wi-Fi\n"); // Blink LED to show successful Wi-Fi connection cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); sleep_ms(1000); cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); sleep_ms(1000); struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_V4); if (pcb == NULL) { printf("PCB Could not be allocated.\n"); cyw43_arch_deinit(); return -1; } // 绑定本地端口(自动分配) err_t bind_err = udp_bind(pcb, IP_ADDR_ANY, htons(0)); if (bind_err != ERR_OK) { printf("Failed to bind UDP PCB: %d\n", bind_err); udp_remove(pcb); cyw43_arch_deinit(); return -1; } ip_set_option(pcb, SOF_BROADCAST); ip_addr_t ip_address; IP4_ADDR(&ip_address, 192, 168, 2, 11); // ipaddr_aton("192.168.2.11", &ip_address); const char *message = "Motion detected!"; while (true) { int sensor_state = gpio_get(SENSOR_PIN); printf("Sensor state: %d\n", sensor_state); // 调试输出传感器状态 if (sensor_state) { cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); printf("Motion detected, sending UDP packet...\n"); struct pbuf *pbuf_struct = pbuf_alloc(PBUF_TRANSPORT, strlen(message), PBUF_RAM); if (!pbuf_struct) { printf("Failed to allocate pbuf\n"); cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); sleep_ms(1000); continue; } // Copy the message to the pbuf memcpy(pbuf_struct->payload, message, strlen(message)); // Send the UDP packet err_t err = udp_sendto(pcb, pbuf_struct, &ip_address, htons(8085)); if (err != ERR_OK) { printf("Failed to send UDP packet: %d\n", err); } else { printf("UDP packet sent successfully\n"); } // Free the pbuf pbuf_free(pbuf_struct); cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); sleep_ms(10000); } else { sleep_ms(150); } } udp_remove(pcb); cyw43_arch_deinit(); return 0; }
内容的提问来源于stack exchange,提问作者Ioannis L.
相关产品推荐
相关产品推荐

