14445|20

640

帖子

0

TA的资源

五彩晶圆(初级)

楼主
 

在LPC1343上利用2个16位的PWM输出做音频输出,源代码和那个bg.wav文件见附件 [复制链接]

在LPC1343上利用2个16位的PWM输出做声音频输出

  今天(星期六)我利用LPC1343的PWM做音频输出,并成功的循环播放了SD卡上的bg.wav歌曲(刘德华的《今天》)。播放十分流畅,高音低音丰富,现在边听《今天》边发贴,感觉还不错。


  下面是步骤和各部分代码,和大家共享,全部代码和那个bg.wav文件见附件:


硬件改造部分:


    0、今天先做单声道的。将一般的耳机的两根线直接焊接到开发板的P1_9和GND。这样我们就给LPC1343开发板加了一个耳机接口,以后他将为你提供动听的音乐。


    可能有人会问:PWM出来的是PWM脉冲,你不滤波啊?其实可以不需要,只要你脉冲频率能够超出耳机的响应范围,他不会带来太大问题。当然有更好,我以后慢慢加。


    至此硬件改造结束。


软件部分:


    1、我用LPC1343的两个16位计时器(你可以选择LPC1343里4个计时器任何两个):一个提供PWM输出;一个做定时器。


    2、PWM输出计时器在这里作为DAC,输出音频。我用了TIMER16_B1_MAT0,输出对应管脚P1_9。


  //PWM初始化设置
  unsigned short pwmizhouqi=256; //10000;
  LPC_TMR16B1->TCR = 0;   //关闭timer16B1
  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<8);  //只有提供了timer16B1的时钟后才能操作timer16B1
  LPC_TMR16B1->TCR = 0;   //关闭timer16B1
  //LPC_TMR16B0->EMR = (1<<EMC3)|(1<<EMC2)|(1<<EMC1)|(1<<EMC0)|(1<<3)|0x01;
  //1、将引脚PIO1_9设为CT16B1_MAT0功能:IOCON_PIO1_9[2:0]=B001
  LPC_IOCON-> PIO1_9=0X01;
  //2、设置CT16B1_MAT0的匹配值:设置TMR16B1MR0值      TMR16B1MR0=空白数
  LPC_TMR16B1->MR0 = pwmizhouqi/2;  //空闲期
  //3、将CT16B1_MAT0的PWM模式打开:TMR16B0PWMC[0]=1
  LPC_TMR16B1-> PWMC = 0x01; //注意:PWM周期的复位由MCR决定,而不是PWMC控制MAT3决定
  //4、设置予分频寄存器
  LPC_TMR16B1-> PR=0;  //为0不予分频
  //5、设置如果MR3和TC匹配,TC复位:TMR16B1MCR[10]=1
  LPC_TMR16B1->MCR = 0x0400;
  //6、设置CT16B0_MAT3的匹配值:设置TMR16B0MR3值      TMR16B0MR3=周期长度
  LPC_TMR16B1->MR3 = pwmizhouqi;  //PWM周期
  //7、设置计数控制寄存器选择计时器模式(每个PCLK上升沿):TMR16B0CTCR[1:0]=B00;也可以选择其他值为CAP引脚
  LPC_TMR16B1->CTCR = 0x00;
  //8、启动计数:TMR16B0TCR[0]=1
  LPC_TMR16B1->TCR |= 1;


   3、另一个定时器TMR16B0根据WAVE文件的采样率而发生定时中断,定时控制输出PWM脉冲宽度。


 //将TIMER0初始化成24000的中断,每计数到3000中断一次修改LPC_TMR16B1->MR0
  nextreadpwm=512;
  LPC_TMR16B0->TCR = 0;   //关闭timer16B1
  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);  //只有提供了timer16B0的时钟后才能操作timer16B0
  LPC_TMR16B0->TCR = 0;   //关闭timer16B1
  //让MCR=0x03表示MR0匹配产生中断、复位
  LPC_TMR16B0->MCR = 0x03;
  //设置CT16B0_MAT0的匹配值:设置TMR16B0MR0值
   LPC_TMR16B0->MR0 = 3000;  //3000个周期
  //3、将CT16B0_MAT0的PWM模式关闭:TMR16B0PWMC[0]=0
  LPC_TMR16B0-> PWMC = 0x00; //注意:PWM周期的复位由MCR决定,而不是PWMC控制MAT3决定
  //4、设置予分频寄存器
  LPC_TMR16B0-> PR=0;  //为0不予分频
  //5、设置计数控制寄存器选择计时器模式(每个PCLK上升沿):TMR16B0CTCR[1:0]=B00;也可以选择其他值为CAP引脚
  LPC_TMR16B0->CTCR = 0x00;  //00
  //6、启动计数:TMR16B0TCR[0]=1
  NVIC_EnableIRQ(TIMER_16_0_IRQn);
  LPC_TMR16B0->TCR |= 1;


 

    4、两个计时器分工合作实现音频输出。


    5、我是在前面发帖说过的“利用LPC1343实现SPI接口读SD卡的文件系统”的基础上开发的(直接用了zhaojun_xf版主的成果,基本没有什么改动。hehe!)。主程序不断读取(播放)SD上的WAV文件。


   char isok=0;
   AppSystemInit();
   char tmpname[16]="bg.wav";
   while (1)
   {
       //读取SD卡文件: bg.wav,

       isok = AppFileRead(tmpname);
   }


    6、在TMR16B0的中断里,将读到的wav定时写入LPC_TMR16B1->MR0,发出声音。


void TIMER16_0_IRQHandler (void)
{
   LPC_TMR16B0->IR = 1;


   if (nextreadpwm>=BUFFER_SIZE)
       return;


   LPC_TMR16B1->MR0 = Buffer[nextreadpwm];
   nextreadpwm++;
   return;

}

[ 本帖最后由 zhdphao 于 2010-7-25 07:41 编辑 ]

sd-fat32-sound.zip

4.89 MB, 下载次数: 546

此帖出自NXP MCU论坛

最新回复

貌似没看到楼主wav文件解码的代码  详情 回复 发表于 2013-6-1 11:10
点赞 关注(1)
 

回复
举报

2751

帖子

0

TA的资源

裸片初长成(初级)

沙发
 
    ..
此帖出自NXP MCU论坛
 
 
 

回复

2641

帖子

0

TA的资源

五彩晶圆(中级)

板凳
 
谢谢分享,很有借鉴价值
此帖出自NXP MCU论坛
 
 
 

回复

640

帖子

0

TA的资源

五彩晶圆(初级)

4
 
SD部分我直接用了zhaojun_xf版主的成果,基本没有什么改动。特别感谢一下。
此帖出自NXP MCU论坛
 
 
 

回复

826

帖子

0

TA的资源

一粒金砂(中级)

5
 

这么厉害啊

很厉害啦!
此帖出自NXP MCU论坛
 
 
 

回复

5979

帖子

8

TA的资源

版主

6
 
  很有创意
此帖出自NXP MCU论坛
 
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 
 

回复

546

帖子

0

TA的资源

一粒金砂(高级)

7
 
我也有一块开发板,要去试试!
此帖出自NXP MCU论坛
 
 
 

回复

640

帖子

0

TA的资源

五彩晶圆(初级)

8
 

原帖由 wulei19880906 于 2010-7-25 15:44 发表 我也有一块开发板,要去试试!

    看大家都跃跃欲试,我说一下要注意的地方。

    由于这是建立在“LPC1343使用SD卡”的基础之上的,所以连接SD卡是必须的:

   

    SD卡兼容MMC卡,同样支持SPI方式读写。这里LPC1343是主机,SD是从机。

    SD卡连接方式:SSEL  -  P0.2       ---->    SD卡引脚1 CS

              SCK    -  P2.11     ---->    SD卡引脚5 CLK

              MISO  -  P 0.8       ---->   SD卡引脚7  DO (DO是从SD卡的角度)

              MOSI  -  P0.9       ---->    SD卡引脚2  DI (DI是从SD卡的角度)

              +3.3V                   ---->    SD卡引脚4  VDD

              GND                    ---->    SD卡引脚2、6 VSS

 

在上一张我以前用的SD卡接线图,图例用的是SD方式,大家只需要参考图的接线编号

 

所以我们要把SD卡座按以上连接方式焊接到LPC1343开发板上。

记得把压缩包里面的bg.wav拷贝到SD卡的根目录下面。

用LPCXpressot打开(impor) sd-fat32-sound.zip,其中的“usbhid_rom”就是这个项目。

 

 

[ 本帖最后由 zhdphao 于 2010-7-26 07:14 编辑 ]
此帖出自NXP MCU论坛
 
 
 

回复

826

帖子

0

TA的资源

一粒金砂(中级)

9
 

很强

这么厉害啊,好好学习!
此帖出自NXP MCU论坛
 
 
 

回复

1万

帖子

16

TA的资源

版主

10
 

楼主强下来学习下

 
此帖出自NXP MCU论坛
 
个人签名http://shop34182318.taobao.com/
https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
 
 

回复

720

帖子

0

TA的资源

纯净的硅(中级)

11
 
向你看齐啊……学习一下啊……:P
此帖出自NXP MCU论坛
 
 
 

回复

640

帖子

0

TA的资源

五彩晶圆(初级)

12
 

    谢谢大家鼓励,又想到了很多不完善和欠考虑的地方,会影响播放音质,周末会一并改正过来。 弄好了再发挥一下,呵呵!

    大家也把声音放出来,电路很简单啊!怎么没看到人出来交流一下。

    其实声音并非十分完美,但还不是很糟糕,以后用在仪器上播放语音提示还是不错的。在仪器上装SD卡并非不合理,我看见华为的设备都装两块CF卡了。

[ 本帖最后由 zhdphao 于 2010-7-28 08:01 编辑 ]
此帖出自NXP MCU论坛
 
 
 

回复

640

帖子

0

TA的资源

五彩晶圆(初级)

13
 
电路就是焊接一个SD卡座和一个耳机到LPC1343开发板上。
众人拾柴火焰高,如果大家都发挥一下,音质肯定完美。
此帖出自NXP MCU论坛
 
 
 

回复

15

帖子

0

TA的资源

一粒金砂(初级)

14
 

学习

你好牛啊,学习
此帖出自NXP MCU论坛
 
 
 

回复

640

帖子

0

TA的资源

五彩晶圆(初级)

15
 

一边发声一边读取数据,MCU忙得过来吗?

    做好以后,一直有个疑问:SD读取缓冲区是否跟不上MCU的发声的数据消耗,而造成瞬时MCU等待发声数据。

    于是我在程序里加上显示断流的部分:

             1、用开发板上唯一的资源LED显示,有数据时关闭LED显示;

                                             GPIOSetValue( LED_PORT, LED_BIT, LED_OFF);

             2、发现音频数据断流点亮LED。

                                            GPIOSetValue( LED_PORT, LED_BIT, LED_ON );

    再次下载到开发板上运行, 惊讶的发现LED在不断的闪亮,断流的太频繁了。但是由于断流时PWM依然工作(输出电压依然是连续的),而且持续时间短,你不仔细听还听不出来。

    现在考虑修改读卡程序,采用两个SD卡数据缓冲区,让他们交替工作:

            1、第一次将两个缓冲区都填满,定义好:在用缓冲区 后备缓冲区

            2、负责发声的中断程序使用“在用缓冲区”发出声音。主程序同时判断“后备缓冲区”是否为空,为空就马上读数据。

            3、负责发声的中断程序发现“在用缓冲区”没有数据,马上将“后备缓冲区”设为“在用缓冲区”,“在用缓冲区”设为“后备缓冲区”,脚色互换。

            4、重复上面的2、3,以保证发声不中断。

[ 本帖最后由 zhdphao 于 2010-7-31 11:08 编辑 ]
此帖出自NXP MCU论坛
 
 
 

回复

640

帖子

0

TA的资源

五彩晶圆(初级)

16
 

    有了以上的方法音频播放就不会断流了,代码如下:

#define  BUFFER_SIZE  (512*6)                     // 缓冲区大小

 

  nextreadpwm=BUFFER_SIZE;
  bakbuffer=0;
  bakshu=0;
  nowbuffer=0;
  nowshu=0;
  needread=BUFFER_SIZE*2;
  do
  {
   if (bakshu==0)  //如果bakisfull为空
   {
    AppClearBuffer(0x00,bakbuffer);   // 缓冲清零
    if(f_read(&file, Buffer+bakbuffer, needread, &br))
    {
     return 0;
    }
    else
    {
     if (needread==BUFFER_SIZE*2) //循环的第一次读
     {
      needread=BUFFER_SIZE;  //以后只需要读BUFFER_SIZE;
      bakbuffer=BUFFER_SIZE;  //备用缓冲区在BUFFER_SIZE
      if (br>BUFFER_SIZE)
      {
       bakshu=br-BUFFER_SIZE;  //备用缓冲区有(br-BUFFER_SIZE)字节
       nowshu=BUFFER_SIZE;
      }
      else
      {
       nowshu=br;
      }
     }
     else
     {
      bakshu=br;    //
     }
     nextreadpwm=0;
     ii+=br;
    }
   }
   else
   {
    GPIOSetValue( LED_PORT, LED_BIT, LED_OFF );
    //__WFI();
   }
  } while (br);  // 判断是否读完(br == 0,表示读取完成)

  /*Close all files*/
      f_close(&file);    // 关闭文件,必须和f_open函数成对出现

 

 

    由于这是"小巧的LPC1114做图象开发板"工作的音频播放部分,所以这里以后不再另外更新了,一并归到:"小巧的LPC1114做图象开发板" 继续。

[ 本帖最后由 zhdphao 于 2010-7-31 19:59 编辑 ]
此帖出自NXP MCU论坛
 
 
 

回复

20

帖子

0

TA的资源

一粒金砂(中级)

17
 

关注

其实我倒觉得LPC1343做播放WAV的音频剩余的时间片应该不少,看一下wav的数据格式就知道很简单,基本上就是 读出SD卡的数据,做一个处理就可以送给PWM了,据我论证LPC1343在72M下应该可以软解码MP3了,网络上有软解码MP3的库,是将原来浮点计算的解码修改成了定点计算,所以很时候嵌入式应用,唯一不足的是可能LPC1343软解mp3 RAM不够。呵呵  我准备在LPC1768上实现!
不要说不可能哟 因为我有在ATMEL的M3上实现的软解mp3的源代码哟!
只是函数蛮多的 没有说明  目前还没有移植过来! 呵呵
此帖出自NXP MCU论坛
 
 
 

回复

2641

帖子

0

TA的资源

五彩晶圆(中级)

18
 

回复 17楼 dengxiaofeng 的帖子

M3软解码有点够呛,CPU不够,除非你自己能优化解压算法才行
此帖出自NXP MCU论坛
 
 
 

回复

12

帖子

0

TA的资源

一粒金砂(初级)

19
 
楼主很强啊 谢谢分享
此帖出自NXP MCU论坛
 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(初级)

20
 
最近在弄1343,感谢分享
此帖出自NXP MCU论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表