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 为示例)

  1. 下载并安装 Arduino IDE
  2. 打开 文件 → 首选项,在“附加开发板管理器网址”中添加:
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
    https://arduino.esp8266.com/stable/package_esp8266com_index.json
    
  3. 进入 工具 → 开发板 → 开发板管理器,分别搜索 esp32esp8266 安装。
  4. 选择对应开发板(例如 ESP32 Dev ModuleNodeMCU 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 数据交换集中在较短时间内,其余时间保持非连接状态,能有效降低功耗与资源冲突。

五、常见问题与调试指南

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 的基石,快去连接万物吧!