很久以前就看到过某知名嵌入式论坛上有大牛用单片机来做WAV播放器,我看到后觉得很不错,有一种制作的冲动,因为那时MP3播放器还很贵。后来我确实也做出来了,还把它送给朋友。但是,当时只是完全copy别人的电路和程序,唯一跟原创不同的是把它外表做得精美点,并没有对里面的原理做出分析。今天突然想起那个WAV播放器来,所以打算把知识点梳理一番。
一、 首先是WAV格式。WAV格式音频是采用原始的PCM编码数据,没有经过压缩。PCM编码只是一种数字的量化手段,直接用它来当做原始数据来处理是可以的。只要我们按照原来的采样速率把数据通过DAC,那么声音就会还原回来。你要PCM数据你首先要知道.WAV后缀文件的格式。
WAV文件是以RIFF格式为标准的,RIFF格式是windows环境下大部分多媒体文件遵循的一种文件结构,由多个chunk(块)组成,:RIFF WAVE Chunk, Format Chunk, Fact Chunk(optinal), Data Chunk,LIST Chunk(optinal)等。如下图所示:
那么,每一个chunk的格式是怎样的呢?每个Chunk 有各自的ID,位于Chunk 最开始位置,作为本Chunk 开始的标识,均为4 个字节字符。紧跟在ID 后面的是Chunk 的大小---Size,也占用4 个字节,Size 是本Chunk所占字节总数减去8 个字节(ID 和Size)的数值,低字节表示数值的低8 位,高字节表示数值的高8 位(类似于小端模式),下面具体介绍各个Chunk 内容。
1.RIFF WAVE Chunk
假设size大小为a,则这个文件大小为(a+8)字节,type标示这是WAV文件。
2.Format Chunk
这一块很重要,包含了重要信息,包括声道数,采样频率,数据位数等
3.Fact Chunk(optinal)
这一块为可选,有些没有此chunk
4.Data Chunk
size大小纯粹是data的大小。
5.LIST Chunk(optinal)
此块也是可选,可以用来在文件最末端添加一些附加信息。
声道数据是怎样反映在data里呢?假如是8位单声道,则是每个采样点一个数据,不间隔。假如是8位双声道,则每个采样点的采样数据包含左右两个声道数据,也就是先左声道的数据,紧跟着是右声道数据,然后下一个采样点。。。。。.16位数据这里就不介绍了。8位PCM的格式为ungsigned char 0~255。刚好与AVR单片机的TCNT0的范围一样,待会讲到PWM时再讨论。相信大家对WAV文件格式有初步了解。大家可以用WinHex软件查看WAV文件,对照上面的表格,自己找出实际音乐数据的位置,查看一下没有声音时PCM数据是多少(0x80)。
二、PWM组成的零阶保持器
PWM是脉冲宽度调制的缩写,可以通过改变“占空比”来改变电压有效值。我们可以考虑,当占空比可以由数字信号的量化值来改变时,那么输出电压的有效值跟量化值应该会有一个近似正比的映射关系,于是,这一个装置可以看做是一个粗糙的DAC。我们可以用这个“DAC”来将PCM信号还原成声音信号(类似于D类放大器)。
我们可以使用AVR的PWM来实现。AVR单片机的PWM有几种模式-----普通模式,CTC模式,相位修正PWM模式,快速PWM模式。每种模式有各自的优缺点。我们这里可以用快速PWM模式。下图是ATMEGA16的快速PWM模式的时序图:
可以看出,当COM01:COM00=1:0时,TCNT0为初值时引脚OC0输出高电平,一直持续到TOP,或者跟OCR0的值匹配后,引脚OC0变低。当改变OCCR0值时,占空比也跟着改变,而且,OCR0值越大(最大0xFF),占空比越大。AVR单片机快速PWM模式的PWM频率F=Fosc/(256*N);N为分频值。F越大,“DAC”的噪声就更多地分布在高频,容易使用低通滤波器滤除,提高音质。我们可以设置TCCR0=0X69;TCNT=0X00;OCR0=0X7F;代表的意义具体查看ATMEGA16的寄存器说明。为了能让从WAV格式文件读取出来的数据转换成音频信号,除了有DAC,我么还需要把数据按照采样率来输送到“DAC”才能还原成原来的声音。相信大家小时候都玩过磁带录音机,磁带录音机的转速是有一个标准的,也就是录音和播放采取一样的转速,如果因为里面的齿轮生锈了,转速变慢,那么播放出来的声音就变得走音、低沉,有时女声变成男声。同样地,这里的采样率跟磁带录音机的转速一个道理。那么,我们可以用单片机的定时器功能来做到,在定时器中断服务程序中发送数据给OCR0,也就是定时发送数据给“DAC”,只要将定时器的频率调节到采样率,那么声音就还原出来了。
如果没有接触过SD卡和文件系统,我们可以简单地,用Windows系统自带的录音机功能录取一段单声道语音,用WinHex查看,找到数据,把它做成一个C语言数组形式。就可以用单片机读取还原出声音了!!