树莓派56/100 - 用Pico连接蜂鸣器演奏音乐,用来纪念儿时玩的超级玛丽游戏

在第18篇文章里,介绍了有源和无源蜂鸣器,通过控制蜂鸣器的频率,也可以发出简单的音乐,这篇文章里介绍了简单的乐理知识,可惜我五音不全,只能把这些频率数据抄下来,更精确的频率数据见这里

也大概学习了十二平均律,Do、Re、Mi、Fa、Sol、La、Si里面还有好几个半音,每12个为一组,低八度频率减半,高八度频率加倍,也就这么多了。

蜂鸣器只需接2个引脚,一端接地,另一端我接GP20,连跳线也省了。
在这里插入图片描述
代码:

import machine
import urandom
import utime

buzzer = machine.PWM(machine.Pin(20, machine.Pin.OUT))

tones = {
    "B0": 31,
    
    "C1": 33, "CS1": 35, "D1": 37, "DS1": 39,  "E1": 41, "F1": 44,
    "FS1": 46, "G1": 49, "GS1": 52, "A1": 55, "AS1": 58, "B1": 62,
    
    "C2": 65, "CS2": 69, "D2": 73, "DS2": 78, "E2": 82, "F2": 87,
    "FS2": 93, "G2": 98, "GS2": 104, "A2": 110, "AS2": 117, "B2": 123,
    
    "C3": 131, "CS3": 139, "D3": 147, "DS3": 156, "E3": 165, "F3": 175,
    "FS3": 185, "G3": 196, "GS3": 208, "A3": 220,  "AS3": 233, "B3": 247,
    
    "C4": 262, "CS4": 277, "D4": 294, "DS4": 311, "E4": 330, "F4": 349,
    "FS4": 370, "G4": 392, "GS4": 415, "A4": 440, "AS4": 466, "B4": 494,
    
    "C5": 523, "CS5": 554, "D5": 587, "DS5": 622, "E5": 659, "F5": 698,
    "FS5": 740, "G5": 784, "GS5": 831, "A5": 880, "AS5": 932, "B5": 988,
    
    "C6": 1047, "CS6": 1109, "D6": 1175, "DS6": 1245, "E6": 1319, "F6": 1397,
    "FS6": 1480, "G6": 1568, "GS6": 1661, "A6": 1760, "AS6": 1865, "B6": 1976,
    
    "C7": 2093, "CS7": 2217, "D7": 2349, "DS7": 2489, "E7": 2637, "F7": 2794,
    "FS7": 2960, "G7": 3136, "GS7": 3322, "A7": 3520, "AS7": 3729, "B7": 3951,
    
    "C8": 4186, "CS8": 4435, "D8": 4699, "DS8": 4978,
}

def playtone(frequency):
    buzzer.duty_u16(1000)
    buzzer.freq(frequency)

def bequiet():
    buzzer.duty_u16(0)

def playsong(mysong):
    for s in mysong:
        if (s == "P"):
            bequiet()
        else:
            playtone(tones[s])
        utime.sleep(0.3)

song = ["E5","G5","A5","P","E5","G5","B5","A5","P","E5","G5","A5","P","G5","E5"]
playsong(song)
bequiet()

另外一篇文章,加上了延时,编个曲还是挺麻烦的。

# Author: peppe8o
# Blog: https://peppe8o.com
# Date: Oct 6th, 2021
# Version: 1.0

from machine import Pin, PWM
from time import sleep

buzzerPIN=20
BuzzerObj=PWM(Pin(buzzerPIN))

def buzzer(buzzerPinObject,frequency,sound_duration,silence_duration):
    # Set duty cycle to a positive value to emit sound from buzzer
    buzzerPinObject.duty_u16(int(65536*0.2))
    # Set frequency
    buzzerPinObject.freq(frequency)
    # wait for sound duration
    sleep(sound_duration)
    # Set duty cycle to zero to stop sound
    buzzerPinObject.duty_u16(int(65536*0))
    # Wait for sound interrumption, if needed 
    sleep(silence_duration)


# Play following notes by changing frequency:
#C (DO)
buzzer(BuzzerObj,523,0.5,0.1)

#D (RE)
buzzer(BuzzerObj,587,0.5,0.1)

#E (MI)
buzzer(BuzzerObj,659,0.5,0.1)

#F (FA)
buzzer(BuzzerObj,698,0.5,0.1)

#G (SOL)
buzzer(BuzzerObj,784,0.5,0.1)

#A (LA)
buzzer(BuzzerObj,880,0.5,0.1)

#B (SI)
buzzer(BuzzerObj,987,0.5,0.1)

#Deactivates the buzzer
BuzzerObj.deinit()

还有一个更强大的,来自这个网站,还可以到 https://onlinesequencer.net 这个网站进行在线创作,把曲谱的代码复制出来,就可以播放了。

类库buzzer_music.py文件是:

"""
Micropython (Raspberry Pi Pico)
Plays music written on onlinesequencer.net through a passive piezo buzzer.
Uses fast arpeggios with a single buzzer to simulate polyphony
Also supports multiple buzzers at once for real polyphony
https://github.com/james1236/buzzer_music
"""

from machine import Pin, PWM
from math import ceil

tones = {
    'C0':16, 'C#0':17, 'D0':18, 'D#0':19, 'E0':21, 'F0':22,
    'F#0':23, 'G0':24, 'G#0':26, 'A0':28, 'A#0':29, 'B0':31,
    'C1':33, 'C#1':35, 'D1':37, 'D#1':39, 'E1':41, 'F1':44,
    'F#1':46, 'G1':49, 'G#1':52, 'A1':55, 'A#1':58, 'B1':62,
    'C2':65, 'C#2':69, 'D2':73, 'D#2':78, 'E2':82, 'F2':87,
    'F#2':92, 'G2':98, 'G#2':104, 'A2':110, 'A#2':117, 'B2':123,
    'C3':131, 'C#3':139, 'D3':147, 'D#3':156, 'E3':165, 'F3':175,
    'F#3':185, 'G3':196, 'G#3':208, 'A3':220, 'A#3':233, 'B3':247,
    'C4':262, 'C#4':277, 'D4':294, 'D#4':311, 'E4':330, 'F4':349,
    'F#4':370, 'G4':392, 'G#4':415, 'A4':440, 'A#4':466, 'B4':494,
    'C5':523, 'C#5':554, 'D5':587, 'D#5':622, 'E5':659, 'F5':698,
    'F#5':740, 'G5':784, 'G#5':831, 'A5':880, 'A#5':932, 'B5':988,
    'C6':1047, 'C#6':1109, 'D6':1175, 'D#6':1245, 'E6':1319, 'F6':1397,
    'F#6':1480, 'G6':1568, 'G#6':1661, 'A6':1760, 'A#6':1865, 'B6':1976,
    'C7':2093, 'C#7':2217, 'D7':2349, 'D#7':2489, 'E7':2637, 'F7':2794,
    'F#7':2960, 'G7':3136, 'G#7':3322, 'A7':3520, 'A#7':3729, 'B7':3951,
    'C8':4186, 'C#8':4435, 'D8':4699, 'D#8':4978, 'E8':5274, 'F8':5588,
    'F#8':5920, 'G8':6272, 'G#8':6645, 'A8':7040, 'A#8':7459, 'B8':7902,
    'C9':8372, 'C#9':8870, 'D9':9397, 'D#9':9956, 'E9':10548, 'F9':11175,
    'F#9':11840, 'G9':12544, 'G#9':13290, 'A9':14080, 'A#9':14917, 'B9':15804
}

#Time, Note, Duration, Instrument (onlinesequencer.net schematic format)
#0 D4 8 0;0 D5 8 0;0 G4 8 0;8 C5 2 0;10 B4 2 0;12 G4 2 0;14 F4 1 0;15 G4 17 0;16 D4 8 0;24 C4 8 0

class music:
    def __init__(self, songString='0 D4 8 0', looping=True, tempo=3, duty=2512, pin=None, pins=[Pin(0)]):
        self.tempo = tempo
        self.song = songString
        self.looping = looping
        self.duty = duty
        
        self.stopped = False
        
        self.timer = -1
        self.beat = -1
        self.arpnote = 0
        
        self.pwms = []
        
        if (not (pin is None)):
            pins = [pin]
            
        i = 0
        for pin in pins:
            self.pwms.append(PWM(pins[i]))
            i = i + 1
        
        self.notes = []

        self.playingNotes = []
        self.playingDurations = []


        #Find the end of the song
        self.end = 0
        splitSong = self.song.split(";")
        for note in splitSong:
            snote = note.split(" ")
            testEnd = round(float(snote[0])) + ceil(float(snote[2]))
            if (testEnd > self.end):
                self.end = testEnd
                
        #Create empty song structure
        while (self.end > len(self.notes)):
            self.notes.append(None)

        #Populate song structure with the notes
        for note in splitSong:
            snote = note.split(" ")
            beat = round(float(snote[0]));
            
            if (self.notes[beat] == None):
                self.notes[beat] = []
            self.notes[beat].append([snote[1],ceil(float(snote[2]))]) #Note, Duration


        #Round up end of song to nearest bar
        self.end = ceil(self.end / 8) * 8
    
    def stop(self):
        for pwm in self.pwms:
            pwm.deinit()
        self.stopped = True
        
    def tick(self):
        if (not self.stopped):
            self.timer = self.timer + 1
            
            #Loop
            if (self.timer % (self.tempo * self.end) == 0 and (not (self.timer == 0))):
                if (not self.looping):
                    self.stop()
                    return False
                self.beat = -1
                self.timer = 0
            
            #On Beat
            if (self.timer % self.tempo == 0):
                self.beat = self.beat + 1

                #Remove expired notes from playing list
                i = 0
                while (i < len(self.playingDurations)):
                    self.playingDurations[i] = self.playingDurations[i] - 1
                    if (self.playingDurations[i] <= 0):
                        self.playingNotes.pop(i)
                        self.playingDurations.pop(i)
                    else:
                        i = i + 1
                        
                #Add new notes and their durations to the playing list
                
                """
                #Old method runs for every note, slow to process on every beat and causes noticeable delay
                ssong = song.split(";")
                for note in ssong:
                    snote = note.split(" ")
                    if int(snote[0]) == beat:
                        playingNotes.append(snote[1])
                        playingDurations.append(int(snote[2]))
                """
                
                if (self.beat < len(self.notes)):
                    if (self.notes[self.beat] != None):
                        for note in self.notes[self.beat]:
                            self.playingNotes.append(note[0])
                            self.playingDurations.append(note[1])
                
                #Only need to run these checks on beats
                i = 0
                for pwm in self.pwms:
                    if (i >= len(self.playingNotes)):
                        pwm.duty_u16(0)
                    else:
                        #Play note
                        pwm.duty_u16(self.duty)
                        pwm.freq(tones[self.playingNotes[i]])
                    i = i + 1
            

            #Play arp of all playing notes
            if (len(self.playingNotes) > len(self.pwms)):
                self.pwms[len(self.pwms)-1].duty_u16(self.duty)
                if (self.arpnote > len(self.playingNotes)-len(self.pwms)):
                    self.arpnote = 0
                self.pwms[len(self.pwms)-1].freq(tones[self.playingNotes[self.arpnote+(len(self.pwms)-1)]])
                self.arpnote = self.arpnote + 1
                
            return True
        else:
            return False

我找了一个超级玛丽的音乐,试着播放了一下,回到了儿时的感觉。

from buzzer_music import music
from time import sleep

# 超级玛丽
song = '0 E5 1 0;0 F#4 1 0;0 D4 1 0;2 E5 2 0;2 D4 2 0;6 E5 2 0;6 D4 2 0;10 D4 1 0;10 F#4 1 0;10 C5 1 0;2 F#4 2 0;6 F#4 2 0;12 E5 2 0;12 F#4 2 0;12 D4 2 0;16 G5 2 0;16 G4 2 0;16 B4 2 0;23 G4 2 0;23 G4 2 0;30 C5 3 0;30 E4 3 0;30 G4 3 0;36 G4 1 0;36 C4 1 0;36 E4 1 0;42 E4 3 0;42 G3 3 0;42 C4 3 0;48 A4 2 0;48 F4 2 0;48 C4 2 0;52 B4 2 0;52 G4 2 0;52 D4 2 0;58 A4 2 0;58 C4 2 0;58 F4 2 0;56 A#4 1 0;56 F#4 1 0;56 C#4 1 0;62 C4 3 0;62 G4 3 0;62 E4 3 0;65 G4 3 0;65 E5 3 0;65 C5 3 0;68 E5 3 0;68 G5 3 0;68 B4 3 0;71 A5 2 0;71 C5 2 0;71 F5 2 0;75 D5 1 0;77 E5 2 0;75 A4 1 0;77 B4 2 0;75 F5 1 0;77 G5 2 0;81 E5 2 0;81 A4 2 0;81 C5 2 0;85 E4 1 0;85 C5 1 0;85 A4 1 0;87 F4 1 0;87 B4 1 0;87 D5 1 0;89 B4 1 0;89 G4 1 0;89 D4 1 0;95 C5 3 0;95 E4 3 0;95 G4 3 0;101 G4 1 0;101 C4 1 0;101 E4 1 0;107 E4 3 0;107 G3 3 0;107 C4 3 0;113 A4 2 0;113 F4 2 0;113 C4 2 0;117 B4 2 0;117 G4 2 0;117 D4 2 0;123 A4 2 0;123 C4 2 0;123 F4 2 0;121 A#4 1 0;121 F#4 1 0;121 C#4 1 0;127 C4 3 0;127 G4 3 0;127 E4 3 0;130 G4 3 0;130 E5 3 0;130 C5 3 0;133 E5 3 0;133 G5 3 0;133 B4 3 0;136 A5 2 0;136 C5 2 0;136 F5 2 0;140 D5 1 0;142 E5 2 0;140 A4 1 0;142 B4 2 0;140 F5 1 0;142 G5 2 0;146 E5 2 0;146 A4 2 0;146 C5 2 0;150 E4 1 0;150 C5 1 0;150 A4 1 0;152 F4 1 0;152 B4 1 0;152 D5 1 0;154 B4 1 0;154 G4 1 0;154 D4 1 0;159 C4 4 0;162 G5 1 0;162 E5 1 0;164 F#5 1 0;164 D#5 1 0;164 G4 1 0;166 F5 1 0;166 D5 1 0;168 D#5 2 0;168 B4 2 0;172 E5 2 0;172 C5 2 0;176 G#4 1 0;176 E4 1 0;178 F4 1 0;178 A4 1 0;180 G4 2 0;180 C5 2 0;184 A4 1 0;184 C4 1 0;186 C5 1 0;188 F4 1 0;188 D5 1 0;170 C5 2 0;174 F4 2 0;182 C5 1 0;186 E4 1 0;190 C4 3 0;207 F5 2 0;207 G5 2 0;207 C6 2 0;211 F5 1 0;211 G5 1 0;211 C6 1 0;213 F5 2 0;213 G5 2 0;213 C6 2 0;217 G4 2 0;221 C4 3 0;193 G5 1 0;193 E5 1 0;195 F#5 1 0;195 D#5 1 0;195 G4 1 0;197 F5 1 0;197 D5 1 0;199 D#5 2 0;199 B4 2 0;203 E5 2 0;203 C5 2 0;224 G5 1 0;224 E5 1 0;226 F#5 1 0;226 D#5 1 0;226 G4 1 0;228 F5 1 0;228 D5 1 0;230 D#5 2 0;230 B4 2 0;234 E5 2 0;234 C5 2 0;240 F4 1 0;238 E4 1 0;238 G#4 1 0;240 A4 1 0;242 G4 2 0;242 C5 2 0;246 C4 1 0;246 A4 1 0;248 E4 1 0;248 C5 1 0;250 D5 1 0;250 F4 1 0;256 D#5 3 0;256 G#4 3 0;262 D5 1 0;262 F4 1 0;267 E4 2 0;267 C5 2 0;252 C4 1 0;273 G4 1 0;275 G4 2 0;279 D4 2 0;283 C4 4 0;286 G5 1 0;286 E5 1 0;288 F#5 1 0;288 D#5 1 0;288 G4 1 0;290 F5 1 0;290 D5 1 0;292 D#5 2 0;292 B4 2 0;296 E5 2 0;296 C5 2 0;300 G#4 1 0;300 E4 1 0;302 F4 1 0;302 A4 1 0;304 G4 2 0;304 C5 2 0;308 A4 1 0;308 C4 1 0;310 C5 1 0;312 F4 1 0;312 D5 1 0;294 C5 2 0;298 F4 2 0;306 C5 1 0;310 E4 1 0;314 C4 3 0;331 F5 2 0;331 G5 2 0;331 C6 2 0;335 F5 1 0;335 G5 1 0;335 C6 1 0;337 F5 2 0;337 G5 2 0;337 C6 2 0;317 G5 1 0;317 E5 1 0;319 F#5 1 0;319 D#5 1 0;319 G4 1 0;321 F5 1 0;321 D5 1 0;323 D#5 2 0;323 B4 2 0;327 E5 2 0;327 C5 2 0;341 G4 2 0;345 C4 3 0;348 G5 1 0;348 E5 1 0;350 F#5 1 0;350 D#5 1 0;350 G4 1 0;352 F5 1 0;352 D5 1 0;354 D#5 2 0;354 B4 2 0;358 E5 2 0;358 C5 2 0;364 F4 1 0;362 E4 1 0;362 G#4 1 0;364 A4 1 0;366 G4 2 0;366 C5 2 0;370 C4 1 0;370 A4 1 0;372 E4 1 0;372 C5 1 0;374 D5 1 0;374 F4 1 0;380 D#5 3 0;380 G#4 3 0;386 D5 1 0;386 F4 1 0;391 E4 2 0;391 C5 2 0;376 C4 1 0;397 G4 1 0;399 G4 2 0;403 D4 2 0;407 C5 1 0;407 G#4 1 0;409 A4 2 0;409 C5 2 0;413 A4 2 0;413 C5 2 0;407 G#3 3 0;413 E4 1 0;417 C5 1 0;417 G#4 1 0;419 C#5 2 0;419 A#4 2 0;423 E5 1 0;423 G4 1 0;425 C5 2 0;425 E4 2 0;429 E4 1 0;429 A4 1 0;431 G4 2 0;431 C4 2 0;438 C5 1 0;438 G#4 1 0;440 C5 2 0;440 A4 2 0;444 C5 2 0;444 A4 2 0;448 C5 1 0;459 G4 2 0;463 C5 1 0;463 G#4 1 0;465 A4 2 0;465 C5 2 0;469 A4 2 0;469 C5 2 0;463 G#3 3 0;469 E4 1 0;473 C5 1 0;473 G#4 1 0;475 C#5 2 0;475 A#4 2 0;479 E5 1 0;479 G4 1 0;481 C5 2 0;481 E4 2 0;485 E4 1 0;485 A4 1 0;487 G4 2 0;487 C4 2 0;454 G4 2 0'

"""
Find a piece of music on onlinesequencer.net, click edit,
then select all notes with CTRL+A and copy them with CTRL+C
Paste string as shown above after removing ";:" from
the end and "Online Sequencer:120233:" from the start
"""

from machine import Pin

mySong = music(song, pins=[Pin(20)])

#Four buzzers
#mySong = music(song, pins=[Pin(0),Pin(1),Pin(2),Pin(3)])

while True:
    mySong.tick()
    sleep(0.04)

这个类库挺强大,支持多上蜂鸣器,我连上2个蜂鸣器,效果稍好了一点,代码稍微修改即可。

mySong = music(song, pins=[Pin(20), Pin(27)])

在这里插入图片描述

树莓派Pico用micropython编程演奏超级玛丽音乐

推荐阅读:
树莓派Pico开发系列文章

### 回答1: 树莓派Pico是树莓派推出的一款微型电脑,Pico中文版是针对中国市场推出的版本。Pico-Python-SDK是树莓派官方提供的软件开发工具包,用于编写和运行Python程序。Pico-Python-SDK中文版是根据中国用户的需求进行本土化开发的版本。 树莓派Pico是一款体积小巧但功能强大的微型电脑,搭载了ARM Cortex-M0+处理器和26个GPIO口,可用于连接各种传感器、执行各种控制任务。同时,Pico支持MicroPython和C/C++两种编程语言,非常适合初学者和嵌入式系统开发人员。 Pico-Python-SDK中文版是官方提供的软件开发工具包,它提供了一系列的API和库函数,可以帮助开发者更方便地编写和调试Python程序。无论是控制外部硬件设备还是实现各种功能,Pico-Python-SDK都提供了丰富的功能和示例代码,使开发工作更加便捷。 Pico-Python-SDK中文版还提供了中文文档和教程,有助于开发者更快速地上手。通过学习这些文档和教程,开发者可以了解Pico的基本原理、功能特性以及编程方法,从而高效地开发出各种应用。 总的来说,树莓派Pico-Python-SDK中文版为中国用户提供了一个方便、易用的软件开发平台,帮助开发者快速上手并实现各种创意和项目。无论是学习编程还是进行嵌入式系统开发,Pico-Python-SDK中文版都是一个不错的选择。 ### 回答2: 树莓派pico-python-sdk-中文版是为了方便中国开发者使用而推出的一款软件开发工具包。它是基于树莓派pico微控制器设计的,通过使用Python语言进行开发。该SDK提供了丰富的功能和接口,使得使用者能够轻松地进行树莓派pico的开发工作。 树莓派pico-python-sdk-中文版包含了各种模块和库,如GPIO库、PWM库、I2C库、SPI库等,这些库可以帮助开发者通过编写Python代码来操控各种外设和传感器。例如,使用GPIO库可以控制LED灯的开关,使用PWM库可以控制舵机的转动,使用I2C库可以与其他设备进行通信,使用SPI库可以实现高速数据传输等等。 此外,树莓派pico-python-sdk-中文版还提供了丰富的示例代码和文档,帮助开发者快速上手。开发者可以参考这些示例代码和文档,了解如何使用SDK中的功能和接口,从而加速自己的开发进程。 总之,树莓派pico-python-sdk-中文版是一款功能强大、易于学习和使用的软件开发工具包。它不仅方便中国开发者使用树莓派pico进行开发工作,还提供了丰富的功能和接口,使得开发者能够更加便捷地实现各种应用和项目。无论是初学者还是有经验的开发者,都可以通过使用这个SDK来实现自己的创意和想法。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

申龙斌

撸代码来深夜,来杯咖啡钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值