播放人聲,只需要 MCU!

不需要外掛任何模組或錄音IC

這個方法,理論上任何MCU都能用,包含AVR(大部分Arduino的MCU)。

這是我當初在學校教8051用的教材,發現網路上很多人都有這個需求,就放上來分享。因為要用MCU錄放聲音不是很容易,很多人都會去買貴鬆鬆的模組來用,錄音IC又很難買,絕大多數包著套件賣,很划不來。所以我就想了這個方法。

這方法雖然不用花錢買特殊零件,但很繞路,不太容易,你需要準備什麼?

  • Matlab, 用來錄音、以及轉換訊號格式。
  • 弄懂你手上MCU的PWM怎麼用。
  • 能定時改變PWM的duty cycle。最好用timer控制,如果不會,delay控制時間也可以試試看。
  • 可以把PWM output接到喇叭或耳機的線路,本文不會教你怎麼接放大電路。

首先請了解一下什麼是數位訊號處理(DSP),因為整個步驟就是DSP過程。以下這個影片請看0:00~2:48就好。注意別超過,不然會睡著。

看完了嗎?接下來就要開始動手摟!


步驟1:用Matlab錄音(A/D過程)

由於人聲的範圍是20~2KHz,加上MCU ROM容量有限,所以我這裡只能用8kHz對聲音取樣。雖然已經高於奈奎斯特取樣定理的下限2kHz*2=4kHz兩倍了,不過音質還是略差。如果你的MCU ROM很大可以提高。

請打開Matlab,輸入這些指令:

fs=8192;
duration=1;
y=wavrecord(duration*fs, fs);

Enter以後,就會立刻開始從你PC上的mic錄音,也可以輸入聲音檔案。

y現在是一個長長的陣列,有8192這麼長(因為fs*duration=8192),這些數值代表剛剛錄下來的聲音。這些數值介於-1~+1之間,為了讓MCU跑得快又不占空間,我們要把這個長長的陣列scale到0~255,在Matlab中輸入這些指令:

amplitude = 1;
y=(y*amplitude+1)*128;

amplitude是給你調大小聲的,如果不夠大聲再調高。
稍微看一下現在y是不是都有介於0~255? 如果有那scale就完成了。


步驟2:把聲音放入MCU

現在把y這個長長的陣列宣告在MCU中。為了不占用RAM,請不要用變數宣告,要用常數宣告,這樣才會把資料放在ROM裡面。

Arduino IDE是用”const”作為常數宣告修飾詞:

unsigned char const Voice[8192]={190,202,210,214,211,…………(略)……….,31,128,169,179,188,193};

keil uVision C是用”code”作為常數宣告修飾詞:

unsigned char code Voice[8192]={190,202,210,214,211,…………(略)……….,31,128,169,179,188,193};

你的MCU有可能不夠大,以下是我估算出來的秒數。89S52的ROM只有8k Bytes,光放這一段就滿了,根本無法跑任何程式,大概只能放0.9秒的內容。AVR的ROM則依型號不同,有4\8\16\32K Bytes,若用到32K Bytes ROM就可以放大約4秒的聲音了。


步驟3:把聲音用MCU的PWM播放出來(D/A過程)

把MCU的PWM設定100%=255(有些MCU是99%=255),0%=0,以這一串陣列為duty cycle,用PWM打出去。

這裡要注意時間控制,因為當初是以8192Hz取樣,播放出去也要用同等速度,所以PWM的數值要每1/8192 sec才可以跳到下一個。

注意!並不是1/8192 sec才打一次PWM,PWM要持續打不能中斷,只是duty cycle要每1/8192 sec才換到陣列中的下一個值。

Q:看了手好癢,想馬上來玩看看!但是手邊沒有Matlab或麥克風,怎麼辦?
A:沒關係,這裡有提供MG82FE(L)564的範例,實際執行狀況如下面的Demo影片。不管你用哪一種MCU,都可以把範例下載回去,將語音資料抓出來使用。

http://web.ntnu.edu.tw/~60132057A/104-1_ElectronicTechnology/EveryWeek/Week15%20-%20PlayVoiceBy8051.rar

Demo 影片

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.