黄帅-深圳市源合 发表于 2013-3-22 10:55:05

[分享]音频编解码芯片VS1003的MP3语音合成

本帖最后由 黄帅-深圳市源合 于 2013-5-14 16:09 编辑

一般简单的语音合成就是用有限的存储单元存储基本语音单元,进而从有限的存储单元中合成出无限词汇,组成连续语句。而为了节省存储空间一般将语音单元压缩成MP3格式存储。并通过MP3解码后播放
目前市场上较多的MP3解决方案是:MP3控制器+MP3解码芯片+NAND Flash。这种方案的MP3并不适合与商业或工业场合,因为对MP3中的音频文件修改时还需要用计算机设备才能完成,这在许多场合是很难满足或成本较高的。所以商业或工业领域所需要的MP3播放器,需要支持自动从U盘或SD卡等移动存储设备中转移数据的能力。
为了满足这样的需求,我们提出了一种嵌入式语音播放的解决方案----单片机 + NAND + VS1003。
此方案用SD卡把音频文件从拷贝大NAND中去,然后再有单片机从NAND中读取文件送入VS1003进行播放。拷贝操作由单片机自动完成。用户操作简单。

方案优势
单片机技术门槛低,容易进行二次开发
主流VS1003解码芯片,能够对MP3、WAV、WMA、MIDI等多种音频格式文件进行解码
音乐存放在NAND中,稳定性好
音乐从SD卡存入模块中的NAND里,自动完成,操作简单
针对Nand Flash的坏块管理,延长Flash的使用寿命
对文件系统的的优化,最大程度减轻了文件系统的开销,从而提高了文件的读取速度
成本低,性价比高

单片机+VS1003MP3方案的系统框图。

在该方案中主芯片采用STC12LE5A系列的单片机
该芯片采用增强型8051内核,功耗低,速度比普通的8051快8-12倍。片内Flash程序存储器最大可达62KB,片内RAM高达1280B。提供1个高速SPI接口,和多达达44个GPIO接口(GPIO有4种工作模式:准双向、推挽、输入、开漏),引脚与普通8051兼容。
解码芯片采用VS1003
VS1003是来自芬兰 VLSI 半导体公司的一款音频芯片,性价比极高,并且使用非常简单。芯片支持MP3、WAV、WMA、MIDI等多种音频格式的硬件解码,音质可与中高档次的MP3播放器相媲美。
方案中设计音频文件从SD卡中拷贝到NAND里进行播放
考虑工业或某些商业场合对可靠性和稳定性要求较高,音频文件被放在播放模块的NAND Flash中,单片机从NAND中读取文件传送给VS1003。此方案中,单片机的GPIO余量较大,可以做其他功能的扩展(如按键、LED等)。此方案最高可播放320kbps的MP3文件。
稳定性高,满足工业场合应用
因为工业场合对设备的稳定性,抗震动,抗干扰等性能要求较高,因此方案中选择把音频文件存放在NAND中,电路板上没有对震动干扰敏感的器件或设备,因此该方案音频文件更新功能操作灵活,而又不失稳定性。 从系统的功能、可靠性方面考虑可以选择使用NAND flash作为存储介质。nand flash一次传输为8位,大大减轻了单片机开销。在工业控制方面使用NAND flash更加牢固。
方案的可裁剪性
方案中的片外RAM,是在使用较复杂应用程序时做的内存扩展,简单应用中不需要扩展。也可以选择只使用SD卡作为MP3音频存储介质的方案,SD卡数据传输用的是SPI模式,数据按位传输,这将导致播放高位率(>320kbps)的MP3文件时会不流畅,但对一般的需求是完全能够满足的。
串口方式固件烧写
单片机程序通过串口进行烧写,便于设备的维护和更新。产品开发投资少,零风险。

技术交流 Q380100225 TEL13751145915

AAA级 发表于 2013-3-25 14:06:43


好消息   世界上最集成的音频编解码芯片VS1005已经量产上市。 欢迎咨询QQ2355355260。

黄帅-深圳市源合 发表于 2013-4-10 10:18:35

用MSP430F149(MCLK=SMCLK=8M,SPI高速2分频,低速8分频)和VS1003B、12864做MP3 下附代码:if(CurrentOffset<(SectorsPerCluster))
{
ReadSectorFromCluster(CurrentCluster,CurrentOffset);
WriteDataToVs1003();
if(IndexFlag)
{
VS1003B_ReadBitRate();
if(BitRate>99)
LCD_DisNum(0,0,BitRate);
else
LCD_DisNum(0,1,BitRate);
IndexFlag=0;
}
CurrentOffset++;
}
else
{
CurrentOffset=0;
CurrentCluster=FindNextCluster(CurrentCluster);
if(CurrentCluster==0x0ffffff8 || CurrentCluster==0x0fffffff)
{
switch(mode)
{
case Repet_All:
if(CurrentAudioFileIndex==AudioFileNumber)
CurrentAudioFileIndex=1;
else CurrentAudioFileIndex++;
break;
case Repet_One:
CurrentCluster = GetAudioFile( CurrentAudioFileIndex);
LCD_Print(3,3,Filestyle);
CurrentOffset=0;
break;
case Shuffle :
uint rand_val = TAR;
srand(rand_val);
CurrentAudioFileIndex = rand()%AudioFileNumber + 1;
CurrentOffset=0;
break;
}
LCD_Print(2,1," ");
GetShortAudioFileName(CurrentAudioFileIndex);
LCD_Print(2,1,ShortFileName);
}
}
}
.读取比特率和解码时间.spi的速率,变成8分频,也就是1M下附代码:
uchar ReceiveByte0() //read one byte from spi port
{
unsigned char temp=0;
while ((IFG1 & UTXIFG0)==0); // USCI_A0 TX buffer ready?
U0TXBUF =0xff; //8 clocks
temp=U0RXBUF;
return temp;
}

uint VS1003B_ReadCMD(unsigned char addr)
{
uint temp;
while(VS1003B_NeedData()==0);
SPI0_Low();
VS1003B_XDCS_H();
VS1003B_XCS_L();
SendByte0(0x03);
SendByte0(addr);
temp = ReceiveByte0();
temp <<= 8;
temp += ReceiveByte0();
VS1003B_XCS_H();
SPI0_High();
return temp;
}

uint VS1003B_ReadDecodeTime()
{
return VS1003B_ReadCMD(0x04);
}

uint VS1003B_ReadBitRate(void)
{
uint HDAT0,HDAT1;
HDAT0=VS1003B_ReadCMD(0x08);
HDAT1=VS1003B_ReadCMD(0x09);
switch(HDAT1)
{
case 0x7665:return 0;//WAV格式
case 0X4D54:return 1;//MIDI格式
case 0X574D://WMA格式
{
HDAT1=HDAT0*2/25;
if((HDAT1%10)>5)return HDAT1/10+1;
else return HDAT1/10;
}
default://MP3格式
{
HDAT1>>=3;
HDAT1=HDAT1&0x03;
if(HDAT1==3)HDAT1=1;
else HDAT1=0;
return BitRate_Table;
}
}
}

竹空闻樱 发表于 2013-5-3 20:53:06

{:soso_e179:}

黄帅-深圳市源合 发表于 2013-5-16 16:09:53

stm32 与VS1003的接口设置
第一点,STM32的端口设置,设置为SCK和MOSI复用推挽,而片选设为推挽输出即可,MISO设为input floating即可。
第二点,因为VS1003控制寄存器是八位数据读写的,所以STM32需要设置发送和接收数据也是八位的。
第三点,根据VS1003的时序关系,需要设置STM32的时钟信号的相位和极性为CPOL为0,CPHA为0。
第四点,NSS模式需要设置软件模式,这样就可以利用另作他用了,可以用GPIO口控制作为片选了。
这里贴一下源码voidSPI1_Init(void)
{   
   SPI_InitTypeDef SPIStruct_Init;
   SPIStruct_Init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    //配置SPI为全双工模式
   SPIStruct_Init.SPI_Mode = SPI_Mode_Master;      //配置SPI为主模式
   SPIStruct_Init.SPI_DataSize = SPI_DataSize_8b;    //配置SPI为8位数据传送
   SPIStruct_Init.SPI_CPOL = SPI_CPOL_Low;         //配置CPOL为低
   SPIStruct_Init.SPI_CPHA = SPI_CPHA_1Edge;         //配置CPHA为第一个上升沿
   SPIStruct_Init.SPI_NSS = SPI_NSS_Soft;            //配置NSS为软件控制
   SPIStruct_Init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;   //配置SPI时钟预分频
   SPIStruct_Init.SPI_FirstBit = SPI_FirstBit_MSB;   //配置传输字节高位在前
   SPIStruct_Init.SPI_CRCPolynomial = 7;             //配置CRC,可不用理
   SPI_Init(SPI1,&SPIStruct_Init);                   //SPI初始化函数   
   SPI_Cmd(SPI1, ENABLE);                            //使能SPI
}
void Mp3WriteRegister(uint8_t addressbyte,uint8_t high,uint8_t low)
{         
Mp3DeselectData();   //释放数据端口
Mp3SelectControl();//选择控制端口
      
      while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)); //判断发送缓冲器是否为空   
      SPI_I2S_SendData(SPI1,VS_WRITE_COMMAND);    //发送写寄存器命令
            
      while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE));
      SPI_I2S_SendData(SPI1, addressbyte);      //发送寄存器的地址
         
      while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE));
      SPI_I2S_SendData(SPI1, high);            //发送参数的高八位
      
      while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
      SPI_I2S_SendData(SPI1, low);            //发送参数的低八位      
Mp3DeselectControl();
}



/*************************************************************/
/*函数名称 :CheckVS1003B_DRQ(void)                           */
/*函数功能 : 判断DREQ引脚状态                           */
/*-----------------------------------------------------------*/
bool CheckVS1003B_DRQ(void)
{
bool bResult;
bResult =GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_4);
return(bResult);
}
页: [1]
查看完整版本: [分享]音频编解码芯片VS1003的MP3语音合成