首頁(yè) > 評(píng)測(cè) > PSoC 6評(píng)測(cè)第四篇-錄音與放音

PSoC 6評(píng)測(cè)第四篇-錄音與放音

PSoC 6   耳機(jī)   PDM   PCM   ADC采樣   
  • 作者:zhanzr
  • 來(lái)源:21ic
  • [導(dǎo)讀]
  • 寫上一篇關(guān)于EInk的文章的時(shí)候,就想著要寫這一篇了.因?yàn)樽髡弑救顺讼矚g閱讀之外,還比較喜歡音樂(lè).也喜歡聽(tīng)也喜歡唱K,故此對(duì)音頻相關(guān)的技術(shù)也較為感興趣,至于水平只能說(shuō)稍知一二.看到這個(gè)CY8CKIT開(kāi)發(fā)套件上帶有數(shù)字麥克風(fēng),就動(dòng)了心思.本文使用開(kāi)發(fā)板子上的資源做一個(gè)簡(jiǎn)單的錄音與放音實(shí)驗(yàn),研究一下相關(guān)知識(shí).
image11.png

圖 8 KHz定時(shí)器用作播放更新

注意產(chǎn)生的頻率有一定的誤差,只要在一定范圍內(nèi)是可以接受的.某些要求苛刻的音頻設(shè)備使用比較不常見(jiàn)的晶體頻率即是為了最大程度提高播放精度.

根據(jù)現(xiàn)有條件,直接將耳機(jī)的兩個(gè)通道分別接在VDAC與PWM輸出上:

image12.jpg

圖 硬件連接細(xì)節(jié)

根據(jù)實(shí)驗(yàn),阻抗大的耳機(jī)效果好一點(diǎn)點(diǎn),因?yàn)橐_驅(qū)動(dòng)有限的緣故.

image13.jpg

圖 入耳式的耳機(jī)阻抗稍大一點(diǎn)

軟件

因?yàn)橹饕K都是硬件生成的,所以軟件上也只是控制一個(gè)流程而已.流程就是錄制-播放兩個(gè)過(guò)程進(jìn)行循環(huán).此例子與上一篇的例子不同,僅僅使用了Cortex M4的內(nèi)核,M0+內(nèi)核除了使能Cortex M4之外沒(méi)有做任何事情.

初始化各模塊:

/* Enable global interrupts. */

__enable_irq();

/* Initialize the PCM interrupt and enable it */

Cy_SysInt_Init(&PCM_ISR_cfg, PCM_ISR_Handler);

NVIC_EnableIRQ(PCM_ISR_cfg.intrSrc);

//The Audio Play ISR

Cy_SysInt_Init(&AudioPlayISR_cfg, AudioPlay_ISR_Handler);

NVIC_EnableIRQ(AudioPlayISR_cfg.intrSrc);

/* Start the UART component for reporting the volume */

UART_Start();

AudioTimer_Start();

VDAC_Start();

AudioPWM_Start();

/* Star the PCM component */

Cy_PDM_PCM_Init(PDM_PCM_HW, &PDM_PCM_config);

Cy_PDM_PCM_Enable(PDM_PCM_HW);

此時(shí)各模塊已經(jīng)開(kāi)始工作,剛剛開(kāi)始是錄音模式.

PDM_PCM的ISR:

void PCM_ISR_Handler(void)

{

/* Set the PCM flag */

flag = 1;

/* Disable PCM ISR to avoid multiple calls to this ISR */

NVIC_DisableIRQ(PCM_ISR_cfg.intrSrc);

}

此處做標(biāo)記表示有一個(gè)FIFO的數(shù)據(jù)轉(zhuǎn)換為PCM完成需要拿走.主循環(huán)中將其放入播放buffer:

for (uint32_t i = 0; i < PDM_PCM_RX_FIFO_TRG_LVL; i++)

{

g_AudioBuff[g_RecIdx++]=(int16_t)PDM_PCM_ReadFifo();

}

一旦buffer滿了即轉(zhuǎn)為播放模式,當(dāng)中需要用戶按下SW2按鈕:

printf("To Enter Play Mode.\n");

printf("Press SW2\n");

/* Clear SW2 interrupt */

Cy_GPIO_ClearInterrupt(SW2_PORT, SW2_NUM);

while(0 == (Cy_GPIO_GetInterruptStatus(SW2_PORT, SW2_NUM)))

{

__WFI();

}

printf("Play...\n");

g_playRecFlag = true;

g_PlayIdx = 0;

在Audio Timer的ISR中更新播放Sample:

void AudioPlay_ISR_Handler(void)

{

if((true == g_playRecFlag) && (g_PlayIdx < SAMPLE_SIZE))

{

int16_t tmpV16 = g_AudioBuff[g_PlayIdx++];

VDAC_SetValueBuffered(tmpV16>>4);

int8_t tmpV8 = tmpV16/256;

if(tmpV8 < 0)

{

AudioPWM_SetCompare0(256 - tmpV8);

}

else

{

AudioPWM_SetCompare0(127 + tmpV8);

}

}

AudioTimer_ClearInterrupt(CY_TCPWM_INT_ON_CC_OR_TC);

}

注意采集進(jìn)來(lái)的數(shù)據(jù)為16bit有符號(hào)數(shù)據(jù),而DAC為12bit,PWM為8bit,需要加以轉(zhuǎn)換.一旦播放完畢需要用戶按下SW2重新開(kāi)始錄音.過(guò)程與上面的過(guò)程類似,反復(fù)循環(huán).

根據(jù)實(shí)際體驗(yàn),目前這個(gè)PDM_PCM轉(zhuǎn)換結(jié)果不是很完美,噪音較多,也有可能是本人使用不當(dāng).如有進(jìn)一步的研究結(jié)果再來(lái)匯報(bào).

總結(jié),資源與參考

Cypress的這個(gè)開(kāi)發(fā)板子CY8CKIT能玩的點(diǎn)較多,拿到板子忍不住做了不少實(shí)驗(yàn).其實(shí)編輯說(shuō)搞一兩篇就算交差了,這次也算超額完成任務(wù).官方也有一篇音頻例程,講的是檢測(cè)當(dāng)前環(huán)境的噪音水平,本人認(rèn)為過(guò)于簡(jiǎn)單于是在此基礎(chǔ)上完成了本文的實(shí)驗(yàn).

關(guān)于音頻,本人一向很感興趣,以前也寫過(guò)不少此方面的文章.包括本文做的一些實(shí)驗(yàn)其實(shí)是之前文章的延伸,故此一些過(guò)于細(xì)節(jié)的部分不想贅述,感興趣的讀者可以在本站找一下之前的文章配合閱讀.目前人工智能,語(yǔ)音識(shí)別比較熱門,作者也有心再做一點(diǎn)此方面的實(shí)驗(yàn),但是這個(gè)話題就太大,不知道能否寫出文章來(lái).

代碼下載連接:

鏈接: https://pan.baidu.com/s/1nw4o2Pr 密碼: cjtc

  • 本文系21ic原創(chuàng),未經(jīng)許可禁止轉(zhuǎn)載!

網(wǎng)友評(píng)論

  • 聯(lián)系人:巧克力娃娃
  • 郵箱:board@21ic.com
  • 我要投稿
  • 歡迎入駐,開(kāi)放投稿

熱門標(biāo)簽
項(xiàng)目外包 more+