前面博客中,咱们尝试使用开关控制有源蜂鸣器的播放。有源蜂鸣器的一大特色是使用简单,无需复杂的程序控制便可发声,然而其缺陷也很明显,其发声的频率是必定的,咱们没法经过频率控制器音调高低。本次实验,咱们将尝试使用无源蜂鸣器来进行音乐的播放。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