当前位置: 首页 > news >正文

[ESP32] I2S播放wav文件

 //代码:循环播放4首内置的wav音乐,I2S连接d类功放用NS4168芯片

//文件取样格式:Wave PCM 签字的 16bit, 采样频率:16KHz ,比特率705kbps

//demo工程打包下载:https://download.csdn.net/download/wabil/89515015

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "esp_system.h"
#include "esp_check.h"
#include "esp_log.h"/* Example configurations */
#define EXAMPLE_SAMPLE_RATE (16000) // 16KHZ
#define EXAMPLE_MCLK_MULTIPLE (384) // If not using 24-bit data width, 256 should be enough
#define EXAMPLE_MCLK_FREQ_HZ (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE)
#define EXAMPLE_VOICE_VOLUME CONFIG_EXAMPLE_VOICE_VOLUME/* I2S port and GPIOs */
#define I2S_NUM (0)
#define I2S_MCK_IO (GPIO_NUM_1)   //[No used]
#define I2S_BCK_IO (GPIO_NUM_36) // SerialCK
#define I2S_WS_IO (GPIO_NUM_35)  // LRCK
#define I2S_DO_IO (GPIO_NUM_37)  // SDATA out
#define I2S_DI_IO (GPIO_NUM_19)  // SDATA in for micphone [No used]static const char *TAG = "i2s_ns4168";
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;/* Import music file as buffer */#define DECLARE_WAV_START(SND) extern const uint8_t SND##_wav_start[] asm("_binary_" #SND "_wav_start")
#define DECALARE_WAV_END(SND) extern const uint8_t SND##_wav_end[] asm("_binary_" #SND "_wav_end")DECLARE_WAV_START(Snd01);
DECALARE_WAV_END(Snd01);DECLARE_WAV_START(Snd02);
DECALARE_WAV_END(Snd02);DECLARE_WAV_START(Snd03);
DECALARE_WAV_END(Snd03);DECLARE_WAV_START(Snd_Hotel); // california_hotel
DECALARE_WAV_END(Snd_Hotel);const uint8_t *music_group[][2] = {{&Snd01_wav_start, &Snd01_wav_end},{&Snd02_wav_start, &Snd02_wav_end},{&Snd03_wav_start, &Snd03_wav_end},{&Snd_Hotel_wav_start, &Snd_Hotel_wav_end},};esp_err_t play_snd_id(uint8_t snd_id, uint32_t timeout_ms)
{uint8_t *data_ptr_start = (uint8_t *)music_group[snd_id][0];uint8_t *data_ptr_end = (uint8_t *)music_group[snd_id][1];size_t data_len = data_ptr_end - data_ptr_start;uint32_t bytes_write = 0;// ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));vTaskDelay(150 / portTICK_PERIOD_MS);uint32_t tick1 = esp_log_timestamp();printf("[%ld] read to play:%d ,length:%d bytes.\n", tick1, snd_id, data_len);esp_err_t ret = i2s_channel_write(tx_handle, data_ptr_start, data_len, &bytes_write, timeout_ms);uint32_t tick2 = esp_log_timestamp();printf("[%ld] end play,written:%ld,take:%ld ms\n", tick2,bytes_write, tick2 - tick1);vTaskDelay(150 / portTICK_PERIOD_MS);//  ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));if (ret != ESP_OK){ESP_LOGE(TAG, "[music] i2s write failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);abort();}if (bytes_write <= 0){ESP_LOGE(TAG, "[music] i2s music play failed.");abort();}return ret;
}static esp_err_t i2s_driver_init(void)
{i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER);chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA bufferESP_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));return ESP_OK;
}static void i2s_music_task(void *args)
{esp_err_t ret = ESP_OK;size_t bytes_write = 0;uint8_t *data_ptr = (uint8_t *)Snd01_wav_start;bytes_write = Snd01_wav_end - Snd01_wav_start;printf("the music bin data length:%d bytes.start_addr:%p\n", bytes_write, data_ptr);/* (Optional) Disable TX channel and preload the data before enabling the TX channel,* so that the valid data can be transmitted immediately */ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));ESP_ERROR_CHECK(i2s_channel_preload_data(tx_handle, data_ptr, Snd01_wav_end - data_ptr, &bytes_write));//  data_ptr += bytes_write;  // Move forward the data pointerprintf("preload data length:%d.EXAMPLE_SAMPLE_RATE=%d\n", bytes_write, EXAMPLE_SAMPLE_RATE);/* Enable the TX channel */ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));vTaskDelay(5000 / portTICK_PERIOD_MS);uint8_t snd_id = 0;while (1){play_snd_id(snd_id, portMAX_DELAY);snd_id = (snd_id + 1) % 4; // 共4个wav音效vTaskDelay(3000 / portTICK_PERIOD_MS);}vTaskDelete(NULL);
}void app_main(void)
{// 634240 bytes are writtenprintf("I2S_NS4168: BCK=%d,WS=%d,DAT_IO=%d.\n", I2S_BCK_IO, I2S_WS_IO, I2S_DO_IO);/* 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");}xTaskCreate(i2s_music_task, "i2s_music_task", 4096, NULL, 5, NULL);
}

http://www.lryc.cn/news/391367.html

相关文章:

  • YOLOv8
  • 协程调度模块
  • 2024 最新docker仓库镜像,6月,7月
  • 探索Vim的文本处理能力:精通查找与替换
  • 2024.7.4学习日报
  • 享元模式(Flyweight Pattern)
  • Oracle连接mysql
  • golang 垃圾回收
  • React 中如何使用 Monaco
  • 开源RAG个人知识库项目开发分析
  • 事务底层与高可用原理
  • 树状数组基础知识
  • 【3分钟准备前端面试】vue3
  • 【数据采集】亮数据浏览器、亮网络解锁器实战指南
  • 暑期编程预习指南
  • 将带有 商店idr 商品信息的json导入到mongodb后,能不能根据商店id把所有商品全部提取并转为电子表格
  • 深入解析 androidx.databinding.BaseObservable
  • MySQL数据恢复(适用于误删后马上发现)
  • [数据结构】——七种常见排序
  • CPU占用率飙升至100%:是攻击还是正常现象?
  • java如何替换字符串中给定索引的字符
  • 基于RK3588的GMSL、FPDLink 、VByone及MIPI等多种摄像模组,适用于车载、机器人工业图像识别领域
  • Windows 的 MFC开发的使用示例——讲得挺好的
  • Spring4.3.x xml配置文件搜索和解析过程
  • 网络爬虫(一)深度优先爬虫与广度优先爬虫
  • JavaScript懒加载图像
  • Git指令
  • DllImport进阶:参数配置与高级主题探究
  • HTTP与HTTPS协议区别及应用场景
  • Vue2-Vue Router前端路由实现思路