ES_WANTRETURN

本文详细介绍了ES_WANTRETURN样式的作用,当用户在对话框的多行编辑控件中输入文本并按下ENTER键时,该样式指定应在文本中插入回车符。如果不指定此样式,则按下ENTER键的效果等同于点击对话框的默认按钮。需要注意的是,此样式对单行编辑控件无效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ES_WANTRETURN  
Specifies that a carriage return be inserted when the user presses the ENTER key while entering text into a multiline edit control in a dialog box. If you do not specify this style, pressing the ENTER key has the same effect as pressing the dialog box's default push button. This style has no effect on a single-line edit control.

用红色标记的比较能够解释 ES_WANTRETURN 作用。




/* * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/i2s_std.h" #include "driver/gpio.h" #include "esp_system.h" #include "esp_check.h" #include "es8311.h" #include "example_config.h" #include "esp_vfs_fat.h" #include "sdmmc_cmd.h" #include "driver/sdmmc_host.h" #include "mp3dec.h" static const char *TAG = "i2s_es8311_mp3"; static const char err_reason[][30] = {"input param is invalid", "operation timeout" }; static i2s_chan_handle_t tx_handle = NULL; static i2s_chan_handle_t rx_handle = NULL; // SD卡相关变量 static sdmmc_card_t *card; static esp_err_t sdcard_init(void) { esp_err_t ret; // 配置SD卡GPIO gpio_set_pull_mode(SD_CLK_IO, GPIO_PULLUP_ONLY); gpio_set_pull_mode(SD_CMD_IO, GPIO_PULLUP_ONLY); gpio_set_pull_mode(SD_D0_IO, GPIO_PULLUP_ONLY); // 配置FAT文件系统 esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = false, .max_files = 5, .allocation_unit_size = 16 * 1024 }; // 配置SDMMC主机 sdmmc_host_t host = SDMMC_HOST_DEFAULT(); host.max_freq_khz = SDMMC_FREQ_HIGHSPEED; // 配置SD卡引脚 sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); slot_config.width = 1; slot_config.clk = SD_CLK_IO; slot_config.cmd = SD_CMD_IO; slot_config.d0 = SD_D0_IO; slot_config.d1 = SD_D1_IO; slot_config.d2 = SD_D2_IO; slot_config.d3 = SD_D3_IO; // 挂载文件系统 ret = esp_vfs_fat_sdmmc_mount(MOUNT_POINT, &host, &slot_config, &mount_config, &card); if (ret != ESP_OK) { if (ret == ESP_FAIL) { ESP_LOGE(TAG, "Failed to mount filesystem. " "If you want the card to be formatted, set format_if_mount_failed = true."); } else { ESP_LOGE(TAG, "Failed to initialize the card (%s). " "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret)); } return ret; } ESP_LOGI(TAG, "SD card mounted successfully"); return ESP_OK; } static esp_err_t es8311_codec_init(void) { /* Initialize I2C peripheral */ #if !defined(CONFIG_EXAMPLE_BSP) const i2c_config_t es_i2c_cfg = { .sda_io_num = I2C_SDA_IO, .scl_io_num = I2C_SCL_IO, .mode = I2C_MODE_MASTER, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = 100000, }; ESP_RETURN_ON_ERROR(i2c_param_config(I2C_NUM, &es_i2c_cfg), TAG, "config i2c failed"); ESP_RETURN_ON_ERROR(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0), TAG, "install i2c driver failed"); #else ESP_ERROR_CHECK(bsp_i2c_init()); #endif /* Initialize es8311 codec */ es8311_handle_t es_handle = es8311_create(I2C_NUM, ES8311_ADDRRES_0); ESP_RETURN_ON_FALSE(es_handle, ESP_FAIL, TAG, "es8311 create failed"); const es8311_clock_config_t es_clk = { .mclk_inverted = false, .sclk_inverted = false, .mclk_from_mclk_pin = true, .mclk_frequency = EXAMPLE_MCLK_FREQ_HZ, .sample_frequency = EXAMPLE_SAMPLE_RATE }; ESP_ERROR_CHECK(es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_16, ES8311_RESOLUTION_16)); ESP_RETURN_ON_ERROR(es8311_sample_frequency_config(es_handle, EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE, EXAMPLE_SAMPLE_RATE), TAG, "set es8311 sample frequency failed"); ESP_RETURN_ON_ERROR(es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL), TAG, "set es8311 volume failed"); ESP_RETURN_ON_ERROR(es8311_microphone_config(es_handle, false), TAG, "set es8311 microphone failed"); #if CONFIG_EXAMPLE_MODE_ECHO ESP_RETURN_ON_ERROR(es8311_microphone_gain_set(es_handle, EXAMPLE_MIC_GAIN), TAG, "set es8311 microphone gain failed"); #endif return ESP_OK; } static esp_err_t i2s_driver_init(void) { #if !defined(CONFIG_EXAMPLE_BSP) i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER); chan_cfg.dma_desc_num = 8; chan_cfg.dma_frame_num = 512; chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle)); i2s_std_config_t std_cfg = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE), .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), .gpio_cfg = { .mclk = I2S_MCK_IO, .bclk = I2S_BCK_IO, .ws = I2S_WS_IO, .dout = I2S_DO_IO, .din = I2S_DI_IO, .invert_flags = { .mclk_inv = false, .bclk_inv = false, .ws_inv = false, }, }, }; std_cfg.clk_cfg.mclk_multiple = EXAMPLE_MCLK_MULTIPLE; ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); ESP_ERROR_CHECK(i2s_channel_enable(rx_handle)); #else ESP_LOGI(TAG, "Using BSP for HW configuration"); i2s_std_config_t std_cfg = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE), .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), .gpio_cfg = BSP_I2S_GPIO_CFG, }; std_cfg.clk_cfg.mclk_multiple = EXAMPLE_MCLK_MULTIPLE; ESP_ERROR_CHECK(bsp_audio_init(&std_cfg, &tx_handle, &rx_handle)); ESP_ERROR_CHECK(bsp_audio_poweramp_enable(true)); #endif return ESP_OK; } #if CONFIG_EXAMPLE_MODE_MUSIC static void i2s_music(void *args) { esp_err_t ret = ESP_OK; size_t bytes_read, bytes_write; FILE *mp3_file = NULL; HMP3Decoder mp3_decoder = NULL; MP3FrameInfo mp3_frame_info; int decode_ret; int bytes_left = 0; uint8_t *read_ptr = mp3_input_buffer; // 输入缓冲区指针 short pcm_output[PCM_OUTPUT_BUFFER_SIZE / 2]; // MP3Decode输出为short类型 // 初始化SD卡(SPI模式,仅使用DAT0) if (sdcard_init() != ESP_OK) { ESP_LOGE(TAG, "Failed to initialize SD card"); goto exit; } // 打开MP3文件 mp3_file = fopen(MOUNT_POINT "/music.mp3", "rb"); if (!mp3_file) { ESP_LOGE(TAG, "Failed to open MP3 file"); goto exit; } ESP_LOGI(TAG, "MP3 file opened successfully"); // 初始化MP3解码器 mp3_decoder = MP3InitDecoder(); if (!mp3_decoder) { ESP_LOGE(TAG, "Failed to initialize MP3 decoder"); goto exit; } // 预读取一部分数据到输入缓冲区 bytes_read = fread(mp3_input_buffer, 1, MP3_INPUT_BUFFER_SIZE, mp3_file); if (bytes_read == 0) { ESP_LOGE(TAG, "Failed to read MP3 file"); goto exit; } bytes_left = bytes_read; // 启用I2S发送通道 // ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); ESP_LOGI(TAG, "Starting MP3 playback"); while (1) { // 确保输入缓冲区有足够数据(至少保留一个帧的可能空间) if (bytes_left < 1024) { // 减小阈值,避免缓冲区溢出 // 移动剩余数据到缓冲区开头 memmove(mp3_input_buffer, read_ptr, bytes_left); // 从文件补充新数据 bytes_read = fread(mp3_input_buffer + bytes_left, 1, MP3_INPUT_BUFFER_SIZE - bytes_left, mp3_file); if (bytes_read == 0) { if (feof(mp3_file)) { ESP_LOGI(TAG, "End of MP3 file reached"); break; } else { ESP_LOGE(TAG, "Error reading MP3 file"); goto exit; } } bytes_left += bytes_read; read_ptr = mp3_input_buffer; // 重置指针到缓冲区开头 } // 解码MP3帧(使用MP3Decode替代MP3DecodeFrame) // 参数说明: // - 解码器句柄:mp3_decoder // - 输入缓冲区指针的指针:&read_ptr(函数会修改指针位置) // - 剩余字节数的指针:&bytes_left(函数会修改剩余字节数) // - 输出PCM缓冲区:pcm_output // - 是否使用固定大小缓冲区:0(自动适应) decode_ret = MP3Decode(mp3_decoder, &read_ptr, &bytes_left, pcm_output, 0); // 处理解码结果 if (decode_ret != ERR_MP3_NONE) { // 错误处理:打印错误信息并尝试跳过错误数据 ESP_LOGW(TAG, "MP3 decode error: %d", decode_ret); if (decode_ret == ERR_MP3_INDATA_UNDERFLOW) { // 输入数据不足,继续读取文件(循环会自动补充数据) continue; } else if (decode_ret == ERR_MP3_INVALID_FRAMEHEADER) { // 无效帧头,跳过1字节继续尝试 read_ptr++; bytes_left--; continue; } else { // 严重错误,终止播放 ESP_LOGE(TAG, "Fatal decode error: %d", decode_ret); goto exit; } } // 获取当前帧信息(采样率、声道数等) MP3GetLastFrameInfo(mp3_decoder, &mp3_frame_info); // 检查采样率是否匹配(可选,不匹配可能导致播放速度异常) if (mp3_frame_info.samprate != EXAMPLE_SAMPLE_RATE) { ESP_LOGW(TAG, "MP3 sample rate (%d) != configured rate (%d)", mp3_frame_info.samprate, EXAMPLE_SAMPLE_RATE); } // 计算PCM数据大小:单帧采样数 &times; 声道数 &times; 每个采样的字节数(16位=2字节) size_t pcm_size = mp3_frame_info.outputSamps * mp3_frame_info.nChans * sizeof(short); // 发送PCM数据到I2S(ES8311) ret = i2s_channel_write(tx_handle, pcm_output, pcm_size, &bytes_write, portMAX_DELAY); if (ret != ESP_OK) { ESP_LOGE(TAG, "[music] I2S write failed: %s", err_reason[ret == ESP_ERR_TIMEOUT]); goto exit; } if (bytes_write != pcm_size) { ESP_LOGW(TAG, "[music] Incomplete write: %d/%d bytes", bytes_write, pcm_size); } } exit: // 清理资源 if (mp3_decoder) { MP3FreeDecoder(mp3_decoder); // 使用MP3FreeDecoder释放解码器 } if (mp3_file) { fclose(mp3_file); } esp_vfs_fat_sdcard_unmount(MOUNT_POINT, NULL); ESP_LOGI(TAG, "Playback finished"); vTaskDelete(NULL); } #endif void app_main(void) { gpio_reset_pin(GPIO_NUM_3); gpio_set_direction(GPIO_NUM_3, GPIO_MODE_OUTPUT); gpio_set_level(GPIO_NUM_3, 1); printf("i2s es8311 mp3 player example start\n-----------------------------\n"); /* Initialize i2s peripheral */ if (i2s_driver_init() != ESP_OK) { ESP_LOGE(TAG, "i2s driver init failed"); abort(); } else { ESP_LOGI(TAG, "i2s driver init success"); } /* Initialize i2c peripheral and config es8311 codec by i2c */ if (es8311_codec_init() != ESP_OK) { ESP_LOGE(TAG, "es8311 codec init failed"); abort(); } else { ESP_LOGI(TAG, "es8311 codec init success"); } if(rx_handle){ i2s_channel_disable(rx_handle); } #if EXAMPLE_PA_CTRL_IO >= 0 /* Enable PA by setting the PA_CTRL_IO to high, because the power amplifier on some dev-kits are disabled by default */ gpio_config_t gpio_cfg = { .pin_bit_mask = (1ULL << EXAMPLE_PA_CTRL_IO), .mode = GPIO_MODE_OUTPUT, }; ESP_ERROR_CHECK(gpio_config(&gpio_cfg)); ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_PA_CTRL_IO, 1)); #endif #if CONFIG_EXAMPLE_MODE_MUSIC /* Play MP3 from SD card */ xTaskCreate(i2s_music, "i2s_music", 2048 * 6, NULL, 8, NULL); #else /* Echo the sound from MIC in echo mode */ xTaskCreate(i2s_echo, "i2s_echo", 8192, NULL, 5, NULL); #endif } 在此源码基础上修改
最新发布
08-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值