如果我要用揚聲器編程一個微控制器(ATMega128)來播放真實音調,我該怎麼做?如何發送聲音給揚聲器
我是否需要使用數字/模擬轉換器來發送不同的幅度值,還是對頻率變化足夠了?無論如何,我如何編碼揚聲器需要接收的頻率和幅度值?我需要某種頻率複用嗎?我不是在談論用發言者發出簡單的聲音,如一個音符,然後是另一個音符。我想用所有的樂器,人聲等來演奏真正的歌曲。
如果我要用揚聲器編程一個微控制器(ATMega128)來播放真實音調,我該怎麼做?如何發送聲音給揚聲器
我是否需要使用數字/模擬轉換器來發送不同的幅度值,還是對頻率變化足夠了?無論如何,我如何編碼揚聲器需要接收的頻率和幅度值?我需要某種頻率複用嗎?我不是在談論用發言者發出簡單的聲音,如一個音符,然後是另一個音符。我想用所有的樂器,人聲等來演奏真正的歌曲。
你可以看看open source MP3 player,看看它們是如何做到的。我的猜測是,你需要一個D/A轉換器才能產生出色的音質。
假設你有一個未壓縮的8位22.1 千赫單波文件:
1)除去了標題
2)每1 /第二萬二千百第二:
2.1)讀取8位
2.2 )使用的DAC轉換到揚聲器的電壓範圍
2.3),它發送到揚聲器
這會給你[22.1 千赫/ 8位/單聲道]品質的聲音,是發揮現實樣本的簡單方法。
所有頻率的東西是不同的合成器所必需的。例如,PC揚聲器實際上是一個位。爲了具有不同的幅度(比'無'和'最大'),可能需要一些技巧,如脈寬調製(如你所說的那樣改變頻率,所以說話者的隔膜有效地具有比兩個更多的位置)。
但是你不需要爲此煩惱。您只需要在揚聲器上每秒發出22,100或44,200個聲音樣本,例如每個樣本8或16位來表示振幅。
非常有趣。所以從你的回答中,我認爲WAV文件實際上是聲音本身的非常真實的表現。這只是將WAV轉換爲其所代表的模擬信號的問題。我會試試這個。 – palako 2009-05-20 22:29:32
DAC部分可以用一個(相對)簡單的R-2R梯子來完成。 http://en.wikipedia.org/wiki/Resistor_Ladder。 – Evansbee 2009-05-21 00:49:11
這取決於WAV文件。 WAV格式實際上可以包含壓縮音頻 - 完整格式規範可在此處獲得:http://msdn.microsoft.com/en-us/library/ms713497.aspx – 2009-05-21 04:35:26
如果您覺得特別有創意,可以使用resistor ladder構建您自己的數模轉換器。
ATMega128上沒有足夠的空間來做任何太花哨的事情。連接揚聲器(小2" 或更小)的最簡單的方法是通過一個電阻。檢查輸出的電流吸收能力,並相應地計算R。
---------------------- +V
|
\
/R
\
/ ----------
| |
| ------ |
----| |-----| Microcontroller
/ \ |
-------- |
Speaker ---------
至於生產音,輸出的基本交換將會產生基本的stylaphone sound crapolla,你可以使用脈衝寬度調製來產生任何模擬聲音的近似值(這裏太複雜了,AtMega可能沒有足夠的吸氣或存儲),這是用來製作音頻驅動程序的方法對於沒有聲卡的電腦(只有內置揚聲器)在良好的時間...
今天,從8位微控制器播放MP3文件既簡單又便宜,您需要一個內存(例如SD卡)和MP3芯片組。例如,請參閱此article。你可以在avrfreaks找到更多。您還可以在沒有外接芯片的情況下找到播放聲音的文章。
您可以用Pulse-width modulation(PWM)播放基本聲音,但對於真正的歌曲,您需要一個DAC。我見過只使用DAC和軟件播放MP3文件的項目,但他們涉及更強大的ARM微控制器。
如果您使用的是Arduino,您可以以22美元購買Lady Ada的WaveShield。 Lady Ada提供許多值得購買的Arduino goodies。一些例子是GPS,以太網和步進/伺服屏蔽。
我試過類似的東西。首先,單片機上沒有足夠的內存來存儲真正的歌曲。你需要外部內存來處理。這意味着使用SPI接口連接外部閃存或EEPROM等。 SD也很好 - 我相信這是一個SPI風格的界面。 ATMegas有代碼與SD卡連接。
第二大問題是以適當的格式獲取數據。我會這樣做的方式是使用pulse-width modulation(PWM)來創建不同的電壓水平。我相信你在這個微控制器上有一個16位的PWM,所以你的聲音可以有16位的保真度。如果你有空間問題,你可以使用8位PWM。因此,您的聲音數據必須位於8位或16位PCM中,0x0000爲最低值,0xFFFF爲最高值。如果您想要高保真音樂,則必須具有44 KHz的採樣率才能獲得所有良好的諧波等。我相信這是PCM - 與在PC上調用相同。
那麼你將擁有所有這些值 - 對於五分鐘的音樂,你將有5 * 60 * 44000 = 13,200,000 16位值,它是211,200,000位(211兆位,26.4兆字節)。這些是您對原始數據的存儲要求。 MP3是一種可能 - 有外部芯片,但你仍然有很大的空間需求。
因此,每1/44000秒就會更新PWM寄存器中的值。您的PWM頻率必須高於4或5 - 即每個值5個PWM週期。
這是您的通用算法 - 更新PWM寄存器中的值,並讓它一直持續到結束。您至少需要一個輸出濾波器 - 將頻率限制在20KHz的可聽範圍內(如果您是發燒友的話)。一個RC濾波器可以工作,但我會選擇一個有源濾波器,因爲如果你使用PWM,你的輸出範圍通常爲0到5V,平均電壓約爲2.5V。演講者不喜歡DC水平 - 只是信號。漂亮的平均電壓爲0的正弦波。所以你的有源濾波器將不得不調整電壓電平,並使用雙電源來提供負電壓。您還可以放大大抽貝司的信號。只是不要吹出你的揚聲器。
對於PCM來說,MP3可能是更好的選擇。有芯片:http://www.sparkfun.com/commerce/product_info.php?products_id=8892
然而,這是一個完整的微控制器。你已經有一個。但是,讓我們面對它 - ATMega不會很快就會自己做MP3,不管你如何爵士樂。
它看起來像上面提到的waveshield基本上這樣做 - 使用SD卡存儲PCM和外部放大器的聲音。祝你好運!
產生穩定音的一種方法是直接數字合成。您需要一個DAC,無論是專用芯片還是電阻器階梯。
您設置了一個計數器,以您想要生成的頻率進行溢出,並在計數器的每個計數器上使用它來索引波表並獲得DAC的輸出值。
我已經爲New Noises From MidiVox寫過幾種不同的Arduino音調生成技術。 DAC更新代碼特定於MidiVox(和Adafruit WaveShield's)MCP4921,但正弦波的產生應該是普遍適用的。我試着將代碼大部分保存到ATmegas中,但是有幾個Arduino-isms悄然進入。
從該帖子粘貼,這裏有一些代碼在一個Arduino上用MCP4921 SPI總線上:
uint16_t sample = 0;
/* incr = freq * (2^16/15625)
* So for 440Hz, incr = 1845 */
uint16_t incr = 1845;
/* oscillator position */
uint16_t pos = 0;
const uint8_t sine[] = {
0x80, 0x83, 0x86, 0x89, 0x8C, 0x8F, 0x92, 0x95, 0x98, 0x9B, 0x9E, 0xA2,
0xA5, 0xA7, 0xAA, 0xAD, 0xB0, 0xB3, 0xB6, 0xB9, 0xBC, 0xBE, 0xC1, 0xC4,
0xC6, 0xC9, 0xCB, 0xCE, 0xD0, 0xD3, 0xD5, 0xD7, 0xDA, 0xDC, 0xDE, 0xE0,
0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEB, 0xED, 0xEE, 0xF0, 0xF1, 0xF3, 0xF4,
0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE,
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFD,
0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xF9, 0xF8, 0xF6, 0xF5, 0xF4, 0xF3, 0xF1,
0xF0, 0xEE, 0xED, 0xEB, 0xEA, 0xE8, 0xE6, 0xE4, 0xE2, 0xE0, 0xDE, 0xDC,
0xDA, 0xD7, 0xD5, 0xD3, 0xD0, 0xCE, 0xCB, 0xC9, 0xC6, 0xC4, 0xC1, 0xBE,
0xBC, 0xB9, 0xB6, 0xB3, 0xB0, 0xAD, 0xAA, 0xA7, 0xA5, 0xA2, 0x9E, 0x9B,
0x98, 0x95, 0x92, 0x8F, 0x8C, 0x89, 0x86, 0x83, 0x80, 0x7D, 0x7A, 0x77,
0x74, 0x71, 0x6E, 0x6B, 0x68, 0x65, 0x62, 0x5E, 0x5B, 0x59, 0x56, 0x53,
0x50, 0x4D, 0x4A, 0x47, 0x44, 0x42, 0x3F, 0x3C, 0x3A, 0x37, 0x35, 0x32,
0x30, 0x2D, 0x2B, 0x29, 0x26, 0x24, 0x22, 0x20, 0x1E, 0x1C, 0x1A, 0x18,
0x16, 0x15, 0x13, 0x12, 0x10, 0x0F, 0x0D, 0x0C, 0x0B, 0x0A, 0x08, 0x07,
0x06, 0x06, 0x05, 0x04, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06,
0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x12, 0x13, 0x15,
0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x29, 0x2B, 0x2D,
0x30, 0x32, 0x35, 0x37, 0x3A, 0x3C, 0x3F, 0x42, 0x44, 0x47, 0x4A, 0x4D,
0x50, 0x53, 0x56, 0x59, 0x5B, 0x5E, 0x62, 0x65, 0x68, 0x6B, 0x6E, 0x71,
0x74, 0x77, 0x7A, 0x7D
};
void setup() {
cli();
/* Enable interrupt on timer2 == 127, with clk/8 prescaler. At 16MHz,
this gives a timer interrupt at 15625Hz. */
TIMSK2 = (1 << OCIE2A);
OCR2A = 127;
/* clear/reset timer on match */
TCCR2A = 1<<WGM21 | 0<<WGM20; /* CTC mode, reset on match */
TCCR2B = 0<<CS22 | 1<<CS21 | 0<<CS20; /* clk, /8 prescaler */
SPCR = 0x50;
SPSR = 0x01;
DDRB |= 0x2E;
PORTB |= (1<<1);
sei();
}
ISR(TIMER2_COMPA_vect) {
/* OCR2A has been cleared, per TCCR2A above */
OCR2A = 127;
pos += incr;
/* shift left a couple of bits for more volume */
sample = sine[highByte(pos)] << 2;
PORTB &= ~(1<<1);
/* buffered, 1x gain, active mode */
SPDR = highByte(sample) | 0x70;
while (!(SPSR & (1<<SPIF)));
SPDR = lowByte(sample);
while (!(SPSR & (1<<SPIF)));
PORTB |= (1<<1);
}
void loop() {
}
有關直接數字合成的漂亮的事情是,它是非常容易發揮多個音調在一起(添加),或在所需卷(添加前通過的體積乘以)其混合。
我發現Arduino可以使用這種方法同時播放約30個音調。我的具體應用是Hammond organ simulation,這也可能證明有用的閱讀。
有趣的項目,但不幸的是他「聲音」的聲音解碼部分到第三方芯片: 「另一個板載芯片是來自芬蘭VLSI的VS1011,它是一個.mp3和.wav解碼器芯片,一個DAC和一個耳機放大器都在一個28引腳封裝「 我自己做了之後,只是爲了學習:) – palako 2009-05-20 22:28:12