【求助】PWM转DA输出WAV音频的一个小程序

2020-01-12 17:25发布

本帖最后由 wicy001 于 2012-4-28 13:45 编辑

利用STC90C516RD+实现PWM输出WAV格式的音频,这是一个非常简单的程序

说明:1.此单片机没有集成PWM,需要使用定时器实现
         2.播放wav音频的格式为8bit,8Khz 单声道,大小<60K,放在程序存储器中。
         3.晶振需要 8Khz*(2^8bit)*12T=24.576Mhz,如果烧写使用6T方式,晶振可减半。
         4.端口接耳机,耳机另一端接+5V,这样声音听着会大一些。

问题:
       输出有噪音,噪音非常尖锐,而且声音很大,比声音信号要大。请各位大侠看看,问题出在哪,应该怎么解决?

-----------
声音尖锐,频率应该很高,试着加一个RC低通,但效果不明显。

---------------为方便大家快速阅读,将帖子相关内容整理如下-------------
图1:RC电路


图2:经过RC电路仿真波形      【如何去掉图中的尖刺?】


图3:未经RC电路前端口的仿真波形  【斜坡受RC影响,正常。如果不加RC电路,输出是平的】



/*************************程序****************************/
#include <reg52.h>   //MCU为STC89/STC90
#include "sound.h"    //wav格式数据

sbit BEEP = P0^0;         //耳机一端接在P0.0脚上,一端接+5V
unsigned int counter,wavedataL;
unsigned char currentdata,nextdata,i;




void sys_start()
{

    TMOD|= 0x02;  //T0,自动重装模式
        TH0 = currentdata;
        TL0 = currentdata;


    ET0 = 1;
        EA  = 1;       

        TR0 = 1;
        BEEP=0;
}



main()
{
  unsigned int tmp;

  tmp=sound[0x29];                           //从wav文件中取,数据长度。数据长度应该是4个字节,
  tmp=tmp<<8;
  wavedataL=tmp+sound[0x28];  //由于wav存在片内flash中,文件大小有限制,数据长度用int型足够表示了。

  counter=0x2c;          //wav文件第一个数据
  
  currentdata=sound[counter];       
  nextdata=sound[counter];

  //以上数字请参考wav格式说明

  sys_start();


  while(1)
  {
   
        if(counter>wavedataL)                //反复重播
                 {
                         counter=0x2c;      
                 }

        if(BEEP) TH0=0xFF-currentdata;
        else TH0=currentdata;

   }


}

/*************************************/

void Timer0int(void) interrupt 1    //定时器0中断
{
   
       
        BEEP=~BEEP;

        if(BEEP)
        {

                counter++;
                nextdata=sound[counter];

        }
        else
        currentdata=nextdata;
}


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
99条回答
wicy001
1楼-- · 2020-01-23 12:38
gamethink 发表于 2013-6-13 14:27
请教LZ,WAV记录的音频数据是有分正/负的,比如8位,究竟如何和PWM的0-255关联起来? ...

你好,WAV中的数据代表了电压的高低(电压的高低由PWM控制),进而表示为喇叭震动的振幅。

所以:正负数据,与0-255线性对应即可。

gamethink
2楼-- · 2020-01-23 16:52
 精彩回答 2  元偷偷看……
bg4gzu
3楼-- · 2020-01-23 22:29
RC滤波改为LC滤波。
效果会好一些。电感可选用33uH,对地电容用0.47uF左右。可以适当增加电感来改变低通频率。
vbvc6
4楼-- · 2020-01-24 04:21
我用LMF4L120试了下,效果差的很,有很明显的尖噪音,我直接用IO驱动蜂鸣器,接音响效果好点,但噪声依然很大
50M/256 等效约200k的DA

void BeepLevelSet(int level);

#define VOICE_TIMER                         SYSCTL_PERIPH_TIMER2
#define VOICE_TIMER_BASE        TIMER2_BASE
#define VOICE_GPIO_PIN_CFG      GPIO_PB0_T2CCP0
#define VOICE_GPIO_PIN          GPIO_PIN_0
#define VOICE_GPIO_PERIPH       SYSCTL_PERIPH_GPIOB
#define VOICE_GPIO_BASE                  GPIO_PORTB_BASE

static unsigned int BufferPosMax=0;
static unsigned char *WaveBufferStart=0;

void IntTimer5HandlerA(void)
{
        static unsigned int BufferPos;
        HWREG(TIMER5_BASE + TIMER_O_ICR)   = 0x01;
        if(0==WaveBufferStart){
                BufferPos=0;
                return;
        }
        BeepLevelSet(WaveBufferStart[BufferPos]);
        BufferPos++;
        if(BufferPos>=BufferPosMax){
                BufferPos=0;
                WaveBufferStart=0;
        }
        return;
}
void BeepInit(void)
{
    //
    // Enable the GPIO Port and Timer for each LED
    //
        SysCtlPeripheralEnable(VOICE_GPIO_PERIPH);
        SysCtlPeripheralEnable(VOICE_TIMER);
        GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE,GPIO_PIN_0);
    //
    // Configure each timer for output mode
    //
        HWREG(VOICE_TIMER_BASE + TIMER_O_CTL)   = 0x00;
    HWREG(VOICE_TIMER_BASE + TIMER_O_CFG)   = 0x04;
    HWREG(VOICE_TIMER_BASE + TIMER_O_TAMR)  = 0x0A;
    HWREG(VOICE_TIMER_BASE + TIMER_O_TAILR) = 0xFF;

    //
    // Invert the output signals.
    //
    HWREG(VOICE_TIMER_BASE + TIMER_O_CTL)   |= 0x40;
    //
    // Enable timers to begin counting
    //
    TimerEnable(VOICE_TIMER_BASE, TIMER_A);
    //
    // Reconfigure each LED's GPIO pad for timer control
    //
    GPIOPinConfigure(VOICE_GPIO_PIN_CFG);
    GPIOPinTypeTimer(VOICE_GPIO_BASE, VOICE_GPIO_PIN);
    GPIOPadConfigSet(VOICE_GPIO_BASE, VOICE_GPIO_PIN, GPIO_STRENGTH_2MA,
                     GPIO_PIN_TYPE_STD);

    BeepLevelSet(0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
        HWREG(TIMER5_BASE + TIMER_O_CTL)   = 0x00;
    HWREG(TIMER5_BASE + TIMER_O_CFG)   = 0x04;
    HWREG(TIMER5_BASE + TIMER_O_TAMR)  = 0x02;
    HWREG(TIMER5_BASE + TIMER_O_TAILR) = 0x186A; //8000
    TimerMatchSet(TIMER5_BASE,TIMER_A,2);
    TimerEnable(TIMER5_BASE, TIMER_A);
    TimerIntEnable(TIMER5_BASE,TIMER_TIMA_TIMEOUT);//TIMER_TIMA_MATCH //TIMER_TIMA_TIMEOUT
    IntEnable(INT_TIMER5A);
}

void BeepLevelSet(int level)
{
        TimerMatchSet(VOICE_TIMER_BASE,TIMER_A,level);
}

void TestWaveOut(void)
{
        BufferPosMax=sizeof(wave_data);
        WaveBufferStart=(unsigned char*)wave_data;
}
wicy001
5楼-- · 2020-01-24 09:57
vbvc6 发表于 2013-6-15 12:17
我用LMF4L120试了下,效果差的很,有很明显的尖噪音,我直接用IO驱动蜂鸣器,接音响效果好点,但噪声依然很大
50 ...

LMF4L120是什么MCU?程序看不懂。

根据经验,不加滤波,播放wav,音质也是很清晰的。 导致噪音的原因有最主要的就是PWM频率,其次是程序处理,有时一点小失误,会造成添加或漏掉数据等情况,肯定也有噪音。最后,音乐输出,是必须接喇叭或耳机的,蜂鸣器是不行的。
chess01
6楼-- · 2020-01-24 10:17
2003要用交流耦合

一周热门 更多>