Beetle ESP32-C6

README

  • 如果出现烧录代码失败、找不到COM口、COM口不断出现又消失等情况,请按住BOOT按键,然后点击RST,再下载代码即可成功烧录代码。
  • 所有demo源码及固件可在该链接中下载【https://gitee.com/DFRobot/DFR1154_Examples】,通过烧录bin文件可以快速体验功能和验证硬件。烧录bin文件的教程

1. 产品描述

1.1 产品简介

ESP32-S3 AI CAM是一款基于ESP32-S3芯片设计的智能摄像头模组,专为视频图像处理和语音交互打造,适用于视频监控、边缘图像识别、语音对话等AI项目。ESP32-S3支持高性能神经网络运算与信号处理能力,赋予设备强大的图像识别和语音交互功能。

强大的AI处理能力,智能图像与语音识别
ESP32-S3 AI CAM内置ESP32-S3芯片,具备卓越的神经网络计算能力。它不仅可以在摄像头图像中进行智能识别,还能进行复杂的边缘计算任务。同时,麦克风和扬声器的集成使其支持语音识别、语音对话,能够实现远程指令控制、实时互动等多种AI功能,适用于物联网设备和智能监控应用。

广角红外摄像头,适应全天候监控需求
ESP32-S3 AI CAM的广角红外摄像头结合红外补光灯和光敏传感器,在弱光和完全黑暗的环境中依然能保持出色的图像清晰度。无论是白天还是夜晚,ESP32-S3 AI CAM都能确保监控画面的稳定性和清晰度,为安防和监控系统提供可靠支持。

语音交互与控制,实现智能自动化
ESP32-S3 AI CAM内置麦克风和扬声器,可实现语音识别与对话功能。在智能家居、物联网(IoT)设备中,这一功能可以帮助用户通过语音控制摄像头或其他设备,简化操作流程,增强智能化体验。

联网支持,扩展在线AI功能
除了本地AI处理能力,ESP32-S3 AI CAM可通过Wi-Fi接入互联网,通过云端或在线大模型扩展更多智能功能。通过Wi-Fi联网,该模组可以与云端AI平台进行对接,调用在线的大规模语言模型和视觉模型,实现更复杂的任务处理,如高级的图像分类、语音翻译、自然语言对话等功能。这使得ESP32-S3 AI CAM不仅限于本地计算,还能依托在线资源进行远程智能操作,显著提升其在物联网(IoT)设备中的应用潜力。

1.2 产品特性

  • 多样的AI玩法
    • 边缘图像识别(基于EdgeImpulse)
    • 在线图像识别(openCV、yolo)
    • 语音、图像在线大模型(ChatGPT)
  • 具有广角夜视摄像头,红外补光,昼夜可用
  • 板载MIC、功放,单板实现语音交互
  • 提供多种AI模型,提供训练模型教程,快速上手

2. 技术规格

2.1 产品参数

基本参数

  • 工作电压: 3.3V
  • Type-C输入电压: 5V DC
  • VIN输入电压:5-12V DC
  • 工作温度:-10~60℃
  • 模块尺寸:42*42mm

摄像头参数

  • 传感器型号:OV3660
  • 像素:300W
  • 感光:可见光、940nm红外
  • 可视角度:160°
  • 焦距:0.95
  • 光圈:2.0
  • 畸变:<8%

硬件信息

  • 处理器:Xtensa® 双核32位LX7微处理器
  • 主频:240 MHz
  • SRAM:512KB
  • ROM:384KB
  • Flash:16MB
  • PSRAM:8MB
  • RTC SRAM:16KB
  • USB: USB 2.0 OTG全速接口
WIFI
  • WIFI协议:IEEE 802.11b/g/n
  • WIFI频宽: 2.4 GHz 频带支持 20 MHz 和 40 MHz 频宽
  • WIFI模式:Station 模式、SoftAP 模式、SoftAP+Station 模式和混杂模式
  • WIFI频率:2.4GHz
  • 帧聚合: TX/RX A-MPDU, TX/RX A-MSDU
蓝牙
  • 蓝牙协议:Bluetooth 5、Bluetooth mesh
  • 蓝牙频率:125 Kbps、500 Kbps、1 Mbps、2 Mbps

2.2 板载功能示意

  • OV3660:160°广角红外摄像头
  • IR:红外补光灯(GPIO47)
  • MIC:I2S PDM麦克风
  • LED:板载LED灯(GPIO3)
  • ALS:LTR-308环境光传感器
  • ESP32-S3:ESP32-S3R8芯片
  • SD:SD卡槽
  • Flash:16MB Flash
  • VIN:5-12V DC输入
  • HM6245:电源芯片
  • Type-C:USB Type-C接口用于供电烧录代码
  • Gravity
    • +: 3.3-5V
    • -:GND
    • 44:GPIO44,ESP32-S3原生RX
    • 43:GPIO43,ESP32-S3原生TX
  • RST:复位按键
  • BOOT:BOOT按键(GPIO0)
  • SPK:MX1.25-2P喇叭接口
  • MAX98357:I2S功放芯片

2.3 板载功能引脚定义

3. 首次使用

3.1 添加板卡

当您首次使用ESP32,您需要了解以下步骤

  1. 在Arduino IDE添加ESP32开发板(如何在Arduino IDE添加ESP32开发板?
  2. 选择开发板以及串口
  3. 烧录程序

3.2 选择开发板

  • 点击Tools->Board:,选择对应型号的开发板"ESP32S3 Dev Module"
Beetle ESP32-C3
  • 在烧录代码前需设置开发板
    • USB CDC On Boot:
      • Enabled: 通过USB接口打印串口数据
      • Disable: 通过TX、RX打印串口数据
    • Partition Scheme: 磁盘分区方案,请根据开发板Flash选择合适的存储空间
    • Port: 开发板端口(COM号正确即可,与后面芯片型号无关)
firebeetle ESP32 \

3.3 烧录代码

  • 将代码复制到窗口内,点击"Upload"上传代码
int led = 3;
void setup() {
  pinMode(led,OUTPUT);
}

void loop() {
  digitalWrite(led,HIGH);
  delay(1000);
  digitalWrite(led,LOW);
  delay(1000);
}
firebeetle ESP32
  • 等待烧录完成,即可看见板载LED灯开始闪烁
    • 若LED灯没有闪烁,请复位开发板
    • 若无法烧录请查看常见问题
firebeetle ESP32

4. ESP32通用教程

FireBeetle 2 ESP32-S3基础教程
FireBeetle 2 ESP32-S3进阶教程

5. 功能示例

通过功能示例可以快速的验证开发板板载功能是否正常

5.1 获取环境光数据

通过该示例可获取环境光数据,并在串口打印(波特率:115200)
注意:使用前请安装LTR308传感器库

#include <DFRobot_LTR308.h>

DFRobot_LTR308 light;

void setup(){
    Serial.begin(115200);
	//如果使用了摄像头,请将摄像头的初始化放在LTR308初始化之前,否则会出现读取数值为0的情况
    while(!light.begin()){
    Serial.println("Initialization failed!");
    delay(1000);
  }
  Serial.println("Initialization successful!");
}
void loop(){
  uint32_t data = light.getData();
  Serial.print("Original Data: ");
  Serial.println(data);
  Serial.print("Lux Data: ");
  Serial.println(light.getLux(data));
  delay(500);
}

结果

5.2 录音&播放

通过该示例可以实现录音、放音功能。烧录代码并复位开发板,LED灯点亮后开始录音5秒,LED灯熄灭后通过喇叭播放录音。

#include <Arduino.h>
#include <SPI.h>

#include "ESP_I2S.h"

#define SAMPLE_RATE     (16000)
#define DATA_PIN        (GPIO_NUM_39)
#define CLOCK_PIN       (GPIO_NUM_38)
#define REC_TIME 5  //Recording time 5 seconds

void setup()
{
  uint8_t *wav_buffer;
  size_t wav_size;
  I2SClass i2s;
  I2SClass i2s1;
  Serial.begin(115200);
  pinMode(3, OUTPUT);
  i2s.setPinsPdmRx(CLOCK_PIN, DATA_PIN);
  if (!i2s.begin(I2S_MODE_PDM_RX, SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
    Serial.println("Failed to initialize I2S PDM RX");
  }
  i2s1.setPins(45, 46, 42);
  if (!i2s1.begin(I2S_MODE_STD, SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
    Serial.println("MAX98357 initialization failed!");
  }
  Serial.println("start REC");
  digitalWrite(3, HIGH);
  wav_buffer = i2s.recordWAV(REC_TIME, &wav_size);
  digitalWrite(3, LOW);
  //Play the recording
  i2s1.playWAV(wav_buffer, wav_size);
}

void loop()
{
  
}

5.3 CameraWebServer

烧录示例代码或bin文件,打开串口监视器(波特率115200),根据提示输入WiFi SSID和Password,即可连接WiFi。连接成功后通过浏览器访问串口监视器打印的IP地址即可监控后台,通过“Start Stream”按钮即可获取图像流。

结果

5.4 USBWebCamera

该代码可将ESP32-S3虚拟为USB摄像头,将摄像头图像数据通过USB传输到电脑,电脑端可通过运行python脚本,接收图像数据。

步骤

  • 给模块烧录bin文件,将模块通过USB连接电脑。
  • 安装python环境(https://www.python.org/),如果安装过,请跳过。
  • 安装opencv-python库
    • 按下Win+R,输入cmd进入命令窗口
    • 输入“pip install opencv-python” 安装opencv-python库
  • 打开python的IDLE,File->Open...,选择Image_reception.py,在弹出的新窗口中按下F5,即可看到画面。

注意:

  • 若窗口无画面,可能因为电脑存在多个摄像头,请修改Image_reception.py文件中“device_id”参数再尝试。
  • bin文件是基于该示例代码编译而出,该示例需在ESP-IDF使用
    项目地址:
    https://github.com/espressif/esp-iot-solution/tree/master/examples/usb/device/usb_webcam

6. 应用示例

6.1 基于电脑openCV实现物体轮廓识别

该示例主要演示了电脑端使用openCV实现物体轮廓识别。

步骤

  • 给模块烧录代码(使用5.3或5.4章节的代码)
  • 安装python环境(https://www.python.org/),如果安装过,请跳过。
  • 安装opencv-python库
    • 按下Win+R,输入cmd进入命令窗口
    • 输入“pip install opencv-python” 安装opencv-python库
  • 打开python的IDLE,File->Open...,选择py文件(如果使用5.3章节示例,请使用openCV_5_3.py;如果使用5.4章节示例请使用openCV_5_4.py),在弹出的新窗口中按下F5,即可看到画面。

注意

  • 使用openCV_5_3.py时,请注意修改IP地址参数
  • 使用openCV_5_4.py时,请注意修改camera_index参数

6.2 基于电脑yoloV5实现物体分类

该示例主要演示了电脑端使用yoloV5实现物体分类。

步骤

  • 给模块烧录代码(使用5.3或5.4章节的代码)
  • 安装python环境(https://www.python.org/),如果安装过,请跳过。
  • 安装opencv-python库
    • 按下Win+R,输入cmd进入命令窗口
    • 输入“pip install opencv-python” 安装opencv-python库
    • 输入“pip install yolov5” 安装yolov5库
  • 打开python的IDLE,File->Open...,选择py文件(如果使用5.3章节示例,请使用yolo_5_3.py;如果使用5.4章节示例请使用yolo_5_4.py),在弹出的新窗口中按下F5,即可看到画面。

注意

  • 使用openCV_5_3.py时,请注意修改IP地址参数
  • 使用openCV_5_4.py时,请注意修改cap = cv2.VideoCapture(0)参数

6.3 基于EdgeImpulse实现图像识别

该示例代码使用了在edgeimpulse训练的Person_Detection_inferencing模型进行人形识别,通过串口可查看识别结果,通过网页视频流可查看摄像头画面。

步骤

  1. 将Person_Detection_inferencing文件夹放入Arduino IDE安装目录的libraries中

  2. 启动Arduino IDE,在示例代码中选择Person_Detection_inferencing -> edge_camera,烧录代码

  3. 打开串口监视器(波特率115200),根据提示输入WiFi SSID和Password,即可连接WiFi。

  4. 连接成功后通过浏览器访问串口监视器打印的IP地址即可监控后台,通过“Start Stream”按钮即可获取图像流。

6.4 自定义EdgeImpulse模型

训练edgeimpulse模型教程请访问Wiki

EdgeImpulse物体检测教程-DFRobot

注:SDK版本不同可能会出现编译报错(演示demo SDK版本 3.0.1)

6.5 接入HomeAssistant

基于该教程可以将ESP32-S3摄像头模组添加到HomeAssistant中,并看到监控画面

接入HomeAssistant教程请访问Wiki
ESP32_S3_HomeAssistant

6.6 接入小智

通过“flash_download_tool”烧录固件,即可实现接入小智AI大模型。使用前建议阅读配网教程。

xiaozhi固件

可实现语音对话交流

xiaozhi-CAM固件

  • 在xiaozhi固件的基础上增加了图像识别功能,通过“画面中有什么”、“你看到了什么”等关键词,可以让识别摄像头中的画面。

  • 小智CAM固件

6.7 接入OpenAI RTC

通过该示例代码,您可以与OpenAl(ChatGPT)进行实时对话。

项目地址:https://github.com/DFRobot/openai-realtime-embedded-sdk

注意

  • 此代码须在ESP-IDF环境下运行
  • 接入OpenAI需要特殊网络
  • 需要购买OpenAI的token

6.8 OpenAI图像问答

此示例演示了DFRobot ESP32-S3 Al CAM与openAl的连接,用于语音和图像识别。在烧录代码后,按住boot按钮并向模块提问,例如“你看到了什么?”?“这是什么植物?”?“他在干什么?”?该模块将音频和图像数据发送到OpenAI或识别,以语音的形式播放识别结果。

注意

  • 接入OpenAI需要特殊网络
  • 需要购买OpenAI的token

6.9 延时摄影

该示例演示了使用DFRobot ESP32-S3 AI Camera定时拍照,并保存到SD卡中。拍照间隔默认设置为25秒,可通过TIME_TO_SLEEP修改拍照间隔时间;拍照时LED将会点亮,拍照后ESP32-S3将进入休眠。

#include "esp_camera.h"
#include "FS.h"
#include "SD.h"
#include "driver/rtc_io.h"
#include "esp_sleep.h"

#define SD_CARD_CS   10

#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     5
#define Y9_GPIO_NUM       4
#define Y8_GPIO_NUM       6
#define Y7_GPIO_NUM       7
#define Y6_GPIO_NUM       14
#define Y5_GPIO_NUM       17
#define Y4_GPIO_NUM       21
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM       16
#define VSYNC_GPIO_NUM    1
#define HREF_GPIO_NUM     2
#define PCLK_GPIO_NUM     15
#define SIOD_GPIO_NUM  8
#define SIOC_GPIO_NUM  9

#define TIME_TO_SLEEP  25 // Shooting interval time (S)
#define uS_TO_S_FACTOR 1000000ULL
#define SLEEP_DURATION (TIME_TO_SLEEP * uS_TO_S_FACTOR)

RTC_DATA_ATTR int photo_count = 0; // Use RTC memory to save counts (lost in case of power failure)

bool initCamera() {
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer   = LEDC_TIMER_0;
  config.pin_d0       = Y2_GPIO_NUM;
  config.pin_d1       = Y3_GPIO_NUM;
  config.pin_d2       = Y4_GPIO_NUM;
  config.pin_d3       = Y5_GPIO_NUM;
  config.pin_d4       = Y6_GPIO_NUM;
  config.pin_d5       = Y7_GPIO_NUM;
  config.pin_d6       = Y8_GPIO_NUM;
  config.pin_d7       = Y9_GPIO_NUM;
  config.pin_xclk     = XCLK_GPIO_NUM;
  config.pin_pclk     = PCLK_GPIO_NUM;
  config.pin_vsync    = VSYNC_GPIO_NUM;
  config.pin_href     = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn     = PWDN_GPIO_NUM;
  config.pin_reset    = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size = FRAMESIZE_UXGA;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 10;
  config.fb_count = 2;
  config.grab_mode = CAMERA_GRAB_LATEST;
  
  esp_err_t err = esp_camera_init(&config);

  sensor_t *s = esp_camera_sensor_get();
  // initial sensors are flipped vertically and colors are a bit saturated
  if (s->id.PID == OV3660_PID) {
    s->set_vflip(s, 1);        // flip it back
    s->set_brightness(s, 1);   // up the brightness just a bit
    s->set_saturation(s, -2);  // lower the saturation
  }
  
  return err == ESP_OK;
}

bool initSDCard() {
  if (!SD.begin(SD_CARD_CS)) {
    return false;
  }
  uint8_t cardType = SD.cardType();
  return cardType != CARD_NONE;
}

void takePhotoAndSave() {
  camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Failed to obtain the image.");
    return;
  }

  String path = "/photo_" + String(photo_count) + ".jpg";
  fs::FS &fs = SD;
  File file = fs.open(path.c_str(), FILE_WRITE);
  if (!file) {
    Serial.println("Save failed");
  } else {
    file.write(fb->buf, fb->len);
    Serial.println("Photo saving path: " + path);
  }
  file.close();
  esp_camera_fb_return(fb);

  photo_count++; // The number of the next picture
}

void setup() {
  Serial.begin(115200);
  delay(3000); // Give the serial port some startup time

  if (!initCamera()) {
    Serial.println("The camera initialization failed.");
    return;
  }

  if (!initSDCard()) {
    Serial.println("The initialization of the SD card failed.");
    return;
  }
  pinMode(3,OUTPUT);
  digitalWrite(3,HIGH);
  takePhotoAndSave();
  //delay(500);
  digitalWrite(3,LOW);
  Serial.println("Get ready to enter deep sleep.");
  esp_sleep_enable_timer_wakeup(SLEEP_DURATION);
  esp_deep_sleep_start();
}

void loop() {
  // It won't be executed up to here.
}

6.10 播放网络音乐

该实例演示了通过ESP32-S3播放网络上的音频文件。烧录代码后,根据串口监视器提示输入WiFi SSID和Password,即可连接WiFi。然后输入网络音频地址即可播放音频。

注意

  • 使用示例代码前请安装ESP32-audioI2S库,库链接:https://github.com/schreibfaul1/ESP32-audioI2S/
//**********************************************************************************************************
//*    audioI2S-- I2S audiodecoder for ESP32,                                                              *
//**********************************************************************************************************
//
// first release on 11/2018
// Version 3  , Jul.02/2020
//
//
// THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT.
// FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR
// OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
//

#include "Arduino.h"
#include "WiFiMulti.h"
#include "Audio.h"
#include "SPI.h"
#include "SD.h"
#include "FS.h"

#include <WiFi.h>
#include <Preferences.h>

// Digital I/O used
#define SD_CS         10
#define SPI_MOSI      11
#define SPI_MISO      13
#define SPI_SCK       12
#define I2S_DOUT      42
#define I2S_BCLK      45
#define I2S_LRC       46

Audio audio;

Preferences preferences;
const char* ssid;
const char* password;

void connectToWiFi(const char* ssid, const char* password) {
  WiFi.begin(ssid, password);
  Serial.printf("Connecting to WiFi: %s\n", ssid);
  int retries = 0;
  while (WiFi.status() != WL_CONNECTED && retries < 20) {
    delay(500);
    Serial.print(".");
    retries++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi connected!");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nFailed to connect to WiFi.");
  }
}

void initWiFi() {
  preferences.begin("wifi", false);
  String savedSSID = preferences.getString("ssid", "");
  String savedPASS = preferences.getString("password", "");

  if (savedSSID.length() > 0 && savedPASS.length() > 0) {
    Serial.println("Found saved WiFi credentials.");
    connectToWiFi(savedSSID.c_str(), savedPASS.c_str());

    if (WiFi.status() == WL_CONNECTED) {
      return;
    } else {
      Serial.println("Stored credentials failed. Please enter new credentials.");
    }
  } else {
    Serial.println("No WiFi credentials found. Please enter:");
  }

  while (Serial.available()) Serial.read();

  Serial.print("Enter SSID: ");
  while (Serial.available() == 0) delay(10);
  String inputSSID = Serial.readStringUntil('\n');
  inputSSID.trim();

  Serial.print("Enter Password: ");
  while (Serial.available() == 0) delay(10);
  String inputPASS = Serial.readStringUntil('\n');
  inputPASS.trim();

  connectToWiFi(inputSSID.c_str(), inputPASS.c_str());

  if (WiFi.status() == WL_CONNECTED) {
    preferences.putString("ssid", inputSSID);
    preferences.putString("password", inputPASS);
    Serial.println("WiFi credentials saved.");
  } else {
    Serial.println("Failed to connect. Credentials not saved.");
  }

  preferences.end();
}

void setup() {
    pinMode(SD_CS, OUTPUT);
    digitalWrite(SD_CS, HIGH);
    SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
    SPI.setFrequency(1000000);
    Serial.begin(115200);
    SD.begin(SD_CS);

    initWiFi();

    audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
    audio.setVolume(15); // 0...21

//    audio.connecttoFS(SD, "test.wav");
//    audio.connecttohost("http://www.wdr.de/wdrlive/media/einslive.m3u");
//    audio.connecttohost("http://somafm.com/wma128/missioncontrol.asx"); //  asx
//    audio.connecttohost("http://mp3.ffh.de/radioffh/hqlivestream.aac"); //  128k aac
      audio.connecttohost("https://ra-sycdn.kuwo.cn/e3f17b5516e9e42b69d4ffd039336e7d/681e0434/resource/n3/128/40/70/356596524.mp3"); //  128k mp3
}

void loop(){
    vTaskDelay(1);
    audio.loop();
    if(Serial.available()){ // put streamURL in serial monitor
        audio.stopSong();
        String r=Serial.readString(); r.trim();
        if(r.length()>5) audio.connecttohost(r.c_str());
        log_i("free heap=%i", ESP.getFreeHeap());
    }
}

// optional
void audio_info(const char *info){
    Serial.print("info        "); Serial.println(info);
}
void audio_id3data(const char *info){  //id3 metadata
    Serial.print("id3data     ");Serial.println(info);
}
void audio_eof_mp3(const char *info){  //end of file
    Serial.print("eof_mp3     ");Serial.println(info);
}
void audio_showstation(const char *info){
    Serial.print("station     ");Serial.println(info);
}
void audio_showstreamtitle(const char *info){
    Serial.print("streamtitle ");Serial.println(info);
}
void audio_bitrate(const char *info){
    Serial.print("bitrate     ");Serial.println(info);
}
void audio_commercial(const char *info){  //duration in sec
    Serial.print("commercial  ");Serial.println(info);
}
void audio_icyurl(const char *info){  //homepage
    Serial.print("icyurl      ");Serial.println(info);
}
void audio_lasthost(const char *info){  //stream URL played
    Serial.print("lasthost    ");Serial.println(info);
}

7. FLASH下载工具使用教程

FLASH下载工具使用教程

8. MicroPython教程

MicroPython教程

9. Platform IO教程

Platform IO教程

10. ESP-IDF教程

即将推出

11. 常见问题

  • 无法将代码下载到开发板 / 找不到COM口 / COM口不断出现又消失 / 串口不断打印复位信息
    • 请按住BOOT按键,然后点击RST,再下载代码即可

12. 资料下载