C/C++ 开发
本章节包含以下部分,请按需阅读:
配置开发环境
请参考 安装和配置 Pico C/C++ 开发环境教程 下载安装 Pico VS Code。
示例程序
C/C++ 示例程序位于 示例程序包 的 examples\C 目录中。
| 示例程序 | 基础例程说明 | 依赖库 |
|---|---|---|
| 01_MQTT | MQTT 示例程序 | - |
01_MQTT
【程序说明】
- 该示例演示 RP2350-POE-ETH 使用 Pico SDK(C 工程)通过以太网连接公网 MQTT Broker(默认
broker.emqx.io:1883),并实现:- 订阅主题:
Sub/ed229f15 - 发布主题:
Pub/ed229f15 - 每 10 秒发布一次设备状态 JSON(包含 MAC、Client ID、温度、VSYS 电压、USB/POE 插入状态、运行时间、网络参数等)
- 订阅主题:
- 程序使用 DHCP 自动获取 IP,并通过 DNS 解析域名
broker.emqx.io得到 Broker IP 后连接;也支持切换为静态 IPv4 与静态 Broker IP。 - 串口日志通过 USB CDC 输出(工程配置为
pico_enable_stdio_usb(main 1)),用于调试与查看 MQTT 交互过程。 - 开源使用注意(强烈建议首次使用就修改,避免多人/多设备冲突)
- MQTT Broker 通常要求
Client ID在同一时刻全局唯一:两台设备使用相同MQTT_CLIENT_ID登录时,后连入的会把先连入的挤掉,表现为设备频繁掉线。 - Topic 如果使用固定值,多台设备的数据会混在一起,且容易被其它人误订阅/误控制。
- 建议至少修改:
MQTT_CLIENT_ID、MQTT_PUBLISH_TOPIC、MQTT_SUBSCRIBE_TOPIC;如你自建 Broker 或启用了鉴权,也要修改MQTT_USERNAME、MQTT_PASSWORD。
- MQTT Broker 通常要求
示例默认配置位于 mqtt_app/mqtt_app.c(宏定义区):
#define MQTT_USERNAME "w6300_test"
#define MQTT_CLIENT_ID "ed229f15"
#define MQTT_PASSWORD "0123456789"
#define MQTT_PUBLISH_TOPIC "Pub/ed229f15"
#define MQTT_SUBSCRIBE_TOPIC "Sub/ed229f15"
【硬件连接】
- 使用 USB 线将开发板连接电脑(用于供电、烧录与 USB CDC 串口日志查看)
- 插入网线到 RJ45 口,并确保网络可访问公网(能访问
broker.emqx.io:1883) - 可选:插入 POE 网线为板子供电(程序会在上报 JSON 中体现
poe_inserted状态)
【代码分析】
-
入口文件
main.c- 本工程使用
main()作为入口;完成板级/外设/网络初始化后进入mqtt_service_run()的无限循环(内部while(1)),负责 MQTT 保活、收包处理与定时发布。 main()核心流程(文字说明)- 系统初始化:
DEV_Module_Init()(时钟/stdio 等)+WS2812_init()(状态指示灯) - 电源/温度相关初始化:
bsp_adc_voltage_detection_init(...)(VSYS 采样配置)+adc_set_temp_sensor_enabled(true)(温度通道) - IO 初始化:
usb_detect_io_init()/poe_detect_io_init() - 业务启动:
mqtt_app_init()(以太网 + DHCP/DNS + MQTT)→mqtt_service_run()(MQTT 主循环:保活/收包/定时发布) - 异常处理:任一步骤返回非 0 时进入
while(1)并点亮错误指示(LED_INDICATOR_ERROR())
- 系统初始化:
- 本工程使用
-
MQTT 逻辑文件
mqtt_app/mqtt_app.c- 关键配置(宏定义区)
- Broker
g_dns_target_domain = "broker.emqx.io":Broker 域名(默认走 DNS 解析)PORT_MQTT (1883):MQTT TCP 端口- 如网络禁用 DNS 或想固定 Broker IP:把
mqtt_connect()中的#if 0改为#if 1,使用MQTT_BROKER_IP_0~3
MQTT_CLIENT_ID / MQTT_USERNAME / MQTT_PASSWORD:连接 Broker 的账号信息(示例默认写死固定值;也支持基于 Unique ID 自动生成)MQTT_PUBLISH_TOPIC / MQTT_SUBSCRIBE_TOPIC:发布/订阅主题MQTT_PUBLISH_PERIOD (10s):定时发布周期
- Broker
- 静态/动态切换(建议只改这一处源码就能切换)
- 网络地址:静态 IP ↔ DHCP(动态)
- 默认(DHCP)
- 网络地址:静态 IP ↔ DHCP(动态)
- 关键配置(宏定义区)
static eth_NetInfo g_net_info = {
.ip = {192, 168, 1, 100},
.sn = {255, 255, 255, 0},
.gw = {192, 168, 1, 1},
.dns = {8, 8, 8, 8},
.dhcp = NETINFO_DHCP,
.ipmode = NETINFO_DHCP_V4
};
- 说明:DHCP 模式下,以上
.ip/.sn/.gw/.dns是占位值,会在ethchip_dhcp_run()成功后被路由器下发的参数覆盖;网关与 DNS 也由路由器下发 - DHCP 入口(成功获取到租约后,会在 DHCP 回调里触发重连)
int mqtt_app_init(void)
{
if (g_net_info.dhcp == NETINFO_DHCP) {
ethchip_dhcp_init(ethchip_dhcp_assign, ethchip_dhcp_assign, ethchip_dhcp_conflict);
return ethchip_dhcp_run();
}
return mqtt_connect();
}
- Broker 地址:静态 IP ↔ DNS(动态解析域名)
- 默认(DNS 解析域名)
static uint8_t g_dns_target_domain[] = "broker.emqx.io";
#if 0
g_mqtt_broker_ip[0] = MQTT_BROKER_IP_0;
g_mqtt_broker_ip[1] = MQTT_BROKER_IP_1;
g_mqtt_broker_ip[2] = MQTT_BROKER_IP_2;
g_mqtt_broker_ip[3] = MQTT_BROKER_IP_3;
#else
ethchip_dns_init();
ethchip_dns_get_domain_ip(g_net_info.dns, g_dns_target_domain, g_mqtt_broker_ip);
#endif
- 切换为静态 Broker IP:把上面代码里的
#if 0改成#if 1,就会改用MQTT_BROKER_IP_0~3 - MQTT 身份:静态 client_id/username ↔ 动态生成(基于 Unique ID)
- 默认(静态 client_id / username)
#if 1
snprintf(g_mqtt_client_id, sizeof(g_mqtt_client_id), "%s", MQTT_CLIENT_ID);
#else
snprintf(g_mqtt_client_id, sizeof(g_mqtt_client_id), "%s%02X%02X%02X%02X",
MQTT_CLIENT_ID_PREFIX, board_id.id[4], board_id.id[5], board_id.id[6], board_id.id[7]);
#endif
#if 1
snprintf(g_mqtt_username, sizeof(g_mqtt_username), "%s", MQTT_USERNAME);
#else
snprintf(g_mqtt_username, sizeof(g_mqtt_username), "%s%02X%02X%02X%02X",
MQTT_USERNAME_PREFIX, board_id.id[4], board_id.id[5], board_id.id[6], board_id.id[7]);
#endif
-
切换为动态生成:把上面两段
#if 1改成#if 0,就会按前缀 + Unique ID 拼出每台设备独立的身份 -
注意:当前发布/订阅主题是固定值(多设备会混在一起)
-
message_arrived(MessageData *msg_data)printf("%.*s\n", ...):打印订阅到的消息内容mqtt_parse_and_execute_commands(...):把订阅消息交给命令解析模块(位于mqtt_execute_commands.c),按 JSON 字段执行指令并回包
static const mqtt_cmd_map_t g_cmd_map[] = {
{"adc", adc_op_handle},
{"led", led_op_handle},
{"io_dect", io_dect_op_handle},
};
- 支持的控制指令(payload 为 JSON,字段存在且值>=0 才会执行)
{"adc":1}:读取 VSYS 电压与 ADC 原始值,并发布一条 JSON 到MQTT_PUBLISH_TOPIC
{"vsys_voltage":5.021,"vsys_adc_raw":2048}
{"led":N}:设置板载 WS2812 颜色(N范围0-8),并发布执行结果到MQTT_PUBLISH_TOPIC- 成功示例:
{"led_color":2,"led_name":"RED"}
- 失败示例(超出范围):
{"error":"invalid_led_color","value":99,"valid_range":"0-8"}
{"io_dect":1}:读取 USB/POE 插入检测 IO,并发布状态到MQTT_PUBLISH_TOPIC
{"usb_inserted":true,"poe_inserted":false}
build_mqtt_payload(...)- 读取温度、Flash 容量、系统运行时间、VSYS 电压、USB/POE 插入状态、网络参数等,拼成 JSON 字符串作为发布 payload
- 关键异常处理:电压读取失败会回退为
0,避免上报异常值
【运行效果】
-
使用 VS Code 导入并编译 01_MQTT 工程,编译完成后,烧录
build目录下 uf2 尾缀文件,或直接烧录firmware\C目录下 01_MQTT.uf2 文件进行快速验证。 -
烧录示例后,打开 USB 串口(常用串口工具默认 115200),可看到类似日志:
DEV_Module_Init OK
========== Device Identity ==========
MAC: 02:08:DC:xx:xx:xx
ClientID: ed229f15
UserName: w6300_test
======================================
DHCP initialization succeed
DHCP success
DHCP assign succeed
mqtt disconnect
mqtt connect
DNS initialized successfully
DNS success
Target domain : broker.emqx.io
IP of target domain : 34.243.217.54
MQTT connected
Published
Subscribed
Published
Published
...
-
使用任意 MQTT 客户端验证(推荐 MQTTX)
- MQTTX 客户端设置:

RP2350-POE-ETH连接参数(与宏配置一致):- Host:
broker.emqx.io - Port:
1883 - Username:
w6300_test - Password:
0123456789 - Client ID:
ed229f15
- Host:
- 订阅主题:
Pub/ed229f15,可以收到开发板每 10 秒上报的 JSON,例如:
{
"device": { "chip": "RP2350A", "mac": "02:08:DC:xx:xx:xx", "client_id": "ed229f15" },
"system": {
"cpu_mhz": 150,
"ram_kb": 520,
"flash_mb": 16,
"temp_c": 36.2,
"vsys_voltage_v": 5.021,
"vsys_adc_raw": 2048,
"usb_inserted": true,
"poe_inserted": false,
"uptime": "0:00:01:23"
},
"network": { "mode": "DHCP", "ip": "192.168.1.100", "subnet": "255.255.255.0", "gateway": "192.168.1.1", "dns": "8.8.8.8" },
"message": "Hello, waveshare!"
}
- 向主题
Sub/ed229f15发布任意字符串或 JSON:-
发布任意字符串:开发板会原样打印到串口(见前文
message_arrived(...)代码片段)。 -
发布 JSON 指令(例如
{"led":2}):会执行对应动作,并把执行结果再次发布到Pub/ed229f15(建议订阅Pub/ed229f15查看执行回包)。

-