I2C液晶

ストロベリーリナックスで扱っているI2Cキャラクタ液晶モジュール。だいぶ前にArduinoに接続して使ってみた時は非常に簡単に使えたので、Raspberry Piでも使ってみようとしたら、意外な所で引っかかってしまった。
193671174

Raspberry Piは標準でI2Cのインタフェースを持っているのだが、初期状態では使えないようになっている。使えるようにするためには設定を変えて、起動時にモジュールを読み込むようにしてやらなくてはならない。

その為の方法は探すと色々出てくる。自分は以下のページを参考にして設定を行った。

I2C Installation for Raspberry Pi – Step by Step Guide | SK Pang Electronics Ltd

I2Cが使えるようになったら、GPIOのピンと液晶を以下のように接続。Raspberry PiのI2Cポートには最初からプルアップ抵抗が付いているので、Arduinoのようにプルアップ抵抗を付ける必要はない。

液晶

Raspberry Pi

1 : RST

1 : 3.3V

2 : SCL

5 : SCL

3 : SDA

3 : SDA

4 : GND

6 : GND

5 : VDD

1 : 3.3V

この状態でインストールしたi2c-toolsに含まれるi2cdetectを使えば、接続されているI2Cデバイスが表示されるはずなのだが、何も出てこない。

pi@raspberrypi ~/PythonProjects $ sudo i2cdetect 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0.
I will probe address range 0x03-0x77.
Continue? [Y/n]
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          — — — — — — — — — — — — —
10: — — — — — — — — — — — — — — — —
20: — — — — — — — — — — — — — — — —
30: — — — — — — — — — — — — — — — —
40: — — — — — — — — — — — — — — — —
50: — — — — — — — — — — — — — — — —
60: — — — — — — — — — — — — — — — —
70: — — — — — — — —

ここでかなり悩んでしまった。配線が間違っているのか、ケーブルが断線しているのか、はたまた液晶が壊れてしまったのかと色々試してみたが、どれも正常。
海外のフォーラムでI2Cデバイスが検出されない、と悩んでいる人の話を見つけて、ようやく原因が分かった。Raspberry Piのリビジョンが新しい基板は、I2Cポートのチャンネルが0→1に変更されていたのだ。これでは検出されるわけがない。

pi@raspberrypi ~/PythonProjects $ sudo i2cdetect 1
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-1.
I will probe address range 0x03-0x77.
Continue? [Y/n]
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          — — — — — — — — — — — — —
10: — — — — — — — — — — — — — — — —
20: — — — — — — — — — — — — — — — —
30: — — — — — — — — — — — — — — 3e —
40: — — — — — — — — — — — — — — — —
50: — — — — — — — — — — — — — — — —
60: — — — — — — — — — — — — — — — —
70: — — — — — — — —

チャンネルを変更すると、正しくI2Cキャラクタ液晶のアドレスが検出された。
もともとRaspberry PiはI2Cを2チャンネル持っていて、以前のリビジョンではGPIOコネクタに0番、その隣にあるヘッダの実装されていないコネクタに1番が割り当てられていたのだが、リビジョン2.0以降はそれが逆転していた。
なぜそうなったのかは良く分からないのだが、巷にある資料は古いリビジョンに基づいて書かれたものが多いため、同じように悩んだ人が多いのではないだろうか?

認識されてしまえばあとは簡単で、Arduinoで作ったプログラムを元にしてPythonで作り直した。PythonのI2C用ライブラリは標準では入っていないので、最初にインストールしておく必要がある。

sudo apt-get install python-smbus

プログラムは以下の通り。クラス化して、初期化とメッセージ表示、ユーザキャラクタの定義ができるようにしてある。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import smbus    # sudo apt-get install python-smbus
import time

class i2clcd:
    i2c = smbus.SMBus(1)    #   
    addr = 0x3e
    contrast = 42   # 0~63
    def __init__(self):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        self.i2c.write_byte_data(self.addr, 0, 0x39)    # function set(IS=1)
        self.i2c.write_byte_data(self.addr, 0, 0x14)    # internal osc
        self.i2c.write_byte_data(self.addr, 0,
                    (0x70 | (self.contrast & 0x0f)))    # contrast
        self.i2c.write_byte_data(self.addr, 0,
                    (0x54 | ((self.contrast >> 4) & 0x03)))      # contrast/icon/power
        self.i2c.write_byte_data(self.addr, 0, 0x6c)    # follower control
        time.sleep(0.2)
    
    def clear(self):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        self.i2c.write_byte_data(self.addr, 0, 0x0C)    # Display On
        self.i2c.write_byte_data(self.addr, 0, 0x01)    # Clear Display
        self.i2c.write_byte_data(self.addr, 0, 0x06)    # Entry Mode Set
        time.sleep(0.2)

    def puts(self, msg):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        [self.i2c.write_byte_data(self.addr, 0x40, ord(c)) for c in msg]

    def setaddress(self, line, col):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        self.i2c.write_byte_data(self.addr, 0,
                    0x80 | (0x40 if line > 0 else 0) | col)
    
    def setcg(self, no, cg):
        self.i2c.write_byte_data(self.addr, 0, 0x38)    # function set(IS=0)
        self.i2c.write_byte_data(self.addr, 0, 0x40 | (no << 3))
        [self.i2c.write_byte_data(self.addr, 0x40, c) for c in cg]

    def putcg(self, line, col, no):
        self.setaddress(line, col)
        self.i2c.write_byte_data(self.addr, 0x40, no)

if __name__ == "__main__":
    lcd = i2clcd()
    lcd.clear()
    # show string
    lcd.setaddress(0, 0)
    lcd.puts('Hello')
    lcd.setaddress(0, 6)
    lcd.puts('Raspberry')
    lcd.setaddress(1, 0)
    lcd.puts('Pi')
    lcd.setaddress(1, 3)
    lcd.puts('World!')
    # set CGRAM
    lcd.setcg(0, (0x00, 0x00, 0x1f, 0x0a, 0x0a, 0x0a, 0x13, 0x00))
    lcd.setcg(1, (0xff, 0x01, 0x05, 0x06, 0x04, 0x04, 0x08, 0x00))
    lcd.setcg(2, (0x01, 0x02, 0x04, 0x0c, 0x14, 0x04, 0x04, 0x00))
    lcd.setcg(3, (0x04, 0x1f, 0x11, 0x11, 0x01, 0x02, 0x04, 0x00))
    # show CG
    lcd.putcg(1, 12, 0)
    lcd.putcg(1, 13, 1)
    lcd.putcg(1, 14, 2)
    lcd.putcg(1, 15, 3)

※初期化コードにミスがあったので修正(2013/02/17)

I2Cデバイスの操作は権限が必要なので、実行する時はsudoを付ける。

sudo python i2c_lcd.py

これを使えば、Raspberry Piの起動時にIPアドレスやメッセージを表示させたりする事も可能だろう。

2013-02-11 11.36.29

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中