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

【我爱DIY】简易WAV播放器  

[复制链接]
creep 发布时间:2017-8-19 21:10
本帖最后由 creep 于 2017-8-22 08:56 编辑
  e: o% u. ^! [2 B
& w% K* J1 C' X' K( f      STM32F769-DISCO 上面有个WM8994可以用于音频解码。WM8994具有高性能低功耗体积小等优点,曾用在早期的三星安卓手机上用到。下面的测试主要是使用WM8994播放WAV文件。/ W! b1 L( ~  {0 k% L3 `
3 I4 |- h, j5 [, H) |
& X0 g) X* q6 T
1、串行音频接口(SAI)" b( p8 o) t, C
SAI 接口(串行音频接口)灵活性高、配置多样,可支持多种音频协议。该接口适用于许多立体声或单声道应用。例如,它可配置为支持 I2S 标准、 LSB 或 MSB 对齐、 PCM/DSP、TDM 和 AC’97 等协议。将音频模块配置为发送器时, SAI 接口可提供 SPDIF 输出。SAI 通过两个完全独立的音频子模块来实现这种灵活性和可配置性。每个模块都有自己的时钟发生器和 I/O 线控制器。SAI 可以配置为主模式或配置为从模式。音频子模块既可作为接收器,又可作为发送器;既可与另一模块同步,又可以不同步。0 ^5 W) w  L; `6 X' ~: T3 H' @
SAI 主要由两个各自带有时钟发生器的音频子模块组成,每个音频模块集成一个 32 位移位寄存器,该寄存器由模块自身的功能状态机控制。数据存储和读取都是通过专用的 FIFO 来完成。 FIFO 可通过 CPU 访问,也可通过 DMA 访问以减轻 CPU 的通信负担。每个音频模块是独立的。这两个音频子模块可彼此同步。SAI 中指定音频模块的 4 个专用引脚IO口( SD、 SCK、 FS、 MCLK)。
9 ^" ^( X! l% s2 c4 p- d
8 ?  r8 o2 z! u5 ]3 T
5 ~0 {7 }" k$ }) R7 x, x/ E# x功能框图如下:$ `( a* H" }% i: O6 t( o7 c
TIM截图20170819170314.png
1 e" ?* n; V# Q8 A' L9 U- P
$ _7 d: ~/ ]1 V3 U2 TSTM32F769-DISOC 上面的WM8994通过SAI1_Block_A和MCU进行解码数据通信,WM8994的初始化和各项配置则通过IIC实现。# T6 J6 F3 k# V' e4 K: A; y

* p, \0 ?( q' j4 ^+ n3 U& D' u8 U& v. E, K( N; {0 v% i
TIM截图20170819171150.png / y+ C# W0 q3 v: ~; p* o2 Y
. H% N$ _$ z# D$ G1 }. @( O8 H
2、WAV格式文件
' M/ M3 Q+ \6 T8 g( |) uWAVE文件是计算机领域最常用的数字化声音文件格式之一,它是微软专门为Windows系统定义的波形文件格式(Waveform Audio)。WAVE是录音时用的标准的WINDOWS文件格式,文件的扩展名为“WAV”,数据本身的格式为PCM或压缩型。简单的理解WAV文件有一个文件头和数据部分组成,文件头里面包含该WAV的详细信息。一个典型的文件头格式如下:
% q2 M4 q  Z6 k* P4 p& | TIM截图20170819173349.png 7 {2 `$ Z5 a3 T8 M- Z
这个文件头共有44字节,不同的格式文件头可能长度不同,为了方便处理我使用开源软件Audacity将WAV的头文件格式都转为相同的44字节模式,其他的参数为立体声44.1KHZ.
( f4 K) s( G( A0 N. s: k- H
7 [0 x5 }# k) H
# @1 |1 G+ z* r% y$ n TIM截图20170819175532.png 2 G0 L* F% e, s

8 r& X+ @: G& F8 q7 m" \, S3、软件解码( n2 f! {+ k- g/ q8 i. W2 z

' l2 r: o( ?+ ^   播放的WAV文件放在TF卡里面,文件系统使用开源的FATFS,为了支持较长的歌曲名字,需要在FATFS中打开长文件名支持模式。同时为了支持中文显示,我把汉字点阵放到了
: D" W7 Y5 N# [0 xSTM32F769-DISCO 的外置NORFLASH里面,具体的操作可以查看之前的帖子。
5 L) x/ B  ^" n& k% O$ p/ Z6 ?: I! e# ^- G- ~% [
WAV的播放是使用DMA 循环模式把数据从SD卡搬送到codec进行解码,其中DMA使能了HalfTransfer和TransferComplete来不断的更新要解码的数据文件。
' ]/ f+ V8 G- p) L* W8 S( v最开始的时候先将要解码的缓存写满,然后开始DMA传输,当传输完成一半时在使能标记开始更新前半部缓存,等传输完成继续更新后半部分缓存,这样可以实现更新缓存和6 k9 x4 @; j& @2 Z- }4 a1 W- X
界面数据“同时进行”,当然这样做的前提是更新缓存数据速度要快于解码的数据,通过测试STM32F7完全没有压力。# a) i1 f, }$ F7 P* Q+ h

; G. _5 b6 O/ e, M& n2 A' |程序的流程如下:
/ a' s! s9 |, S: U# A
  • 先扫描SD卡找到WAV文件,将找到的WAV文件信息放入到一个链表中。
  • 显示找到的WAV文件名称到LCD上,并更新要播放的文件(名称为绿色字体)。
  • 根据预设的要播放的文件序号找到要要播放的WAV文件的信息,从SD卡里面读取填充播放缓存。
  • 开始播放WAV后不断的填充播放缓存直到播放完成。
  • 播放完成一个WAV文件后,根据播放模式(单曲循环、列表循环、随机循环)播放下一个WAV文件。
  • 播放的过程中可以通过用户按键切换下一个WAV文件进行播放。
    ' ~: O/ O2 v  A- U, V
" O% m* y+ M, f% H  Z8 q
程序下载后的:
/ p$ h' `3 \0 Y3 L; E5 m5 V, b" S0 n  \+ L8 j
IMG_0161.JPG & }  L  P) m$ l* O. |
* U( ^( C0 I6 S
使用按键切换歌曲:9 m4 l% n) @* \

+ A7 v! @& F) A0 ]0 H DJDL9465.GIF
2 v3 n8 S% Q8 t- q9 {# c
- C3 s: E* F+ G6 Ymian 函数如下:
, O7 d0 X+ _5 k
  1.     _listfile_list *playfile;9 f7 A1 L# b4 I8 _  R
  2.     CPU_CACHE_Enable();
    1 }$ A* M( d2 g6 o& U8 s
  3.     HAL_Init();
    ( D( h! J( L5 W) d, Z
  4.     SystemClock_Config();0 x1 v! a4 L# K1 D- X% o
  5.     USART1_Init();
    4 V3 c0 d6 D- i- T/ q$ f
  6.     HAL_Delay(200);; C  E) ?0 E. R1 R- E
  7.     BSP_LED_Init(LED_GREEN);* F& Y% B9 ~* U) P. g! r
  8.     BSP_LCD_Init();$ V3 C/ G* D) v3 o+ @8 _. X0 F
  9.     BSP_LCD_LayerDefaultInit(0, LCD_FB_START_ADDRESS);; r2 g7 A. w* e' J2 t9 X  H" K
  10.     BSP_LCD_SetTextColor(LCD_COLOR_RED);! |% }) A  R! a: v6 |' g2 |
  11.     BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
    2 N) |3 V' r* Z5 Q" X7 H8 O
  12.     HAL_Delay(500);
    $ v$ G5 x* R+ ?
  13.     BSP_QSPI_Init();7 e4 r8 n6 @; N
  14.     CopyFont2NorFlash();
    " }/ M5 e7 K# @
  15.     BSP_QSPI_EnableMemoryMappedMode();
    & W7 M/ l+ G$ J3 o' I: Z$ C% H
  16.     CheckGBKFont4NorFlash();. b, a3 @6 t- n; h) W+ V
  17.     BSP_LCD_Clear(LCD_COLOR_WHITE);
    * M+ o% w$ l6 C" l6 ?+ M( P

  18. 6 t0 ^0 G: j2 p3 A9 o& H9 q
  19.     FatFs_SD_Init();2 H0 Q; V6 I: r2 B" S
  20.     wavfilenum = ScanWavFiles("/");
    ! A  p: z  E% n' g# z: Y
  21.     PrintfWavFileTest();6 q4 ~& k; Z1 o; Q
  22.     UpdateWavFileColor(playfilepos,playfilepos);+ ~' S" f. a9 C4 t( P3 g
  23.     playfile = list_search(WavFileList, playfilepos);" E3 t. b0 e1 P
  24. : I' j. ]8 H0 [& J4 I; K
  25.     if(playfile == NULL)while(1);* a; c, t7 C# O9 ?  f5 F( X  p: X
  26. + H& i  [. v# ?, v; p7 ?8 n- |# M
  27.     //´4 j: Q2 T% n4 s5 @+ I/ G
  28.     wavFileLen = OpendWavFile(playfile->filename);
    0 p: ]8 L; G  l( O' `* Q
  29.     //
    ' r. c$ T: l! ?. E2 e8 \
  30.     ReadWaveFile(BuffHead, PLAY_HEADER);
    9 R& s  C. Y6 K- ]% @
  31.     //
    - _8 E$ z. H1 G% f" m
  32.     ReadWaveFile((uint8_t *)PlayBuff, PLAY_BUFF_SIZE * 2);
    * |! U0 a- H& V
  33.     Playback_Init();
    , `- S% K9 `/ k8 c/ @

  34. % j/ \0 v0 z5 c! S/ k, H
  35.     /* Start the playback */9 ^  \* [! k* G
  36.     if(0 != audio_drv->Play(AUDIO_I2C_ADDRESS, NULL, 0))$ T! t5 `, p; v; o8 r
  37.     {
    * i7 m4 F& U7 B8 i
  38.         while(1);: n' B2 a% p. P" ^! s$ D7 w+ G% o
  39.     }; g8 H; C4 x' C+ w' O
  40. : `4 c2 G' n# j3 [# u$ J' q9 [
  41.     if(HAL_OK != HAL_SAI_Transmit_DMA(&SaiHandle, (uint8_t *)PlayBuff, PLAY_BUFF_SIZE))6 q! P! `# A, |& U# H8 `
  42.     {
      i0 n3 D* x2 L: B
  43.         while(1);
    ; s3 v7 Y6 U. K- @/ A. K
  44.     }
复制代码
需要注意的是程序里面默认播放是44.1KHZ立体声的WAV文件,如果是其他的格式的要在播放之前更新SAI的配置。
7 x3 Q3 a- e" G
  1.    SaiHandle.Init.AudioMode      = SAI_MODEMASTER_TX;
    ! p, a9 Q/ P' [0 |9 A
  2.     SaiHandle.Init.Synchro        = SAI_ASYNCHRONOUS;; {+ M0 Y, R( U) E- U) L
  3.     SaiHandle.Init.OutputDrive    = SAI_OUTPUTDRIVE_ENABLE;% U7 c+ A! N* Z) G
  4.     SaiHandle.Init.NoDivider      = SAI_MASTERDIVIDER_ENABLE;5 _* D% C# Z: `! ^2 l' ^2 j
  5.     SaiHandle.Init.FIFOThreshold  = SAI_FIFOTHRESHOLD_1QF;$ l" _* C6 {6 N7 z* m) \+ W. ~, W
  6.     SaiHandle.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_44K;
    # W* J/ x. ]& d
  7.     SaiHandle.Init.Protocol       = SAI_FREE_PROTOCOL;) e6 D5 q. ^) Q) u# J; N
  8.     SaiHandle.Init.DataSize       = SAI_DATASIZE_16;' E' v7 A0 X  U! Q
  9.     SaiHandle.Init.FirstBit       = SAI_FIRSTBIT_MSB;
    6 e1 X' f" |: T: {* X# K5 g
  10.     SaiHandle.Init.ClockStrobing  = SAI_CLOCKSTROBING_FALLINGEDGE;- l' f; ~) A% P/ W
  11. * ]( |1 Y; f1 m  u
  12.     SaiHandle.FrameInit.FrameLength       = 32;( z* J7 d( l5 e" M+ j
  13.     SaiHandle.FrameInit.ActiveFrameLength = 16;& n( J2 q0 d- Y# r0 T" {0 u! j+ W
  14.     SaiHandle.FrameInit.FSDefinition      = SAI_FS_CHANNEL_IDENTIFICATION;
    7 j; j  L+ a. W+ a* H) C. O8 {
  15.     SaiHandle.FrameInit.FSPolarity        = SAI_FS_ACTIVE_LOW;" K. }: u% C' @3 j9 l% h+ B
  16.     SaiHandle.FrameInit.FSOffset          = SAI_FS_BEFOREFIRSTBIT;+ _: b; H$ D) j4 H1 B2 t

  17. / s0 N+ R9 z' g9 ~* k7 B
  18.     SaiHandle.SlotInit.FirstBitOffset = 0;
    5 ]) n/ T/ C; r9 ~
  19.     SaiHandle.SlotInit.SlotSize       = SAI_SLOTSIZE_DATASIZE;0 a0 P- a9 l# A; b3 Y, t" h% O+ d6 p
  20.     SaiHandle.SlotInit.SlotNumber     = 2;, {, s% M$ L9 ^# I; s  M
  21.     SaiHandle.SlotInit.SlotActive     = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1);
    * r* v. N* ^7 }3 Q* x
复制代码

( _7 w: e( J) V% L7 C4 u! g! R; w) o2 X) f" G$ J

& L2 w9 q3 g, i# }( ?6 J7 Q
2 _( T0 U& Z: U0 O/ j* h
8 y* A( G/ L0 j$ Z$ g* l' T4、最后/ A! g3 b+ c7 C/ R# l  i

6 k' d7 r+ y, Q$ s7 n) W9 `     使用STM32F769-DISOC配合论坛之前送的小音箱,播放音乐的效果和我手机电脑播放的听不出区别。我用手机语音备忘录录制了一段放在附件里面,感兴趣可以试听下。7 @5 v6 c6 L5 G; B

3 x  u6 u+ y5 R' I( V! V" y
$ z- ~2 G' P! L; ^PS:附件的源码里面我默认关闭了汉字库下载到NORFLASH,如果是第一次运行程序请打开相应的宏定义加载字库。
! A/ `# {: l* o+ L4 Q' o/ I
( z$ J: G( C8 J! v# j$ s6 J; c
$ H; x( c. V, t) O. y! Z测试代码和文件:) T* j7 G" a+ {$ P+ s' a, P8 y
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

( O* u+ A8 i7 @1 `7 t顶,好贴
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 手机版