You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 04:21:06