前面博客中,咱們嘗試使用開關控制有源蜂鳴器的播放。有源蜂鳴器的一大特色是使用簡單,無需複雜的程序控制便可發聲,然而其缺陷也很明顯,其發聲的頻率是必定的,咱們沒法經過頻率控制器音調高低。本次實驗,咱們將嘗試使用無源蜂鳴器來進行音樂的播放。python
在開始本實驗前,咱們先來對樂理只是和無源蜂鳴器的工做原理進行簡單的學習。編程
簡單的物理學知識告訴咱們,聲音的聲調高低是有聲波的頻率決定的,而聲音的大小是有聲波的振幅決定的。人耳能夠聽到的聲音頻率在20Hz-20000Hz之間。頻率低於20Hz的聲波被稱爲次聲波,咱們聽不到。一樣,頻率高於20000Hz的聲波稱爲超聲波,咱們也聽不到。生活中,咱們都喜歡聽美妙的音樂,音樂是由不少不一樣的音調和參差的拍子組合而成的。小時候音樂課上常說的Do,Re,Mi,Fa,So,La,Xi就是最多見的音調。咱們以C大調爲例,其7個音階與對應的頻率以下表所示:markdown
Do | Re | Mi | Fa | So | La | Xi |
---|---|---|---|---|---|---|
262 | 294 | 330 | 350 | 393 | 441 | 495 |
與上表對應,若是是高音音調,只須要將上面的頻率乘以2,若是是低音音調,須要將上面的音頻除以2。ide
要演奏出美妙的旋律,僅僅只控制音調是不夠的,咱們還須要把握每一個音調演奏的節奏,即每一個音調播放的時長。在樂曲中,節奏的把控是經過節拍來定義的,例如常見的四分之四節拍,指的是四分音符爲一拍,每小節有四拍,這樣,每遇到一個四分音符咱們就播放這個音調一拍的單位時間,若是遇到八分音符,咱們就播放二分之一拍的單位時間,若是遇到二分音符,咱們就播放兩拍的單位時間。oop
如今,你能夠練習一下,將喜歡的歌曲翻譯爲編程符號,音調翻譯成頻率,對應的節拍翻譯爲毫秒時間。後面,咱們將使用樹莓派控制蜂鳴器來播放它。佈局
以前,咱們分析過有源蜂鳴器的工做原理,其很好理解,電壓觸發器內部的振盪源工做,震盪源的震動產生必定頻率的聲波,從而發出聲音讓咱們聽到。無源蜂鳴器內部沒有震盪源,若是直接經過直流電,其沒法產生週期性的聲波,所以簡單的接通電源是沒法使無源蜂鳴器工做的。無源蜂鳴器內部沒有震盪源,但卻有震盪片,當通電時,無源蜂鳴器經過電磁感應現象來吸引震盪片,當失去電流時,震盪片位置還原。所以,咱們只要週期性的給蜂鳴器通電,其就會產生週期性的振盪,從而產生聲波,發出聲音。學習
因爲無源蜂鳴器的這種特色,咱們能夠很是容易的經過控制加壓的頻率來實現播放不一樣音調的聲音。相比有源蜂鳴器而言,無源蜂鳴器成本更低,且能夠控制音調高低,惟一的不足之處是程序要略微複雜一些。編碼
本次實驗,咱們使用的無源蜂鳴器是低電平觸發的,以下圖所示:翻譯
明白了無源蜂鳴器的工做原理,本實驗對你來講應該很是簡單,使用到的知識都是咱們以前實驗有涉及過的。當你聽到視頻頻率來控制無緣蜂鳴器的發聲時,你必定已經想到了,使用PWM脈衝寬度調製技術,其恰好能夠產生指定頻率的脈衝電壓。code
連線自己很是簡單,只是在開始以前,咱們要先肯定所使用的樹莓派引腳。無緣蜂鳴器有3個引腳,其中VCC接3.3V電源,GMD接地,I/O控制引腳接一個樹莓派的GPIO功能引腳,咱們選擇BCM編碼爲17的GPIO引腳,即物理引腳11。筆者這裏使用的擴展板鏈接以下圖所示:
這一步很是簡單,下面咱們來開始程序的編寫。
在本實驗中,咱們將編寫這個一個程序,其相似一個簡易的電子琴,有7個按鍵來發出不一樣音調的7種聲音,同時咱們內置一首示例樂曲。筆者這裏選用周杰倫的《花海》前奏做爲示例樂曲。完整的程序示例代碼以下(我建議先自主動手實踐,遇到問題再參考示例代碼):
#coding:utf-8 # 導入UI模塊 import tkinter as Tkinter import RPi.GPIO as GPIO import time # 定義音調頻率 # C調低音 CL = [0, 131, 147, 165, 175, 196, 211, 248] # C調中音 CM = [0, 262, 294, 330, 350, 393, 441, 495] # C調高音 CH = [0, 525, 589, 661, 700, 786, 882, 990] # 定義曲譜 # 音調 0表示休止符 songP = [ CM[1],CM[2],CM[3],CM[5],CM[5],CM[0],CM[3],CM[2],CM[1],CM[2],CM[3],CM[0], CM[1],CM[2],CM[3],CM[7],CH[1],CH[1],CH[1],CM[7],CH[1],CM[7],CM[6],CM[5],CM[0], CM[1],CM[2],CM[3],CM[5],CM[5],CM[0],CM[3],CM[2],CM[1],CM[2],CM[1],CM[0], CM[1],CM[2],CM[3],CM[5],CM[1],CM[0],CM[1],CL[7],CL[6],CL[7],CM[1],CM[0] ] # 音調對應的節拍 songT = [ 2,2,2,1,5,4,2,2,2,1,5,4, 2,2,2,1,5,2,2,2,1,3,2,4,4, 2,2,2,1,5,4,2,2,2,1,3,5, 2,2,2,1,5,4,2,2,2,2,8,2 ] # 定義標準節拍時間 metre = 0.125 # 初始化要使用的引腳 io = 11 GPIO.setmode(GPIO.BOARD) GPIO.setup(io, GPIO.OUT) pwm = GPIO.PWM(io, 440) # 開始設置佔空比爲100 則無緣蜂鳴器不會發聲 pwm.start(100) # 播放示例樂曲的方法 def playSong(): # 修改佔空比爲50 此時頻率生效 pwm.ChangeDutyCycle(50) # 遍歷全部音調 for i in range(0, len(songP)): # 0表示休止 禁聲 if songP[i] == 0: pwm.ChangeDutyCycle(100) # 更改頻率控制音調 else: pwm.ChangeDutyCycle(50) pwm.ChangeFrequency(songP[i]) # 經過節拍控制播放時間 time.sleep(songT[i] * metre) # 禁聲 pwm.ChangeDutyCycle(100) # 分別播放各個音階的方法 def playDo(): pwm.ChangeDutyCycle(50) pwm.ChangeFrequency(CM[1]) time.sleep(0.5) pwm.ChangeDutyCycle(100) def playRe(): pwm.ChangeDutyCycle(50) pwm.ChangeFrequency(CM[2]) time.sleep(0.5) pwm.ChangeDutyCycle(100) def playMi(): pwm.ChangeDutyCycle(50) pwm.ChangeFrequency(CM[3]) time.sleep(0.5) pwm.ChangeDutyCycle(100) def playFa(): pwm.ChangeDutyCycle(50) pwm.ChangeFrequency(CM[4]) time.sleep(0.5) pwm.ChangeDutyCycle(100) def playSo(): pwm.ChangeDutyCycle(50) pwm.ChangeFrequency(CM[5]) time.sleep(0.5) pwm.ChangeDutyCycle(100) def playLa(): pwm.ChangeDutyCycle(50) pwm.ChangeFrequency(CM[6]) time.sleep(0.5) pwm.ChangeDutyCycle(100) def playXi(): pwm.ChangeDutyCycle(50) pwm.ChangeFrequency(CM[7]) time.sleep(0.5) pwm.ChangeDutyCycle(100) # UI相關設置 # 主頁面設置 top = Tkinter.Tk() top.geometry('360x300') top.minsize(420, 300) top.maxsize(420, 300) top.title("自制電子琴") l = Tkinter.Label(top, text='自制電子琴', font=('Arial', 18), width=30, height=2) l.pack() # UI上的按鈕佈局 songBtn = Tkinter.Button(top, text="示例歌曲:花海", command=playSong) songBtn.place(x=30,y=30,width=120,height=40) doBtn = Tkinter.Button(top,bitmap="gray50", text="Do", compound=Tkinter.LEFT, command=playDo) doBtn.place(x=0,y=105,width=60,height=200) reBtn = Tkinter.Button(top,bitmap="gray50", text="Re", compound=Tkinter.LEFT, command=playRe) reBtn.place(x=60,y=105,width=60,height=200) miBtn = Tkinter.Button(top,bitmap="gray50", text="Mi", compound=Tkinter.LEFT, command=playMi) miBtn.place(x=120,y=105,width=60,height=200) faBtn = Tkinter.Button(top,bitmap="gray50", text="Fa", compound=Tkinter.LEFT, command=playFa) faBtn.place(x=180,y=105,width=60,height=200) soBtn = Tkinter.Button(top,bitmap="gray50", text="So", compound=Tkinter.LEFT, command=playSo) soBtn.place(x=240,y=105,width=60,height=200) laBtn = Tkinter.Button(top,bitmap="gray50", text="La", compound=Tkinter.LEFT, command=playLa) laBtn.place(x=300,y=105,width=60,height=200) xiBtn = Tkinter.Button(top,bitmap="gray50", text="Xi", compound=Tkinter.LEFT, command=playXi) xiBtn.place(x=360,y=105,width=60,height=200) stopButton = Tkinter.Button(top, text="關閉") stopButton.place(x=340,y=30,width=60,height=40) # 進入消息循環 top.mainloop()
上面代碼有比較詳盡的註釋,程序運行的UI效果以下圖所示:
如今,盡情的玩耍吧!
專一技術,懂的熱愛,願意分享,作個朋友
QQ:316045346