硬核 Rust 嵌入式:为 ESP32-C3 实现网页配网与智能点灯

在嵌入式开发中,最头疼的问题之一就是:换个 Wi-Fi 环境就要重新改代码编译?

今天,我们用 Rust 语言 基于 esp-idf-svc 框架,为 ESP32-C3 Super Mini 开发一套完整的解决方案。它具备以下硬核功能:

1.自动重连:开机自动读取 NVS(闪存)中保存的 Wi-Fi 信息。

2.网页配网:若无配置或连接失败,自动开启热点,手机扫码即可输入 Wi-Fi 密码。

3.双模共存:联网后同时保留热点和客户端模式(Mixed Mode)。

4.Web 控制台:通过网页远程控制板载 LED 灯,并支持一键重置(清除配网信息)。


🛠️ 硬件准备

•开发板:ESP32-C3 Super Mini (或其他 ESP32 系列)

•核心配置:GPIO 8 (板载蓝色 LED,低电平点亮)


🚀 核心逻辑流程

程序运行分为三个阶段:

1.自检阶段:尝试从 NVS 读取 ssid 和 password,有则尝试连接。

2.配网阶段:若失败,开启名为 ESP32-Config-AP 的无密码热点,运行 Web 服务器接收表单数据。

3.业务阶段:连接成功后,运行主控制网页,展示 IP 地址并提供 LED 开关按钮。


💻 核心代码解析

1. 状态共享与并发

在 Rust 中,Web 服务器的任务回调是在独立线程中运行的。为了跨线程修改 LED 状态或 Wi-Fi 配置,我们使用了 Arc<Mutex<T>>:

// 共享状态:用于跨线程接收配网信息type SharedCreds = Arc<Mutex<Option<(String, String)>>>;let led_shared = Arc::new(Mutex::new(led));

2. NVS 持久化存储

使用 ESP32 的非易失性存储(NVS)来保存 SSID 和密码,确保掉电不丢失:

let nvs_storage = EspNvs::new(nvs_default_partition.clone(), "wifi_cfg", true)?;// 读取保存的配置if let (Some(s), Some(p)) = (saved_ssid, saved_pass) {    info!("💾 发现保存的配置,正在尝试自动连接...");    is_connected = connect_sta_logic(&mut blocking_wifi, s, p);}

3. 优雅的网页配网 UI

代码中内置了一个极简的 HTML/CSS 界面,适配手机端。通过 POST 请求接收 Wi-Fi 凭据并进行 URL 解码:

setup_server.fn_handler("/", Method::Get, |req| {    let html = r#"<form action="/connect" method="post">        <input name="ssid" placeholder="WiFi名称">        <input name="password" type="password" placeholder="WiFi密码">        <button type="submit">保存并连接</button>    </form>"#;    req.into_ok_response()?.write_all(html.as_bytes())?;    Ok(())})?;

4. 混合模式(STA + AP)

为了方便调试,当 ESP32 连上路由器(STA 模式)后,它依然会开启一个自己的热点(AP 模式),你可以通过两个 IP 访问控制台:

// 核心逻辑:获取路由器信道并开启混合模式let _ = wifi.set_configuration(&Configuration::Mixed(client_config, ap_config));

⚡ 细节决定成败:功率踩坑指南

在代码中有一行看似不起眼但至关重要的 unsafe 调用:

unsafe { esp_idf_svc::sys::esp_wifi_set_max_tx_power(40); }

为什么要这样做?
ESP32-C3 在启动 Wi-Fi 瞬时电流巨大,如果使用电脑 USB 供电或劣质数据线,经常会导致供电不足触发重置。将最大发射功率限制在 10dBm(参数 40),能极大提高小型开发板的稳定性。


💡 如何一键重置?

如果 Wi-Fi 密码改了,或者想带去公司用,只需要在 Web 界面点击“清除 WiFi 配置并重启”。程序会执行 nvs.remove(...) 并调用系统重启:

main_server.fn_handler("/reset", Method::Get, move |req| {    // 清除 NVS 记录...    thread::spawn(|| {        thread::sleep(Duration::from_secs(2));        unsafe { esp_idf_svc::sys::esp_restart(); } // 重启系统    });    Ok(())})?;

📥 结语

使用 Rust 开发 ESP32 不仅能享受类型安全带来的愉悦,配合 esp-idf-svc 强大的生态,我们可以快速构建出媲美工业级产品的配网系统。

想要获取完整代码工程?
欢迎关注本公众号,后台回复 “ESP32网页配网” 获取源码仓库地址!

发表评论