内容介绍
内容介绍
硬件介绍
恩智浦LPC Cortex-M4/M0系列开发板,采用LQFP64封装的LPC54110 MCU,Arduino板型架构,板载调试器和常用外设扩展,通常可直接利用LPC54110开发板对MCU性能进行评估和软件开发。
功能:
- LPC54114J256BD64 Cortex-M4/M0+ 双核MCU
- ISP多启动选项跳线,支持3.3V/1.8V工作电压选择,板载32.768KHz振荡器
- 4个用户定义按键和一个复位按键
- 9个发光二极管,其中4个低电平驱动(绿色),4个高电平驱动(红色),一个电源指示
- 一个电位器模拟输入
- 一个Micro USB接口连接到LPC54114的USB口
- 一个Micro USB接口连接到板载调试器
- 一个单线SPI方式TF卡接口和一个SPI Flash存储器
- 一个支持I2S音频输入/输出接口(WM8904)
- 一个I2C 温度传感器(PCT2075DP)
- 一个PDM数字麦克风(SPH0641LM4H)
- 多个欧姆跳线电阻使能板载外部设备
- 板载调试器及支持外部仿真器的10芯1.27mm SWD仿真插座
- Arduino扩展接口
- 支持Keil/EWARM集成开发环境
设计思路及细节 开机
默认情况下直接用 Keil 是读不到 DAP 烧写器的,而且也识别不到虚拟串口。这时候就要手动升级调试器固件。按住 RESET 上电,直至电脑出现 CRP DISABLED 盘符。删除所有文件,把附件中的文件拖进去。
TF卡读取遍历
char music_name[FILE_NAME_LEN];
f_mount(&fs, driverNumberBuffer, 1);
file_scan(path);
if (file_num == 0) {
printf("no mp3 file!\r\n");
return;
}
printf("Music Num= %d", file_num);
all_page = (file_num + 7) / 8;
current_page = 1;
printf("file_num = %d, all_page= %d\r\n", file_num, all_page);
memcpy(music_name, musicPathList, 30);
if (strstr(music_name, ".mp3") || strstr(music_name, ".MP3")) {
printf("Playing: %s\r\n", music_name);
mp3_player(music_name);
}
读取 TF 卡有如下几步:
- 挂载 TF 卡
- 遍历文件及子目录
- 如果是文件夹,则递归进入子目录
- 如果是文件,则判断文件后缀名是否为 .mp3,如果是则进行播放
MP3 解析
手动实现 MP3 文件的解析就比较复杂,这里直接使用写好的第三方 MP3 解析模块进行调用。
earlephilhower/ESP8266AudioMP3: Port of Helix MP3 code to ESP8266 (github.com)
static void mp3_player(const char *filename) {
int err, i, outputSamps, current_sample_rate = 0;
int read_offset = 0;
int bytes_left = 0;
unsigned long Frames = 0;
unsigned char *read_ptr = buffer;
HMP3Decoder Mp3Decoder;
unsigned char ReadFlag = 0;
fres = f_open(&file, filename, FA_READ);
if (fres != FR_OK) {
printf("read file %s error ! open another file\r\n", filename);
fres = f_close(&file);
if (++play_index >= file_num) {
play_index = 0;
}
return;
}
Mp3Decoder = MP3InitDecoder();
while (player_state != S_SWITCH) {
fres = f_read(&file, buffer, sizeof(buffer), &rw_num);
if (fres != FR_OK) {
printf("Error Reading %s (%d)\r\n", filename, fres);
break;
}
read_ptr = buffer;
bytes_left = rw_num;
while (player_state != S_SWITCH) {
if (player_state == S_STOP) {
continue;
}
player_state = S_PLAY;
if (!ReadFlag) {
read_offset = MP3FindSyncWord(read_ptr, bytes_left);
if (read_offset < 0) {
break;
}
read_ptr += read_offset;
bytes_left -= read_offset;
if (bytes_left < 1024) {
i = (uint32_t)(bytes_left)&3;
if (i)
i = 4 - i;
memcpy(buffer + i, read_ptr, bytes_left);
read_ptr = buffer + i;
fres = f_read(&file, buffer + bytes_left + i,
sizeof(buffer) - bytes_left - i, &rw_num);
bytes_left += rw_num;
}
err = MP3Decode(Mp3Decoder, &read_ptr, &bytes_left, outBuf[bufflag], 0);
Frames++;
} else {
while (!DMA_Flag) {
if (1 == ReadFlag) {
read_offset = MP3FindSyncWord(read_ptr, bytes_left);
if (read_offset < 0) {
break;
}
read_ptr += read_offset;
bytes_left -= read_offset;
if (bytes_left < 1024) {
i = (uint32_t)(bytes_left)&3;
if (i)
i = 4 - i;
memcpy(buffer + i, read_ptr, bytes_left);
read_ptr = buffer + i;
fres = f_read(&file, buffer + bytes_left + i,
sizeof(buffer) - bytes_left - i, &rw_num);
bytes_left += rw_num;
}
err = MP3Decode(Mp3Decoder, &read_ptr, &bytes_left, outBuf[bufflag],
0);
Frames++;
ReadFlag = 2;
}
}
DMA_Flag = 0;
ReadFlag = 1;
}
if (err != ERR_MP3_NONE) {
switch (err) {
case ERR_MP3_INDATA_UNDERFLOW:
printf("ERR_MP3_INDATA_UNDERFLOW\r\n");
read_ptr = buffer;
fres = f_read(&file, read_ptr, sizeof(buffer), &rw_num);
bytes_left = rw_num;
break;
case ERR_MP3_MAINDATA_UNDERFLOW:
printf("ERR_MP3_MAINDATA_UNDERFLOW\r\n");
break;
default:
printf("UNKNOWN ERROR:%d\r\n", err);
if (bytes_left > 0) {
bytes_left--;
read_ptr++;
}
break;
}
} else {
MP3GetLastFrameInfo(Mp3Decoder, &Mp3FrameInfo);
if (Mp3FrameInfo.samprate != current_sample_rate) {
current_sample_rate = Mp3FrameInfo.samprate;
printf(" \r\n Bitrate %dKbps", Mp3FrameInfo.bitrate / 1000);
printf(" \r\n Samprate %dHz", current_sample_rate);
printf(" \r\n BitsPerSample %db", Mp3FrameInfo.bitsPerSample);
printf(" \r\n nChans %d", Mp3FrameInfo.nChans);
printf(" \r\n Layer %d", Mp3FrameInfo.layer);
printf(" \r\n Version %d", Mp3FrameInfo.version);
printf(" \r\n OutputSamps %d", Mp3FrameInfo.outputSamps);
}
outputSamps = Mp3FrameInfo.outputSamps;
if (outputSamps > 0) {
if (Mp3FrameInfo.nChans == 1) {
for (i = outputSamps - 1; i >= 0; i--) {
outBuf[bufflag][i * 2] = outBuf[bufflag][i];
outBuf[bufflag][i * 2 + 1] = outBuf[bufflag][i];
}
outputSamps *= 2;
}
for (copyCount = 0; copyCount < 2500; copyCount++) {
outBufDouble[copyCount] = outBuf[0][copyCount];
outBufDouble[copyCount + outputSamps] = outBuf[1][copyCount];
}
DMA_Init(DMA0);
DMA_EnableChannel(DMA0, 15);
DMA_SetChannelPriority(DMA0, 15, kDMA_ChannelPriority3);
DMA_CreateHandle(&s_DmaTxHandle, DMA0, 15);
s_TxTransfer.data = (uint8_t *)outBufDouble;
s_TxTransfer.dataSize = outputSamps * 4;
I2S_TxTransferCreateHandleDMA(I2S1, &s_TxHandle, &s_DmaTxHandle,
MyTxCallback, (void *)&s_TxTransfer);
I2S_TxTransferSendDMA(I2S1, &s_TxHandle, s_TxTransfer);
bufflag = 1 - bufflag;
}
}
if (file.fptr == file.fsize) {
printf("END\r\n");
if (play_index < file_num - 1) {
play_index++;
player_state = S_SWITCH;
} else {
play_index = 0;
player_state = S_SWITCH;
}
break;
}
}
}
f_close(&file);
MP3FreeDecoder(Mp3Decoder);
}
MP3 输出
这里需要提前调节 `app_wm8904.c` 文件中的 db 值,以免听力受损!!!
/* Adjust it to your needs, 0x0006 for -51 dB, 0x0039 for 0 dB etc. */
WM8904_SetVolume(&codecHandle, 0x0025, 0x0025);
输出使用 DMA 技术,解码后直接搬迁至音频输出 IC。
实现功能
- 自动读取 TF 卡中的 MP3 文件并播放
- 自动输出 MP3 文件的格式参数
结尾
WM8904 低频信号输出比较差,提前将 MP3 做一个高通,滤去 1K 以下信号分量可以很大程度上减少噪声。
LPC54114 扩展性非常强大,可以实现多样的功能,在此感谢硬核团队的技术支持。
软硬件
附件下载
LPC54114固件.zip
lpc54110_example.zip
团队介绍
中国计量大学
评论
0 / 100
查看更多
猜你喜欢
NXP LPC54114双核MCU开发板:基于板载麦克风的声音氛围灯万利LPC54114开发板资源非常丰富,板载音频采集及播放芯片、MEMS麦克风、SD卡槽等,特别适合视频音频引用的开发。本项目将利用LPC54114内置dmic外设采集麦克风信号,并通过WS2812显示声音频谱。
不是茄子
1315
基于MAX78000FTHR的MP3播放器基于MAX78000FTHR的MP3播放器,软件解码MP3支持MPEG-1、MPEG-2 以及MPEG-2.5 标准的Layer3 解码
llzx
918
基于MAX78000实现MP3播放器使用MAX78000FTHR开发板制作一个MP3音乐播放器。
wakojosin
1285