網上有很多關于pos機成功錄音,阿波羅 STM32F767 開發板資料連載第五十三章 錄音機實驗的知識,也有很多人為大家解答關于pos機成功錄音的問題,今天pos機之家(www.tonybus.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
1、pos機成功錄音
pos機成功錄音
1)實驗平臺:alientek 阿波羅 STM32F767 開發板2)摘自《STM32F7 開發指南(HAL 庫版)》關注官方微信號公眾號,獲取更多資料:正點原子
第五十三章 錄音機實驗
上一章,我們實現了一個簡單的音樂播放器,本章我們將在上一章的基礎上,實現一個簡
單的錄音機,實現 WAV 錄音。本章分為如下幾個部:
53.1 SAI 錄音簡介
53.2 硬件設計
53.3 軟件設計
53.4 下載驗證
53.1 SAI 錄音簡介
本章涉及的知識點基本上在上一章都有介紹。本章要實現 WAV 錄音,還是和上一章一樣,
要了解:WAV 文件格式、WM8978 和 SAI 接口。WAV 文件格式,我們在上一章已經做了詳細
介紹了,這里就不作介紹了。
ALIENTEK 阿波羅 STM32F767 開發板將板載的一個 MIC 分別接入到了 WM8978 的 2 個
差分輸入通道(LIP/LIN 和 RIP/RIN,原理圖見:圖 52.2.1)。代碼上,我們采用立體聲 WAV
錄音,不過,左右聲道的音源都是一樣的,錄音出來的 WAV 文件,聽起來就是個單聲道效果。
WM8978 上一章也做了比較詳細的介紹,本章我們主要看一下要進行 MIC 錄音,WM8978
的配置步驟:
1,寄存器 R0(00h),該寄存器用于控制 WM8978 的軟復位,寫任意值到該寄存器地址,
即可實現軟復位 WM8978。
2,寄存器 R1(01h),該寄存器主要要設置 MICBEN(bit4)和 BIASEN(bit3)兩個位為 1,
開啟麥克風(MIC)偏置,以及使能模擬部分放大器。
3,寄存器 R2(02h),該寄存器要設置 SLEEP(bit6)、INPGAENR(bit3)、INPGAENL(bit2)、
ADCENR(bit1)和ADCENL(bit0)等五個位。SLEEP設置為0,進入正常工作模式;INPGAENR
和 INPGAENL 設置為 1,使能 IP PGA 放大器;ADCENL 和 ADCENR 設置為 1,使能左
右通道 ADC。
4,寄存器 R4(04h),該寄存器要設置 WL(bit6:5)和 FMT(bit4:3)等 4 個位。WL(bit6:5)用
于設置字長(即設置音頻數據有效位數),00 表示 16 位音頻,10 表示 24 位音頻;FMT(bit4:3)
用于設置 I2S 音頻數據格式(模式),我們一般設置為 10,表示 I2S 格式,即飛利浦模式。
5,寄存器 R6(06h),該寄存器我們直接全部設置為 0 即可,設置 MCLK 和 BCLK 都來
自外部,即由 STM32F767 提供。
6,寄存器 R14(0Eh),該寄存器要設置 ADCOSR128(bit3)為 1,ADC 得到最好的 SNR。
7,寄存器 R44(2Ch),該寄存器我們要設置 LIP2INPPGA(bit0)、LIN2INPPGA(bit1)、
RIP2INPPGA(bit4)和 RIN2INPPGA(bit5)等 4 個位,將這 4 個位都設置為 1,將左右通道差
分輸入接入 IN PGA。
8,寄存器 R45(2Dh)和 R46(2Eh),這兩個寄存器用于設置 PGA 增益(調節麥克風增
益),一個用于設置左通道(R45),另外一個用于設置右通道(R46)。這兩個寄存器的
最高位(INPPGAUPDATE)用于設置是否更新左右通道的增益,最低 6 位用于設置左右
通道的增益,我們可以先設置好兩個寄存器的增益,最后設置其中一個寄存器最高位為 1,
即可更新增益設置。
9,寄存器 R47(2Fh)和 R48(30h),這兩個寄存器也類似,我們只關心其最高位(bit8),
都設置為 1,可以讓左右通道的 MIC 各獲得 20dB 的增益。
10,寄存器 R49(31h),該寄存器我們要設置 TSDEN(bit1)這個位,設置為 1,開啟過熱
保護。
以上,就是我們用 WM8978 錄音時的設置,按照以上所述,對各個寄存器進行相應的配置,
即可使用 WM8978 正常錄音了。不過我們本章還要用到播放錄音的功能,WM8978 的播放配置
在 50.1.2 節已經介紹過了,請大家參考這個章節。
上一章我們向大家介紹了 STM32F767 的 SAI 放音,通過上一章的了解,我們知道:
STM32F767 SAI 的全雙工通信,需要用到 SAI 的兩個子模塊(SAI_A 和 SAI_B)),一個工作
在主模式,產生 FS、SCK 和 MCLK,一個工作在從模式,通過 SD 引腳接收數據。
本章我們必須向 WM8978 提供 WS(FS),CK(SCK)和 MCK(MCLK)等時鐘,同時又要錄音,
所以只能使用全雙工模式。工作在主模式的 SAI 子模塊循環發送數據 0X0000,給 WM8978,
以產生 CK、WS 和 MCK 等信號,工作在從模式的 SAI 子模塊,則接收來自 WM8978 的 ADC
數據(ADCDAT),并保存到 SD 卡,實現錄音。
本章我們將同時使用 SAI 的兩個子模塊,以實現錄音功能,SAI 的相關寄存器,我們在上
一章已經介紹的差不多了,這里就不再進行寄存器介紹,大家可以參考《STM32F7 中文參考手
冊.pdf》第 33.5 小節。
要實現錄音功能,我們根據上一章,圖 50.2.1 的連接關系可知,SAI_A 子模塊必須工作在
主模式,循環發送 0X0000,以提供 FS、SCK 和 MCLK 等時鐘信號,SAI_B 子模塊則工作在從
模式,讀取 ADCDAT 輸出的數據流(SAI_SD_B),從而實現錄音功能。
最后,我們看看要通過 STM32F767 的 SAI,驅動 WM8978 實現 WAV 錄音的簡要步驟,
如下:
1)初始化 WM8978
這個過程就是前面所講的 WM8978 MIC 錄音配置步驟,讓 WM8978 的 ADC 以及其模擬部
分工作起來。
2)初始化 SAI_A 和 SAI_B
本章要用到 SAI 的全雙工模式,所以,SAI_A 和 SAI_B 都需要配置,其中 SAI_A 配置為
主模式,SAI 設置為從模式,且與 SAI_A 同步。他們的其他配置(協議、時鐘電平特性、slot
相關參數)基本一樣,只是一個是發送一個是接收,且都要使能 DMA。同時,還需要設置音
頻采樣率,不過這個只需要設置 SAI_A 的即可,還是通過上一章介紹的查表法設置。
3)設置發送和接收 DMA
放音和錄音都是采用 DMA 傳輸數據的,本章放音其實就是個幌子,不過也得設置 DMA
(使用 DMA2 數據流 3 的通道 0),配置同上一章一模一樣,不過不需要開啟 DMA 傳輸完成
中斷。對于錄音,則使用的是 DMA2 數據流 5 的通道 0 實現的 DMA 數據接收,我們需要配置
DMA2 的數據流 5,本章將 DMA2 數據流 5 設置為:雙緩沖循環模式,外設和存儲器都是 16
位寬,并開啟傳輸完成中斷(方便接收數據)。
4)編寫接收通道 DMA 傳輸完成中斷服務函數
為了方便接收音頻數據,我們使用 DMA 傳輸完成中斷,每當一個緩沖接數據滿了,硬件
自動切換為下一個緩沖,同時進入中斷服務函數,將已滿緩沖的數據寫入 SD 卡的 wav 文件。
過程如圖 53.1.1 所示:
圖 53.1.1 DMA 雙緩沖接收音頻數據流框圖
5)創建 WAV 文件,并保存 wav 頭
前面 4 步完成,其實就可以開始讀取音頻數據了,不過在錄音之前,我們需要先在創建一
個新的文件,并寫入 wav 頭,然后才能開始寫入我們讀取到的的 PCM 音頻數據。
6)開啟 DMA 傳輸,接收數據
然后,我們就只需要開啟 DMA 傳輸,然后及時將 SAI_SD_B 讀到的數據寫入到 SD 卡之
前新建的 wav 文件里面,就可以實現錄音了。
7)計算整個文件大小,重新保存 wav 頭并關閉文件
在結束錄音的時候,我們必須知道本次錄音的大?。〝祿笮『驼麄€文件大小),然后更新
wav 頭,重新寫入文件,最后因為 FATFS,在文件創建之后,必須調用 f_close,文件才會真正
體現在文件系統里面,否則是不會寫入的!所以最后還需要調用 f_close,以保存文件。
53.2 硬件設計
本章實驗功能簡介:開機后,先初始化各外設,然后檢測字庫是否存在,如果檢測無問題,
再檢測 SD 卡根目錄是否存在 RECORDER 文件夾,如果不存在則創建,如果創建失敗,則報
錯。在找到 SD 卡的 RECORDER 文件夾后,即進入錄音模式(包括配置 WM8978 和 SAI 等),
此時可以在耳機(或喇叭)聽到采集到的音頻。KEY0 用于開始/暫停錄音,KEY2 用于保存并
停止錄音,KEY_UP 用于播放最近一次的錄音。
當我們按下 KEY0 的時候,可以在屏幕上看到錄音文件的名字、碼率以及錄音時間等,然
后通過 KEY2 可以保存該文件,同時停止錄音(文件名和時間也都將清零),在完成一段錄音
后,我們可以通過按 KEY_UP 按鍵,來試聽剛剛的錄音。DS0 用于提示程序正在運行,DS1
用于提示是否處于暫停錄音狀態。
本實驗用到的資源如下:
1) 指示燈 DS0,DS1
2) 三個按鍵(KEY_UP/KEY0/KEY2)
3) 串口
4) LCD 模塊
5) SD 卡
6) SPI FLASH
7) WM8978
8) SAI
這些前面都已介紹過。本實驗,大家需要準備 1 個 SD 卡和一個耳機,分別插入 SD 卡接
口和耳機接口(PHONE),然后下載本實驗就可以實現一個簡單的錄音機了。
53.3 軟件設計
打開本章實驗工程可以看到我們在 APP 分組下新增了 recorder.c 文件,用來存放錄音相關
源碼。因為 recorder.c 代碼比較多,我們這里僅介紹其中幾個重要的函數,代碼如下:
u8 *sairecbuf1; //SAI1 DMA 接收 BUF1u8 *sairecbuf2; //SAI1 DMA 接收 BUF2 //REC 錄音 FIFO 管理參數.//由于 FATFS 文件寫入時間的不確定性,如果直接在接收中斷里面寫文件,可能導致某次寫//入時間過長從而引起數據丟失,故加入 FIFO 控制,以解決此問題.vu8 sairecfifordpos=0; //FIFO 讀位置vu8 sairecfifowrpos=0; //FIFO 寫位置u8 *sairecfifobuf[SAI_RX_FIFO_SIZE]; //定義 10 個錄音接收 FIFOFIL* f_rec=0; //錄音文件u32 wavsize; //wav 數據大小(字節數,不包括文件頭!!)u8 rec_sta=0; //錄音狀態//[7]:0,沒有開啟錄音;1,已經開啟錄音;//[6:1]:保留//[0]:0,正在錄音;1,暫停錄音; //讀取錄音 FIFO//buf:數據緩存區首地址//返回值:0,沒有數據可讀;// 1,讀到了 1 個數據塊u8 rec_sai_fifo_read(u8 **buf){if(sairecfifordpos==sairecfifowrpos)return 0;sairecfifordpos++; //讀位置加 1if(sairecfifordpos>=SAI_RX_FIFO_SIZE)sairecfifordpos=0;//歸零*buf=sairecfifobuf[sairecfifordpos];return 1;}//寫一個錄音 FIFO//buf:數據緩存區首地址//返回值:0,寫入成功;// 1,寫入失敗u8 rec_sai_fifo_write(u8 *buf){u16 i;u8 temp=sairecfifowrpos;//記錄當前寫位置sairecfifowrpos++; //寫位置加 1if(sairecfifowrpos>=SAI_RX_FIFO_SIZE)sairecfifowrpos=0;//歸零 if(sairecfifordpos==sairecfifowrpos){sairecfifowrpos=temp;//還原原來的寫位置,此次寫入失敗 return 1;}for(i=0;i<SAI_RX_DMA_BUF_SIZE;i++)sairecfifobuf[sairecfifowrpos][i]=buf[i];//拷貝return 0;} //錄音 SAI_DMA 接收中斷服務函數.在中斷里面寫入數據void rec_sai_dma_rx_callback(void) { if(rec_sta==0X80)//錄音模式{ if(DMA2_Stream5->CR&(1<<19))rec_sai_fifo_write(sairecbuf1);//sairecbuf1 寫 FIFOelse rec_sai_fifo_write(sairecbuf2);//sairecbuf2 寫入 FIFO } } const u16 saiplaybuf[2]={0X0000,0X0000};//2 個數據,用于錄音時 SAI_A 主機循環發送 0.//進入 PCM 錄音模式 void recoder_enter_rec_mode(void){WM8978_ADDA_Cfg(0,1); //開啟 ADCWM8978_Input_Cfg(1,1,0); //開啟輸入通道(MIC&LINE IN)WM8978_Output_Cfg(0,1); //開啟 BYPASS 輸出WM8978_MIC_Gain(46); //MIC 增益設置WM8978_SPKvol_Set(0); //關閉喇叭.WM8978_I2S_Cfg(2,0); //飛利浦標準,16 位數據長度SAIA_Init(SAI_MODEMASTER_TX,SAI_CLOCKSTROBING_RISINGEDGE,SAI_DATASIZE_16); //SAI1 Block A,主發送,16 位數據SAIB_Init(SAI_MODESLAVE_RX,SAI_CLOCKSTROBING_RISINGEDGE,SAI_DATASIZE_16);//SAI1 Block B 從模式接收,16 位SAIA_SampleRate_Set(REC_SAMPLERATE);//設置采樣率SAIA_TX_DMA_Init((u8*)&saiplaybuf[0],(u8*)&saiplaybuf[1],1,1);//TX DMA,16 位 __HAL_DMA_DISABLE_IT(&SAI1_TXDMA_Handler,DMA_IT_TC);//關閉傳輸完成中斷(這里不用中斷送數據) SAIA_RX_DMA_Init(sairecbuf1,sairecbuf2,SAI_RX_DMA_BUF_SIZE/2,1);//配置 RX DMA sai_rx_callback=rec_sai_dma_rx_callback;//初始化回調函數指 sai_rx_callbackSAI_Play_Start(); //開始 SAI 數據發送(主機)SAI_Rec_Start(); //開始 SAI 數據接收(從機)recoder_remindmsg_show(0); } //初始化 WAV 頭.void recoder_wav_init(__WaveHeader* wavhead) //初始化 WAV 頭 {wavhead->riff.ChunkID=0X46464952; //"RIFF"wavhead->riff.ChunkSize=0; //還未確定,最后需要計算wavhead->riff.Format=0X45564157; //"WAVE"wavhead->fmt.ChunkID=0X20746D66; //"fmt "wavhead->fmt.ChunkSize=16; //大小為 16 個字節wavhead->fmt.AudioFormat=0X01; //0X01,表示 PCM;0X01,表示 IMA ADPCMwavhead->fmt.NumOfChannels=2; //雙聲道wavhead->fmt.SampleRate=REC_SAMPLERATE;//設置采樣速率wavhead->fmt.ByteRate=wavhead->fmt.SampleRate*4;//采樣率*通道數*(ADC 位數/8)wavhead->fmt.BlockAlign=4; //塊大小=通道數*(ADC 位數/8)wavhead->fmt.BitsPerSample=16; //16 位 PCM wavhead->data.ChunkID=0X61746164; //"data"wavhead->data.ChunkSize=0; //數據大小,還需要計算 } //WAV 錄音void wav_recorder(void){ u8 res,i; u8 key; u8 rval=0;__WaveHeader *wavhead=0; DIR recdir; //目錄 u8 *pname=0; u8 *pdatabuf;u8 timecnt=0; //計時器 u32 recsec=0; //錄音時間 while(f_opendir(&recdir,"0:/RECORDER"))//打開錄音文件夾{Show_Str(30,230,240,16,"RECORDER 文件夾錯誤!",16,0); delay_ms(200);LCD_Fill(30,230,240,246,WHITE); delay_ms(200); //清除顯示 f_mkdir("0:/RECORDER"); //嘗試創建該目錄 } sairecbuf1=mymalloc(SRAMIN,SAI_RX_DMA_BUF_SIZE); //SAI 錄音內存 1 申請sairecbuf2=mymalloc(SRAMIN,SAI_RX_DMA_BUF_SIZE); //SAI 錄音內存 2 申請 for(i=0;i<SAI_RX_FIFO_SIZE;i++){sairecfifobuf[i]=mymalloc(SRAMIN,SAI_RX_DMA_BUF_SIZE);//FIFO 內存申請if(sairecfifobuf[i]==NULL)break; //申請失敗} f_rec=(FIL *)mymalloc(SRAMIN,sizeof(FIL)); //開辟 FIL 字節的內存區域 wavhead=(__WaveHeader*)mymalloc(SRAMIN,sizeof(__WaveHeader));//申請內存pname=mymalloc(SRAMIN,30);//申請30字節內存,類似"0:RECORDER/REC00001.wav" if(!sairecbuf1||!sairecbuf2||!f_rec||!wavhead||!pname||i!=SAI_RX_FIFO_SIZE)rval=1; if(rval==0){recoder_enter_rec_mode(); //進入錄音模式,此時耳機可以聽到咪頭采集到的音頻 pname[0]=0; //pname 沒有任何文件名 while(rval==0){key=KEY_Scan(0);switch(key){case KEY2_PRES: //STOP&SAVEif(rec_sta&0X80)//有錄音{rec_sta=0; //關閉錄音wavhead->riff.ChunkSize=wavsize+36; //整個文件的大小-8; wavhead->data.ChunkSize=wavsize; //數據大小f_lseek(f_rec,0); //偏移到文件頭. f_write(f_rec,(const void*)wavhead,sizeof(__WaveHeader),&bw); f_close(f_rec);wavsize=0;sairecfifordpos=0; //FIFO 讀寫位置重新歸零sairecfifowrpos=0;}rec_sta=0; recsec=0;LED1(1); //關閉 DS1LCD_Fill(30,190,lcddev.width="360px",height="auto" />
這里總共 6 個函數,接下來,我們分別介紹。
1,rec_sai_fifo_read 和 rec_sai_fifo_write 函數
這兩個函數用于我們構建的 FIFO 里面的數據讀取和寫入,SAI 采集到的數據,通過 FATFS
寫入 SD 卡的時候,因為 FATFS 寫入時間不確定(有時候短,有時候長),可能導致數據寫入
不及時,出現數據丟失,從而錄音會有間隔(丟失一部分)。所以,我們構建了一個 FIFO,SAI
采集的數據,通過 rec_sai_fifo_write 函數寫入 FIFO 里面,在主循環里面,我們通過
rec_sai_fifo_read 函數不停的讀取 FIFO 里面的數據,并將數據通過 FATFS 寫入 SD 卡里面,只
要 rec_sai_fifo_read 的速度,不小于 rec_sai_fifo_write 的速度,就可以保證數據不丟失,這個
FIFO 起到了一個緩沖的作用,從而保證錄音文件的流暢性。
2,rec_sai_dma_rx_callback 函數
該函數用于 SAI_B 的 DMA 接收完成中斷回調函數(通過 sai_rx_callback 指向該函數實現),
在該函數里面調用 rec_sai_fifo_write 函數,將采集到的音頻數據,寫入 FIFO。
3,recoder_enter_rec_mode 函數
該函數用于設置 WM8978 進入錄音模式,并設置 SAI_A 和 SAI_B 的工作模式和位數等信
息,然后配置 DMA 和回調函數的指向,最后開啟錄音。調用該函數后,就可以開始錄音了。
4,recoder_wav_init 函數
該函數初始化 wav 頭的絕大部分數據,采樣率通過 REC_SAMPLERATE 宏定義修改,默
認是 44.1Khz,位數為 16 位,線性 PCM 格式,另外由于錄音還未真正開始,所以文件大小和
數據大小都還是未知的,要等錄音結束才能知道。該函數__WaveHeader 結構體就是由上一章
(50.1.1 節)介紹的三個 Chunk 組成,結構為:
//wav 頭
typedef __packed struct
{
ChunkRIFF riff;
//riff 塊
ChunkFMT fmt; //fmt 塊
//
ChunkFACT fact; //fact 塊 線性 PCM,沒有這個結構體
ChunkDATA data; //data 塊
}__WaveHeader;
5,wav_recorder 函數
該函數實現了我們在硬件設計時介紹的功能(開始/暫停錄音、保存錄音文件、播放最近一
次錄音等),實現方法請大家參考源碼理解。另外,該函數使用上一章實現的 audio_play_song
函數,來播放最近一次錄音。
recorder.c 的其他代碼和 recorder.h 的代碼我們這里就不再貼出了,請大家參考光盤本實驗
的源碼。然后,我們在 sai.c 里面也增加了幾個函數,如下:
//SAI Block B 初始化,I2S,飛利浦標準//mode:工作模式,可以設置:SAI_MODEMASTER_TX///SAI_MODEMASTER_RX/SAI_MODESLAVE_TX/SAI_MODESLAVE_RX//cpol:數據在時鐘的上升/下降沿選通,可以設置://SAI_CLOCKSTROBING_FALLINGEDGE/SAI_CLOCKSTROBING_RISINGEDGE//datalen:數據大小,可以設置:SAI_DATASIZE_8/10/16/20/24/32void SAIB_Init(u32 mode,u32 cpol,u32 datalen){ HAL_SAI_DeInit(&SAI1B_Handler); //清除以前的配置 SAI1B_Handler.Instance=SAI1_Block_B; //SAI1 Bock B SAI1B_Handler.Init.AudioMode=mode; //設置 SAI1 工作模式 SAI1B_Handler.Init.Synchro=SAI_SYNCHRONOUS; //音頻模塊同步 SAI1B_Handler.Init.OutputDrive=SAI_OUTPUTDRIVE_ENABLE; //立即驅動輸出 SAI1B_Handler.Init.NoDivider=SAI_MASTERDIVIDER_ENABLE; //使能主時鐘分頻器 SAI1B_Handler.Init.FIFOThreshold=SAI_FIFOTHRESHOLD_1QF //設置 FIFO 閾值 SAI1B_Handler.Init.ClockSource=SAI_CLKSOURCE_PLLI2S; //SIA 時鐘源為 PLL2S SAI1B_Handler.Init.MonoStereoMode=SAI_STEREOMODE; //立體聲模式 SAI1B_Handler.Init.Protocol=SAI_FREE_PROTOCOL; //設置 SAI1 協議為自由協議 SAI1B_Handler.Init.DataSize=datalen; //設置數據大小 SAI1B_Handler.Init.FirstBit=SAI_FIRSTBIT_MSB; //數據 MSB 位優先 SAI1B_Handler.Init.ClockStrobing=cpol; //數據在時鐘的上升/下降沿選通 //幀設置 SAI1B_Handler.FrameInit.FrameLength=64; //設置幀長度為 64,左/右通道各 32 個 SCK, SAI1B_Handler.FrameInit.ActiveFrameLength=32; //設置幀同步有效電平長度 SAI1B_Handler.FrameInit.FSDefinition=SAI_FS_CHANNEL_IDENTIFICATION;//FS 信號為 SOF 信號+通道識別信號 SAI1B_Handler.FrameInit.FSPolarity=SAI_FS_ACTIVE_LOW; //FS 低電平有效(下降沿) SAI1B_Handler.FrameInit.FSOffset=SAI_FS_BEFOREFIRSTBIT; //在 slot0 的第一位的前一位使能 FS,以匹配飛利浦標準 //SLOT 設置 SAI1B_Handler.SlotInit.FirstBitOffset=0; //slot 偏移(FBOFF)為 0 SAI1B_Handler.SlotInit.SlotSize=SAI_SLOTSIZE_32B; //slot 大小為 32 位 SAI1B_Handler.SlotInit.SlotNumber=2; //slot 數為 2 個 SAI1B_Handler.SlotInit.SlotActive=SAI_SLOTACTIVE_0|SAI_SLOTACTIVE_1;//使能 slot0 和 slot1 HAL_SAI_Init(&SAI1B_Handler); SAIB_DMA_Enable(); //使能 SAI 的 DMA 功能 __HAL_SAI_ENABLE(&SAI1B_Handler); //使能 SAI }//SAIA TX DMA 配置//設置為雙緩沖模式,并開啟 DMA 傳輸完成中斷//buf0:M0AR 地址.//buf1:M1AR 地址.//num:每次傳輸數據量//width="360px",height="auto" />
這里新增了5個函數,SAIB_Init函數完成SAI_B子模塊的初始化,通過3個參數設置SAI_B
的詳細配置信息。SAIB_RX_DMA_Init 函數,用于設置 SAI_B 的 DMA 接收,使用雙緩沖循環
模式,接收來自 WM8978 的數據,并開啟了傳輸完成中斷。而 DMA2_Stream5_IRQHandler 函
數,則是 DMA2 數據流 5 傳輸完成中斷的服務函數,該函數調用 sai_rx_callback 函數(函數指
針,使用前需指向特定函數)實現 DMA 數據接收保存。最后,SAI_ Rec_Start 和 SAI_ Rec_Stop,
用于開啟和關閉 SAI_B 的 DMA 傳輸。
其他代碼,我們就不再介紹了,請大家參考開發板光盤本例程源碼。最后我們看看 main
函數源碼:
int main(void){ Cache_Enable(); //打開 L1-Cache HAL_Init(); //初始化 HAL 庫 Stm32_Clock_Init(432,25,2,9); //設置時鐘,216Mhz delay_init(216); //延時初始化uart_init(115200); //串口初始化 LED_Init(); //初始化KEY_Init(); //初始化按鍵 SDRAM_Init(); //初始化 SDRAM LCD_Init(); //初始化 LCDW25QXX_Init(); //初始化 W25Q256 WM8978_Init(); //初始化 WM8978WM8978_HPvol_Set(40,40); //耳機音量設置WM8978_SPKvol_Set(40); //喇叭音量設置 my_mem_init(SRAMIN); //初始化內部內存池 my_mem_init(SRAMEX); //初始化外部 SDRAM 內存池 my_mem_init(SRAMDTCM); //初始化內部 DTCM 內存池 exfuns_init(); //為 fatfs 相關變量申請內存 f_mount(fs[0],"0:",1); //掛載 SD 卡f_mount(fs[1],"1:",1); //掛載 SPI FLASH. f_mount(fs[2],"2:",1); //掛載 NAND FLASH. POINT_COLOR=RED; while(font_init()) //檢查字庫{ LCD_ShowString(30,50,200,16,16,"Font Error!");delay_ms(200); LCD_Fill(30,50,240,66,WHITE);//清除顯示 delay_ms(200); } POINT_COLOR=RED; Show_Str(30,40,200,16,"阿波羅 STM32F4/F7 開發板",16,0); Show_Str(30,60,200,16,"錄音機實驗",16,0); Show_Str(30,80,200,16,"正點原子@ALIENTEK",16,0); Show_Str(30,100,200,16,"2016 年 1 月 29 日",16,0); while(1){ wav_recorder(); } }
該函數代碼同上一章的 main 函數代碼幾乎一樣,十分簡單,我們就不再多說了。
至此,本實驗的軟件設計部分結束。
53.4 下載驗證
在代碼編譯成功之后,我們下載代碼到 ALIENTEK 阿波羅 STM32 開發板上,程序先檢測
字庫,然后檢測 SD 卡的 RECORDER 文件夾,一切順利通過之后,進入錄音模式,得到,如
圖 53.4.1 所示:
圖 53.4.1 錄音機界面
此時,我們按下 KEY0 就開始錄音了,此時看到屏幕顯示錄音文件的名字、碼率以及錄音
時長,如圖 53.4.2 所示:
圖 53.4.2 錄音進行中
在錄音的時候按下 KEY0 則執行暫停/繼續錄音的切換,通過 DS1 指示錄音暫停。通過按
下 KEY2,可以停止當前錄音,并保存錄音文件。在完成一次錄音文件保存之后,我們可以通
過按 KEY_UP 按鍵,來實現播放這個錄音文件(即播放最近一次的錄音文件),實現試聽。
我們將開發板的錄音文件放到電腦上面,可以通過屬性查看錄音文件的屬性,如圖 53.4.3
所示:
圖 53.4.3 錄音文件屬性
這和我們預期的效果一樣,通過電腦端的播放器(winamp/千千靜聽等)可以直接播放我們
所錄的音頻。經實測,效果還是非常不錯的。
以上就是關于pos機成功錄音,阿波羅 STM32F767 開發板資料連載第五十三章 錄音機實驗的知識,后面我們會繼續為大家整理關于pos機成功錄音的知識,希望能夠幫助到大家!
