ESP32/ESP8266 开发:Wi-Fi 模组与低功耗蓝牙
FreeGuideOnline
最新
2026-06-15
ESP32/ESP8266 开发全攻略:Wi‑Fi 模组与低功耗蓝牙(BLE)实战教程
本教程面向初学者,带你系统掌握 ESP32 与 ESP8266 的无线通信能力。无论你是想快速开发物联网原型,还是深入理解 Wi‑Fi 和低功耗蓝牙,这里都提供了从环境搭建到完整代码示例的硬核内容。
一、硬件选型与开发环境准备
1.1 ESP32 vs ESP8266:我该选谁?
| 特性 | ESP8266 (如 NodeMCU) | ESP32 (如 DevKitC) |
|---|---|---|
| Wi‑Fi | 仅 2.4 GHz | 仅 2.4 GHz |
| 蓝牙 | 不支持 | 支持 BLE 4.2 / Classic BT |
| 处理器 | Tensilica L106 单核 | Tensilica LX6 双核 |
| 主频 | 80/160 MHz | 最高 240 MHz |
| SRAM | ~80 KB 可用 | ~520 KB |
| GPIO / 外设 | 较少 | 更多, 含电容触摸、DAC、CAN 等 |
| 价格 | 更低 | 稍高 |
结论:若仅需 Wi‑Fi 联网且对成本敏感,选 ESP8266;若需要 BLE、更丰富的外设或更高性能,选 ESP32。
1.2 开发环境选择
- Arduino IDE:上手最快,库丰富,适合快速原型。
- ESP‑IDF:乐鑫官方框架,功能完整、性能最优,适合产品级开发。
- PlatformIO:基于 VS Code 的插件,兼具易用性与专业性,强烈推荐。
本教程以 Arduino IDE 为例,兼顾易懂与实用。
1.3 安装与配置(以 Arduino IDE 为示例)
- 下载并安装 Arduino IDE。
- 打开 文件 → 首选项,在“附加开发板管理器网址”中添加:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json https://arduino.esp8266.com/stable/package_esp8266com_index.json - 进入 工具 → 开发板 → 开发板管理器,分别搜索
esp32和esp8266安装。 - 选择对应开发板(例如
ESP32 Dev Module或NodeMCU 1.0),并根据需要设置 Flash Size 与 Partition Scheme。
二、Wi‑Fi 功能从入门到精通
ESP32 与 ESP8266 的 Wi‑Fi 库高度相似,下列代码在两者上通用(除特别说明外)。
2.1 Wi‑Fi 模式与基本连接
ESP 的 Wi‑Fi 可工作在三种模式:
- STA(Station):连接到现有路由器,像手机连 Wi‑Fi。
- AP(Access Point):自身建立热点,其他设备可连接。
- STA+AP:同时充当客户端和热点。
示例 1:作为 STA 连接网络
#include <WiFi.h> // ESP32 用 <WiFi.h>,ESP8266 用 <ESP8266WiFi.h>
const char* ssid = "你的WiFi名";
const char* password = "你的WiFi密码";
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA); // 设置为 STA 模式
WiFi.begin(ssid, password); // 开始连接
Serial.print("连接中...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n连接成功!IP 地址:" + WiFi.localIP().toString());
}
void loop() {
// 保持连接不需要持续处理,这里留空
}
2.2 创建自己的 Wi‑Fi 热点(AP 模式)
#include <WiFi.h> // ESP8266 改为 <ESP8266WiFi.h>
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.softAP("My_ESP_Device", "12345678"); // SSID 和密码(至少8位)
Serial.print("AP IP 地址:");
Serial.println(WiFi.softAPIP());
}
void loop() {}
2.3 Wi‑Fi 事件处理与重连机制
生产环境中必须监控连接状态。使用事件回调可以优雅地处理掉线重连。
ESP32 示例(使用 WiFi 事件)
#include <WiFi.h>
const char* ssid = "xx";
const char* password = "xx";
void WiFiEvent(WiFiEvent_t event) {
switch (event) {
case SYSTEM_EVENT_STA_GOT_IP:
Serial.print("获得 IP:");
Serial.println(WiFi.localIP());
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("WiFi 断开,尝试重连...");
WiFi.reconnect();
break;
default: break;
}
}
void setup() {
Serial.begin(115200);
WiFi.onEvent(WiFiEvent);
WiFi.begin(ssid, password);
}
void loop() {}
ESP8266 对应的事件处理 使用 WiFi.onStationModeConnected 等回调,逻辑类似,具体查阅 ESP8266WiFi 库文档。
2.4 网络通信示例:HTTP 客户端
连接到互联网后,下一步通常是收发数据。这里用 HTTP GET 请求获取天气信息。
#include <WiFi.h> // 或 <ESP8266WiFi.h>
#include <HTTPClient.h>
const char* ssid = "xx";
const char* password = "xx";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(500);
Serial.println("已连接");
HTTPClient http;
http.begin("http://wttr.in/Tokyo?format=3"); // 简易天气 API
int httpCode = http.GET();
if (httpCode > 0) {
Serial.println(http.getString());
} else {
Serial.printf("请求失败,错误码:%d\n", httpCode);
}
http.end();
}
void loop() {}
三、低功耗蓝牙(BLE)开发 – ESP32 独占技能
ESP8266 不支持蓝牙,以下内容仅适用于 ESP32。我们将从最核心的 GATT 概念讲起。
3.1 BLE 核心概念速览
- GATT(通用属性协议):BLE 数据传输的框架。设备之间通过“服务(Service)”和“特征(Characteristic)”交互。
- Server / Client:提供数据的设备称为“服务器”,读取数据的称为“客户端”。
- UUID:128 位通常用 16 位短 UUID 表示,如
0x180F为电池服务。 - Notify 与 Read:特征可被客户端读取,或由服务器主动通知。
3.2 创建 BLE 服务器
以下代码创建一个名为 ESP32_BLE 的设备,包含一个可读、可通知的特征。
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
Serial.println("客户端已连接");
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println("客户端断开,开始重新广播");
pServer->startAdvertising(); // 重新允许连接
}
};
void setup() {
Serial.begin(115200);
BLEDevice::init("ESP32_BLEDemo");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->setValue("Hello BLE");
pService->start();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->start();
Serial.println("服务器已启动,等待连接...");
}
void loop() {
if (deviceConnected) {
pCharacteristic->setValue("Time: " + String(millis()));
pCharacteristic->notify(); // 推送新数据
delay(2000);
}
}
3.3 创建 BLE 客户端(扫描并连接)
客户端代码扫描周围的 BLE 设备,连接到指定的服务器,并读取特征值。
#include <BLEDevice.h>
#include <BLEAdvertisedDevice.h>
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
static BLEAddress *pServerAddress;
static BLERemoteCharacteristic* pRemoteCharacteristic;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) {
advertisedDevice.getScan()->stop();
pServerAddress = new BLEAddress(advertisedDevice.getAddress());
Serial.println("发现目标设备");
}
}
};
void setup() {
Serial.begin(115200);
BLEDevice::init("ESP32_Client");
BLEScan* pScan = BLEDevice::getScan();
pScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pScan->setActiveScan(true);
pScan->start(5); // 扫描 5 秒
delay(6000); // 等待扫描完成
pScan->clearResults();
if(pServerAddress == nullptr) {
Serial.println("未找到设备,重启...");
ESP.restart();
}
BLEClient* pClient = BLEDevice::createClient();
pClient->connect(*pServerAddress);
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
std::string value = pRemoteCharacteristic->readValue();
Serial.print("特征值: ");
Serial.println(value.c_str());
}
void loop() {}
3.4 BLE 信标(Beacon)示例 – 一个极简 iBeacon
iBeacon 是 Apple 的协议,ESP32 可以模拟。
#include <BLEDevice.h>
#include <BLEBeacon.h>
void setup() {
Serial.begin(115200);
BLEDevice::init("MyBeacon");
BLEServer *pServer = BLEDevice::createServer();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
BLEBeacon oBeacon;
oBeacon.setManufacturerId(0x4C00); // Apple 公司 ID
oBeacon.setMajor(1);
oBeacon.setMinor(100);
oBeacon.setSignalPower(-59);
// UUID: 必须符合 iBeacon 规范
oBeacon.setProximityUUID(BLEUUID("FDA50693-A4E2-4FB1-AFCF-C6EB07647825"));
BLEAdvertisementData oAdvertisementData;
oAdvertisementData.setFlags(0x04);
oAdvertisementData.setManufacturerData(oBeacon.getData());
pAdvertising->setAdvertisementData(oAdvertisementData);
pAdvertising->start();
}
void loop() { delay(1000); }
四、Wi‑Fi 与 BLE 共存 – 资源调度与低功耗
ESP32 的 Wi‑Fi 和 BLE 共用同一根天线,同时使用时需要注意以下要点:
- 时间分片:两者不能同时进行高速收发。乐鑫的底层会自动仲裁,但应用层应避免长时间占用。
- 连接间隔:BLE 的连接间隔与 Wi‑Fi 的 DTIM 可能互相影响,极低速场景可适当增大 BLE 连接间隔。
- 低功耗模式:
- 仅 BLE 工作时,可调用
esp_bt_sleep_enable()进入 Modem‑sleep。 - Wi‑Fi 连接时也可启用 Modem‑sleep,在 Arduino 中默认开启。
- 深度睡眠(Deep Sleep)时,Wi‑Fi 和 BLE 均停止,常用于电池供电设备。
- 仅 BLE 工作时,可调用
实用技巧:将 BLE 数据交换集中在较短时间内,其余时间保持非连接状态,能有效降低功耗与资源冲突。
五、常见问题与调试指南
5.1 烧录失败/端口找不到
- 确认驱动已安装(CH340/CP2102)。
- 按住 BOOT 键后点下载,部分开发板需手动进入下载模式。
- 检查 USB 线是否为数据线。
5.2 Wi‑Fi 反复断开
- 确保供电充足(3.3V 不低于 500mA),ESP32 瞬时电流可达 500mA+。
- 在代码中加入
WiFi.setAutoReconnect(true);(ESP32 默认开启)。 - 排查路由器是否限制设备数或启用了 5GHz only。
5.3 BLE 连接不稳定
- 检查天线是否被遮挡,或开发板靠近金属物。
- 尝试降低 BLE 的连接间隔
pClient->setConnectionInterval(0x0006, 0x0C80);。 - 避免在 BLE 回调中执行耗时操作,可设置标志在 loop 中处理。
5.4 内存不足
- ESP8266 的堆存空间较小,避免创建大型字符串,使用
PROGMEM存储常量。 - ESP32 若报
heap corruption,检查是否有数组越界,或通过ESP.getFreeHeap()监控内存。
六、进阶学习路径
- 深入阅读乐鑫官方编程指南 ESP-IDF 文档。
- 尝试 MQTT 通信:使用
PubSubClient库搭建物联平台。 - 研究 Wi‑Fi Mesh 与 BLE Mesh,构建大规模自组网。
- 使用 OTA 无线更新,实现设备固件空中升级。
现在你已经掌握了 Wi‑Fi 与 BLE 的基石,快去连接万物吧!