GPIO接続のLCDへ表示する(MCP23017を使う その1)


前回はRaspberry Piを使って、GPIO接続のLCDモジュールへの表示を紹介しました。
今回、I2C接続のIOエクスパンダを入手したのでその使い方を紹介します。
使用するにIOエクスパンダはMCP23017で す。
なお、結線に際しては、以下のページを参考にさせていただきました。
http://raspi.tv/2013/using-the-mcp23017-port-expander-with-wiringpi2-to-give-you-16-new-gpio-ports-part-3

WiringPiのライブラリをよく調べてみると、mcp23017.hとかpcf8574.hなど、IOエクスパンダに関するライブラリが含ま れていることがわかります。
以下のページで使い方が紹介されています。
http://wiringpi.com/extensions/i2c-mcp23008-mcp23017/

まずは簡単なサンプルを紹介します。
紹介するサンプルは下の回路図のように、2つのボタンと2つのLEDから構成される簡単なものです。



サンプルコードは以下のとおりです。
ボタン1が押されるとLED1が点灯し、ボタン2が押されるとLED2が点灯する簡単なものです。
#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>

#define BUTTON1 0       // GPIO17
#define BUTTON2 1       // GPIO18
#define LED1    2       // GPIO27
#define LED2    3       // GPIO22
#define PINBASE 0

int main(int argc, char **argv) {
    int i;

    if (wiringPiSetup() == -1){
        printf("
Setup Fail\n");
        exit(1);
    }

    pinMode(PINBASE+BUTTON1,INPUT);
    pinMode(PINBASE+BUTTON2,INPUT);
    pinMode(PINBASE+LED1,OUTPUT);
    pinMode(PINBASE+LED2,OUTPUT);
    digitalWrite(PINBASE+LED1,0);
    digitalWrite(PINBASE+LED2,0);

    for(i=0;i<20;i++) {
        if(digitalRead(PINBASE+BUTTON1)) {
            digitalWrite(PINBASE+LED1,1);
            digitalWrite(PINBASE+LED2,0);
        }
        if(digitalRead(PINBASE+BUTTON2)) {
            digitalWrite(PINBASE+LED1,0);
            digitalWrite(PINBASE+LED2,1);
        }
        delay(500);
    }
    digitalWrite(PINBASE+LED1,0);
    digitalWrite(PINBASE+LED2,0);
}

同じことをMCP23017で行う場合は以下のようになります。



この場合のコードは以下のようになります。
コードを実行する前に、この ページなどを参考にしてi2cを有効にしてください。
またi2cdetectコマンドがインストールされていない場合は、以下のコマンドでインストールしてください。
$ sudo apt-get install i2c-tools
$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

i2cアドレスはA0 A1 A2ピンの設定で以下の様になります。
A2 A1 A0 I2C Address
GND GND GND 0x20
GND GND 3.3V 0x21
GND 3.3V GND 0x22
GND 3.3V 3.3V 0x23
3.3V GND GND 0x24
3.3V GND 3.3V 0x25
3.3V 3.3V GND 0x26
3.3V 3.3V 3.3V 0x27
(この表、MCP23017 のデータシートのどこにもないような)

#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <mcp23017.h>

#define BUTTON1 0       // MCP23017 GPA0
#define BUTTON2 1       // MCP23017 GPA1
#define LED1    2       // MCP23017 GPA2
#define LED2    3       // MCP23017 GPA3
#define PINBASE 100

int main(int argc, char **argv) {
    int i;

    if (mcp23017Setup(PINBASE,0x20) == -1){
        printf("
Setup Fail\n");
        exit(1);
    }

    pinMode(PINBASE+BUTTON1,INPUT);
    pinMode(PINBASE+BUTTON2,INPUT);
    pinMode(PINBASE+LED1,OUTPUT);
    pinMode(PINBASE+LED2,OUTPUT);
    digitalWrite(PINBASE+LED1,0);
    digitalWrite(PINBASE+LED2,0);

    for(i=0;i<20;i++) {
        if(digitalRead(PINBASE+BUTTON1)) {
            digitalWrite(PINBASE+LED1,1);
            digitalWrite(PINBASE+LED2,0);
        }
        if(digitalRead(PINBASE+BUTTON2)) {
            digitalWrite(PINBASE+LED1,0);
            digitalWrite(PINBASE+LED2,1);
        }
        delay(500);
    }
    digitalWrite(PINBASE+LED1,0);
    digitalWrite(PINBASE+LED2,0);
}

変更したのは下線部分の3箇所だけです。
mcp23017Setup()の1番目の引数には65以上の任意の数字を指定します。
mcp23017Setup()の2番目の引数はMCP23017のi2cアドレスです。
例えば2つのMCP23017を使用する場合は以下のようになります。
#define PINBASE1 100
#define PINBASE2 200
(中略)
    mcp23017Setup(PINBASE1,0x20);
    mcp23017Setup(PINBASE2,0x21);
(以下略)

そもそもWiringPiの初期設定に、wiringPiSetup()とwiringPiSetupGpio()の2つの関数が用意されている のが不思議だったのですが、
wiringPiSetup()はこのようにIOエクスパンダなどを使うために用意されていることが分かりました。

次回はIOエクスパンダ経由でLCDの使い方を紹介します。