你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【我爱DIY】简易WAV播放器  

[复制链接]
creep 发布时间:2017-8-19 21:10
本帖最后由 creep 于 2017-8-22 08:56 编辑
2 k4 T! {/ x2 _( M  a6 v0 Y
1 e# d5 g1 ?; c      STM32F769-DISCO 上面有个WM8994可以用于音频解码。WM8994具有高性能低功耗体积小等优点,曾用在早期的三星安卓手机上用到。下面的测试主要是使用WM8994播放WAV文件。7 f' V- U. P. |* m
9 ^/ `- `! M- Z9 d+ Z0 ]
! H6 W) _# S; C" K% G2 r9 K# Q8 S
1、串行音频接口(SAI)
8 }. d' a" C  e& H9 j$ r6 H2 _SAI 接口(串行音频接口)灵活性高、配置多样,可支持多种音频协议。该接口适用于许多立体声或单声道应用。例如,它可配置为支持 I2S 标准、 LSB 或 MSB 对齐、 PCM/DSP、TDM 和 AC’97 等协议。将音频模块配置为发送器时, SAI 接口可提供 SPDIF 输出。SAI 通过两个完全独立的音频子模块来实现这种灵活性和可配置性。每个模块都有自己的时钟发生器和 I/O 线控制器。SAI 可以配置为主模式或配置为从模式。音频子模块既可作为接收器,又可作为发送器;既可与另一模块同步,又可以不同步。
* \. h8 H- z/ l& cSAI 主要由两个各自带有时钟发生器的音频子模块组成,每个音频模块集成一个 32 位移位寄存器,该寄存器由模块自身的功能状态机控制。数据存储和读取都是通过专用的 FIFO 来完成。 FIFO 可通过 CPU 访问,也可通过 DMA 访问以减轻 CPU 的通信负担。每个音频模块是独立的。这两个音频子模块可彼此同步。SAI 中指定音频模块的 4 个专用引脚IO口( SD、 SCK、 FS、 MCLK)。
: z; K( A2 d3 E9 \$ X3 P; P2 o- ~7 ]( l, i9 }
' T: _8 M2 ?2 A8 v
功能框图如下:, G" v+ _) D5 b; w, L' E
TIM截图20170819170314.png
% u$ A* h; Y1 b7 Q
: v& a# o1 Q. M5 f3 ?9 h! a7 [, }STM32F769-DISOC 上面的WM8994通过SAI1_Block_A和MCU进行解码数据通信,WM8994的初始化和各项配置则通过IIC实现。
+ C# Y% ]$ v+ p) J' S1 c# ~* k1 l( k8 [6 f( c& }

( T" y9 S$ d, ], m4 S TIM截图20170819171150.png
1 _2 J3 x" X* F$ S
# {4 Q& @5 _/ _( K! ]2、WAV格式文件
5 {! P* }+ s$ a2 P! s% i; [WAVE文件是计算机领域最常用的数字化声音文件格式之一,它是微软专门为Windows系统定义的波形文件格式(Waveform Audio)。WAVE是录音时用的标准的WINDOWS文件格式,文件的扩展名为“WAV”,数据本身的格式为PCM或压缩型。简单的理解WAV文件有一个文件头和数据部分组成,文件头里面包含该WAV的详细信息。一个典型的文件头格式如下:/ K: W: c% w+ h+ A4 [
TIM截图20170819173349.png
9 p0 M7 Q2 v- N5 ]9 B; Z9 f  ?; L3 M 这个文件头共有44字节,不同的格式文件头可能长度不同,为了方便处理我使用开源软件Audacity将WAV的头文件格式都转为相同的44字节模式,其他的参数为立体声44.1KHZ.
0 T. V0 u' S! C2 T. L% Y4 E: k7 c' X+ @. J8 `8 n( I8 t* A
) t/ x# S/ n! H+ R! p
TIM截图20170819175532.png 1 {6 Y' E' g0 {
) ~1 d' E/ z- Z4 N# j: D: f
3、软件解码
1 y  `- ^; M: z7 D; s6 K# H, X# S& G) g$ M
   播放的WAV文件放在TF卡里面,文件系统使用开源的FATFS,为了支持较长的歌曲名字,需要在FATFS中打开长文件名支持模式。同时为了支持中文显示,我把汉字点阵放到了
7 j4 s, I* D8 a5 l: z9 F3 dSTM32F769-DISCO 的外置NORFLASH里面,具体的操作可以查看之前的帖子。* U2 u; P/ L0 _7 Y. p) L: s
! ^, k/ E3 n+ L7 q5 ]* R" L
WAV的播放是使用DMA 循环模式把数据从SD卡搬送到codec进行解码,其中DMA使能了HalfTransfer和TransferComplete来不断的更新要解码的数据文件。+ t. D. i& l$ @6 e1 k8 M5 Y
最开始的时候先将要解码的缓存写满,然后开始DMA传输,当传输完成一半时在使能标记开始更新前半部缓存,等传输完成继续更新后半部分缓存,这样可以实现更新缓存和
' P0 a5 y2 H7 J) ]2 m界面数据“同时进行”,当然这样做的前提是更新缓存数据速度要快于解码的数据,通过测试STM32F7完全没有压力。
. g+ `4 ~: G8 n* m% M8 A: w  _' A4 H5 T
程序的流程如下:, x# K7 v: h# R  j# i) m
  • 先扫描SD卡找到WAV文件,将找到的WAV文件信息放入到一个链表中。
  • 显示找到的WAV文件名称到LCD上,并更新要播放的文件(名称为绿色字体)。
  • 根据预设的要播放的文件序号找到要要播放的WAV文件的信息,从SD卡里面读取填充播放缓存。
  • 开始播放WAV后不断的填充播放缓存直到播放完成。
  • 播放完成一个WAV文件后,根据播放模式(单曲循环、列表循环、随机循环)播放下一个WAV文件。
  • 播放的过程中可以通过用户按键切换下一个WAV文件进行播放。
    1 J. Y$ I4 E5 J: ^) w" }4 n

7 n1 q1 _$ x% {) L6 \, L程序下载后的:: T7 i9 j& j. [* S) ~/ f

0 `2 ^  ?; o# @2 g/ |1 d1 y IMG_0161.JPG
" |4 S# _5 f0 g( G1 S0 ?$ H5 f! A; |. @( F: i5 ]7 Y# ]( q; r6 J" G
使用按键切换歌曲:: z2 h8 x& L) y# w) Q* A

) H+ {7 y- z$ ]: _- Y  @: v) [ DJDL9465.GIF
& F; M! J/ q9 I  O( Y) M) P4 U+ L3 X9 G3 _7 M; i
mian 函数如下:; r, p3 {2 U! ]  s
  1.     _listfile_list *playfile;
    6 k0 n( |4 ]! _9 ?+ t$ F0 G% t
  2.     CPU_CACHE_Enable();
    5 X$ J2 h0 q& ]1 f
  3.     HAL_Init();
    ( }" f# U. n7 z0 |! @5 N9 [
  4.     SystemClock_Config();
    ; r4 ?+ \( a# @7 a7 j) \1 l" c
  5.     USART1_Init();
    % m6 O5 o0 X8 d# x, |7 c7 m
  6.     HAL_Delay(200);; U) g% w) T& a/ T8 z0 @) d8 m
  7.     BSP_LED_Init(LED_GREEN);" ]- a* @5 S; V5 G5 d
  8.     BSP_LCD_Init();7 I3 w% p& v0 P4 ^5 e7 h* F
  9.     BSP_LCD_LayerDefaultInit(0, LCD_FB_START_ADDRESS);) I: O3 {9 C. ~9 g$ e" q* S/ i
  10.     BSP_LCD_SetTextColor(LCD_COLOR_RED);
    # a2 U6 r$ y: i
  11.     BSP_LCD_SetBackColor(LCD_COLOR_BLACK);) b& L; N' a3 ?" v# x% y, c& h9 o
  12.     HAL_Delay(500);0 _8 m( L0 B7 O0 V  x0 U
  13.     BSP_QSPI_Init();
    # d4 I) h, t  l! ]% J
  14.     CopyFont2NorFlash();- y. X$ y( Z' ?: c8 n9 U" ~/ c& t4 D. R
  15.     BSP_QSPI_EnableMemoryMappedMode();+ j( A7 k6 ]; d7 X* g1 o$ q
  16.     CheckGBKFont4NorFlash();  `% E/ O  p- Q) F
  17.     BSP_LCD_Clear(LCD_COLOR_WHITE);
    + N" }2 x  b7 J; i
  18. 6 V- s5 R; q2 C- X1 u
  19.     FatFs_SD_Init();* W) c& q) ]) t. P$ S) Q& N' M" l
  20.     wavfilenum = ScanWavFiles("/");
    " p7 [7 d4 \0 h( O- J2 H; f# _
  21.     PrintfWavFileTest();
    * r9 c: S) t- A( Z1 E3 k
  22.     UpdateWavFileColor(playfilepos,playfilepos);& N( k" i+ V3 ~% e& Z  t
  23.     playfile = list_search(WavFileList, playfilepos);
    % i  L& |: d3 u* V9 p, ]8 w$ w

  24. + W0 W5 J0 A8 _% n
  25.     if(playfile == NULL)while(1);
    ' k& s! R4 N4 p9 i

  26. ; v7 X( ~1 X( S( F1 M* B9 w
  27.     //´) `# C. D1 ?6 \- I7 O. W
  28.     wavFileLen = OpendWavFile(playfile->filename);: s  c- t3 ~8 b5 u: u: A& \, y
  29.     //
    ' S0 z. Z% K6 M1 A( ?5 U
  30.     ReadWaveFile(BuffHead, PLAY_HEADER);. {8 v6 J" H# u% o' C: n3 H& T
  31.     //
    $ i( d3 `3 @0 f  x8 P( l5 v, k- F
  32.     ReadWaveFile((uint8_t *)PlayBuff, PLAY_BUFF_SIZE * 2);
    ) ]/ |& m4 o/ l4 I" h
  33.     Playback_Init();0 j8 H% V2 a; i) W
  34. 4 A4 z# P: C7 g$ e2 m7 j
  35.     /* Start the playback */
    - q+ v( P0 k1 h) u/ o' _
  36.     if(0 != audio_drv->Play(AUDIO_I2C_ADDRESS, NULL, 0))$ y. a# {1 t* a3 k+ V# X% L4 r
  37.     {
    + C- a5 w3 \* ~  a) e2 j4 S
  38.         while(1);
    : d) T; y4 |' x
  39.     }: E8 r0 k2 A/ C$ j/ {! C$ y1 ^# x7 Z
  40. , G4 P4 S) y* s( O3 b0 H0 X9 ^
  41.     if(HAL_OK != HAL_SAI_Transmit_DMA(&SaiHandle, (uint8_t *)PlayBuff, PLAY_BUFF_SIZE))' z/ y, r) \/ [1 [+ f
  42.     {' d; c" `( ~3 }' j+ N- [
  43.         while(1);
    , v7 ]2 G8 Z& Y- P& ]- {
  44.     }
复制代码
需要注意的是程序里面默认播放是44.1KHZ立体声的WAV文件,如果是其他的格式的要在播放之前更新SAI的配置。
/ l! x' M: w: @3 y
  1.    SaiHandle.Init.AudioMode      = SAI_MODEMASTER_TX;
    ; E  a7 S! A4 l7 f6 l) c6 {$ }3 y6 v& P
  2.     SaiHandle.Init.Synchro        = SAI_ASYNCHRONOUS;
      e7 v: o' e5 f' O+ B: s" k8 x7 E
  3.     SaiHandle.Init.OutputDrive    = SAI_OUTPUTDRIVE_ENABLE;1 |. a. [" }8 @
  4.     SaiHandle.Init.NoDivider      = SAI_MASTERDIVIDER_ENABLE;! h* m$ O( R, h
  5.     SaiHandle.Init.FIFOThreshold  = SAI_FIFOTHRESHOLD_1QF;' E0 P4 N. |4 L) q7 t) J
  6.     SaiHandle.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_44K;
    * F9 H2 T2 w/ o9 r$ ~
  7.     SaiHandle.Init.Protocol       = SAI_FREE_PROTOCOL;9 t" L/ }! m& L2 ~8 B$ U
  8.     SaiHandle.Init.DataSize       = SAI_DATASIZE_16;4 e+ L3 P2 G9 h6 Z
  9.     SaiHandle.Init.FirstBit       = SAI_FIRSTBIT_MSB;
    3 s/ Z- H; @2 y7 w! h; }! i
  10.     SaiHandle.Init.ClockStrobing  = SAI_CLOCKSTROBING_FALLINGEDGE;) P; d5 T* Y5 V& P, D: p9 E

  11. ; Z3 ]$ c, P8 S, H! o9 S+ E) z
  12.     SaiHandle.FrameInit.FrameLength       = 32;
    ! `. u* e8 |6 x7 L/ J
  13.     SaiHandle.FrameInit.ActiveFrameLength = 16;
      ^0 d4 ]7 Z7 M: q; N1 p* ^
  14.     SaiHandle.FrameInit.FSDefinition      = SAI_FS_CHANNEL_IDENTIFICATION;
    ' p6 u- J0 D5 G( h2 r# q
  15.     SaiHandle.FrameInit.FSPolarity        = SAI_FS_ACTIVE_LOW;0 F9 E1 U, W/ }" q# E, N3 z! q
  16.     SaiHandle.FrameInit.FSOffset          = SAI_FS_BEFOREFIRSTBIT;" _5 g$ g  W( {( T; W

  17. / a: d& l6 b; E
  18.     SaiHandle.SlotInit.FirstBitOffset = 0;) w( a6 l1 z, h0 U' K. g0 N' M% Y
  19.     SaiHandle.SlotInit.SlotSize       = SAI_SLOTSIZE_DATASIZE;
    - v( B; \! W2 Y: V3 [+ |& D# Q
  20.     SaiHandle.SlotInit.SlotNumber     = 2;, x0 `9 M/ t1 Q$ `
  21.     SaiHandle.SlotInit.SlotActive     = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1);
    7 ~1 k9 U7 @% N2 O
复制代码

) l1 C7 o9 \  e: I: G  V( E5 g5 t, F% m4 h- j! a
4 j4 {" g6 Y! ^: }
0 Y8 ]$ H* G) l0 N+ e
7 U, c/ z# D: z  r- s
4、最后9 f" o* l1 y1 s' w
) y& H8 f% ~( B* K9 p
     使用STM32F769-DISOC配合论坛之前送的小音箱,播放音乐的效果和我手机电脑播放的听不出区别。我用手机语音备忘录录制了一段放在附件里面,感兴趣可以试听下。9 }& _. Z0 A+ N+ x+ W
2 P9 Y) v, d3 R0 h/ h" |& z7 l. `3 M
4 j, i" e) @: u6 w' |5 [# i
PS:附件的源码里面我默认关闭了汉字库下载到NORFLASH,如果是第一次运行程序请打开相应的宏定义加载字库。
$ ^$ f7 N7 j  t# H& F6 c
8 B4 m# S- Q9 J' |0 L* ?. w/ W  Y% q; O' s$ P
测试代码和文件:3 `8 w- M3 T7 n7 ~3 ]8 i/ r7 u. c
audio.rar (3.89 MB, 下载次数: 378)
1 收藏 7 评论18 发布时间:2017-8-19 21:10

举报

18个回答
wamcncn 回答时间:2017-8-25 15:24:58
学习            
jocelynxx 回答时间:2020-12-25 08:24:10
这个为什么会显示那个stm32xx.h头文件打不开
yijuanzhi 回答时间:2019-1-21 11:30:56
谢谢分享辛苦了,先看看怎么用
netlhx 回答时间:2017-8-20 08:43:00
顶,好贴
戏如人生 回答时间:2017-8-20 18:16:08
赞一个!
andey 回答时间:2017-8-20 23:35:43
提示: 作者被禁止或删除 内容自动屏蔽
zero99 回答时间:2017-8-21 08:31:15
顶,好贴
Stm32McuLover 回答时间:2017-8-21 12:49:52

  n9 e& |" y9 ^4 A0 y0 H% Z8 ^" a" [顶,好贴
leifeng1 回答时间:2017-8-21 23:59:39
刚好有这个开发板,回头试试
群星闪烁 回答时间:2017-8-22 11:00:37
谢谢分享,学习了
Paderboy 回答时间:2017-8-28 08:52:42
赞,刚看到。。。。支持晚了。。
张亚飞 回答时间:2017-8-28 15:17:04
不错,学习了l
cp1300 回答时间:2020-2-14 09:26:52
顶一个   
Amaker 回答时间:2020-6-28 11:49:06
谢谢分享!
zhi13750358839 回答时间:2020-9-17 11:44:00
顶,好贴
12下一页

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版