FastBond3挑战部分-基于ESP32-C3的AI对话助手
该项目使用了ESP32-C3芯片,实现了AI人工智能对话的设计的设计,它的主要功能为:能够连接AI大模型进行对话,然后把对话内容显示在屏幕上。
标签
嵌入式系统
显示
FastBond
Tide
更新2024-10-28
92

一、前言

随着物联网和人工智能技术的发展,越来越多的智能设备开始集成语音交互功能。ESP32-C3是一款由乐鑫科技推出的低成本、低功耗的微控制器,它集成了Wi-Fi和蓝牙功能,并且具有足够的计算能力来处理音频信号,使其成为实现AI对话助手的理想选择。该项目是基于ESP32-C3的AI对话助手,主要通过ESP32-C3芯片连接网络,然后通过麦克风接收声音后将pcm音频数据发送至STT语音识别服务转换为文字,再将文字发送至大语言模型API提问,最后将回答的文字发送至TTS语音合成服务,并通过NS4150B播放音频,过程中可以用TFT触摸显示屏进行交互显示。

二、原理图和PCB介绍

整个电路的原理为:首先USB口通过CH343P芯片将USB信号转换成TTL信号给ESP32-C3烧录程序,MX25L6433是ESP32-C3的外挂FLASH,其次USB口提供了电源输入,通过ME6217这个LDO可以给整个系统供电,用户通过麦克风说话,麦克风将声音转换为电信号,ES8311将电信号转换为数字音频数据,通过I2C发送给ESP32-C3。ESP32-C3将数字音频数据通过STT语音识别服务转文本,然后接入API大语言模型提问,获取回答,ESP32-C3将回答的文本发送至TTS服务转换为音频数据NS4150B放大音频信号,并通过喇叭播放出来。接下来我来介绍一下各模块的原理:

USB转串口

image.png

USB接口用于供电和数据传输,CH343P将计算机的USB接口信号转换为ESP32-C3能够识别的串行通信信号,用于烧录程序和调试。RTS和DTR信号通过晶体管Q1和Q2来控制Reset和GPIO9的电平,以实现自动进入下载模式

FLASH

image.png

通过SPI(串行外设接口)总线与外部设备进行通信。它支持通过SPI接口进行数据的读写操作,提供额外的非易失性存储空间,可用于存储较大的程序、数据或音频文件

LDO

image.png

将USB接口提供的5V电源转换为适合ESP32-C3和其他组件工作的电压,为整个系统提供稳定的电源。R17用于限流。C25和C26则用于滤除电源线上的高频噪声,确保电源的稳定性。

音频输入

image.png

通过麦克风采集音频信号,捕捉用户的语音指令或对话内容,ES8311将麦克风采集的模拟信号通过其内部的模数转换器(ADC)将这些模拟信号转换为数字信号。转换后的数字音频信号通过I2C接口发送给ESP32-C3微控制器。在I2C通信中,ES8311的地址是:0x18,这表明在I2C总线上,ESP32-C3可以通过这个地址与ES8311进行通信。

音频功放

image.png

NS4150B可以将TTS服务生成的音频信号放大,驱动喇叭播放经过处理的语音回答,提供音频反馈给用户。IO13_PA_EN是一个使能信号,用于控制音频功放的开启和关闭。音频信号滤波后通过隔直电容和输入电阻输入到NS4150B的INP与 INN。输入电容与输入电阻构成一个高通滤波器,截止频率为

ESP32-C3

image.png

主控制器,集成了Wi-Fi和蓝牙功能。它包含一个或多个处理器核心、内存、存储接口、多种通信接口(如I2C、SPI、UART)等。ESP32-C3运行固件,处理来自ES8311的音频数据,执行语音识别、与API交互和语音合成等任务。

屏幕

image.png

TFT显示屏接口采用SPI通信,

DC:数据/命令控制线,用于区分传输的是数据还是命令。

SDA:数据/命令线,用于传输数据和命令。

CS(Chip Select):片选信号,用于激活显示屏,通常为低电平有效

RST(Reset):复位信号,用于重置显示屏

SCK(Serial Clock):串行时钟线,由主控制器产生,控制数据的发送和接收时机

BL_A:背光控制线,用于控制显示屏背光的开关。

电容触摸屏接口采用IIC通信。IO0_I2C_SDA和IO1_I2C_SCL:分别为I2C数据线和时钟线,RESET为触摸屏复位信号。

PCB设计

PCB采用四层板设计,电阻电容都为0603的封装,方便焊接。对地进行了分割,避免产生干扰。天线部分进行了铺铜挖空,避免天线受到屏蔽接收不到信号。

capture_20241021211636744.png

3D图

2024-10-03_22-21-17.png

实物图


IMG_20241021_212859_edit_4189480443355895.jpg


三、代码

代码的结构包括这些部分:main.c文件包含主函数。baidu_vtt.c和baidu_vtt.h是“语音转文字”程序。minimax_chat.c和minimax_chat.h是“聊天”程序。baidu_tts.c和baidu_tts.h是“文字转语音”程序。lv_gui.c和lv_gui.h是lvgl界面程序,可以在这里修改自己想要的界面。img_bilibili120.c是开机时gif图片的c代码。font_alipuhui20.c是阿里字体文件,这个包含了27780个中文汉字。

图片.png


主函数的核心功能:

初始化:包括NVS、网络接口、音频芯片、LCD屏幕和触摸屏的初始化。

LCD屏幕配置:设置LCD屏幕的SPI总线和触摸屏的I2C总线,注册显示驱动和触摸驱动。

LVGL图形库:初始化LVGL库,创建显示缓冲区。

任务创建:创建主界面任务和AI对话任务。

事件处理:处理按钮事件、Wi-Fi连接事件、语音识别和语音合成事件。


初始化初始化NVS:调用nvs_flash_init来初始化非易失性存储(NVS)。如果NVS分区被截断(没有足够的空间),则擦除NVS分区并重试初始化。调用esp_netif_init来初始化ESP32的网络接口。

 /************ 初始化NVS *************/
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(esp_netif_init());

初始化音频芯片ES8311:配置I2C总线,初始化音频编解码器,设置最大音量并关闭声音输出。

    ESP_LOGI(TAG, "[ 2 ] Start codec chip");
    audio_board_handle_t board_handle = audio_board_init();
    audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
    es8311_codec_set_voice_volume(100); // 最大音量
    es8311_pa_power(false);  // 关闭声音

初始化LCD屏幕:配置SPI总线用于连接LCD屏幕。初始化LCD面板IO接口和面板驱动。进行LCD屏幕的一系列设置,如重置、初始化、颜色交换、镜像和颜色反转。

    /************* 初始化液晶屏  ************/
static lv_disp_draw_buf_t disp_buf;
static lv_disp_drv_t disp_drv;

ESP_LOGI(TAG, "Initialize SPI bus");
spi_bus_config_t buscfg = {
.sclk_io_num = EXAMPLE_PIN_NUM_SCLK,
.mosi_io_num = EXAMPLE_PIN_NUM_MOSI,
.miso_io_num = EXAMPLE_PIN_NUM_MISO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t),
};
ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

ESP_LOGI(TAG, "Install panel IO");
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = EXAMPLE_PIN_NUM_LCD_DC,
.cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS,
.pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
.spi_mode = 0,
.trans_queue_depth = 10,
.on_color_trans_done = example_notify_lvgl_flush_ready,
.user_ctx = &disp_drv,
};

ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));

esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
};

ESP_LOGI(TAG, "Install ST7789 panel driver");
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));

ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

初始化触摸屏:配置I2C总线用于连接触摸屏,初始化触摸屏控制器。

 /************* 初始化触摸屏 **************/
    esp_lcd_touch_handle_t tp = NULL;
    esp_lcd_panel_io_handle_t tp_io_handle = NULL;
    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();


    esp_lcd_touch_config_t tp_cfg = {
        .x_max = EXAMPLE_LCD_V_RES,
        .y_max = EXAMPLE_LCD_H_RES,
        .rst_gpio_num = -1,
        .int_gpio_num = -1,
        .flags = {
            .swap_xy = 1,                                          
            .mirror_x = 1,
            .mirror_y = 0,
        },
    };


    ESP_LOGI(TAG, "Initialize touch controller FT6336");
    ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));

初始化LVGL图形库:分配显示缓冲区。注册显示驱动程序和触摸输入设备驱动程序。设置LVGL的定时器回调函数。

    /************ 初始化LVGL *************/
    ESP_LOGI(TAG, "Initialize LVGL library");
    lv_init();
   
    lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);
    lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf2);
   
    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 20);


    ESP_LOGI(TAG, "Register display driver to LVGL");
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = EXAMPLE_LCD_H_RES;
    disp_drv.ver_res = EXAMPLE_LCD_V_RES;
    disp_drv.flush_cb = example_lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    disp_drv.user_data = panel_handle;
    lv_disp_t *disp = lv_disp_drv_register(&disp_drv);


    ESP_LOGI(TAG, "Install LVGL tick timer");
   
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = &example_increase_lvgl_tick,
        .name = "lvgl_tick"
    };
    esp_timer_handle_t lvgl_tick_timer = NULL;
    ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));


    static lv_indev_drv_t indev_drv;    // Input device driver (Touch)
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.disp = disp;
    indev_drv.read_cb = example_lvgl_touch_cb;
    indev_drv.user_data = tp;


    lv_indev_drv_register(&indev_drv);

初始化液晶屏背光:配置LED控制器(LEDC)用于调节背光亮度

    /******************* 初始化液晶屏背光 **********************/
    lcd_brightness_init();
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191*(1-0.5)));  // 设置占空比 0.5表示占空比是50%
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0)); // 更新背光


    my_event_group = xEventGroupCreate();

创建任务:创建主界面任务和AI对话任务,分别处理用户界面和AI交互逻辑。

    lv_gui_start();
    xTaskCreate(main_page_task, "main_page_task", 8192, NULL, 5, NULL);        
    xTaskCreate(ai_chat_task, "ai_chat_task", 8192, NULL, 5, NULL);

主循环:在app_main函数的无限循环中,调用lv_timer_handler来处理LVGL的定时任务,如屏幕刷新等。整个app_main函数负责设置设备的基本功能,包括存储、网络、音频、显示和触摸输入,并启动用户界面和AI交互任务。

    while (1) {
        // raise the task priority of LVGL and/or reduce the handler period can improve the performance
        vTaskDelay(pdMS_TO_TICKS(10));
        // The task running lv_timer_handler should have lower priority than that running `lv_tick_inc`
        lv_timer_handler();
    }

四、活动总结

通过本次活动,我熟悉了esp32-c3芯片的硬件特性并学会了如何搭建开发环境,编写代码实现语音识别功能,了解了AI语音识别和处理的基本原理。这是一次非常宝贵的学习经历。它不仅提升了我的技术能力,还培养了我的创新思维。我相信这次活动的经历和收获将对我的未来产生深远的影响。我期待未来能参加更多类似的活动,继续探索AI和物联网的结合应用。



KiCad文件
使用说明
全屏
附件下载
Voice assistant PCB工程.7z
Voice assistant代码.7z
团队介绍
个人
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号