esp32s3 idf读取sd卡音频文件完整的音频播放功能详细程序
时间: 2023-08-15 19:06:13 浏览: 748
以下是一个ESP32-S3 IDF读取SD卡音频文件并播放的详细程序:
首先,需要包含一些必要的头文件:
```c
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
```
然后,定义一些常量和变量:
```c
// SD卡的CS引脚
#define SD_CS_GPIO 5
// I2S输出的引脚
#define I2S_BCK 26
#define I2S_WS 25
#define I2S_DO 22
// I2S配置
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 64
};
// I2S引脚配置
static const i2s_pin_config_t i2s_pin_config = {
.bck_io_num = I2S_BCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_DO,
.data_in_num = I2S_PIN_NO_CHANGE
};
// 文件名
static const char* FILENAME = "/sdcard/test.wav";
// 文件句柄
static FILE* file;
// 文件大小
static size_t file_size;
// 文件读取缓冲区
static uint8_t file_buffer[1024];
```
在配置I2S之前,需要初始化SD卡:
```c
static esp_err_t init_sd_card()
{
esp_err_t ret;
// 配置SD卡的CS引脚
gpio_pad_select_gpio(SD_CS_GPIO);
gpio_set_direction(SD_CS_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_CS_GPIO, 1);
// 初始化SDMMC驱动
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
slot_config.gpio_cs = SD_CS_GPIO;
ret = esp_vfs_fat_sdspi_mount("/sdcard", &host, &slot_config, NULL);
if (ret != ESP_OK) {
return ret;
}
return ESP_OK;
}
```
接下来,配置I2S并初始化:
```c
static esp_err_t init_i2s()
{
esp_err_t ret;
// 配置I2S
ret = i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
if (ret != ESP_OK) {
return ret;
}
ret = i2s_set_pin(I2S_NUM_0, &i2s_pin_config);
if (ret != ESP_OK) {
return ret;
}
return ESP_OK;
}
```
然后,打开文件并获取文件大小:
```c
static esp_err_t open_file()
{
// 打开文件
file = fopen(FILENAME, "rb");
if (file == NULL) {
return ESP_FAIL;
}
// 获取文件大小
fseek(file, 0, SEEK_END);
file_size = ftell(file);
fseek(file, 0, SEEK_SET);
return ESP_OK;
}
```
最后,读取文件并通过I2S输出音频:
```c
static esp_err_t read_file()
{
size_t bytes_read;
size_t bytes_to_read = sizeof(file_buffer);
while (file_size > 0) {
// 读取文件
if (file_size < bytes_to_read) {
bytes_to_read = file_size;
}
bytes_read = fread(file_buffer, 1, bytes_to_read, file);
if (bytes_read == 0) {
return ESP_FAIL;
}
// 输出音频
i2s_write(I2S_NUM_0, file_buffer, bytes_read, portMAX_DELAY);
file_size -= bytes_read;
}
return ESP_OK;
}
```
完整的程序如下:
```c
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
// SD卡的CS引脚
#define SD_CS_GPIO 5
// I2S输出的引脚
#define I2S_BCK 26
#define I2S_WS 25
#define I2S_DO 22
// I2S配置
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 64
};
// I2S引脚配置
static const i2s_pin_config_t i2s_pin_config = {
.bck_io_num = I2S_BCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_DO,
.data_in_num = I2S_PIN_NO_CHANGE
};
// 文件名
static const char* FILENAME = "/sdcard/test.wav";
// 文件句柄
static FILE* file;
// 文件大小
static size_t file_size;
// 文件读取缓冲区
static uint8_t file_buffer[1024];
static esp_err_t init_sd_card()
{
esp_err_t ret;
// 配置SD卡的CS引脚
gpio_pad_select_gpio(SD_CS_GPIO);
gpio_set_direction(SD_CS_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(SD_CS_GPIO, 1);
// 初始化SDMMC驱动
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
slot_config.gpio_cs = SD_CS_GPIO;
ret = esp_vfs_fat_sdspi_mount("/sdcard", &host, &slot_config, NULL);
if (ret != ESP_OK) {
return ret;
}
return ESP_OK;
}
static esp_err_t init_i2s()
{
esp_err_t ret;
// 配置I2S
ret = i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
if (ret != ESP_OK) {
return ret;
}
ret = i2s_set_pin(I2S_NUM_0, &i2s_pin_config);
if (ret != ESP_OK) {
return ret;
}
return ESP_OK;
}
static esp_err_t open_file()
{
// 打开文件
file = fopen(FILENAME, "rb");
if (file == NULL) {
return ESP_FAIL;
}
// 获取文件大小
fseek(file, 0, SEEK_END);
file_size = ftell(file);
fseek(file, 0, SEEK_SET);
return ESP_OK;
}
static esp_err_t read_file()
{
size_t bytes_read;
size_t bytes_to_read = sizeof(file_buffer);
while (file_size > 0) {
// 读取文件
if (file_size < bytes_to_read) {
bytes_to_read = file_size;
}
bytes_read = fread(file_buffer, 1, bytes_to_read, file);
if (bytes_read == 0) {
return ESP_FAIL;
}
// 输出音频
i2s_write(I2S_NUM_0, file_buffer, bytes_read, portMAX_DELAY);
file_size -= bytes_read;
}
return ESP_OK;
}
void app_main()
{
esp_err_t ret;
// 初始化SD卡
ret = init_sd_card();
if (ret != ESP_OK) {
ESP_LOGE("MAIN", "Failed to initialize SD card (%d)", ret);
return;
}
// 初始化I2S
ret = init_i2s();
if (ret != ESP_OK) {
ESP_LOGE("MAIN", "Failed to initialize I2S (%d)", ret);
return;
}
// 打开文件
ret = open_file();
if (ret != ESP_OK) {
ESP_LOGE("MAIN", "Failed to open file (%d)", ret);
return;
}
// 读取文件并输出音频
ret = read_file();
if (ret != ESP_OK) {
ESP_LOGE("MAIN", "Failed to read file (%d)", ret);
return;
}
// 关闭文件
fclose(file);
}
```
注意:此程序中的音频文件必须是16位PCM格式,采样率为44100Hz。如果要播放其他格式的音频文件,请参考ESP-IDF官方文档中的示例程序。
阅读全文