Arduino Nano ESP32

元器件
开发板
库存 130

介绍

Arduino Nano ESP32,基于ESP32-S3主控(Xtensa LX7双核240MHz),WiFi+BLE 5.0,16MB Flash,8MB PSRAM,512KB SRAM,支持Arduino IoT Cloud和MicroPython。内置USB-CDC/JTAG,Type-C接口。3.3V逻辑,尺寸18×45mm。Nano系列中性能最强,支持WiFi/BLE/Zigbee(Thread),适合边缘计算和AI推理

规格参数

参数
I2C1路
SPI1路
SRAM512KB
Flash16MB(Quad SPI)
PSRAM8MB(Octal SPI)
串口1路硬UART(可多路软串口)
内核Xtensa LX7 双核 240MHz
尺寸18mm×45mm
无线WiFi 802.11 b/g/n + BLE 5.0 + BLE Mesh
特色支持Arduino IoT Cloud, MicroPython, ESP-IDF
重量约6g
数字IO14路(PWM全部)
USB接口USB Type-C(原生USB-CDC/JTAG)
主控芯片ESP32-S3 (Espressif)
工作电压3.3V(逻辑)
模拟输入8路(12位ADC)
输入电压5V(USB)/4.5-21V(VIN)

代码例程

Arduino Nano ESP32 — 代码例程.md
# Arduino Nano ESP32 (ESP32-S3) 代码例程

## 例程 1:WiFi + BLE 共存 — Web 服务器 + BLE 通知

```cpp
// Nano ESP32 - WiFi AP 模式 + BLE 同时运行
// ESP32-S3 支持 WiFi 和 BLE 共存(分时复用)
#include <WiFi.h>
#include <BLEDevice.h>
#include <BLEServer.h>

#define SERVICE_UUID "12345678-1234-1234-1234-123456789abc"
#define CHAR_UUID    "abcd1234-5678-1234-5678-123456789abc"

WiFiServer server(80);
BLECharacteristic *pCharacteristic;

void setup() {
    Serial.begin(115200);
    
    // 1. WiFi AP 模式
    WiFi.softAP("NanoESP32", "12345678");
    Serial.print("AP IP: ");
    Serial.println(WiFi.softAPIP());
    server.begin();
    
    // 2. BLE 外设
    BLEDevice::init("NanoESP32-BLE");
    BLEServer *pServer = BLEDevice::createServer();
    BLEService *pService = pServer->createService(SERVICE_UUID);
    pCharacteristic = pService->createCharacteristic(
        CHAR_UUID,
        BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
    );
    pCharacteristic->setValue("Hello from Nano ESP32!");
    pService->start();
    BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
    pAdvertising->addServiceUUID(SERVICE_UUID);
    pAdvertising->start();
    
    Serial.println("WiFi AP + BLE both running!");
}

void loop() {
    // Web 服务器
    WiFiClient client = server.available();
    if (client) {
        String req = client.readStringUntil('\r');
        client.println("HTTP/1.1 200 OK\nContent-Type: text/plain\n");
        client.printf("Uptime: %lu ms\nADC0: %d\n", millis(), analogRead(A0));
        client.stop();
    }
    
    // 更新 BLE 特征值
    static unsigned long last = 0;
    if (millis() - last > 2000) {
        last = millis();
        char buf[32];
        snprintf(buf, 32, "ADC: %d", analogRead(A0));
        pCharacteristic->setValue(buf);
        pCharacteristic->notify();
    }
}
```

---

## 例程 2:PSRAM 使用 — 大内存缓冲

```cpp
// Nano ESP32 - 8MB PSRAM 使用示例
// 检查并利用 PSRAM 存储大数据

void setup() {
    Serial.begin(115200);
    delay(1000);
    
    // 内存统计
    Serial.println("=== Memory Info ===");
    Serial.printf("Total SRAM:    %d KB\n", ESP.getHeapSize() / 1024);
    Serial.printf("Free SRAM:     %d KB\n", ESP.getFreeHeap() / 1024);
    Serial.printf("Total PSRAM:   %d KB\n", ESP.getPsramSize() / 1024);
    Serial.printf("Free PSRAM:    %d KB\n", ESP.getFreePsram() / 1024);
    
    if (!psramFound()) {
        Serial.println("PSRAM not available!");
        return;
    }
    
    // 在 PSRAM 中分配大数组(SRAM 无法容纳)
    const int ARRAY_SIZE = 500000;  // 50万个 float = 2MB
    float* bigArray = (float*)ps_malloc(ARRAY_SIZE * sizeof(float));
    
    if (bigArray == nullptr) {
        Serial.println("PSRAM allocation failed!");
        return;
    }
    
    Serial.printf("Allocated %d floats in PSRAM\n", ARRAY_SIZE);
    
    // 填充和验证
    for (int i = 0; i < ARRAY_SIZE; i++) {
        bigArray[i] = sin(i * 0.01f);
    }
    
    Serial.printf("bigArray[0] = %.4f\n", bigArray[0]);
    Serial.printf("bigArray[%d] = %.4f\n", ARRAY_SIZE-1, bigArray[ARRAY_SIZE-1]);
    
    free(bigArray);
    Serial.println("PSRAM freed.");
}

void loop() {
    delay(1000);
}
```

---

## 例程 3:深度睡眠 + RTC 唤醒

```cpp
// Nano ESP32 - 深度睡眠 + RTC 定时唤醒 + RTC 内存保留
#include <esp_sleep.h>

#define SLEEP_SECONDS 10

RTC_DATA_ATTR int bootCount = 0;  // RTC 内存,深度睡眠后保留

void setup() {
    Serial.begin(115200);
    delay(100);
    
    bootCount++;
    Serial.printf("\n=== Boot #%d ===\n", bootCount);
    Serial.printf("Wake reason: ");
    
    switch (esp_sleep_get_wakeup_cause()) {
        case ESP_SLEEP_WAKEUP_TIMER:
            Serial.println("Timer");
            break;
        case ESP_SLEEP_WAKEUP_EXT0:
            Serial.println("External GPIO (RTC_IO)");
            break;
        default:
            Serial.println("Power-on / Reset");
            break;
    }
    
    // 做一些工作...
    Serial.println("Working... (entering deep sleep in 2s)");
    Serial.printf("Boot count (persists in RTC RAM): %d\n", bootCount);
    delay(2000);
    
    // 配置唤醒源
    esp_sleep_enable_timer_wakeup(SLEEP_SECONDS * 1000000ULL);
    
    // 也可以用 GPIO 唤醒(D2 = RTC GPIO)
    // esp_sleep_enable_ext0_wakeup(GPIO_NUM_2, LOW);
    
    Serial.printf("Sleeping for %d seconds...\n", SLEEP_SECONDS);
    Serial.flush();
    
    esp_deep_sleep_start();
}

void loop() {
    // 永远不会执行(深度睡眠后从头运行 setup)
}
```

---

## 例程 4:TinyML 边缘推理 — 语音唤醒词检测

```cpp
// Nano ESP32 - TinyML 语音唤醒词检测框架
// 利用 240MHz + 8MB PSRAM 运行轻量神经网络
// 需安装: Arduino_TensorFlowLite 库

#include <TensorFlowLite_ESP32.h>
// #include "trained_model.h"  // 你的 TFLite 模型

// 实际模型需通过 TensorFlow Lite Micro 导出
// 此处展示框架结构

// tflite::MicroErrorReporter error_reporter;
// tflite::Model* model;
// tflite::MicroInterpreter* interpreter;

const int SAMPLE_RATE = 16000;
const int WINDOW_SIZE = 1000;  // 1秒窗口

int16_t audioBuffer[WINDOW_SIZE];
int bufferIndex = 0;

void setup() {
    Serial.begin(115200);
    Serial.println("TinyML Wake Word Demo (Framework)");
    Serial.printf("PSRAM: %d KB available\n", ESP.getFreePsram() / 1024);
    
    // 1. 加载模型
    // model = tflite::GetModel(trained_model);
    
    // 2. 创建解释器(利用 PSRAM)
    // static tflite::MicroMutableOpResolver<4> resolver;
    // resolver.AddFullyConnected();
    // ...
    
    // 3. 分配张量
    // interpreter->AllocateTensors();
    
    Serial.println("Model loaded. Listening for wake word...");
}

void loop() {
    // 模拟音频采样(实际需 PDM/I2S 麦克风)
    // audioBuffer[bufferIndex++] = readMicrophone();
    
    // if (bufferIndex >= WINDOW_SIZE) {
    //     // 执行推理
    //     float* input = interpreter->input(0)->data.f;
    //     memcpy(input, audioBuffer, WINDOW_SIZE * sizeof(int16_t));
    //     
    //     interpreter->Invoke();
    //     
    //     float* output = interpreter->output(0)->data.f;
    //     if (output[0] > 0.8f) {
    //         Serial.println("🔔 Wake word detected!");
    //     }
    //     
    //     bufferIndex = 0;
    // }
    
    delay(10);
}
```

---

## 例程 5:OTA 固件升级(无线更新)

```cpp
// Nano ESP32 - OTA 无线固件升级
// 通过网络远程更新固件,无需 USB 连接

#include <WiFi.h>
#include <ArduinoOTA.h>

const char* ssid = "YOUR_SSID";
const char* pass = "YOUR_PASSWORD";

void setup() {
    Serial.begin(115200);
    
    // WiFi 连接
    WiFi.begin(ssid, pass);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nWiFi OK");
    Serial.print("IP: ");
    Serial.println(WiFi.localIP());
    
    // 配置 OTA
    ArduinoOTA.setHostname("NanoESP32");
    ArduinoOTA.setPassword("ota_password");  // 可选密码保护
    
    ArduinoOTA.onStart([]() {
        Serial.println("OTA Update Started");
    });
    ArduinoOTA.onEnd([]() {
        Serial.println("\nOTA Update Complete! Rebooting...");
    });
    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
        Serial.printf("Progress: %u%%\r", (progress * 100) / total);
    });
    ArduinoOTA.onError([](ota_error_t error) {
        Serial.printf("OTA Error[%u]: ", error);
    });
    
    ArduinoOTA.begin();
    Serial.println("OTA Ready. Use Arduino IDE → Network Port to upload.");
}

void loop() {
    ArduinoOTA.handle();  // 处理 OTA 请求
    
    // 正常运行的应用代码
    static unsigned long last = 0;
    if (millis() - last > 5000) {
        last = millis();
        Serial.printf("Running firmware v1.0 | Uptime: %lu s\n", millis() / 1000);
    }
}
```

> **编译提示**:Arduino IDE → `Tools → Board → Arduino Nano ESP32`,需安装 `Arduino ESP32 Boards`(v2.0.11+)。OTA 例程烧录后,后续可通过 IDE 的"网络端口"无线烧录。

参考资料

暂无参考文献