Abort 、Exit、Break、Continue之区别

本文详细解释了编程中几种常见的流程控制语句:exit用于退出函数;abort用于触发异常,实质上等于RaiseException();break用于跳出循环;而continue则跳过本次循环的剩余部分并继续下一次循环。此外还探讨了abort与exit的区别,即abort可以执行异常块中的代码而exit则不能。

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

exit: 退出函数体
abort: 遇到异常,安静处理,就是不显示不提示
break: 退出当前循环体,包括for ,while, repeat等循环体
continue: 结束循环内的本次处理,继续从循环体的开始位置继续执行
Abort 是从 EAbort 过来的,可以激发 exception,其实质就是 Abort = RaiseException(),是一个不出现对话框的异常。所以 Abort 的行为和异常是一样的,其代码执行顺序也是follow异常的流程。
例如:
try
(1) //执行了
abort;
(2) //不执行
exception
(3) //执行了
end;

用 Abort 能够执行 exception 里边的代码,但是如果用 Exit,就直接离开,不管 exception。

例如:
procedure p1;
begin
p2;
p3;
end;
procedure p2;
begin
abort; //exit;
end;
procedure p3;
begin
//showmessage()..
end;

如果用 Abort,则执行不到 P3,如果用 Exit 就能够执行到 P3 注:Exit 是跳出当前代码块,也就是当前函数,跳出后是要继续向下执行的(如果有后续代码)。

/* * 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_STEREO), .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数据大小:单帧采样数 × 声道数 × 每个采样的字节数(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、付费专栏及课程。

余额充值