您现在的位置是:首页 > 正文

树莓派4B ubuntu20.04 python控制pwm 蜂鸣器播放歌曲 教程

2024-04-01 03:32:59阅读 1

本文参考自:

https://shumeipai.nxez.com/2020/11/18/raspberry-pi-controls-the-buzzer-to-play-music.html

 

驱动蜂鸣器

蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电

 

有源蜂鸣器和无源蜂鸣器

有源蜂鸣器是给一个高电平就会响,响的频率不会改变,内部带震荡电路,一通电就鸣叫,所以可以跟前面LED一样,给个高电平就能响,编程比无源的更方便。

无源蜂鸣器内部没有震荡源,直流信号无法让它鸣叫。必须用去震荡的电流驱动它,给一系列脉冲才会响,声音频率可控,可以做出不同的音效。这里我们以无源蜂鸣器为例子。

 

 

蜂鸣器的外观

 

PWM

PWM(Pulse Width Modulation)即脉冲宽度调制,是一种利用微处理器的数字输出来控制模拟电路的控制技术。可以用下面的一幅图来形象地说明PWM:

 

图中tpwm就是一个周期的时间长度。对于2KHz频率来说,那么周期就是1s/2K=500us。图中的D叫做占空比,指的是高电平的时间占用整个周期时间的百分比。第一个周期D=50%,那么就是高电平低电平的时间各占一半。接下来的D为33%,那就是通电时间为33%,剩余的不通电时间占用67%。

所有引脚都能够进行软件PWM,而GPIO12、GPIO13、GPIO18、GPIO19(对应引脚12 、32、33 、35)则能够进行硬件脉冲宽度调制。具体引脚可以参考上面开头介绍GPIO的图。

需要注意的是BCM2711芯片只支持两路PWM输出,所以以上12 Pin脚和32 Pin脚对应的都是channel 1的PWM输出,即如果这两个Pin的功能都选择的是PWM输出,则它们输出的PWM是完全相同的,同理33 Pin脚和35 Pin脚对应芯片channel 2的PWM输出。

 

硬件连接图

红色杜邦线一头连接树莓派的32 Pin脚(PWM0),一头连接蜂鸣器正极。黑色杜邦线一头连接树莓派的30Pin脚(ground),一头连接蜂鸣器负极。

 

此程序的是将pwm频率从1000hz每次递增10,一直到2000hz,再从2000hz每次递减10到1000hz,如此反复。

 

软件编写

# -*- coding: utf-8 -*-
#coding=utf-8
import RPi.GPIO as GPIO
import time


GPIO.setwarnings(False)     
GPIO.setmode(GPIO.BCM)      #设置GPIO模式
GPIO.setup(12,GPIO.OUT)      #将BCM12号引脚设置为输出模式


pwm = GPIO.PWM(12,1000)     #设置BCM12号引脚, 设置pwm频率为1000HZ
pwm.start(50)                #设置初始占空比(范围:0.0 <= dc <= 100.0)
#pwm.ChangeFrequency(freq)   # freq 为设置的新频率,单位为 Hz
#pwm.ChangeDutyCycle(dc)     # dc 为设置的新的占空比 范围:0.0-100.0



i=1000    #频率
dirs = 1    #频率递增方向,1为正,-1为负

try:
    while i:
        pwm.ChangeFrequency(i)   #为设置的新频率,单位为 Hz
        i=i+10*dirs               #当前频率加上要增加的频率(10)乘以方向
        time.sleep(0.05)          #延时0.05秒
        print('pwm当前频率为: %d '% i)#控制台打印当前的频率
        if i>=2000:               #如果当前频率大于2000hz,方向改为负
            dirs = -1
        elif i<=1000:              #如果当前频率小于1000hz,方向改为正
            dirs = 1


finally:
        print("clean up all GPIO..." )



 

扩展延伸

通过pwm播放音乐。每个音符由音调和演奏时间组成。不同的音调在物理上就对应不同频率的音波。所以我们只要控制输出的频率和时长就能输出一首音乐了。每个音符都会播放一定的时间,这样就能构成一首歌曲。在音乐上,音符节奏分为1拍、1/2拍、1/4拍、1/8拍,假设一拍音符的时间为1;半拍为0.5;1/4拍为0.25;1/8拍为0.125……,所以我们可以为每个音符赋予这样的拍子播放出来,音乐就成了。

 

程序

# -*- coding: utf-8 -*-
#coding=utf-8
import RPi.GPIO as GPIO
import time


#定义不同音调的频率
NOTE_B0=31
NOTE_C1=33
NOTE_CS1=35
NOTE_D1=37
NOTE_DS1=39
NOTE_E1=41
NOTE_F1=44
NOTE_FS1=46
NOTE_G1=49
NOTE_GS1=52
NOTE_A1=55
NOTE_AS1=58
NOTE_B1=62
NOTE_C2=65
NOTE_CS2=69
NOTE_D2=73
NOTE_DS2=78
NOTE_E2=82
NOTE_F2=87
NOTE_FS2=93
NOTE_G2=98
NOTE_GS2=104
NOTE_A2=110
NOTE_AS2=117
NOTE_B2=123
NOTE_C3=131
NOTE_CS3=139
NOTE_D3=147
NOTE_DS3=156
NOTE_E3=165
NOTE_F3=175
NOTE_FS3=185
NOTE_G3=196
NOTE_GS3=208
NOTE_A3=220
NOTE_AS3=233
NOTE_B3=247
NOTE_C4=262
NOTE_CS4=277
NOTE_D4=294
NOTE_DS4=311
NOTE_E4=330
NOTE_F4=349
NOTE_FS4=370
NOTE_G4=392
NOTE_GS4=415
NOTE_A4=440
NOTE_AS4=466
NOTE_B4=494
NOTE_C5=523
NOTE_CS5=554
NOTE_D5=587
NOTE_DS5=622
NOTE_E5=659
NOTE_F5=698
NOTE_FS5=740
NOTE_G5=784
NOTE_GS5=831
NOTE_A5=880
NOTE_AS5=932
NOTE_B5=988
NOTE_C6=1047
NOTE_CS6=1109
NOTE_D6=1175
NOTE_DS6=1245
NOTE_E6=1319
NOTE_F6=1397
NOTE_FS6=1480
NOTE_G6=1568
NOTE_GS6=1661
NOTE_A6=1760
NOTE_AS6=1865
NOTE_B6=1976
NOTE_C7=2093
NOTE_CS7=2217
NOTE_D7=2349
NOTE_DS7=2489
NOTE_E7=2637
NOTE_F7=2794
NOTE_FS7=2960
NOTE_G7=3136
NOTE_GS7=3322
NOTE_A7=3520
NOTE_AS7=3729
NOTE_B7=3951
NOTE_C8=4186
NOTE_CS8=4435
NOTE_D8=4699
NOTE_DS8=4978



#歌曲谱子,[音调,时间]
melody =[
   # 1
   [NOTE_A4, 1.5],      # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_A4, 1],        # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_E4, 0.5],      # 3
   # 2
   [NOTE_G4, 1],        # 5
   [NOTE_D4, 3],        # 2
   # 3
   [NOTE_C4, 1.5],      # 1
   [NOTE_A3, 0.5],      # .6
   [NOTE_D4, 0.5],      # 2
   [NOTE_E4, 0.5],      # 3
   [NOTE_G4, 0.5],      # 5
   [NOTE_F4, 0.5],      # 4
   # 4
   [NOTE_E4, 3],        # 3
   [NOTE_E4, 0.5],      # 3
   [NOTE_G4, 0.5],      # 5
   # 5
   [NOTE_A4, 1.5],      # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_A4, 1],        # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_E4, 0.5],      # 5
   # 6
   [NOTE_G4, 1],        # 5
   [NOTE_D4, 3],        # 2
   # 7
   [NOTE_C4, 1.5],      # 1
   [NOTE_A3, 0.5],      # .6
   [NOTE_D4, 0.5],      # 2
   [NOTE_E4, 0.5],      # 3
   [NOTE_G3, 0.5],      # .5
   [NOTE_B3, 0.5],      # .7
   # 8
   [NOTE_A3, 4],        # .6
   [0, 1],              # 0
   [NOTE_E4, 0.5],      # 3
   [NOTE_D4, 0.5],      # 2
   [NOTE_C4, 1.5],      # 1
   [NOTE_B3, 0.5],      # .7
   #
   [NOTE_A3, 1.5],      # .6
   [NOTE_E3, 0.5],      # .3
   [NOTE_A3, 2],        # .6
   #
   [NOTE_A3, 1],        # .6
   [NOTE_A4, 0.5],      # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_E4, 1],        # 3
   [NOTE_G4, 0.5],      # 5
   [NOTE_D4, 0.5],      # 2
   [NOTE_E4, 3],        # 3
   [NOTE_E4, 0.5],      # 3
   [NOTE_D4, 0.5],      # 2
   [NOTE_C4, 1.5],      # 1
   [NOTE_B3, 0.5],      # .7
   [NOTE_A3, 1.5],        # .6
   [NOTE_E3, 0.5],        # .6
   [NOTE_A3, 2],          # .6
   [0, 1],              # 0
   [NOTE_D4, 0.5],      # 2
   [NOTE_C4, 0.5],      # 1
   [NOTE_A3, 1],        # .6
   [NOTE_C4, 0.5],      # 1
   [NOTE_D4, 0.5],      # 1
   [NOTE_E4, 3],        # 3
   [NOTE_E4, 1],        # 3
   [NOTE_A4, 1.5],      # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_A4, 1],        # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_E4, 0.5],      # 3
   [NOTE_G4, 1],        # 5
   [NOTE_D4, 3],        # 2
   [NOTE_C4, 1.5],      # 1
   [NOTE_A3, 0.5],      # .6
   [NOTE_D4, 0.5],      # 2
   [NOTE_E4, 0.5],      # 3
   [NOTE_G4, 0.5],      # 5
   [NOTE_FS4, 0.5],     # #4

    

   [NOTE_E4, 3],        # 3
   [NOTE_E4, 0.5],      # 3
   [NOTE_G4, 0.5],      # 5

    
   [NOTE_A4, 1.5],      # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_A4, 1.0],      # 6
   [NOTE_G4, 0.5],      # 5
   [NOTE_E4, 0.5],      # 3

    

   [NOTE_G4, 1.0],      # 5
   [NOTE_D4, 3],        # 2

    

   [NOTE_C4, 1.5],      # 1
   [NOTE_A3, 0.5],      # .6
   [NOTE_D4, 0.5],      # 2
   [NOTE_E4, 0.5],      # 3
   [NOTE_G3, 0.5],      # .5
   [NOTE_B3, 0.5],      # .7

    

   [NOTE_A3, 3],         # .6


   [0, 1],              # 0
   [NOTE_E4, 0.5],      # 3
   [NOTE_D4, 0.5],      # 2
   [NOTE_C4, 1.0],      # 1
   [NOTE_C4, 0.5],      # 1
   [NOTE_B3, 0.5],      # .7

    

   [NOTE_A3, 1.5],      # .6
   [NOTE_E3, 0.5],      # .3
   [NOTE_A3, 2.0],      # .6

    

   [0, 1],              # 0
   [NOTE_A3, 0.5],      # .6
   [NOTE_G3, 0.5],      # .5
   [NOTE_E3, 1.0],      # .3
   [NOTE_G3, 0.5],      # .5
   [NOTE_D3, 0.5],      # .2

    

   [NOTE_E3, 3.0],      # .3

    

   [0, 1],              # 0
   [NOTE_E4, 0.5],      # 3
   [NOTE_D4, 0.5],      # 2
   [NOTE_C4, 1.0],      # 
   [NOTE_C4, 0.5],      # 1
   [NOTE_B3, 0.5],      # .7

    
   [NOTE_A3, 1.5],      # .6
   [NOTE_E4, 0.5],      # 3
   [NOTE_D4, 2.0],      # 2

    

   [0, 1],              # 0
   [NOTE_D4, 0.5],      # 2
   [NOTE_C4, 0.5],      # 1
   [NOTE_A3, 1.0],      # .6
   [NOTE_B3, 0.5],      # .7
   [NOTE_G3, 0.5],      # .5
    
   [NOTE_A3, 3.0],      # .6
 ]



#播放一组音调,(频率,时间,pwm对象)
def  beep(freq, t_ms ,pwm):
    if freq == 0:
        ranges=1
    else :
        ranges=freq
    print("will call change freq: %d range: %d\n" %(freq, ranges))
    pwm.ChangeFrequency(ranges)   # 设置的新频率,单位为 Hz
    pwm.ChangeDutyCycle(95)  # 改变占空比范围:0.0 <= dc <= 100.0


    if t_ms>0:
        time.sleep(t_ms)      #持续输出此频率t_ms秒
    return



GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)      #设置GPIO模式
GPIO.setup(12,GPIO.OUT)      #设置BCM12引脚为输出模式


pwm = GPIO.PWM(12,1000)    #设置BCM12引脚为PWM模式 , 设置频率为1000HZ
pwm.start(50)   #设置初始占空比为50%(范围:0.0 <= dc <= 100.0)



index=0  #索引,为了遍历出melody列表


try:
    while 1:
        noteDuration = melody[index][1]     #获取当前索引melody列表中的时间
        beep(melody[index][0], noteDuration,pwm)   #设置当前索引的频率和时间给beep函数
        index = index + 1    #索引加一,向下索引
        if index>=121:      #列表一共121条,到了120跳出循环
            break

finally:
        print("clean up all GPIO..." )
        pwm.ChangeDutyCycle(0)       #将占空比设置为0停止播放

        
pwm.ChangeDutyCycle(0)               #将占空比设置为0停止播放

 

网站文章

  • Fiddler “抓包“最新详细教程,黑客入门到精通,从这篇文章开始

    Fiddler “抓包“最新详细教程,黑客入门到精通,从这篇文章开始

    Fiddler工具介绍是一个通过的方式来进行抓包工具,运行时会在本地建立一个代理服务,默认地址:127.0.0.1:8888。Fiddler开启之后,配置代理,再打开IE浏览器,IE的PROXY会自动...

    2024-04-01 03:32:53
  • js 数组中赋值对象 组成数组中的对象

    function activeitySubmit(){//模糊搜索id以schoolplan_two开头的标签长度 var confCount = $('[id^=schoolplan_two]').length;//conf为元素id值 var data=[];//声明一个数组 var a=new Aarray(); 推荐使用 var data=[]; for(var...

    2024-04-01 03:32:46
  • 学习算法

    转载请注明出处:http://blog.csdn.net/awebkit1. BM算法(模式串匹配)看了好几天,终于半看懂了,太复杂,自己也比较迟钝我觉得网上讲解的比较清楚的应该属于如下链接。http://blog.csdn.net/sealyao/article/details/4568167注:1. 算法正确(我觉得很多其他网站讲的算法是错误的),讲解清楚,

    2024-04-01 03:32:05
  • 【leetcode 二叉树 C++】1325. Delete Leaves With a Given Value

    【leetcode 二叉树 C++】1325. Delete Leaves With a Given Value

    1325. Delete Leaves With a Given Value /** * Definition for a binary tree node. * struct TreeNode { ...

    2024-04-01 03:31:58
  • Javaweb设置session过期时间

    在Java Web开发中,Session为我们提供了很多方便,Session是由浏览器和服务器之间维护的。Session超时理解为:浏览器和服务器之间创建了一个Session,由于客户端长时间(休眠时间)没有与服务器交互,服务器将此Session销毁,客户端再一次与服务器交互时之前的Session就不存在了。 设置Session超时时间方式 方式一:在web.xml中设置sess...

    2024-04-01 03:31:51
  • Halting problem(停机问题)

    1.Introduction In computability theory, the halting problem is the problem of determining, from a description of an arbitrary computer program and an input, whether the program will finish running or

    2024-04-01 03:31:45
  • 修改 navigator.platform 的值

    // ==UserScript== // @name 修改 navigator.platform 的值 // @namespace http://tampermonkey.net/ // @versi...

    2024-04-01 03:31:02
  • php require_once 绝对路径,关于php:使用require_once的路径错误

    我在尝试使用require_once时遇到问题。我指定了错误的路径,但找不到解决方案。我有一个名为header.php的文件,该文件通过使用require_once包括两个文件:functions.p...

    2024-04-01 03:30:54
  • Centos6.5 安装Composer

    对于现代语言而言,包管理器基本上是标配。Java有Maven,Python有pip,Ruby有gem,Nodejs有npm。PHP的则是PEAR,不过PEAR坑不少:依赖处理容易出问题配置非常复杂难用的命令行接口好在我们有Composer,PHP依赖管理的利器。它是开源的,使用起来也很简单,提交自己的包也很容易。安装ComposerComposer需要PHP 5.3.2+才能运

    2024-04-01 03:30:46
  • 南农计算机考研真题,2021南京农业大学考研历年真题

    该楼层疑似违规已被系统折叠隐藏此楼查看此楼来源:http://fangcai.100xuexi.com/Ebook/DigitalLibrary/BookNew.aspx?BookName=%u535...

    2024-04-01 03:30:03