文档类型:早期 Korvo S3 综合验板/多页 UI 笔记。
请优先阅读:Korvo korvo_board_test · P4C5 p4c5_board_test
1. 项目概述
本教程将介绍如何使用 ESP32-S3 Korvo 开发板进行开发,包括按键输入、摄像头、语音识别和显示功能的实现。这个项目基于 ESP-IDF 框架,使用 LVGL 图形库进行界面显示。
2. 硬件介绍
ESP32-S3 Korvo 开发板是一款功能强大的开发板,具有以下主要特性:
- ESP32-S3 处理器:双核 Xtensa LX7 处理器,主频高达 240MHz
- 内置 Wi-Fi 和蓝牙功能
- 摄像头接口
- 显示屏接口
- 音频编解码器
- 多个 ADC 按键输入
- 触摸屏支持
3. 开发环境搭建
3.1 安装 ESP-IDF
首先需要安装 ESP-IDF 开发环境,ESP-IDF 是乐鑫官方的开发框架。
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.bat
3.2 项目依赖
本项目使用了多个组件,在 idf_component.yml 文件中定义:
dependencies:
idf: ">=4.4"
lvgl/lvgl: "~8.4.0"
esp_lcd_touch_cst816s: "^1.0"
espressif/esp-sr: "^1.9.0"
espressif/esp_codec_dev: "^1.3.1"
esp_io_expander_tca9554: "^2.0.0"
espressif/button: "^3.3.1"
4. 项目结构
项目主要包含以下几个模块:
- 按键模块:处理 ADC 按键输入
- 摄像头模块:初始化和获取摄像头图像
- 显示模块:使用 LVGL 库显示界面
- 语音识别模块:实现语音唤醒和识别功能
5. 按键模块详解
5.1 按键初始化
按键模块使用 ADC 方式读取多个按键状态,通过电压值区分不同按键。
void ADC_BUTTON_Init(void)
{
printf("Button Init!\n");
/*
{0, 280, 600}, //1键 2.25v 315
{1, 780, 1000}, //2键 1.12v 820
{2, 1100, 1400}, //3键 1.689v 1290
{3, 1500, 2100}, //4键 0.562v 1460
{4, 2200, 2600}, //5键 2.81v 2480
{5, 2800, 3200}, //5键 2.81v 2480
*/
const uint16_t vol[BUTTON_NUM] = {380, 820, 1180, 1570, 1980, 2410};
button_config_t cfg = {0};
cfg.type = BUTTON_TYPE_ADC;
// 配置每个按键的电压范围
for (size_t i = 0; i < BUTTON_NUM; i++)
{
cfg.adc_button_config.adc_channel = ADC_CHANNEL_4,
cfg.adc_button_config.button_index = i;
// 设置电压下限
if (i == 0)
{
cfg.adc_button_config.min = (0 + vol[i]) / 2;
}
else
{
cfg.adc_button_config.min = (vol[i - 1] + vol[i]) / 2;
}
// 设置电压上限
if (i == 5)
{
cfg.adc_button_config.max = (vol[i] + 3000) / 2;
}
else
{
cfg.adc_button_config.max = (vol[i] + vol[i + 1]) / 2;
}
// 创建按键并注册回调函数
g_btns[i] = iot_button_create(&cfg);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_DOWN, (void *)button_press_down_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, (void *)button_press_up_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, (void *)(void *)button_press_repeat_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, (void *)button_double_click_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, (void *)button_long_press_start_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, (void *)button_long_press_hold_cb, NULL);
}
}
5.2 按键回调函数
每种按键事件都有对应的回调函数,例如按下、释放、单击、双击等:
static void button_press_down_cb(void *arg)
{
ESP_LOGI(TAG, "BTN%d: PRESS_DOWN", get_btn_index((button_handle_t)arg));
memset(button_str, 0, sizeof(button_str));
sprintf(button_str, "BTN%d: PRESS_DOWN", get_btn_index((button_handle_t)arg) + 1);
Button_Value = 1;
}
static void button_single_click_cb(void *arg)
{
ESP_LOGI(TAG, "BTN%d: SINGLE_CLICK", get_btn_index((button_handle_t)arg));
memset(button_str, 0, sizeof(button_str));
sprintf(button_str, "BTN%d: SINGLE_CLICK", get_btn_index((button_handle_t)arg) + 1);
Button_Value = 1;
}
6. 摄像头模块详解
6.1 摄像头配置
摄像头模块使用 ESP32 的摄像头驱动,需要配置摄像头的引脚和参数:
static camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN,
.pin_reset = CAM_PIN_RESET,
.pin_xclk = CAM_PIN_XCLK,
.pin_sscb_sda = CAM_PIN_SIOD,
.pin_sscb_scl = CAM_PIN_SIOC,
.pin_d7 = CAM_PIN_D7,
.pin_d6 = CAM_PIN_D6,
.pin_d5 = CAM_PIN_D5,
.pin_d4 = CAM_PIN_D4,
.pin_d3 = CAM_PIN_D3,
.pin_d2 = CAM_PIN_D2,
.pin_d1 = CAM_PIN_D1,
.pin_d0 = CAM_PIN_D0,
.pin_vsync = CAM_PIN_VSYNC,
.pin_href = CAM_PIN_HREF,
.pin_pclk = CAM_PIN_PCLK,
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.fb_location = CAMERA_FB_IN_DRAM,
.pixel_format = PIXFORMAT_RGB565, //YUV422,GRAYSCALE,RGB565,JPEG
.frame_size = FRAMESIZE_96X96, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
.jpeg_quality = 12, //0-63 lower number means higher quality
.fb_count = 2, //if more than one, i2s runs in continuous mode. Use only with JPEG
.grab_mode = CAMERA_GRAB_WHEN_EMPTY
};
6.2 摄像头初始化
esp_err_t app_camera_init()
{
// camera init
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Camera init failed with error 0x%x", err);
return err;
}
sensor_t *s = esp_camera_sensor_get();
s->set_vflip(s, 0);
s->set_hmirror(s, 1);
return err;
}
7. 显示模块详解
7.1 LVGL 初始化
LVGL 是一个轻量级的图形库,用于创建嵌入式 GUI。在 ksdiy_lvgl_port.c 中初始化 LVGL:
void ksdiy_lvgl_port_init(void)
{
// 初始化 LVGL 库
lv_init();
// 配置显示屏
// ...
// 配置触摸屏
// ...
// 创建 LVGL 任务
// ...
}
7.2 创建界面元素
在 app_main.cpp 中创建界面元素:
void label_init(void)
{
/*创建图像显示区域*/
img_cam = lv_img_create(lv_scr_act());
lv_obj_set_pos(img_cam, 180, 10);
/*创建文本标签*/
label_test = lv_label_create(lv_scr_act());
lv_obj_set_style_text_font(label_test, &myFont, 0);
lv_obj_align(label_test, LV_ALIGN_TOP_LEFT, 0, 0);
lv_obj_set_width(label_test, 180);
lv_label_set_long_mode(label_test, LV_LABEL_LONG_WRAP);
/*创建按钮标签*/
label_adc = lv_label_create(lv_scr_act());
lv_obj_set_style_text_font(label_adc, &myFont, 0);
lv_obj_align(label_adc, LV_ALIGN_TOP_MID, 0, 100);
lv_obj_set_width(label_adc, 240);
lv_label_set_long_mode(label_adc, LV_LABEL_LONG_WRAP);
}
8. 语音识别模块详解
8.1 语音模块初始化
语音识别模块使用 ESP-SR 库实现语音唤醒和命令识别:
void Wakenet_init()
{
// 初始化音频编解码器
// ...
// 初始化语音识别模型
// ...
// 创建语音识别任务
// ...
}
8.2 语音处理任务
static void afe_task(void *arg)
{
int audio_chunksize = afe_handle->get_feed_chunksize(afe_data);
int16_t *buffer = (int16_t *)malloc(audio_chunksize * sizeof(int16_t));
while (1)
{
// 读取音频数据
// ...
// 处理音频数据
// ...
// 检测唤醒词
// ...
// 识别命令
// ...
}
}
9. 主程序流程
主程序在 app_main.cpp 中实现,主要流程如下:
extern "C" void app_main(void)
{
// 初始化 NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// 初始化 LVGL
ksdiy_lvgl_port_init();
// 创建界面元素
label_init();
lv_ex_btn_1();
// 初始化按键
ADC_BUTTON_Init();
// 初始化摄像头
app_camera_init();
// 初始化语音识别
Wakenet_init();
// 主循环
while (1)
{
// 更新界面显示
// ...
// 处理按键事件
// ...
// 获取摄像头图像
// ...
// 延时
vTaskDelay(pdMS_TO_TICKS(10));
}
}
10. 实际应用示例
10.1 显示摄像头图像
// 获取摄像头图像
fb = esp_camera_fb_get();
if (fb)
{
// 将图像数据转换为 LVGL 图像格式
// ...
// 显示图像
lv_img_set_src(img_cam, &img_dsc);
// 释放图像缓冲区
esp_camera_fb_return(fb);
}
10.2 处理按键事件
// 检查是否有按键事件
if (Button_Value)
{
// 更新按键文本显示
lv_label_set_text(label_adc, button_str);
// 重置按键状态
Button_Value = 0;
}
10.3 语音唤醒响应
// 检查是否有语音唤醒事件
if (detect_flag)
{
// 显示唤醒提示
wakeup_set_text("#FF0000 已唤醒#\n请说出指令");
// 播放提示音
play_wav("/spiffs/wakeup.wav");
// 重置唤醒标志
detect_flag = 0;
}
11. 调试技巧
11.1 日志输出
使用 ESP-IDF 的日志系统输出调试信息:
ESP_LOGI(TAG, "按键 %d 被按下", button_index);
ESP_LOGW(TAG, "警告信息");
ESP_LOGE(TAG, "错误信息: %d", error_code);
11.2 内存监控
监控系统内存使用情况:
printf("可用堆内存: %d 字节\n", esp_get_free_heap_size());
printf("最小未使用内存: %d 字节\n", esp_get_minimum_free_heap_size());
12. 常见问题解决
- 摄像头初始化失败:检查摄像头连接和引脚配置
- 按键无响应:检查 ADC 通道和电压范围配置
- 显示屏无显示:检查 SPI 配置和 LVGL 初始化
- 语音识别不工作:检查麦克风连接和音频编解码器配置
13. 扩展开发
- 添加 Wi-Fi 连接功能:使用 ESP32 的 Wi-Fi 功能连接网络
- 添加云服务对接:将数据上传到云平台
- 优化用户界面:使用 LVGL 的更多控件美化界面
- 添加更多传感器:连接温湿度、光线等传感器
14. 总结
本教程介绍了使用 ESP32-S3 Korvo 开发板进行开发的基本流程,包括按键输入、摄像头、显示和语音识别功能的实现。通过这些基础模块,可以构建各种智能设备应用,如智能家居控制器、语音助手、视觉识别设备等。
希望本教程能帮助初学者快速上手 ESP32-S3 Korvo 开发板,开始自己的嵌入式开发之旅!