1. 基础示例
通过基础示例可以快速的验证开发板板载功能是否正常。
1.1 获取环境光数据
通过该示例可以验证开发板的LTR308环境光传感器是否正常。通过该示例程序可获取开发板上集成的LTR308环境光传感器数据,并将这些采集到的环境光数据通过串口输出(串口波特率: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);
}
结果

1.2 录音&播放
通过该示例可以验证开发板的MIC和功放是否正常。该示例程序演示了通过MIC采集声音并通过喇叭播放声音,烧录代码后并复位开发板,板载LED点亮后开始录音5秒。LED熄灭后喇叭开始播放录音。
注意:使用前请将喇叭连接到SPK座子上。
#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()
{
}
1.3 CameraWebServer
通过该示例可以验证开发板的摄像头和WiFi是否正常。该示例通过ESP32创建一个网页服务器,可以通过浏览器查看摄像头的实时画面。
烧录示例代码后打开串口监视器(串口波特率:115200),根据提示输入WiFi SSID和Password,即可连接WiFi,连接成功后可在串口监视器中看到IP地址,通过浏览器访问IP地址即可进入监控后台(须在同局域网),点击“Start Stream”按钮即可查看监控画面。
结果

1.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
2. 应用示例
2.1 基于电脑openCV实现物体轮廓识别
该示例将ESP32作为WiFi摄像头或USB摄像头,将图像数据给到电脑,电脑基于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参数

2.2 基于电脑yoloV5实现物体分类
该示例将ESP32作为WiFi摄像头或USB摄像头,将图像数据给到电脑,电脑基于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)参数

2.3 基于EdgeImpulse实现图像识别
该示例代码使用了edgeimpulse训练的Person_Detection_inferencing模型进行人形识别,可实现在ESP32本地实现人形识别。通过串口监视器可查看识别结果输出,通过网页视频流可查看摄像头画面。
步骤
-
将Person_Detection_inferencing文件夹放入Arduino IDE安装目录的libraries中
-
启动Arduino IDE,在示例代码中选择Person_Detection_inferencing -> edge_camera,烧录代码
-
打开串口监视器(波特率115200),根据提示输入WiFi SSID和Password,即可连接WiFi。
-
连接成功后通过浏览器访问串口监视器打印的IP地址即可监控后台,通过“Start Stream”按钮即可获取图像流。
2.4 自定义EdgeImpulse模型
可以通过EdgeImpulse平台自定义训练图像识别模型,训练EdgeImpulse模型模型教程请访问Wiki:
EdgeImpulse物体检测教程-DFRobot
注:SDK版本不同可能会出现编译报错(演示demo SDK版本 3.0.1)
2.5 接入HomeAssistant
该示例代码将ESP32接入HomeAssistant作为监控摄像头使用。
接入HomeAssistant教程请访问Wiki:ESP32_S3_HomeAssistant
2.6 接入小智AI
小智AI是“虾哥”的开源人工智能语音对话项目,面向开发者与技术极客。它集成语音识别、自然语言对话等核心技术,支持开发者构建具备情绪感知等多模态交互能力的定制化 AI 应用,为智能终端等领域提供技术支撑。
xiaozhi固件
xiaozhi固件可实现语音对话交流。
xiaozhi-CAM固件
xiaozhi-CAM固件在xiaozhi固件的基础上增加了调用摄像头功能功能,通过“画面中有什么”、“你看到了什么”等关键词,可以让识别摄像头中的画面。
固件烧录方法请参考:FLASH Download Tool使用教程
配网教程
- 在烧录固件后,按下开发板上的RST按钮,复位重启开发板,设备语音提示“进入配网模式”,3/LED开始闪烁。
- 使用手机或电脑连接到ESP32的热点(通常以 Xiaozhi-XXXX 命名)。连接成功后将进入网络配置页面(如果没有进入网络配置页面,可使用浏览器访问192.168.4.1进入),在页面中输入需要连接的WiFi SSID和密码。
- WiFi连接成功并重启设备后,可听到语音播放“请登录到控制面板添加设备,请输入验证码xxxxxx”(如果听到“正在升级系统”请等待升级完成)。
- 电脑浏览器访问“https://xiaozhi.me”,进入控制台 -> 添加设备,输入设备播报的验证码,完成设备添加。
- 设备添加成功后3/LED将微亮,可通过“你好小智”或点击“BOOT”按键唤醒(此时3/LED将以呼吸闪烁)。
2.7 接入OpenAI RTC
通过该示例代码,您可以与OpenAl(ChatGPT)进行实时对话。
项目地址:https://github.com/DFRobot/openai-realtime-embedded-sdk
注意
- 此代码须在ESP-IDF环境下运行
- 接入OpenAI需要特殊网络
- 需要购买OpenAI的token
2.8 OpenAI图像问答
此示例演示了DFRobot ESP32-S3 Al CAM与openAl的连接,用于语音和图像识别。在烧录代码后,按住boot按钮并向模块提问,例如“你看到了什么?”?“这是什么植物?”?“他在干什么?”?该模块将音频和图像数据发送到OpenAI或识别,以语音的形式播放识别结果。
注意
- 接入OpenAI需要特殊网络
- 需要购买OpenAI的token

2.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.
}
2.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);
}