count0.org

門外漢、I2Cで55個のLEDを光らせる

18 December 2015 raspberrypi

I2Cという言葉、Raspberry Pi関連の調べ物をしていると時折見かける言葉でした。センサーを扱うときに使うじゃないかな多分。このようにI2Cのことを全くわからない門外漢がその持ち前の野蛮さでI2Cをいじってみました。

購入

始まりは先日注文したRaspberry Pi Zeroが届いたところから。購入したところはたまたま在庫があったPimonori。本体+各種アダプタセット、ケース、出来心で追加した55個のLEDを備えたScroll pHATと送料で£22.33でした。決済時に1割引されていました。一週間でイギリスから到着。

セットアップ

今回はNOOBSを使わずmicro SDにRaspbian Jessie Liteのイメージを焼いて、HDMIでTVに繋ぎ、一つしか使えないmicro USBにはUSBハブ。そこにキーボードとWifiレシーバーを繋いでセットアップしました。ヘッドレスで行う方法もあるみたいですが、機材が部屋に転がっていたのでオーソドックスな方法で行いました。

ハンダ付け

セットについてきたGPIOヘッダーをRaspberry Pi Zeroにハンダ付けします。同じくScroll pHATにもGPIOヘッダーをハンダ付けします。ハンダ付けはなんとかやりましたね。見た目が相当アレですけど。

I2C

I2Cを扱うためにraspi-configAdvanced OptionsからI2Cを選択して有効化します。再起動の前にi2cdetectが使えるようにパッケージをインストールします。

sudo apt-get install i2c-tools
sudo reboot

そしてGPIOで本体とScroll pHATを合体させて認識しているか確認します。

pi@raspizero:~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --   

Scroll pHATのアドレスは0x60であることがわかります。わかったけどどうすればいいのか。

写経

Pimonoriが作成、公開しているScroll pHATのライブラリとサンプルプログラムを動かしたりソースを読んでも理解が進まないので、一部をNode.jsに書き直してxとyの座標を指定して光らせるようにしました。

var sleep = require('sleep');
var i2c   = require('i2c-bus');
var i2c1  = i2c.openSync(1);

const I2C_ADDR           = 0x60;
const CMD_SET_MODE       = 0x00;
const CMD_SET_BRIGHTNESS = 0x19;
const MODE_5X11          = 0b00000011;

var buffer = new Buffer(12);
buffer.fill(0);

function update() {
  console.log(buffer);

  try {
    i2c1.writeI2cBlockSync(I2C_ADDR, 0x01, buffer.byteLength, buffer);
  } catch (e) {
    console.log(e);
  }
}

function set_mode() {
  i2c1.writeByteSync(I2C_ADDR, CMD_SET_MODE, MODE_5X11);
}

function set_brightness(brightness) {
  i2c1.writeByteSync(I2C_ADDR, CMD_SET_BRIGHTNESS, brightness);
}

function set_pixel(x, y, val) {
  if (val) {
    buffer[x] |= (1 << y);
  } else {
    buffer[x] &= ~(1 << y);
  }
}

function clear() {
  buffer = new Buffer(12);
  buffer.fill(0);
  update();
}

function chika(val) {
  for (var x = 0; x < 11; x++) {
    for (var y = 0; y < 5; y++) {
      set_pixel(x, y, val);
      update();
      sleep.usleep(30000);
    }
  }
}

set_mode();
set_brightness(2);

chika(1);
chika(0);

// clear();

定数のI2C_ADDRi2cdetectで取得した値なのでいいとして、CMD_SET_MODECMD_SET_BRIGHTNESSMODE_5X11の値は何なんだ。どこから来たんだ? という疑問はデータシートに答えが載っていました。ふーむ、ビットを束ねてライブラリ経由で送ればいいわけだな。という雑な理解を得られたので、Bufferの中身をコンソールに表示しつつLEDをひたすらピカピカさせました。

計算機

2進数、10進数、16進数の変換がパパッとできないので参るわけですが、OSXにデフォルトで入っている計算機のプログラマモード(⌘3)がとても重宝しました。

まとめ

Pythonのコードをそのまま移植してNode.jsのBufferであるところをArrayにしていてエラーをいただいたり、データシートの読み方が全くわからずデータの桁数間違えたりして前途は暗かったのですが、雑な理解ながら最初の壁を乗り越えると次もI2Cで何かできるかも? とAmazonでセンサー探していたりするから不思議なもんです。

何となく感づいていましたが、いろいろ検索するとRaspberry PiはPythonが一級市民のようなので、Python人間になった方がいいのかもしれないなと思いました。

あと「Raspberry Piで実践! 中学校の数学が怪しい奴でもわかるI2C」なんて本があったりしたら飛びつきますね。