ラベル ADT7410 の投稿を表示しています。 すべての投稿を表示
ラベル ADT7410 の投稿を表示しています。 すべての投稿を表示

2013年6月13日木曜日

ruby gem 'aruduino_firmata'のsysexを用いたI2C通信(温度センサと気圧センサ)でのlinda-arduino-sensor的なもの

2013/06/14-18:11JST u2sで負の値の求め方の間違いを修正(緑色)

気圧の値も妥当なものになった(と思う).
2013/06/14-13:30JST 返り値のバイト数が要求バイト数と合っていないことがあるのでその場合スキップするように修正(赤色)
これまでの記事(APT7410MPL115A2)でのコードを利用したlinda-arduino-sensor的なもの
#!/usr/bin/env ruby 
require 'rubygems'
require 'sinatra/rocketio/linda/client'
require 'arduino_firmata'
$stdout.sync = true

url   = ENV["LINDA_BASE"]  || ARGV.shift || "http://localhost:5000"
space = ENV["LINDA_SPACE"] || "test"
linda = Sinatra::RocketIO::Linda::Client.new url
ts = linda.tuplespace[space]

linda.io.on :connect do  ## RocketIO's "connect" event
  puts "connect!! <#{linda.io.session}> (#{linda.io.type})"
end

linda.io.on :disconnect do
  puts "RocketIO disconnected.."
end

STRING_DATA= 0x71
I2C_REQUEST= 0x76
I2C_REPLY= 0x77
I2C_CONFIG= 0x78

_WRITE= 0x00
_READ= 0x08

ADDRESS_ADT7410= 0x48
ADDRESS_MPL115A2= 0x60

#MPL115A2 coefficients
a0= b1= b2= c12= 0.0

def readByte(data, pos)
  return data[pos]+data[pos+1]*(1<<7)
end

def readData(msb, lsb)
  return (msb<<8)+lsb
end

def u2s(v)
  return (v<(1<<15)) ? v : v-(1<<15)*2
end

def bytes2str(bytes)
  ret= ''
  bytes.each do |o|
    ret+= o.chr
  end
  return ret;
end

def decodeData(data)
  ret= {}
  ret[:address]= readByte(data, 0) if (data.length>1)
  ret[:register]= readByte(data, 2) if (data.length>3)
  ary= [];
  i= 4
  while i+1<data.length
    ary.push( readByte(data, i))
    i+= 2
  end
  ret[:data]= ary
  return ret;
end

arduino = ArduinoFirmata.connect ENV["ARDUINO"], :nonblock_io => true

arduino.on :sysex do |command, data|
  #puts "command : #{command}"
  #puts "data    : #{data.inspect}"
  data= (command == STRING_DATA) ? bytes2str(data) : decodeData(data)
  if command == STRING_DATA
    p data
  elsif command == I2C_REPLY
    if data[:address] == ADDRESS_ADT7410
      if data[:data].length == 2
        tout= u2s(readData(data[:data][0], data[:data][1])) / (1<<7).to_f
        ts.write ["sensor", "temperature", tout]
      end
    elsif data[:address] == ADDRESS_MPL115A2
      if data[:register] == 0x04
        if data[:data].length == 8
          a0 = u2s(readData(data[:data][0], data[:data][1]))/(1<< 3).to_f
          b1 = u2s(readData(data[:data][2], data[:data][3]))/(1<<13).to_f
          b2 = u2s(readData(data[:data][4], data[:data][5]))/(1<<14).to_f
          c12= u2s(readData(data[:data][6], data[:data][7]))/(1<<24).to_f
        end
      elsif data[:register] == 0x00
        if data[:data].length == 4
          padc= readData(data[:data][0], data[:data][1])>>6
          tadc= readData(data[:data][2], data[:data][3])>>6
          pcomp= a0 + ( b1 + c12 * tadc ) * padc + b2 * tadc
          pout= pcomp * 650.0/1023.0 + 500.0
          ts.write ["sensor", "pressure", pout] if padc>0
        end
      end
    end
  end
end

#i2c enable
arduino.sysex I2C_CONFIG, [0x00, 0x00]

#APT7410 16bit mode
arduino.sysex I2C_REQUEST, [ADDRESS_ADT7410, _WRITE, 0x03, 0x00, 0x00, 0x01]

#MPL115A2 coefficients
arduino.sysex I2C_REQUEST, [ADDRESS_MPL115A2, _READ, 0x04, 0x00, 0x08, 0x00]

loop do
  arduino.sysex I2C_REQUEST, [ADDRESS_ADT7410, _READ, 0x00, 0x00, 0x02, 0x00]

  arduino.sysex I2C_REQUEST, [ADDRESS_MPL115A2, _WRITE, 0x12, 0x00, 0x01, 0x00]
  sleep 0.02
  arduino.sysex I2C_REQUEST, [ADDRESS_MPL115A2, _READ, 0x00, 0x00, 0x04, 0x00]

  sleep 1
end

2013年6月12日水曜日

ruby gem 'arduino_firmata' の sysex を使ってADT7410使用の温度モジュールから値を取得する

2013/06/14-18:11JST u2sで負の値を求め方の間違いを修正(緑色)
2013/06/14-13:30JST 返り値のバイト数が要求バイト数と合っていないことがあるのでその場合スキップするように修正(青色)
2013/06/13-16:34JST "arduino.sysex I2C_REQUEST, [ADDRESS_ADT7410, _WRITE, 0x03, 0x00, 0x00, 0x001]"で16bit-modeで動くこともあるが, ケースによっては13bitのままだったりする.

  • 0.1度の中に複数の計測点があるので16bit modeであることがわかる.
2013/06/13-15:36JST 16bit mode指定がやっぱり正しく動いてないので削除
2013/06/13-15:06JST 16bit mode指定の間違いを訂正
2013/06/13-01:53JST readDataの間違いを訂正(奇数バイトは128倍(8bit目?))
2013/06/12-23:27JST readDataの間違いを訂正(shiftの係数が2だった)
これを使って,やってみた.のでメモ.
#!/usr/bin/env ruby -Ku
require 'rubygems'
require 'arduino_firmata'
$stdout.sync = true

ADDRESS_ADT7410= 0x48
I2C_READ= 0x08

def readData(data, shift)
  msb= data[4+4*shift]+data[5+4*shift]*128
  lsb= data[6+4*shift]+data[7+4*shift]*128
  return (msb*256+lsb)
end

def readDataS(data, shift)
  v= readData(data, shift)
  return (v<(1<<15)) ? v : v-(1<<15)*2
end

def data2string(data)
  i=0
  msg= ''
  while i+1<data.length
    msg+= data[i].chr
    i+= 2
  end
  return msg;
end

arduino = ArduinoFirmata.connect ENV["ARDUINO"], :nonblock_io => true
puts "firmata version #{arduino.version}"

arduino.on :sysex do |command, data|
  puts "command : #{command}"
  puts "data    : #{data.inspect}"
  if command == 0x77
    if data[0] == ADDRESS_ADT7410
      if data.length == 8
        t= readDataS(data, 0) / (1<<7).to_f #デフォルトは13bit modeで下位三ビットが1固定で無効ですが割っちゃいます.
        puts "#{t} [度]"
      end
    end
  else
    if command == 0x71
      p data2string(data);
    end
  end
end

#i2c enable
arduino.sysex 0x78, [0x00, 0x00]

loop do
  arduino.sysex 0x76, [ADDRESS_ADT7410, I2C_READ, 0x00, 0x00, 0x02, 0x00]
  sleep 1
end