Skip to content

Instantly share code, notes, and snippets.

@hasumikin
Last active February 16, 2026 08:09
Show Gist options
  • Select an option

  • Save hasumikin/c6d9f06e0494b3db10e1ed05da730324 to your computer and use it in GitHub Desktop.

Select an option

Save hasumikin/c6d9f06e0494b3db10e1ed05da730324 to your computer and use it in GitHub Desktop.

※和文はページ下部にあります

PicoRuby Workshop 2025 - Microphone & ADC

Previous sections:

  1. Setup + LED: https://tinyurl.com/picoruby-2025

In this section, we'll learn about analog-to-digital conversion (ADC) and explore how to read analog sensors. We'll use a microphone to detect sound levels and also explore the RP2350's built-in temperature sensor.

But first, let's learn how to write longer programs and run them as scripts!

From IRB to Ruby Scripts

So far we've been using IRB (Interactive Ruby) for quick experimentation. For longer programs, it's better to write Ruby scripts on your laptop:

The Workflow:

  1. Experiment in IRB - Test your hardware connections and basic functionality
  2. Write a script - Use your favorite text editor on your laptop to write a .rb file
  3. Upload to R2P2 - Drag and drop the script file into the "home" directory of the R2P2 drive
  4. Execute - Run the script from R2P2 shell with $> ./[script name].rb

Example: Save this as led.rb:

class LED < GPIO
  def initialize(pin)
    super(pin, GPIO::OUT)
  end

  def on
    write 1
  end

  def off
    write 0
  end

  def toggle
    high? ? off : on
  end
end

led = LED.new(16)
10.times do
  led.toggle
  sleep 0.5
end

Drag and drop led.rb into R2P2's home directory. Run ls in the R2P2 shell:

$> ls

You should see the file listed in the shell prompt.

Then run the script:

$> ./led.rb

What is ADC?

ADC (Analog-to-Digital Converter) converts continuous analog signals (like sound levels, temperature, or light intensity) into digital values that a computer can understand.

Think of it like translating a smooth curve into a series of discrete steps that represent the original signal.

The RP2350/RP2040 has a 12-bit ADC, which means:

  • Range: 0 to 4095 (2^12 - 1)
  • 0 represents 0 volts
  • 4095 represents maximum voltage (3.3V for RP2350/RP2040)

Microphone Circuit

We'll use an analog microphone module to detect sound levels.

Components needed:

Wiring:

RP2[3V3]  --- Microphone[VCC]
RP2[GND]  --- Microphone[GND]
RP2[GP26] --- Microphone[OUT(AUD)]

RP2[GP16] --- Resistor(1kΩ) --- LED[Anode(long leg)]
RP2[GND]  --- LED[Cathode(short leg)]

See the diagrams in the previous section for breadboard setup.

Pin Reference:

  • GP26 is ADC0
  • 3V3 (pin 36) is the 3.3V power output

Basic Sound Detection

Connection on the breadboard can be seen in the previous section.

Let's start with IRB to test our circuit:

irb> require 'adc'
irb> mic = ADC.new 26
irb> mic.read_raw
=> 2048  # Should be around 2048 (middle value) in silence
irb> mic.read
=> 1.65  # Voltage reading (around 1.65V in silence)

Try to check the values while clapping or speaking near the microphone.

Sound-Activated LED

Now let's create our first sound-activated circuit. Save this as sound_led.rb:

require 'adc'

led = GPIO.new(16, GPIO::OUT)
mic = ADC.new(26)

puts "Sound-activated LED started!"
puts "Clap or make noise to turn on the LED"

while true
  sound_level = mic.read_raw - 2048  # -2048..2047
  if 1000 < sound_level.abs  # Adjust threshold as needed
    led.write 1
    puts "Sound detected: #{sound_level}"
  else
    led.write 0
  end
  sleep 0.1
end

In R2P2 shell, Ctrl+C to stop the program.

Built-in Temperature Sensor

The RP2350 has a built-in temperature sensor that we can access through ADC:

irb> temp_adc = ADC.new :temperature
irb> temp_adc.read
=> 0.721  # This is the raw voltage from temperature sensor

Save this as temperature.rb and try running it:

require 'adc'

def voltage_to_celsius(voltage)
  reference_temp = 27.0
  reference_voltage = 0.706
  temp_coefficient = -0.001721

  temp_difference = (voltage - reference_voltage) / temp_coefficient
  reference_temp + temp_difference
end

temp_adc = ADC.new(:temperature)

while true
  voltage = temp_adc.read
  temperature = voltage_to_celsius(voltage)
  puts "Temperature: #{temperature.round(1)}°C"
  sleep 2
end

Unfortunately, the built-in sensor of the Raspi Pico is not very accurate. Please use this material as a reference when using discrete sensors.

Advanced Sound Level Monitor

Let's create a more sophisticated sound monitoring program. Save as sound_monitor.rb:

require 'adc'

led = GPIO.new(16, GPIO::OUT)
mic = ADC.new(26)
temp_adc = ADC.new(:temperature)

def voltage_to_celsius(voltage)
  reference_temp = 27.0
  reference_voltage = 0.706
  temp_coefficient = -0.001721

  temp_difference = (voltage - reference_voltage) / temp_coefficient
  reference_temp + temp_difference
end

puts "=== Sound & Temperature Monitor ==="
puts "Press Ctrl+C to stop"

loop do
  # Read sensors
  sound = mic.read_raw - 2048
  temp_voltage = temp_adc.read
  temperature = voltage_to_celsius(temp_voltage)

  # Sound detection with multiple thresholds
  if 1500 < sound.abs
    led.write 1
    puts "LOUD! Sound: #{sound}, Temp: #{temperature.round(1)}°C"
  elsif 500 < sound
    led.write(led.high? ? 0 : 1)  # Blink for moderate sound
    puts "Sound: #{sound}, Temp: #{temperature.round(1)}°C"
  else
    led.write 0
    puts "Quiet: #{sound}, Temp: #{temperature.round(1)}°C"
  end

  sleep 0.5
end

Exercises

For those who want to explore further:

  1. Calibration: Create a calibration routine that measures the baseline noise level for 5 seconds and automatically sets the threshold.

  2. Sound Patterns: Create different LED patterns for different sound levels:

    • Quiet: LED off
    • Moderate: Slow blink
    • Loud: Fast blink
    • Very loud: Solid on
  3. Data Logging: Modify the sound monitor to keep track of:

    • Maximum sound level detected
    • Average sound level over time
    • Number of sound events above threshold
  4. Multi-Sensor Dashboard: Combine multiple ADC readings:

    # Read multiple sensors and display formatted output
    def init
      @mic = ADC.new(26)
      @temp = ADC.new(:temperature)
    end
    
    def display_sensor_dashboard
      puts "┌─────────────────────────┐"
      puts "│ Sensor Dashboard        │"
      puts "├─────────────────────────┤"
      puts "│ Sound Level: #{@mic.read_raw.to_s.rjust(4)}      │"
      puts "│ Temperature: #{voltage_to_celsius(@temp.read).to_i}°C     │"
      puts "└─────────────────────────┘"
    end
  5. Sound Trigger Recording: Create a system that detects when sound exceeds a threshold and records the maximum value reached during that "event":

    # Pseudo-code structure:
    # - Monitor continuously
    # - When sound > threshold, start "recording"
    # - Track peak value during the event
    # - When sound drops below threshold for 1 second, end recording
    # - Display event summary (duration, peak value)

マイク & ADC

前のセクション:

  1. Setup + LED: https://tinyurl.com/picoruby-2025

このセクションでは、アナログ・デジタル変換(ADC)について学び、アナログセンサの読み取り方法を探求します。マイクを使って音量レベルを検出し、さらに RP2350 の内蔵温度センサも試します。

その前に、もう少し長いプログラムを書いて、スクリプトとして実行する方法を学びましょう!

IRB から Ruby スクリプトへ

これまでは IRB(Interactive Ruby)を使って、すばやく実験してきました。 より長いプログラムの場合は、PC 上で Ruby スクリプトを書く方が適しています。

ワークフロー:

  1. IRB で実験 - 配線と基本機能をテストします
  2. スクリプトを書く - PC の好きなテキストエディタで .rb ファイルを書きます
  3. R2P2 にアップロード - スクリプトファイルを R2P2 ドライブの "home" ディレクトリへドラッグ&ドロップします
  4. 実行 - R2P2 シェルから $> ./[script name].rb でスクリプトを実行します

例: led.rb として保存します:

class LED < GPIO
  def initialize(pin)
    super(pin, GPIO::OUT)
  end

  def on
    write 1
  end

  def off
    write 0
  end

  def toggle
    high? ? off : on
  end
end

led = LED.new(16)
10.times do
  led.toggle
  sleep 0.5
end

led.rb を R2P2 の home ディレクトリへドラッグ&ドロップします。 R2P2 シェルで ls を実行してください。

$> ls

シェルの一覧にファイルが表示されるはずです。 次にスクリプトを実行します。

$> ./led.rb

ADC とは?

ADC(Analog-to-Digital Converter) は、連続的なアナログ信号(例:音量、温度、光の強さ)を、コンピュータが理解できるデジタル値に変換します。

なめらかな曲線を、元の信号を表す離散的な段(ステップ)の集まりへ変換するようなものだと考えてください。

RP2350 / RP2040 には 12 ビット ADC が搭載されています。これは次の意味です。

  • 範囲: 0〜4095(2^12 - 1)
  • 0 は 0 ボルトを表します
  • 4095 は最大電圧を表します(RP2350 / RP2040 の場合は 3.3V)

マイク回路

音量レベルを検出するために、アナログマイクモジュールを使います。

必要な部品:

配線:

RP2[3V3]  --- Microphone[VCC]
RP2[GND]  --- Microphone[GND]
RP2[GP26] --- Microphone[OUT(AUD)]

RP2[GP16] --- Resistor(1kΩ) --- LED[Anode(long leg)]
RP2[GND]  --- LED[Cathode(short leg)]

ブレッドボードのセットアップについては、前のセクションの図を参照してください。

ピンの参考:

  • GP26 は ADC0 です
  • 3V3(ピン 36)は 3.3V の電源出力です

基本的な音検出

ブレッドボード上の接続は、前のセクションで確認できます。

まずは IRB で回路をテストしましょう。

irb> require 'adc'
irb> mic = ADC.new 26
irb> mic.read_raw
=> 2048  # Should be around 2048 (middle value) in silence
irb> mic.read
=> 1.65  # Voltage reading (around 1.65V in silence)

マイクの近くで手を叩いたり話したりしながら、値を確認してみてください。

音で点灯する LED

次に、最初の「音で点灯する」回路を作ります。これを sound_led.rb として保存してください。

require 'adc'

led = GPIO.new(16, GPIO::OUT)
mic = ADC.new(26)

puts "Sound-activated LED started!"
puts "Clap or make noise to turn on the LED"

while true
  sound_level = mic.read_raw - 2048  # -2048..2047
  if 1000 < sound_level.abs  # Adjust threshold as needed
    led.write 1
    puts "Sound detected: #{sound_level}"
  else
    led.write 0
  end
  sleep 0.1
end

R2P2 シェルでプログラムを止めるには Ctrl+C を押します。

内蔵温度センサ

RP2350 には内蔵温度センサがあり、ADC 経由でアクセスできます。

irb> temp_adc = ADC.new :temperature
irb> temp_adc.read
=> 0.721  # This is the raw voltage from temperature sensor

これを temperature.rb として保存し、実行してみてください。

require 'adc'

def voltage_to_celsius(voltage)
  reference_temp = 27.0
  reference_voltage = 0.706
  temp_coefficient = -0.001721

  temp_difference = (voltage - reference_voltage) / temp_coefficient
  reference_temp + temp_difference
end

temp_adc = ADC.new(:temperature)

while true
  voltage = temp_adc.read
  temperature = voltage_to_celsius(voltage)
  puts "Temperature: #{temperature.round(1)}°C"
  sleep 2
end

注意: Raspi Pico の内蔵センサは残念ながら精度があまり高くありません。外付けセンサを使うときの参考資料として、この内容を活用してください。

高度な音量モニタ

より本格的な音モニタリングプログラムを作りましょう。sound_monitor.rb として保存してください。

require 'adc'

led = GPIO.new(16, GPIO::OUT)
mic = ADC.new(26)
temp_adc = ADC.new(:temperature)

def voltage_to_celsius(voltage)
  reference_temp = 27.0
  reference_voltage = 0.706
  temp_coefficient = -0.001721

  temp_difference = (voltage - reference_voltage) / temp_coefficient
  reference_temp + temp_difference
end

puts "=== Sound & Temperature Monitor ==="
puts "Press Ctrl+C to stop"

loop do
  # Read sensors
  sound = mic.read_raw - 2048
  temp_voltage = temp_adc.read
  temperature = voltage_to_celsius(temp_voltage)

  # Sound detection with multiple thresholds
  if 1500 < sound.abs
    led.write 1
    puts "LOUD! Sound: #{sound}, Temp: #{temperature.round(1)}°C"
  elsif 500 < sound
    led.write(led.high? ? 0 : 1)  # Blink for moderate sound
    puts "Sound: #{sound}, Temp: #{temperature.round(1)}°C"
  else
    led.write 0
    puts "Quiet: #{sound}, Temp: #{temperature.round(1)}°C"
  end

  sleep 0.5
end

演習

さらに探求したい方へ:

  1. キャリブレーション: 5 秒間の基準ノイズレベルを測定し、しきい値を自動設定するキャリブレーション処理を作ってください。

  2. 音のパターン: 音量レベルに応じて LED のパターンを変えてください。

    • Quiet: LED off
    • Moderate: Slow blink
    • Loud: Fast blink
    • Very loud: Solid on
  3. データ記録: 音モニタを改造して、次を記録できるようにしてください。

    • Maximum sound level detected
    • Average sound level over time
    • Number of sound events above threshold
  4. マルチセンサ・ダッシュボード: 複数の ADC 読み取りを組み合わせてください。

    # Read multiple sensors and display formatted output
    def init
      @mic = ADC.new(26)
      @temp = ADC.new(:temperature)
    end
    
    def display_sensor_dashboard
      puts "┌─────────────────────────┐"
      puts "│ Sensor Dashboard        │"
      puts "├─────────────────────────┤"
      puts "│ Sound Level: #{@mic.read_raw.to_s.rjust(4)}      │"
      puts "│ Temperature: #{voltage_to_celsius(@temp.read).to_i}°C     │"
      puts "└─────────────────────────┘"
    end
  5. 音トリガー記録: 音がしきい値を超えたときに、その「イベント」の間に到達した最大値を記録する仕組みを作ってください。

    # Pseudo-code structure:
    # - Monitor continuously
    # - When sound > threshold, start "recording"
    # - Track peak value during the event
    # - When sound drops below threshold for 1 second, end recording
    # - Display event summary (duration, peak value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment