若此时不能听到声音,你也不必着急,试着转动红色的电位器旋钮,直至触摸板下的3个指示灯全部亮起,则说明音量是最大了,此时就应听到播放的声音。若还不能发出声音,就属异常情况了。 语音播放的工作原理 实现语音播放功能主要经过的环节有:指定播放文件->读取SD卡->数据缓冲区缓存数据->PIT周期性输出数据->DCA输出模拟信号->运放功率放大->扬声器还原语音输出 在这个过程中,使用的SD卡为mini型高容量SD卡,其容量介于2GB到32GB之间,采用FAT32文件系统格式,在使用中我需要的是4GB的SD卡。 那么SD卡有何特点呢? SD卡是一种基于Flash存储器的新型存储设备,被广泛应用于便携式装置上,具有读取速度快和存储容量大的特点。一般是采9针的接口与专用驱动器相连,不需要额外的电源来保持信息,由于是一种固体介质,所以不必担心运动性损坏。 SD卡定义了两种通讯协议来传递信息,一种是SD接口,另一种则是SPI接口。对于YL-KL26Z开发板,其所用的是SPI接口。对于K60 所采用的则是SD接口。 在使用SD卡时,需用到SD初始化函数SD_Init()及SD卡读取函数。在SD卡的读取操作中是以扇区为单位的,一个扇区包含512个字节。 由于语音信息是以音频文件方式存储的,因而还需要文件管理函数的配合,所用的函数有TAT初始化函数FAT_Init()、根目录搜索函数FAT_DisDir()、读取扇区函数FAT_LoadPartCluster()和读取下一个扇区函数AT_NextCluster()。 在数据输出由于方面,由于音频文件的格式为16KHz 采样率的8bit数据,所以在输出时是借助PIT周期中断定时器来等间隔的频率来读取缓冲区中的数据进行输出,其频率会与16KHz 的采样率相匹配。 在数模转换方面是采用微控器内部的DAC转换器,其转换精度为12bit,较音频的8bit数据要高。 为了便于动态地调节音量,是采用微控器内部的模数转换器来完成的,其转换精度为16bit。在数据位数统一方面是由下面2条语句来实现: Volume=Volume_Num*adcGetUint()>>16; dacTrigger(Buffer[FIFO_out]/(Volume_Num-Volume)); 在音量指示方面是以3个LED等来反应,它是将A/D转换器的采用值分为3个等级来处理的,其判别值依次为AD_Sample_Num/3、2*AD_Sample_Num/3和AD_Sample_Num。
程序改进与完善 如果你要播放自己的声音文件,可以通过电脑中附件的录音机来录制,当然对语音文件的格式是有要求的,即以16KHz 采样率8bit 格式的音频文件。此外,如果你有其它格式的声音文件,也可通过相应的软件转换为该格式的文件来使用。 此时,你是否觉得一切技术方面的问题都已解决了呢?回答是否定的,因为故事通常是由多个故事段组成的,要想播放多段语音就必须对程序进行改造。改造的对象选取main.c文件即可,方法是在适当的位置添加一个循环,使播放文件的过程反复进行直到退出为止,期间通过变换相应的文件名即可达到变换播放内容的需要。 但通过实践你会发现这一想法很难实现,似乎程序从未离开第一段程序的播放,根本就无法脱离出来,问题出在哪里呢? 仔细研读程序,可以发现有这样一条语句,即while(size<FileInfo.Size)。 其含义是当size变量的值不小于文件长度FileInfo.Size时,则退出数据的读取过程。然而遍寻整个主函数也没发现一条更改size变量的语句,程序又怎能退出数据读取过程那,程序是一段永无休止的死循环呀! 那如何来修改size变量呢?通过程序分析可以发现,size是与扇区及簇分不开的。因为在SD卡的读取过程中其基本单位不是字节而是扇区,所以无法直接以字节数来作为判别条件,因采用语句:size=size+SectorsPerClust*512; 在程序运行中,为了能够控制语音播放的节奏,可用K3 键来限制下一段语音的播放时机。其方法是在退出数据读取后,添加一条等待语句,其内容为:while((FGPIOD_PDIR & 1<<6) == 1<<6); 随着节奏控制的实现,此时会有一个新的问题出现,就是伴随语音内容的结束,机制而起的是无规则的噪音声。这又是什么原因导致的?原来随着正常语音数据输出的结束,DAC的输出过程并未停止,所以就出现了无规则的噪音声。解决的方法是设置输出字节计数器size2和文件长度存储变量size1,当输出字节等于文件长度时就关断DAC的输出,其语句为: if(size2 < size1) dacTrigger(Buffer[FIFO_out]/(Volume_Num-Volume));
|