wicy001 发表于 2012-4-27 20:24:49

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

本帖最后由 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电路
http://cache.ourdev.cn/new2012/forum/201204/28/100736pvf1tqqouclsquns.jpg

图2:经过RC电路仿真波形      【如何去掉图中的尖刺?】
http://cache.ourdev.cn/new2012/forum/201204/28/130727vgijf18gvaauevwg.jpg.thumb.jpg

图3:未经RC电路前端口的仿真波形【斜坡受RC影响,正常。如果不加RC电路,输出是平的】
http://cache.ourdev.cn/new2012/forum/201204/28/131721yp66ghs0hp062lpw.jpg.thumb.jpg


/*************************程序****************************/
#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;                           //从wav文件中取,数据长度。数据长度应该是4个字节,
tmp=tmp<<8;
wavedataL=tmp+sound;//由于wav存在片内flash中,文件大小有限制,数据长度用int型足够表示了。

counter=0x2c;          //wav文件第一个数据

currentdata=sound;       
nextdata=sound;

//以上数字请参考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;

        }
        else
        currentdata=nextdata;
}


wicy001 发表于 2012-4-27 20:26:23

自己沙发

BXAK 发表于 2012-4-27 21:39:20

PWM频率要足够高,最好40K左右,
STC90C516RD 无硬件PWM,又速度慢(6T)定时器模拟PWM频率不高也不方便,
可以使用电阻网络搭建DA转换器电路,这样大大提高CPU效率,
详见:小玩意,单片AT89C2051 + SD卡 + 3310LCD = 音乐播放器


zhanzhipeng 发表于 2012-4-27 21:46:09

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

wicy001 发表于 2012-4-27 22:26:24

TO BXAK

PWM频率要足够高,最好40K左右----------------
当然高一些好,我用的是24.576MHz的晶振,可以满足播放我程序中的声音文件。
(这个声音文件的模拟输出点没有接近0v,和5V的极限值,都在2.5V左右,程序处理起来完全满足。)


可以使用电阻网络搭建DA转换器电路,这样大大提高CPU效率,
---------------------------------
嗯,以前做过使用DA芯片。但是这里就是想用一下PWM方式的。


声音可以清晰的听出来,就是背景噪音太大,这个噪音一直持续,分贝很高。

wicy001 发表于 2012-4-27 22:28:33

那段声音是转CS里的一个wav文件, “OK,let‘s go”

512826028 发表于 2012-4-27 22:36:50

楼主 这个可不可以通过单片机读取PWM,然后在LCD显示出音频的频谱呢?

可否给个简单的思路呢?

amazing030 发表于 2012-4-27 23:03:45

这个PWM值是已知的.....WAV数据就是PWM(DA)值,并不是通常意义上的频谱

zjk 发表于 2012-4-28 08:52:10

有尖波干扰吧

wicy001 发表于 2012-4-28 09:28:06

512826028 发表于 2012-4-27 22:36 static/image/common/back.gif
楼主 这个可不可以通过单片机读取PWM,然后在LCD显示出音频的频谱呢?

可否给个简单的思路呢? ...

楼主 这个可不可以通过单片机读取PWM,然后在LCD显示出音频的频谱呢?

可否给个简单的思路呢?
--------------------------------------------------



这个不是读PWM,而直接读wav文件,对wav数据进行数学变化,可以分析频谱。这个算法用单片机实现不了,DSP或许可以。

xh2010 发表于 2012-4-28 09:29:59

滤波电路是不是不到位?
发电路来看看!

wicy001 发表于 2012-4-28 10:10:16

RC电路附上

wicy001 发表于 2012-4-28 13:19:39

wicy001 发表于 2012-4-28 10:10 static/image/common/back.gif
RC电路附上

端口输出的PWM经过RC前后的仿真波形。

wicy001 发表于 2012-4-28 13:25:10

如何去掉图一中的尖刺?

mobile01 发表于 2012-4-28 17:15:00

wicy001 发表于 2012-4-28 13:25 static/image/common/back.gif
如何去掉图一中的尖刺?

请问你是否有 Proteus 范例?另外你的Proteus是第几版本?

wicy001 发表于 2012-4-28 20:07:31

mobile01 发表于 2012-4-28 17:15 static/image/common/back.gif
请问你是否有 Proteus 范例?另外你的Proteus是第几版本?

有范例,proteus V7.5

mobile01 发表于 2012-4-28 21:48:20

wicy001 发表于 2012-4-28 20:07 static/image/common/back.gif
有范例,proteus V7.5

你说的是proteus内部范例吗?但是找不到?{:sad:}

wicy001 发表于 2012-4-28 22:15:51

我以为你说是poteus自己内部的sample。

附件是范例。

if_else 发表于 2012-4-29 00:04:02

原来我用51做过类似的实验,也是噪声大,我用收音机的音频变压器做低通效果好一些.

wicy001 发表于 2012-4-29 15:14:53

if_else 发表于 2012-4-29 00:04 static/image/common/back.gif
原来我用51做过类似的实验,也是噪声大,我用收音机的音频变压器做低通效果好一些. ...

用音频变压器能到什么程度? 我感觉音频变压器主要用来变换音频信号电压的,滤波效果不应该很强。

我现在用RC电路,一方面起到滤波作用,另一方面由于加入电阻,使信号变弱了,整体的效果是声音和背景噪声信号强度都削弱了,使背景噪声变得不那么刺耳而已,但是滤波效果不明显,背景噪声依然存在。

wicy001 发表于 2012-4-29 16:00:59

今天尝试从电路和软件上看看能否消除毛刺
1.软件调试时,在中断判读BEEP,始终不能进入counter++语句,counter不变化。查stc数据手册,问题可能是由于刚给BEEP(P0.0)端口赋值,而端口还没有变化,就读端口,造成误差。这样另加了一个bit变量,与BEEP同步,调试通过。

2.硬件上,不再采用直接加5V的接法,变为上拉电阻方式,使其有公共接地端,以尽量减少噪音。

做完改动后,还是有背景噪声,比以前有一点点的提高。

xwkm 发表于 2012-4-30 12:38:07

干脆用da的了
用pwm很费cpu时间

wicy001 发表于 2012-5-1 09:36:10

xwkm 发表于 2012-4-30 12:38 static/image/common/back.gif
干脆用da的了
用pwm很费cpu时间

纯定时器做的PWM确实费时间,带PCA,PWM的还是可以用一用的。

backup 发表于 2012-5-1 13:36:37

不懂,但是感兴趣,关注!

weixinal 发表于 2012-5-1 16:25:26

刚做了个实验,用c8051f340做pwm模拟da输出wav,刚开始pwm在6k的时候高频噪声很大,试着提高单片机时钟到12M,增加延时,这时候的声音效果特别好,不是几乎听不到噪声,是一点噪声也没有,但是pwm频率就不能测出了,我示波器是5MHz的,五一结束去测下频率

结论是什么呢,pwm模拟音频da,完全可行!

wicy001 发表于 2012-5-1 18:04:30

weixinal 发表于 2012-5-1 16:25 static/image/common/back.gif
刚做了个实验,用c8051f340做pwm模拟da输出wav,刚开始pwm在6k的时候高频噪声很大,试着提高单片机时钟到12 ...

期待。
直接用C8051F做一出来,分享一下,看看效果如何。

weixinal 发表于 2012-5-1 20:40:02

正在处理,稍后上传吧

weixinal 发表于 2012-5-1 20:45:39

http://www.tudou.com/programs/view/7ZCNyB-Hbw4/

weixinal 发表于 2012-5-1 20:47:02

本帖最后由 weixinal 于 2012-5-1 20:48 编辑

应该是这样贴视频吧,试下
http://www.tudou.com/v/7ZCNyB-Hbw4/&rpid=12538900&resourceId=12538900_04_05_99/v.swf

wicy001 发表于 2012-5-2 07:50:58

weixinal 发表于 2012-5-1 20:47 static/image/common/back.gif
应该是这样贴视频吧,试下

声音效果很好,谢谢分享。

请问,MCU端口是直接与小音箱相连的吗?还是中间加了什么? 视频中看不太清楚。

chess01 发表于 2012-5-2 08:14:20

PWM频率8KHz,太低了,至少得大于20K,你把定时器设为1T模式试试

yanglong5918 发表于 2012-5-2 09:18:00

楼主的问题解决了没

wicy001 发表于 2012-5-2 09:23:44

chess01 发表于 2012-5-2 08:14 static/image/common/back.gif
PWM频率8KHz,太低了,至少得大于20K,你把定时器设为1T模式试试

嗯。STC90/89不支持1T,最大支持6T,我可以试一下。

播放8KHz的wav,按理说接着8Khz输出是可以的。

wicy001 发表于 2012-5-2 09:28:26

yanglong5918 发表于 2012-5-2 09:18 static/image/common/back.gif
楼主的问题解决了没

根据楼上几位所讲的,应该是PWM输出频率的问题。

PWM的频率越高,尖刺就会越窄,频率达到一定程度,尖刺可以近似消除,这样就听不出背景噪音了。

weixinal 发表于 2012-5-2 15:35:27

直接接小音箱的输入端,音响内部有功放的,我自己是用耳机试验的,为了让大家听清楚才接音响的,今天实测频率47k,wicy001说的没错,频率达到一定数值,尖刺可以消除

wicy001 发表于 2012-5-2 15:51:44

weixinal 发表于 2012-5-2 15:35 static/image/common/back.gif
直接接小音箱的输入端,音响内部有功放的,我自己是用耳机试验的,为了让大家听清楚才接音响的,今天实测频 ...

你太给力了,全靠你的测试了。

weixinal 发表于 2012-5-2 16:03:31

wicy001 发表于 2012-5-2 15:51 static/image/common/back.gif
你太给力了,全靠你的测试了。

最近在做这方面的东西,学校实验室也有示波器,比较方便

wicy001 发表于 2012-5-2 21:16:42

我用STC90C516RD+,24.576晶振,6T模式,可以在一个采样时间内输出2次,即PWM频率为16KHz,可以消去尖锐的背景噪音,同时加上RC低通滤波,音效还是可以的。

yanglong5918 发表于 2012-5-3 11:13:59

我用STC12C5A60S2实验成功,11.0592晶振,定时器0频率18K,PWM输出频率21K,音质很好…
PS:为什么接上TDA2003,2003会非常烫,昨天搞挂2片了

wicy001 发表于 2012-5-3 11:51:04

yanglong5918 发表于 2012-5-3 11:13 static/image/common/back.gif
我用STC12C5A60S2实验成功,11.0592晶振,定时器0频率18K,PWM输出频率21K,音质很好…
PS:为什么接上TDA2 ...

贴个电路图上来,分析一下。

weixinal 发表于 2012-5-3 12:05:04

pwm出来经过低通滤波再进功放吧,也可能功放电路有问题,试着接入正常音频信号源试下

mfkqtd 发表于 2012-11-8 15:51:38

兄弟啊,能不能把你做的那个STC单片机播放WAV的资料程序发给我啊,小弟现在在做这些方面的东西.急需这方面的资料.    15215193@qq.com                      先谢谢啦

wicy001 发表于 2012-11-8 16:10:51

mfkqtd 发表于 2012-11-8 15:51 static/image/common/back.gif
兄弟啊,能不能把你做的那个STC单片机播放WAV的资料程序发给我啊,小弟现在在做这些方面的东西.急需这方面的 ...

程序都在楼主位贴出来了。

而且还打了个包提供下载,其他也就没什么了。

wuyiduan 发表于 2012-11-26 15:01:34

有几个问题:
1.低通滤波的参数,阻容值怎么确定
2.当PWM很高,比如44K以上了,2个相邻的音差距较大的时候,RC会不会使音频失真?
3.WAV的值是8位还是16位的,如果是8位的那么用16位的PWM就得传给高8位寄存器了
4.一个44K的WAV文件,用44K的PWM,是不是取一个WAV的值进行一次PWM转换,再取下一个进行一次转换。每个值只转换一次?
如果用88K的PWM进行2次输出会不会音质好点?

wicy001 发表于 2012-11-26 21:49:09

wuyiduan 发表于 2012-11-26 15:01 static/image/common/back.gif
有几个问题:
1.低通滤波的参数,阻容值怎么确定
2.当PWM很高,比如44K以上了,2个相邻的音差距较大的时候 ...


1.低通滤波器的参数:
通常人声和乐器的频率在4kH以内(我查的最高是女高音为3.6Khz),截止频率可以设为f=4K=1/(2πRC)
R取值1-10K之间,计算出C的值。
RC网络本身就不是精准的网络,不必强求RC的值,从音效上,听不出多大的差别。
其实只要不是直流,各个频率经过RC时,幅度都会有衰减。在截止频率时,幅度衰减到原来的0.7而已。


2.这种RC肯定有失真的。RC的作用主要是DA变换,顺便过滤一部分杂音。

3.可以看WAV文件格式标准,有8位wav和16位wav。无论那种,WAV的数据都是以字节的形式存储的,16Bit是低字节在前,高字节在后。

4.PWM的频率越高过滤的效果越好,但是44K与88K的效果差别多少,没做过实验,就不知道了。
我个人分析:如果截止频率设在4K,一般情况PWM超16K以后的效果可能就不是很明显了。再加上人耳接收频率最大20K,所以44K足够了。

liangjiatian 发表于 2012-11-28 16:34:50

不知道是什么原理如果能详细讲解一下 就好了{:mad:}

lcmdw 发表于 2012-11-28 21:44:26

mark{:smile:}

wuyiduan 发表于 2012-11-29 08:42:41

PWM频率就是音频文件的采样频率,那么只靠8位的PWM的占空比等效出256种电压值就能表示出大千世界这么多种声音?
比如高音低音,节拍,每个字的发音...
我们所说的高音是指什么?模拟的频率高?
节拍是不是音速的快慢?

wicy001 发表于 2012-11-29 10:07:17

wuyiduan 发表于 2012-11-29 08:42 static/image/common/back.gif
PWM频率就是音频文件的采样频率,那么只靠8位的PWM的占空比等效出256种电压值就能表示出大千世界这么多种声 ...


音频信号是一段模拟信号(包含音高,节拍),对这段音频采样就可以得到数字信号。

如果以8KHz的频率,8位的精度(256种电压)采样后,按照wav的格式存储起来,就是我们平时播放的wav文件了。

我们知道采样频率越快,采样精度越高,那么文件的音质就越好。当频率和精度达到一定程度时,人耳就分辨不出来了。

44khz,16位精度已经达到CD的音质了,基本上也就可以了。

我们用PWM播放文件,就是按照采样的频率,采样的精度将数字文件还原成模拟音频。

所以在播放时,你不需要考虑节拍,音高的问题。

我们所说的高音,就是模拟音频的高音。

wuyiduan 发表于 2012-11-29 10:10:38

谢谢解惑

wuyiduan 发表于 2012-11-29 10:12:06

另外能不能讨论一下,低通滤波和声音放大的电路
最好是能不用运放,就用电阻电容三极管这类的便宜的器件
呵呵

wicy001 发表于 2012-11-29 11:04:27

wuyiduan 发表于 2012-11-29 10:12 static/image/common/back.gif
另外能不能讨论一下,低通滤波和声音放大的电路
最好是能不用运放,就用电阻电容三极管这类的便宜的器件
呵 ...

呵呵,这个玩不了。

canidream 发表于 2012-12-5 10:23:32

先收集,回头再看。。。

wuyiduan 发表于 2012-12-7 20:37:53

今天用洞洞板做了一个
STM8S103F3,16M内部RC
PWM频率62500,经过2K电阻驱动三极管,5V接喇叭再到三极管集电极,射极到地,用示波器看了脉冲有尖峰,用个1N4007续流就好点了。三极管深度饱和。用你的WAV数据,每个播放8次,杂音倒是没听到什么,就是有2个问题:
1.声音很小,好像有点含糊。用个纸杯贴在纸杯底部声音能在3M处听到,不过环境要安静
2.喇叭播了十几分钟就有点热了,不是很烫的那种,就是有点温度,电流210MA


受限于MCU的容量,采样频率肯定上不去,要么加外部存储,要不用串口一边下一边放


还有个问题:把PWM做DA转换的电路应该叫积分电路更贴切吧

wuyiduan 发表于 2012-12-7 20:39:03

wicy001 发表于 2012-11-29 11:04 static/image/common/back.gif
呵呵,这个玩不了。

今天用洞洞板做了一个
STM8S103F3,16M内部RC
PWM频率62500,经过2K电阻驱动三极管,5V接喇叭再到三极管集电极,射极到地,用示波器看了脉冲有尖峰,用个1N4007续流就好点了。三极管深度饱和。用你的WAV数据,每个播放8次,杂音倒是没听到什么,就是有2个问题:
1.声音很小,好像有点含糊。用个纸杯贴在纸杯底部声音能在3M处听到,不过环境要安静
2.喇叭播了十几分钟就有点热了,不是很烫的那种,就是有点温度,电流210MA


受限于MCU的容量,采样频率肯定上不去,要么加外部存储,要不用串口一边下一边放


还有个问题:把PWM做DA转换的电路应该叫积分电路更贴切吧

wicy001 发表于 2012-12-8 08:35:37

喇叭的驱动不足,导致声音很小。

常见的喇叭都1-2W,正常工作起来,声音是很大的。但是你的喇叭功率已经达到5V*210A>1W了,声音不应该像你说的那么小。
你在确认一下:
1.5V的电压是否全部加在了喇叭上? 中间是否有电阻分压了?
2.喇叭的功率是多大,如果远大于1W,声音会小
3.确定一下三级管的参数,通常用的9013,9014最大驱动0.5W的设备。

wicy001 发表于 2012-12-8 09:17:57

电流210M比较正常。如果按照2W喇叭算,工作电流可达2W/5V=400ma,1W喇叭是200ma。

你可以改变一下电路,加上电容,看看效果。

vb65f4 发表于 2012-12-10 17:35:53

支持楼主

wx85105157 发表于 2012-12-12 16:34:59

wuyiduan 发表于 2012-12-7 20:37 static/image/common/back.gif
今天用洞洞板做了一个
STM8S103F3,16M内部RC
PWM频率62500,经过2K电阻驱动三极管,5V接喇叭再到三极管集 ...

不能用直流驱动。你要用电容耦合过去来驱动喇叭。

wuyiduan 发表于 2012-12-13 10:58:39

本帖最后由 wuyiduan 于 2012-12-13 11:27 编辑

wicy001 发表于 2012-12-8 08:35 static/image/common/back.gif
喇叭的驱动不足,导致声音很小。

常见的喇叭都1-2W,正常工作起来,声音是很大的。但是你的喇叭功率已经达 ...

8欧 0.5W,直径3CM的喇叭
三极管8050
没用电阻分压限流
在喇叭上并了一个104和一个105和一个续流二极管4007,不加二极管会有很高的尖峰
按照喇叭的参数计算,电压2V就可以了
看了三极管CE电压波形是三角波,1.2~5V,振幅是3.8V
喇叭两端的波形也是三角波,0.3~3.5V,振幅3.2V
单片机输出波形是方波0~5V

wicy001 发表于 2012-12-13 11:42:36

wuyiduan 发表于 2012-12-13 10:58 static/image/common/back.gif
8欧 0.5W,直径3CM的喇叭
三极管8050
没用电阻分压限流


现在的效果如何?


从喇叭的参数来看,以前喇叭过载了,所以会发热。

wuyiduan 发表于 2012-12-13 11:54:13

电路一直没改动
直流源显示的电流还是220MA
声音也很小,照样发热

wicy001 发表于 2012-12-13 12:09:04

wuyiduan 发表于 2012-12-13 11:54 static/image/common/back.gif
电路一直没改动
直流源显示的电流还是220MA
声音也很小,照样发热

我画了个图,现在传不上去。吃完饭再试试。

wuyiduan 发表于 2012-12-13 12:49:45

我的KK: 1 9 0 5 5 7 5 1 1

wicy001 发表于 2012-12-13 13:04:43

wuyiduan 发表于 2012-12-13 12:49 static/image/common/back.gif
我的KK: 1 9 0 5 5 7 5 1 1




上拉的阻值建议初始1K,根据效果增大或减小,最小值要保证不能烧了三极管
电容一定要大容量的,推荐100uf以上(这个是用来增加驱动力的)

wicy001 发表于 2012-12-13 13:06:38

上面的电路没有经过测试, 你实验出结果,说明一下。

wicy001 发表于 2012-12-13 13:07:43

R2用电位器调节最适合了。

ru_king 发表于 2012-12-13 15:22:33

不错 挺妙的!

wuyiduan 发表于 2012-12-15 19:05:26

改接后听不见
可能是焊接的问题

wuyiduan 发表于 2012-12-15 19:05:53

也有可能是电流大部分走三极管了

wuyiduan 发表于 2012-12-15 19:06:52

这种方式是不是不适合驱动喇叭,真不知道外面儿童玩具车上的喇叭怎么驱动的

wicy001 发表于 2012-12-16 11:33:56

wuyiduan 发表于 2012-12-15 19:06 static/image/common/back.gif
这种方式是不是不适合驱动喇叭,真不知道外面儿童玩具车上的喇叭怎么驱动的 ...

我以前拆过玩具,就是三极管驱动的。

把我那个电路中,电容和喇叭串联,再试试。 电容的正极接三极管C端

wuyiduan 发表于 2012-12-16 22:40:23

这个电路能否驱动8欧1W或者0.5W的喇叭,音量是否可以满足童车级别,就是很多便利店门口放着给儿童做着一边摇一边唱歌的那种。

wicy001 发表于 2012-12-17 08:15:41

wuyiduan 发表于 2012-12-16 22:40 static/image/common/back.gif
这个电路能否驱动8欧1W或者0.5W的喇叭,音量是否可以满足童车级别,就是很多便利店门口放着给儿童做着一边 ...

有些玩具是用蜂鸣器来做的,蜂鸣器比较容易驱动,几十毫安就可以,缺点就是声音不够圆润。

驱动1W喇叭,三极管可以实现。或者直接用个UNL2003。

wuyiduan 发表于 2012-12-17 14:59:01

今天把并在喇叭上的电容去掉,声音更响点
把电容串进去只能是如果用极性电容没声音,用无极限的22UF的有点小声音
呵呵
明天买个大点的喇叭

wuyiduan 发表于 2012-12-17 15:00:45

我拆开一个玩具0.58W8 欧的喇叭,那叫一个响啊,整个房间的人都受不了
用了一个音频功放
型号忘记了

wicy001 发表于 2012-12-18 08:49:17

wuyiduan 发表于 2012-12-17 14:59 static/image/common/back.gif
今天把并在喇叭上的电容去掉,声音更响点
把电容串进去只能是如果用极性电容没声音,用无极限的22UF的有点 ...

嗯。现在有声就好。

但是对于你最初的电路,电流也很大,为什么没有声音呢?一直没想通呀。不知道现在有声的时候电流是多大?

wicy001 发表于 2012-12-18 09:06:22

wuyiduan 发表于 2012-12-17 15:00 static/image/common/back.gif
我拆开一个玩具0.58W8 欧的喇叭,那叫一个响啊,整个房间的人都受不了
用了一个音频功放
型号忘记了


这与喇叭的设计也有很大关系。不同的厂家,做出来的也不一样,有的喇叭就是很响。

至于功放你可以先试试TDA2822M,TDA2030A 。 这是入门级的。

sbiigu5211314 发表于 2012-12-18 09:44:40

楼主的问题多看看视频就懂的
单片机学习视频免费下载地址:http://item.taobao.com/item.htm? ... &id=21688772847

国防大学 发表于 2013-3-19 20:57:42

wicy001 发表于 2012-4-27 20:26 static/image/common/back.gif
自己沙发

楼主你好,小弟有两句看不懂,希望你能给指点一下               

if(BEEP)
{
   TH0=0xFF-currentdata;//这里为什么要0xFF-currentdata?               
else
{
   TH0=currentdata;
}

wicy001 发表于 2013-3-19 21:39:34

国防大学 发表于 2013-3-19 20:57 static/image/common/back.gif
楼主你好,小弟有两句看不懂,希望你能给指点一下               

if(BEEP)


单片机每计数0-127,就是一个PWM周期。
WAV中的音频数据currentdata代表一个PWM周期内高电平的计数值(也就是高电平的时间),那么0XFF-currentdata代表低电平的计数值(也就是低电平时间)。

刚才想到,这样会不会高电平多计一个数,低电平少计一个数。

国防大学 发表于 2013-3-20 15:40:39

wicy001 发表于 2013-3-19 21:39 static/image/common/back.gif
单片机每计数0-127,就是一个PWM周期。
WAV中的音频数据currentdata代表一个PWM周期内高电平的计数值(也 ...

谢谢楼主!
我现在想用stc12c5a60s2的硬PWM做PWM转DA输出WAV音频实验,看了stc12c5a60s2的datasheet,上面说CCAP0L,CCAP0H,是控制PWM0的占空比的。我将PWM频率设成43.2Khz,将WAV音频数据直接赋给CCAP0L和CCAP0H,楼主帮忙看看我这个程序可行不?

#include "stc12xxx_reg.h"
#include "sound.h"

unsigned int counter,wavedataL;
unsigned char currentdata,nextdata,i;
unsigned int tmp;

void PWM_Init(void)
{
        CMOD = 0x80;//将PWM时钟源设成系统时钟11.0592MHZ,即PWM时钟频率为11.0592/256=43.2khz
        CCON = 0x00;
        CCAPM0 = 0x42; //8位PWM输出,无中断
}

void main(void)
{
        tmp=sound;                           //从wav文件中取,数据长度。数据长度应该是4个字节,
        tmp=tmp<<8;
        wavedataL=tmp+sound;//由于wav存在片内flash中,文件大小有限制,数据长度用int型足够表示了。
       
        counter=0x2c;          //wav文件第一个数据
       
//        currentdata=sound;       
//        nextdata=sound;
        PWM_Init();

        CR = 1;

        while(1)
        {
                CCAP0L = sound;
                CCAP0H = sound;
                counter++;

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

这个东西我搞了大半年了,直到看到楼主的帖子才有点头绪,望楼主能帮帮忙,小弟在这谢谢了

wicy001 发表于 2013-3-20 17:58:08

国防大学 发表于 2013-3-20 15:40 static/image/common/back.gif
谢谢楼主!
我现在想用stc12c5a60s2的硬PWM做PWM转DA输出WAV音频实验,看了stc12c5a60s2的datasheet,上 ...

我以前做的有。给你一个参考下吧

keil4版本的

wicy001 发表于 2013-3-20 18:10:48

while(1)
      {
                CCAP0L = sound;
                CCAP0H = sound;
                counter++;
               ……
               ……
                }
你在while中,用上counter++ ,一个时钟counter加一次,会是什么效果? 你参考我的程序,再理解一下PWM吧

国防大学 发表于 2013-3-21 08:39:14

wicy001 发表于 2013-3-20 18:10 static/image/common/back.gif
while(1)
      {
                CCAP0L = sound;


真是太谢谢楼主了!看了楼主的程序恍然大悟,以后还要像楼主多学习,昨天仔细研究了楼主的程序,然后自己又写了 个,竟然可以了!真是太神奇了,谢谢楼主!

wicy001 发表于 2013-3-21 11:38:31

国防大学 发表于 2013-3-21 08:39 static/image/common/back.gif
真是太谢谢楼主了!看了楼主的程序恍然大悟,以后还要像楼主多学习,昨天仔细研究了楼主的程序,然后自己 ...

很高兴,能够帮到你。{:biggrin:}

xwkm 发表于 2013-3-21 18:51:06

wicy001 发表于 2012-5-2 09:23 static/image/common/back.gif
嗯。STC90/89不支持1T,最大支持6T,我可以试一下。

播放8KHz的wav,按理说接着8Khz输出是可以的。 ...

8K的WAVE文件是指采样率8K。而不是载波频率8K.对于这种东西载波频率得弄到人耳听不到的频率,比如说8K至少得32k的PWM.44K至少得100k的PWM。

lr120363092 发表于 2013-4-28 16:57:35

wicy001 发表于 2012-5-2 09:23 static/image/common/back.gif
嗯。STC90/89不支持1T,最大支持6T,我可以试一下。

播放8KHz的wav,按理说接着8Khz输出是可以的。 ...

播放8KHZ的WAV,如果PWM超过了8Khz,那播放出来的 声音不是被加快播放了??就是说话变快了

xwkm 发表于 2013-4-29 02:00:46

lr120363092 发表于 2013-4-28 16:57 static/image/common/back.gif
播放8KHZ的WAV,如果PWM超过了8Khz,那播放出来的 声音不是被加快播放了??就是说话变快了 ...

PWM只是载波而已。
8kHz的WAVE指的是对占空比,或者说有效功率的改变量是8K次。对载波频率没有要求。对于8K的WAVE的话,20K的PWM载波是起步价(注意某些人,比如我能听到23k左右的声音,那种尖锐的令人头疼的声音,在这个PWM输出的下面要接个RC滤波。中心频点在4K左右就可以了)。
如果你要播放 CD音质的WAVE的话。对不起,PWM载波频率至少要100k。这个就别软件模拟了。老实用硬件PWM吧。

wicy001 发表于 2013-4-29 07:56:54

lr120363092 发表于 2013-4-28 16:57 static/image/common/back.gif
播放8KHZ的WAV,如果PWM超过了8Khz,那播放出来的 声音不是被加快播放了??就是说话变快了 ...

8Khz的wav,如果PWM也是8K,那就是每个PWM的周期播放一个WAV数据,播放出来的WAV就是8Khz,正常语速

如果PWM是16K,WAV数据需要要PWM连续播放2次,再播放下一数据,这样播放出来WAV也是8Khz,正常语速,如果一个PWM周期仍播放一个WAV,语速就会快一倍。


人耳听得的范围在20K以内,所以PWM频率超过20K,基本上就听不到杂音(主要指PWM自身的杂音),效果还是可以的。如果对音效要求高,则可以提高PWM频率。

wicy001 发表于 2013-6-13 19:15:26

gamethink 发表于 2013-6-13 14:27 static/image/common/back.gif
请教LZ,WAV记录的音频数据是有分正/负的,比如8位,究竟如何和PWM的0-255关联起来? ...

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

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

bg4gzu 发表于 2013-6-14 09:21:47

RC滤波改为LC滤波。
效果会好一些。电感可选用33uH,对地电容用0.47uF左右。可以适当增加电感来改变低通频率。

vbvc6 发表于 2013-6-15 12:17:38

我用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++;
        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 发表于 2013-6-16 08:25:00

vbvc6 发表于 2013-6-15 12:17 static/image/common/back.gif
我用LMF4L120试了下,效果差的很,有很明显的尖噪音,我直接用IO驱动蜂鸣器,接音响效果好点,但噪声依然很大
50 ...

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

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

chess01 发表于 2013-6-16 10:37:23

2003要用交流耦合

vbvc6 发表于 2013-6-16 12:44:52

wicy001 发表于 2013-6-16 08:25 static/image/common/back.gif
LMF4L120是什么MCU?程序看不懂。

根据经验,不加滤波,播放wav,音质也是很清晰的。 导致噪音的原因有最 ...

写错了,是LM4F120,TI的cortex-M4单片机,PWM频率,应该很高了,用音箱试过,效果是好些,但也有明显的噪音,同样的WAV,用脑放就没噪声,8K*8bit

wicy001 发表于 2013-6-16 15:15:17

vbvc6 发表于 2013-6-16 12:44 static/image/common/back.gif
写错了,是LM4F120,TI的cortex-M4单片机,PWM频率,应该很高了,用音箱试过,效果是好些,但也有明显的噪音,同 ...

对于8bit 8hz的数据来说,IO端口要将每个数据PWM输24.4次才可以(可以粗略的输出24次)。你是否是这样输出的?


vbvc6 发表于 2013-6-16 15:23:02

为什么是24.4次? 有什么算法?请明示下,谢谢

现在每个数据,输出次数,为 50M/256/8000=24次

vbvc6 发表于 2013-6-16 15:28:57

知道了,计算器没设置好,只有整数了
50M/256/8000=24.41次
不过,这个是硬件PWM,代码只是以8K的速率给它发一个占空比的数据而已

wicy001 发表于 2013-6-16 16:40:36

vbvc6 发表于 2013-6-16 15:28 static/image/common/back.gif
知道了,计算器没设置好,只有整数了
50M/256/8000=24.41次
不过,这个是硬件PWM,代码只是以8K的速率给它发一 ...



你仔细对比一下两者的差别。 如果只以8K的频率发送脉冲,虽然你的端口是50M,端口输出的PWM的频率也只有8k(这种情况就是我原本帖子里求助的情况,PWM频率太低了)。
如果PWM频率是8K*24的话,那么每T=1/8K的时间里,应该发送24个脉冲才对。
页: [1] 2
查看完整版本: 【求助】PWM转DA输出WAV音频的一个小程序