From 646b29790ee47a1fc6a7dc95fde0052a5b4ada55 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 21 Dec 2025 18:49:03 +0800 Subject: [PATCH] Add recoder every 60s. --- .vscode/c_cpp_properties.json | 17 +++ .vscode/settings.json | 21 +++ CMakeLists.txt | 2 +- main/CMakeLists.txt | 4 +- main/app_sr.c | 8 +- main/app_ui.c | 5 +- main/main.c | 255 ++++++++++++++++++++++++---------- sdkconfig.defaults | 5 + 8 files changed, 229 insertions(+), 88 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..f5f2c5c --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "intelliSenseMode": "macos-clang-arm64", + "compileCommands": [ + "${workspaceFolder}/build/compile_commands.json" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..23af880 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "files.associations": { + "BUILD": "bazel", + "*.inc": "cpp", + "__config": "c", + "__hash_table": "c", + "__locale": "c", + "atomic": "c", + "deque": "c", + "istream": "c", + "iterator": "c", + "memory": "c", + "sstream": "c", + "string": "c", + "string_view": "c", + "vector": "c", + "unordered_map": "c", + "esp_netif_sntp.h": "c", + "sdmmc_cmd.h": "c" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fac8c2..26ce668 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,5 +5,5 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(speech_recognition) +project(listener) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index e8f04b6..01d2d67 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,2 @@ idf_component_register(SRCS "app_sr.c" "esp32_s3_szp.c" "main.c" "app_ui.c" - INCLUDE_DIRS ".") - -spiffs_create_partition_image(storage ../spiffs FLASH_IN_PROJECT) + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/main/app_sr.c b/main/app_sr.c index 9916500..e1bc975 100644 --- a/main/app_sr.c +++ b/main/app_sr.c @@ -175,8 +175,8 @@ void app_sr_init(void) { ESP_LOGI(TAG, "wakenet:%s", afe_config.wakenet_model_name); // 打印唤醒名称 task_flag = 1; - xTaskCreatePinnedToCore(&detect_Task, "detect", 8 * 1024, (void*)afe_data, 5, - NULL, 1); - xTaskCreatePinnedToCore(&feed_Task, "feed", 8 * 1024, (void*)afe_data, 5, - NULL, 0); + // xTaskCreatePinnedToCore(&detect_Task, "detect", 8 * 1024, (void*)afe_data, 5, + // NULL, 1); + // xTaskCreatePinnedToCore(&feed_Task, "feed", 8 * 1024, (void*)afe_data, 5, + // NULL, 0); } diff --git a/main/app_ui.c b/main/app_ui.c index 0016e64..57567da 100644 --- a/main/app_ui.c +++ b/main/app_ui.c @@ -122,9 +122,8 @@ void mp3_player_init(void) { player_config.priority = 6; player_config.coreID = 1; - // ESP_ERROR_CHECK(audio_player_new(player_config)); - // ESP_ERROR_CHECK(audio_player_callback_register(_audio_player_callback, - // NULL)); + ESP_ERROR_CHECK(audio_player_new(player_config)); + ESP_ERROR_CHECK(audio_player_callback_register(_audio_player_callback, NULL)); // 显示界面 music_ui(); diff --git a/main/main.c b/main/main.c index 0623dd8..65430fb 100644 --- a/main/main.c +++ b/main/main.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "app_sr.h" #include "app_ui.h" @@ -10,49 +12,53 @@ #include "es7210.h" #include "esp32_s3_szp.h" #include "esp_check.h" +#include "esp_netif_sntp.h" +#include "esp_sntp.h" #include "esp_vfs_fat.h" +#include "esp_wifi.h" #include "format_wav.h" +#include "nvs_flash.h" #include "sdkconfig.h" #include "sdmmc_cmd.h" /* I2C port and GPIOs */ -#define EXAMPLE_I2C_NUM (0) -#define EXAMPLE_I2C_SDA_IO (1) -#define EXAMPLE_I2C_SCL_IO (2) +#define I2C_NUM (0) +#define I2C_SDA_IO (1) +#define I2C_SCL_IO (2) /* I2S port and GPIOs */ -#define EXAMPLE_I2S_NUM (0) -#define EXAMPLE_I2S_MCK_IO (38) -#define EXAMPLE_I2S_BCK_IO (14) -#define EXAMPLE_I2S_WS_IO (13) -#define EXAMPLE_I2S_DI_IO (12) +#define I2S_NUM (0) +#define I2S_MCK_IO (38) +#define I2S_BCK_IO (14) +#define I2S_WS_IO (13) +#define I2S_DI_IO (12) /* SD card GPIOs */ -#define EXAMPLE_SD_CMD_IO (48) -#define EXAMPLE_SD_CLK_IO (47) -#define EXAMPLE_SD_DAT0_IO (21) +#define SD_CMD_IO (48) +#define SD_CLK_IO (47) +#define SD_DAT0_IO (21) /* I2S configurations */ -#define EXAMPLE_I2S_TDM_FORMAT (ES7210_I2S_FMT_I2S) -#define EXAMPLE_I2S_CHAN_NUM (2) -#define EXAMPLE_I2S_SAMPLE_RATE (48000) -#define EXAMPLE_I2S_MCLK_MULTIPLE (I2S_MCLK_MULTIPLE_256) -#define EXAMPLE_I2S_SAMPLE_BITS (I2S_DATA_BIT_WIDTH_16BIT) -#define EXAMPLE_I2S_TDM_SLOT_MASK (I2S_TDM_SLOT0 | I2S_TDM_SLOT1) +#define I2S_TDM_FORMAT (ES7210_I2S_FMT_I2S) +#define I2S_CHAN_NUM (2) +#define I2S_SAMPLE_RATE (48000) +#define I2S_MCLK_MULTIPLE (I2S_MCLK_MULTIPLE_256) +#define I2S_SAMPLE_BITS (I2S_DATA_BIT_WIDTH_16BIT) +#define I2S_TDM_SLOT_MASK (I2S_TDM_SLOT0 | I2S_TDM_SLOT1) /* ES7210 configurations */ -#define EXAMPLE_ES7210_I2C_ADDR (0x41) -#define EXAMPLE_ES7210_I2C_CLK (100000) -#define EXAMPLE_ES7210_MIC_GAIN (ES7210_MIC_GAIN_30DB) -#define EXAMPLE_ES7210_MIC_BIAS (ES7210_MIC_BIAS_2V87) -#define EXAMPLE_ES7210_ADC_VOLUME (0) +#define ES7210_I2C_ADDR (0x41) +#define ES7210_I2C_CLK (100000) +#define ES7210_MIC_GAIN (ES7210_MIC_GAIN_30DB) +#define ES7210_MIC_BIAS (ES7210_MIC_BIAS_2V87) +#define ES7210_ADC_VOLUME (0) /* SD card & recording configurations */ -#define EXAMPLE_RECORD_TIME_SEC (10) -#define EXAMPLE_SD_MOUNT_POINT "/sdcard" -#define EXAMPLE_RECORD_FILE_PATH "/RECORD.WAV" +#define RECORD_TIME_SEC (60) +#define SD_MOUNT_POINT "/sdcard" -static const char* TAG = "example"; +static const char* TAG = "main"; +static char* record_file_name = NULL; static i2s_chan_handle_t es7210_i2s_init(void) { i2s_chan_handle_t i2s_rx_chan = NULL; // 定义接收通道句柄 @@ -66,16 +72,15 @@ static i2s_chan_handle_t es7210_i2s_init(void) { // 定义接收通道为I2S TDM模式 并配置 i2s_tdm_config_t i2s_tdm_rx_conf = { .slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG( - EXAMPLE_I2S_SAMPLE_BITS, I2S_SLOT_MODE_STEREO, - EXAMPLE_I2S_TDM_SLOT_MASK), + I2S_SAMPLE_BITS, I2S_SLOT_MODE_STEREO, I2S_TDM_SLOT_MASK), .clk_cfg = {.clk_src = I2S_CLK_SRC_DEFAULT, - .sample_rate_hz = EXAMPLE_I2S_SAMPLE_RATE, - .mclk_multiple = EXAMPLE_I2S_MCLK_MULTIPLE}, - .gpio_cfg = {.mclk = EXAMPLE_I2S_MCK_IO, - .bclk = EXAMPLE_I2S_BCK_IO, - .ws = EXAMPLE_I2S_WS_IO, + .sample_rate_hz = I2S_SAMPLE_RATE, + .mclk_multiple = I2S_MCLK_MULTIPLE}, + .gpio_cfg = {.mclk = I2S_MCK_IO, + .bclk = I2S_BCK_IO, + .ws = I2S_WS_IO, .dout = -1, // ES7210 only has ADC capability - .din = EXAMPLE_I2S_DI_IO}, + .din = I2S_DI_IO}, }; ESP_ERROR_CHECK(i2s_channel_init_tdm_mode( @@ -100,17 +105,17 @@ sdmmc_card_t* mount_sdcard(void) { sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); // SDMMC插槽配置 slot_config.width = 1; // 设置为1线SD模式 - slot_config.clk = EXAMPLE_SD_CLK_IO; - slot_config.cmd = EXAMPLE_SD_CMD_IO; - slot_config.d0 = EXAMPLE_SD_DAT0_IO; + slot_config.clk = SD_CLK_IO; + slot_config.cmd = SD_CMD_IO; + slot_config.d0 = SD_DAT0_IO; slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; // 打开内部上拉电阻 ESP_LOGI(TAG, "Mounting filesystem"); esp_err_t ret; while (1) { - ret = esp_vfs_fat_sdmmc_mount(EXAMPLE_SD_MOUNT_POINT, &sdmmc_host, - &slot_config, &mount_config, &sdmmc_card); + ret = esp_vfs_fat_sdmmc_mount(SD_MOUNT_POINT, &sdmmc_host, &slot_config, + &mount_config, &sdmmc_card); if (ret == ESP_OK) { break; } else if (ret == ESP_FAIL) { @@ -134,23 +139,110 @@ sdmmc_card_t* mount_sdcard(void) { static void es7210_codec_init(void) { // 创建es7210器件句柄 es7210_dev_handle_t es7210_handle = NULL; - es7210_i2c_config_t es7210_i2c_conf = {.i2c_port = EXAMPLE_I2C_NUM, - .i2c_addr = EXAMPLE_ES7210_I2C_ADDR}; + es7210_i2c_config_t es7210_i2c_conf = {.i2c_port = I2C_NUM, + .i2c_addr = ES7210_I2C_ADDR}; ESP_ERROR_CHECK(es7210_new_codec(&es7210_i2c_conf, &es7210_handle)); // 初始化es7210芯片 ESP_LOGI(TAG, "Configure ES7210 codec parameters"); es7210_codec_config_t codec_conf = { - .i2s_format = EXAMPLE_I2S_TDM_FORMAT, - .mclk_ratio = EXAMPLE_I2S_MCLK_MULTIPLE, - .sample_rate_hz = EXAMPLE_I2S_SAMPLE_RATE, - .bit_width = (es7210_i2s_bits_t)EXAMPLE_I2S_SAMPLE_BITS, - .mic_bias = EXAMPLE_ES7210_MIC_BIAS, - .mic_gain = EXAMPLE_ES7210_MIC_GAIN, + .i2s_format = I2S_TDM_FORMAT, + .mclk_ratio = I2S_MCLK_MULTIPLE, + .sample_rate_hz = I2S_SAMPLE_RATE, + .bit_width = (es7210_i2s_bits_t)I2S_SAMPLE_BITS, + .mic_bias = ES7210_MIC_BIAS, + .mic_gain = ES7210_MIC_GAIN, .flags.tdm_enable = true}; ESP_ERROR_CHECK(es7210_config_codec(es7210_handle, &codec_conf)); - ESP_ERROR_CHECK( - es7210_config_volume(es7210_handle, EXAMPLE_ES7210_ADC_VOLUME)); + ESP_ERROR_CHECK(es7210_config_volume(es7210_handle, ES7210_ADC_VOLUME)); +} + +// wifi事件组 +static EventGroupHandle_t s_wifi_event_group = NULL; +// wifi事件 +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 +#define WIFI_START_BIT BIT2 +#define WIFI_GET_SNTP_BIT BIT3 +// wifi最大重连次数 +#define EXAMPLE_ESP_MAXIMUM_RETRY 3 + +typedef struct { + char wifi_ssid[32]; // 获取wifi名称 + char wifi_password[64]; // 获取wifi密码 + char back_flag; // 是否退出 +} wifi_account_t; + +static void wifi_connect() { + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + assert(esp_netif_create_default_wifi_sta()); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + // ESP_ERROR_CHECK(esp_event_handler_instance_register( + // WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id)); + // ESP_ERROR_CHECK(esp_event_handler_instance_register( + // IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, + // &instance_got_ip)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + wifi_account_t wifi_account; + strcpy(wifi_account.wifi_ssid, "Liang"); + strcpy(wifi_account.wifi_password, "wifi1234"); + ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", wifi_account.wifi_ssid, + wifi_account.wifi_password); + wifi_account.back_flag = 0; // 正常连接 + + wifi_config_t wifi_config = { + .sta = + { + .threshold.authmode = WIFI_AUTH_WPA2_PSK, + .sae_pwe_h2e = WPA3_SAE_PWE_BOTH, + .sae_h2e_identifier = "", + }, + }; + strcpy((char*)wifi_config.sta.ssid, wifi_account.wifi_ssid); + strcpy((char*)wifi_config.sta.password, wifi_account.wifi_password); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + + esp_wifi_connect(); +} + +time_t now; +struct tm timeinfo; + +static void get_time_task() { + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("cn.pool.ntp.org"); + esp_netif_sntp_init(&config); + // wait for time to be set + int retry = 0; + // const int retry_count = 6; + while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == + ESP_ERR_TIMEOUT) { + ESP_LOGI(TAG, "Waiting for system time to be set... (%d)", retry++); + } + + esp_netif_sntp_deinit(); + // 设置时区 + setenv("TZ", "CST-8", 1); + tzset(); + // 获取系统时间 + time(&now); + localtime_r(&now, &timeinfo); + + ESP_LOGI(TAG, "%d年%02d月%02d日", timeinfo.tm_year + 1900, + timeinfo.tm_mon + 1, timeinfo.tm_mday); + ESP_LOGI(TAG, "%02d:%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min, + timeinfo.tm_sec); +} + +static char* get_file_name_from_time(void) { + get_time_task(); + strftime(record_file_name, 48, "/sdcard/Record_%Y%m%d%H%M%S.wav", &timeinfo); + return record_file_name; } static esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan) { @@ -158,19 +250,18 @@ static esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan) { "invalid i2s channel handle pointer"); esp_err_t ret = ESP_OK; - uint32_t byte_rate = EXAMPLE_I2S_SAMPLE_RATE * EXAMPLE_I2S_CHAN_NUM * - EXAMPLE_I2S_SAMPLE_BITS / 8; - uint32_t wav_size = byte_rate * EXAMPLE_RECORD_TIME_SEC; + uint32_t byte_rate = I2S_SAMPLE_RATE * I2S_CHAN_NUM * I2S_SAMPLE_BITS / 8; + uint32_t wav_size = byte_rate * RECORD_TIME_SEC; - const wav_header_t wav_header = - WAV_HEADER_PCM_DEFAULT(wav_size, EXAMPLE_I2S_SAMPLE_BITS, - EXAMPLE_I2S_SAMPLE_RATE, EXAMPLE_I2S_CHAN_NUM); + const wav_header_t wav_header = WAV_HEADER_PCM_DEFAULT( + wav_size, I2S_SAMPLE_BITS, I2S_SAMPLE_RATE, I2S_CHAN_NUM); - ESP_LOGI(TAG, "Opening file %s", EXAMPLE_RECORD_FILE_PATH); - FILE* f = fopen(EXAMPLE_SD_MOUNT_POINT EXAMPLE_RECORD_FILE_PATH, "w"); + get_file_name_from_time(); + ESP_LOGI(TAG, "Opening file %s", record_file_name); + FILE* f = fopen(record_file_name, "w"); + ESP_LOGI(TAG, "fopen error: %s", strerror(errno)); ESP_RETURN_ON_FALSE(f, ESP_FAIL, TAG, "error while opening wav file"); - /* Write wav header */ ESP_GOTO_ON_FALSE(fwrite(&wav_header, sizeof(wav_header_t), 1, f), ESP_FAIL, err, TAG, "error while writing wav header"); @@ -182,7 +273,7 @@ static esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan) { while (wav_written < wav_size) { if (wav_written % byte_rate < sizeof(i2s_readraw_buff)) { ESP_LOGI(TAG, "Recording: %" PRIu32 "/%ds", wav_written / byte_rate + 1, - EXAMPLE_RECORD_TIME_SEC); + RECORD_TIME_SEC); } size_t bytes_read = 0; /* Read RAW samples from ES7210 */ @@ -205,33 +296,43 @@ err: } void app_main(void) { - bsp_i2c_init(); // I2C初始化 - pca9557_init(); // IO扩展芯片初始化 - bsp_lvgl_start(); // 初始化液晶屏lvgl接口 + // Initialize 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); + + bsp_i2c_init(); // I2C初始化 + // pca9557_init(); // IO扩展芯片初始化 + // bsp_lvgl_start(); // 初始化液晶屏lvgl接口 bsp_spiffs_mount(); // SPIFFS文件系统初始化 - bsp_codec_init(); // 音频初始化 - mp3_player_init(); // MP3播放器初始化 + // bsp_codec_init(); // 音频初始化 + // mp3_player_init(); // MP3播放器初始化 app_sr_init(); // 语音识别初始化 /* 初始化I2S接口 */ i2s_chan_handle_t i2s_rx_chan = es7210_i2s_init(); - /* 初始化es7210芯片 */ es7210_codec_init(); - /* 挂载SD卡 */ + wifi_connect(); + + record_file_name = malloc(64); + sdmmc_card_t* sdmmc_card = mount_sdcard(); - /* 录音 */ - esp_err_t err = record_wav(i2s_rx_chan); - /* 弹出SD卡 */ - esp_vfs_fat_sdcard_unmount(EXAMPLE_SD_MOUNT_POINT, sdmmc_card); - if (err == ESP_OK) { - ESP_LOGI(TAG, - "Audio was successfully recorded into " EXAMPLE_RECORD_FILE_PATH - ". You can now remove the SD card safely"); - } else { - ESP_LOGE(TAG, "Record failed, " EXAMPLE_RECORD_FILE_PATH - " on SD card may not be playable."); + + while (1) { + esp_err_t err = record_wav(i2s_rx_chan); + if (err == ESP_OK) { + ESP_LOGI(TAG, "Audio was successfully recorded into %s.", + record_file_name); + } else { + ESP_LOGE(TAG, "Record failed, %s .", record_file_name); + } } + esp_vfs_fat_sdcard_unmount(SD_MOUNT_POINT, sdmmc_card); } diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 884385c..14840c0 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -3,6 +3,11 @@ # CONFIG_IDF_TARGET="esp32s3" CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_CODEPAGE_936=y +CONFIG_FATFS_API_ENCODING_UTF_8=y +CONFIG_FATFS_VFS_FSTAT_BLKSIZE=4096 + CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y