※和文はページ下部にあります
Previous sections:
- Setup + LED: https://tinyurl.com/picoruby-2025
- Microphone: https://tinyurl.com/picoruby-mic
In this section, we'll learn about PWM (Pulse Width Modulation) - a powerful technique that allows us to simulate analog signals using digital outputs. We'll use PWM to create sounds with a buzzer and control LED brightness smoothly.
PWM (Pulse Width Modulation) is a technique used to control the amount of power delivered to a device by rapidly switching it on and off. Think of it like a very fast light dimmer switch.
PWM has two key parameters:
- Frequency: How many times per second the signal switches (measured in Hz)
- Duty Cycle: The percentage of time the signal is "high" vs "low" (0-100%)
Digital signals simulating analog: By rapidly switching a digital signal on and off, we can simulate analog behavior. The device "sees" an average voltage proportional to the duty cycle.
Components needed:
- 1x Piezo buzzer or small speaker
- Jumper wires
Wiring:
RP2[GP11] --- Resistor(1kΩ) --- Buzzer[Arbitrary pin]
RP2[GND] --- Buzzer[Another pin]
Let's start experimenting with PWM in IRB:
irb> require 'pwm'
irb> buzzer = PWM.new 11
irb> buzzer.frequency 440 # A4 note (440 Hz)
irb> buzzer.duty 50 # 50% duty cycle
irb> buzzer.duty 25 # 25% duty cycle
irb> buzzer.duty 0 # Turn off the soundYou should hear a tone! Let's try different frequencies:
irb> buzzer.duty 50 # 50% duty cycle
irb> buzzer.frequency 880 # A5 note (one octave higher)
irb> buzzer.frequency 220 # A3 note (one octave lower)
irb> buzzer.duty 0 # Turn off the soundLet's create the classic "Do-Re-Mi" scale. Save this as scale.rb:
require 'pwm'
buzzer = PWM.new(11)
# Musical notes frequencies (Hz)
notes = {
'C' => 261.63, # Do
'D' => 293.66, # Re
'E' => 329.63, # Mi
'F' => 349.23, # Fa
'G' => 392.00, # Sol
'A' => 440.00, # La
'B' => 493.88, # Si
'C2' => 523.25 # Do (one octave higher)
}
scale = %w(C D E F G A B C2)
puts "Playing Do-Re-Mi scale..."
scale.each do |note|
puts "Playing: #{note} (#{notes[note]} Hz)"
buzzer.frequency(notes[note])
buzzer.duty(50) # 50% duty cycle for clear tone
sleep 0.5
end
buzzer.duty(0) # Turn off buzzer
puts "Scale complete!"Let's play a simple melody. Save this as twinkle.rb:
require 'pwm'
buzzer = PWM.new(11)
# Note frequencies
notes = {
'C' => 261.63, 'D' => 293.66, 'E' => 329.63,
'F' => 349.23, 'G' => 392.00, 'A' => 440.00,
'B' => 493.88, 'C2' => 523.25, 'REST' => 0
}
# Twinkle, Twinkle, Little Star
melody = %w(
C C G G A A G REST
F F E E D D C REST
)
puts "Playing 'Twinkle, Twinkle, Little Star'..."
melody.each_with_index do |note, i|
buzzer.frequency notes[note]
sleep_ms 200
buzzer.frequency 0 # Staccato
sleep_ms 200
end
buzzer.duty 0
puts "Melody complete!"PWM isn't just for sound - it's also perfect for controlling LED brightness! The human eye perceives the rapid on/off switching as variable brightness.
Additional Components:
- 1x LED and 1x 1kΩ resistor (from previous sections)
Additional Wiring:
RP2[GP16] --- Resistor(1kΩ) --- LED[Anode(long leg)]
RP2[GND] --- LED[Cathode(short leg)]
Let's create smooth LED fading. Save this as fade_led.rb:
require 'pwm'
led = PWM.new(16) # Not GPIO this time!
led.frequency(1000) # 1kHz frequency for smooth dimming
puts "LED breathing effect - Press Ctrl+C to stop"
loop do
# Fade in
puts "Fade in..."
0.upto(100) do |brightness|
led.duty(brightness)
sleep_ms 20 # 20ms delay for smooth transition
end
# Fade out
puts "Fade out..."
100.downto(0) do |brightness|
led.duty(brightness)
sleep_ms 20
end
endLet's combine sound and light! Save this as music_visualizer.rb:
require 'pwm'
buzzer = PWM.new(11)
led = PWM.new(16)
notes = {
'C' => 261.63, 'D' => 293.66, 'E' => 329.63,
'F' => 349.23, 'G' => 392.00, 'A' => 440.00,
'B' => 493.88, 'C2' => 523.25
}
# Map frequency to LED brightness (higher pitch = brighter)
def frequency_to_brightness(freq)
# Map 261Hz (C) to 523Hz (C2) → 20% to 100% brightness
min_freq, max_freq = 261.63, 523.25
min_bright, max_bright = 20, 100
# Linear mapping
brightness = min_bright + (freq - min_freq) * (max_bright - min_bright) / (max_freq - min_freq)
[brightness, 100].min.to_i # Cap at 100%
end
scale = %w(C D E F G A B C2)
puts "Musical LED Visualizer!"
puts "Higher notes = brighter LED"
led.frequency(2000) # High frequency for smooth LED dimming
scale.each do |note|
freq = notes[note]
brightness = frequency_to_brightness(freq)
puts "#{note}: #{freq}Hz → #{brightness}% brightness"
# Play note and set LED brightness
buzzer.frequency(freq)
buzzer.duty(40)
led.duty(brightness)
sleep_ms 600
end
# Turn off both
buzzer.duty(0)
led.duty(0)
puts "Visualization complete!"Let's combine our microphone knowledge with PWM to create a sound-reactive buzzer. Save this as sound_reactive.rb:
require 'pwm'
require 'adc'
buzzer = PWM.new(11)
led = PWM.new(16)
mic = ADC.new(26)
puts "Sound-reactive system started!"
puts "Make noise to trigger different tones"
led.frequency(1000)
loop do
sound_level = mic.read_raw
sound_intensity = (sound_level - 2048).abs # 0..2048
if 500 < sound_intensity
# Map sound intensity to frequency (100-2000 Hz)
frequency = (sound_intensity - 500).clamp(100, 2000)
brightness = ((sound_intensity - 500) / 20).clamp(0, 100)
buzzer.frequency(frequency)
buzzer.duty(30)
led.duty(brightness)
puts "Sound: #{sound_level} → #{frequency}Hz, #{brightness}%"
else
buzzer.duty(0)
led.duty(0)
end
sleep_ms 50 # 20 updates per second
endFor those who want to explore further:
-
Custom Melodies: Create your own melodies using the note frequency system. Try "Happy Birthday" or your favorite song's melody.
ref: https://www.hoffmanacademy.com/store/sheet-music/happy-birthday-to-you
-
Advanced PWM Patterns: Experiment with different duty cycles for the buzzer:
# Try different duty cycles and observe sound quality [10, 25, 50, 75, 90].each do |duty| buzzer.duty(duty) sleep 1 end
-
LED Breathing with Math: Create more natural breathing patterns using sine waves:
require 'pwm' led = PWM.new(16) led.frequency(2000) t = 0 loop do brightness = (Math.sin(t) * 40 + 50).to_i # 10-90% range led.duty(brightness) t += 0.1 sleep_ms 50 end
-
RTTTL Parser: Research and implement a basic RTTTL (Ring Tone Text Transfer Language) parser to play cell phone ringtones:
# Example RTTTL string for "Twinkle": RTTTL.play "Twinkle:d=4,o=5,b=120:c,c,g,g,a,a,2g,f,f,e,e,d,d,2c"
d= default duration,o= octave,b= beats per minute