LoginSignup
4
5

More than 5 years have passed since last update.

A/D コンバータの MCP3002, MCP3208 を raspberry pi 上の Ruby から扱う

Last updated at Posted at 2015-08-15

A/D コンバータでデジタル化して SPI 経由で raspberry pi 上から扱いたい。A/Dコンバータも SPI も使ってみたのが初めてだったので、学習もかねてライブラリ化してみた。

require 'spi_mcp'

mcp = MCP3208.new
val = mcp.channel(0)
puts val # 0 ~ 4095

もしくは適当にライブラリ単体で引数つけて実行する。

$ watch -n 1 sudo ruby spi_mcp.rb MCP3208

console.png

MCP3002(秋月で180円)を複数買ってしまったけど、特に理由が無ければ MCP3208(320円) の方が分解能高いし、たくさんチャンネル使えるし、繋ぐ必要ある配線もあんまり変わらないのでこちらを買った方が良いと思う。

MCP3208_MCP3002.JPG

ちょっとしたハマりどころとしては、Ruby から SPI を扱える pi_piper gem が raspi2 だと Ruby の FFI から呼び出してる libbcm2835.img を最新のを使わなくてはならない。2015/08/16現在、gem install pi_piper だと古い物が使われてしまう、かつ最新の gem install pi_piper --version 2.0.beta.4 を入れてもうまくいかないため、自前で gem を build して使った方が良い(git 最新の方が libbcm2835.img が新しかったし)。

git clone https://github.com/jwhitehorn/pi_piper.git
cd pi_piper
gem install bundler rake
bundle install
rake gem
sudo gem install pkg/pi_piper-2.0.beta.4.gem

あとあと MISO と MOSI がどっちが out でどっちが in か解らなくなる…。自分用メモ。

MCP3208_3002_memo.jpg

# spi_mcp.rb

require 'pi_piper'

class SpiMCP
  attr_reader :bit_resolution
  attr_reader :channels

  def initialize(options = {})
    @bit_resolution = options[:bit_resolution] or ArgumentError.new("require :bit_resolution")
    @channels = options[:channels] or ArgumentError.new("require :channels")
  end

  def channel(ch)
    raise ArgumentError.new("channel #{ch} is not support.") unless channels.include?(ch)
    result = 0
    PiPiper::Spi.begin do |spi|
      result = convert spi.write(*write_data(ch))
    end
    result
  end

  def convert(raw_data)
    ((raw_data[-2] << 8) + raw_data[-1]) & (2**bit_resolution - 1)
  end
end

class MCP3002 < SpiMCP
  def initialize
    super bit_resolution: 10, channels: 0..1
  end

  def write_data(ch)
    [
      0b01101000 | (ch<<4),
      0b00000000
    ]
  end
end

class MCP3208 < SpiMCP
  def initialize
    super bit_resolution: 12, channels: 0..7
  end

  def write_data(ch)
    control_bit = channel_control_bit(ch)
    [
      0b00000100 | (control_bit>>2), # 0b000001#{SINGLE/DIFF}#{D2}
      (control_bit & 0b11) << 6,     # 0b#{D1}#{D0}000000 (D1, D0)
      0b00000000
    ]
  end

  # return 4-bit (SINGLE/DIFF, D2, D1, D0)
  def channel_control_bit(ch)
    (0b1000 | ch) & 0b1111
  end
end

if __FILE__ == $0
  begin
    mcp_class = Object.const_get(ARGV[0])
  rescue NameError => e
    abort "usage: $ ruby #{__FILE__} MCP3208"
  end

  mcp = mcp_class.new
  mcp.channels.each do |ch|
    puts "ch #{ch}: #{mcp.channel(ch)}"
  end
end

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5