音乐播放器课程设计报告之欧阳光明创编.docx

上传人:b****6 文档编号:6381534 上传时间:2023-01-05 格式:DOCX 页数:20 大小:39.14KB
下载 相关 举报
音乐播放器课程设计报告之欧阳光明创编.docx_第1页
第1页 / 共20页
音乐播放器课程设计报告之欧阳光明创编.docx_第2页
第2页 / 共20页
音乐播放器课程设计报告之欧阳光明创编.docx_第3页
第3页 / 共20页
音乐播放器课程设计报告之欧阳光明创编.docx_第4页
第4页 / 共20页
音乐播放器课程设计报告之欧阳光明创编.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

音乐播放器课程设计报告之欧阳光明创编.docx

《音乐播放器课程设计报告之欧阳光明创编.docx》由会员分享,可在线阅读,更多相关《音乐播放器课程设计报告之欧阳光明创编.docx(20页珍藏版)》请在冰豆网上搜索。

音乐播放器课程设计报告之欧阳光明创编.docx

音乐播放器课程设计报告之欧阳光明创编

课程设计报告

欧阳光明(2021.03.07)

课程设计名称:

音乐播放器

院系:

信息工程学院

学生姓名:

班级:

学号:

成绩:

指导教师:

开课时间:

2016-2017学年2学期

音乐播放器

一、实践的内容和要求

1.1实验内容

学习WAV格式音频播放原理、数字音频接口及的相关知识。

了解模拟音频信号和数字音频信号的概念。

掌握编写音频播主要内容放器的方法。

实现音频播放,小键盘输入操作。

1.2实验要求

本系统要做一个音乐播放器,使用通用定时器定时,用比较输出功能,输出乐谱频率的方波产生声音,对3首歌曲编码,其支持WAV格式音频播放(上键:

暂停;左键:

上一首;右键:

下一首)。

利用硬件ARM嵌入式开发平台、用于ARM7TDMI的JTAG仿真器、PC机Pentium100开发实现实现音频播放。

主要实现:

上一首按键:

当点击上一首按键时,当前播放歌曲的上一首歌首被播放。

下一首按键:

当点击下一首按键时,当前播放歌曲的下一首歌曲即被播放。

当点击停止键时,当前歌曲即会被停止。

播放界面设计:

在歌曲进行播放时,界面应包含所有的按键,并且要歌曲的曲目单。

二、实践原理

WAV播放器系统要求能够对mp3、wav格式的音频文件进行解码,处理起来速度是有要求的,尤其是对320Kbps的MP3格式数据流的处理,必须非常快,才能实现MP3的流畅播放,可供选择的八位机有AVR、PIC,可供选择的32位处理器有SAMSUNG、STM32、ATMEL等。

选择MCU优先考虑于拥有丰富的RAM,八位机RAM主要靠扩展,内部RAM一般在4Kbyte以内,32位机里面,SAMSUNG一般不内带RAM,也要外扩。

本实验使用了ARM7处理器,MP3解码可以有两种方法,一是通过ARM处理器软解码,通过对MP3数据格式的解析实现MP3播放,二是通过外部解码芯片直接解码。

第一种方法在解码高码率的MP3时,ARM7处理能力吃紧,而且STM32还需要外部DAC来做音频输出,所以采用第二种方法进行解码。

MP3常见的解码芯片有VS100X系列和STA01系列,STA01需要外接DAC做音频输出,而VS1003自带DAC,且解码的文件格式包含mp3和wav,另外它还可以实现录音功能,方便以后进行功能的拓展应用。

三、实践步骤

3.1功能设计

开机后,先初始化各外设,然后检测字库文件夹是否存在,如果有问题,则提示Error,如果检测无问题,则开始循环播放SD卡内MUSIC文件夹里面的歌曲,在TFTLCD上显示歌曲名字、播放时间、歌曲总时间、歌曲数目、当前歌曲的编号等信息。

KEY0选择下一首,KEY2选择上一首,KEY_UP控制暂停/继续播放。

3.2实验步骤

1)初始化WM8978,这个过程包括软复位、DAC设置、输出设置和音量设置等。

2)初始化I2S,此过程主要设置SPI_I2SCFGR寄存器,设置I2S模式、I2S标准、时钟空闲电平和数据帧长等,最后开启I2STXDMA,使能I2S外设。

在库函数中初始化I2S调用的函数为:

voidI2S_Init(SPI_TypeDef*SPIx,I2S_InitTypeDef*I2S_InitStruct);结构体I2S_InitTypeDef的定义为:

typedefstruct

{uint16_tI2S_Mode;

uint16_tI2S_Standard;

uint16_tI2S_DataFormat;

uint16_tI2S_MCLKOutput;

uint32_tI2S_AudioFreq;

uint16_tI2S_CPOL;}I2S_InitTypeDef;

第一个参数用来设置I2S的模式,也就是设置SPI_I2SCFGR寄存器的I2SCFG相关位。

可以配置为主模式发送I2S_Mode_MasterTx,主模式接受I2S_Mode_MasterRx,从模式发送I2S_Mode_SlaveTx以及从模式接受I2S_Mode_SlaveRx四种模式。

第二个参数I2S_Standard用来设置I2S标准,这个前面已经讲解过。

可以设置为:

飞利浦标准I2S_Standard_Phillips,MSB对齐标准I2S_Standard_MSB,LSB对齐标准I2S_Standard_LSB以及PCM标准I2S_Standard_PCMShort。

第三个参数I2S_DataFormat用来设置I2S的数据通信格式。

这里实际包含设置SPI_I2SCFGR寄存器的HCLEN位(通道长度)以及DATLEN位(传输的数据长度)。

当我们设置为16位标准格式I2S_DataFormat_16b的时候,实际上传输的数据长度为16位,通道长度为16位。

当我们设置为其他值的时候,通道长度都为32位。

第四个参数I2S_MCLKOutput用来设置是否使能主时钟输出。

我们实验会使能主时钟输出。

第五个参数I2S_AudioFreq用来设置I2S频率。

实际根据输入的频率值,会来计算SPI预分频寄存器SPI_I2SPR的预分频奇数因子以及I2S线性预分频器的值。

这里支持10中频率:

#defineI2S_AudioFreq_192k((uint32_t)192000)

#defineI2S_AudioFreq_96k((uint32_t)96000)

#defineI2S_AudioFreq_48k((uint32_t)48000)

#defineI2S_AudioFreq_44k((uint32_t)44100)

#defineI2S_AudioFreq_32k((uint32_t)32000)

#defineI2S_AudioFreq_22k((uint32_t)22050)

#defineI2S_AudioFreq_16k((uint32_t)16000)

#defineI2S_AudioFreq_11k((uint32_t)11025)

#defineI2S_AudioFreq_8k((uint32_t)8000)

#defineI2S_AudioFreq_Default((uint32_t)2)

第六个参数I2S_CPOL用来设置空闲状态时钟电平,取值为高电平I2S_CPOL_High以及低电平I2S_CPOL_Low。

3)解析WAV文件,获取音频信号采样率和位数并设置I2S时钟分频器这里,要先解析WAV文件,取得音频信号的采样率(fs)和位数(16位或32位),根据这两个参数,来设置I2S的时钟分频,这里我们用前面介绍的查表法来设置即可。

这是我们单独写了一个设置频率的函数为I2S2_SampleRate_Set。

4)设置DMAI2S播放音频的时候,一般都是通过DMA来传输数据的,所以必须配置DMA,本章我们用I2S2,其TX是使用的DMA1数据流4的通道0来传输的。

并且STM32F4的DMA具有双缓冲机制,这样可以提高效率,大大方便了我们的数据传输,本章将DMA1数据流4设置为:

双缓冲循环模式,外设和存储器都是16位宽,并开启DMA传输完成中断(方便填充数据)。

5)编写DMA传输完成中断服务函数为了方便填充音频数据,我们使用DMA传输完成中断,每当一个缓冲数据发送完后,硬件自动切换为下一个缓冲,同时进入中断服务函数,填充数据到发送完的这个缓冲。

6)开启DMA传输,填充数据最后,我们就只需要开启DMA传输,然后及时填充WAV数据到DMA的两个缓存区即可。

此时,就可以在WM8978的耳机和喇叭通道听到所播放音乐了。

操作方法为:

DMA_Cmd(DMA1_Stream4,ENABLE);//开启DMATX传输,开始播放。

3.3流程图

3.4关键代码

I2s.c代码:

#include"i2s.h"

#include"usart.h"

voidI2S2_Init(u16I2S_Standard,u16I2S_Mode,u16I2S_Clock_Polarity,u16I2S_DataFormat)

{

I2S_InitTypeDefI2S_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//使能SPI2时钟

RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,ENABLE);//复位SPI2

RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);//结束复位

I2S_InitStructure.I2S_Mode=I2S_Mode;//IIS模式

I2S_InitStructure.I2S_Standard=I2S_Standard;//IIS标准

I2S_InitStructure.I2S_DataFormat=I2S_DataFormat;//IIS数据长度

I2S_InitStructure.I2S_MCLKOutput=I2S_MCLKOutput_Disable;//主时钟输出禁止

I2S_InitStructure.I2S_AudioFreq=I2S_AudioFreq_Default;//IIS频率设置

I2S_InitStructure.I2S_CPOL=I2S_Clock_Polarity;//空闲状态时钟电平

I2S_Init(SPI2,&I2S_InitStructure);//初始化IIS

SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx,ENABLE);//SPI2TXDMA请求使能.

I2S_Cmd(SPI2,ENABLE);//SPI2I2SEN使能.

}

//采样率计算公式:

Fs=I2SxCLK/[256*(2*I2SDIV+ODD)]

//I2SxCLK=(HSE/pllm)*PLLI2SN/PLLI2SR

//一般HSE=8Mhz

//pllm:

在Sys_Clock_Set设置的时候确定,一般是8

//PLLI2SN:

一般是192~432

//PLLI2SR:

2~7

//I2SDIV:

2~255

//ODD:

0/1

//I2S分频系数表@pllm=8,HSE=8Mhz,即vco输入频率为1Mhz

//表格式:

采样率/10,PLLI2SN,PLLI2SR,I2SDIV,ODD

constu16I2S_PSC_TBL[][5]=

{

{800,256,5,12,1},//8Khz采样率

{1102,429,4,19,0},//11.025Khz采样率

{1600,213,2,13,0},//16Khz采样率

{2205,429,4,9,1},//22.05Khz采样率

{3200,213,2,6,1},//32Khz采样率

{4410,271,2,6,0},//44.1Khz采样率

{4800,258,3,3,1},//48Khz采样率

{8820,316,2,3,1},//88.2Khz采样率

{9600,344,2,3,1},//96Khz采样率

{17640,361,2,2,0},//176.4Khz采样率

{19200,393,2,2,0},//192Khz采样率

};

//设置IIS的采样率(@MCKEN)

//samplerate:

采样率,单位:

Hz

//返回值:

0,设置成功;1,无法设置.

u8I2S2_SampleRate_Set(u32samplerate)

{

u8i=0;

u32tempreg=0;

samplerate/=10;//缩小10倍

for(i=0;i<(sizeof(I2S_PSC_TBL)/10);i++)//看看改采样率是否可以支持

{

if(samplerate==I2S_PSC_TBL[i][0])break;

}

RCC_PLLI2SCmd(DISABLE);//先关闭PLLI2S

if(i==(sizeof(I2S_PSC_TBL)/10))return1;//搜遍了也找不到

RCC_PLLI2SConfig((u32)I2S_PSC_TBL[i][1],(u32)I2S_PSC_TBL[i][2]);//设置I2SxCLK的频率(x=2)设置PLLI2SNPLLI2SR

RCC->CR|=1<<26;//开启I2S时钟

while((RCC->CR&1<<27)==0);//等待I2S时钟开启成功.

tempreg=I2S_PSC_TBL[i][3]<<0;//设置I2SDIV

tempreg|=I2S_PSC_TBL[i][4]<<8;//设置ODD位

tempreg|=1<<9;//使能MCKOE位,输出MCK

SPI2->I2SPR=tempreg;//设置I2SPR寄存器

return0;

}

//I2S2TXDMA配置

//设置为双缓冲模式,并开启DMA传输完成中断

//buf0:

M0AR地址.

//buf1:

M1AR地址.

//num:

每次传输数据量

voidI2S2_TX_DMA_Init(u8*buf0,u8*buf1,u16num)

{

NVIC_InitTypeDefNVIC_InitStructure;

DMA_InitTypeDefDMA_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能

DMA_DeInit(DMA1_Stream4);

while(DMA_GetCmdStatus(DMA1_Stream4)!

=DISABLE){}//等待DMA1_Stream1可配置

/*配置DMAStream*/

DMA_InitStructure.DMA_Channel=DMA_Channel_0;//通道0SPI2_TX通道

DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&SPI2->DR;//外设地址为:

(u32)&SPI2->DR

DMA_InitStructure.DMA_Memory0BaseAddr=(u32)buf0;//DMA存储器0地址

DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral;//存储器到外设模式

DMA_InitStructure.DMA_BufferSize=num;//数据传输量

DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设非增量模式

DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器增量模式

DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//外设数据长度:

16位

DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//存储器数据长度:

16位

DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//使用循环模式

DMA_InitStructure.DMA_Priority=DMA_Priority_High;//高优先级

DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;//不使用FIFO模式

DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_1QuarterFull;

DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;//外设突发单次传输

DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;//存储器突发单次传输

DMA_Init(DMA1_Stream4,&DMA_InitStructure);//初始化DMAStream

DMA_DoubleBufferModeConfig(DMA1_Stream4,(u32)buf1,DMA_Memory_0);//双缓冲模式配置

DMA_DoubleBufferModeCmd(DMA1_Stream4,ENABLE);//双缓冲模式开启

DMA_ITConfig(DMA1_Stream4,DMA_IT_TC,ENABLE);//开启传输完成中断

NVIC_InitStructure.NVIC_IRQChannel=DMA1_Stream4_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00;//抢占优先级0

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00;//子优先级0

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断通道

NVIC_Init(&NVIC_InitStructure);//配置

}

//I2SDMA回调函数指针

void(*i2s_tx_callback)(void);//TX回调函数

//DMA1_Stream4中断服务函数

voidDMA1_Stream4_IRQHandler(void)

{

if(DMA_GetITStatus(DMA1_Stream4,DMA_IT_TCIF4)==SET)////DMA1_Stream4,传输完成标志

{

DMA_ClearITPendingBit(DMA1_Stream4,DMA_IT_TCIF4);

i2s_tx_callback();//执行回调函数,读取数据等操作在这里面处理

}

}

//I2S开始播放

voidI2S_Play_Start(void)

{

DMA_Cmd(DMA1_Stream4,ENABLE);//开启DMATX传输,开始播放

}

//关闭I2S播放

voidI2S_Play_Stop(void)

{

DMA_Cmd(DMA1_Stream4,DISABLE);//关闭DMA,结束播放

}

wm8978代码:

#include"wm8978.h"

#include"myiic.h"

#include"delay.h"

staticu16WM8978_REGVAL_TBL[58]=

{

0X0000,0X0000,0X0000,0X0000,0X0050,0X0000,0X0140,0X0000,

0X0000,0X0000,0X0000,0X00FF,0X00FF,0X0000,0X0100,0X00FF,

0X00FF,0X0000,0X012C,0X002C,0X002C,0X002C,0X002C,0X0000,

0X0032,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,

0X0038,0X000B,0X0032,0X0000,0X0008,0X000C,0X0093,0X00E9,

0X0000,0X0000,0X0000,0X0000,0X0003,0X0010,0X0010,0X0100,

0X0100,0X0002,0X0001,0X0001,0X0039,0X0039,0X0039,0X0039,

0X0001,0X0001

};

//WM8978初始化

//返回值:

0,初始化正常

//其他,错误代码

u8WM8978_Init(void)

{

u8res;

GPIO_InitTypeDefGPIO_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC,ENABLE);//使能外设GPIOB,GPIOC时

//PB12/13复用功能输出

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//复用功能

GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//100MHz

GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉

GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化

//PC2/PC3/PC6复用功能输出

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_6;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//复用功能

GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//100MHz

GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉

GPIO_Init(GPIOC,&GPIO_InitStructure);//初始化

GPIO_PinAFConfig(GPIOB,GPIO_PinSource12,GPIO_AF_SPI2);//PB12,AF5I2S_LRCK

GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2);//PB13,AF5I2S_SCLK

GPIO_PinAFConfig(GPIOC,GPIO_PinSource3,GPIO_AF_SPI2);//PC3,AF5I2S_DACDATA

GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_SPI2);//PC6,AF5I2S_MCK

GPIO_PinAFConfig(GPIOC,GPIO_PinSource2,GPIO_AF6_SPI2);//PC2,AF6I2S_ADC

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1