Youtubeでも活動中

チャンネル登録してくれたら喜びます。
リンクはフリーです。共有・拡散は大歓迎!

このボタンで簡単にチャンネル登録!
PR

MCP23017をRaspberryPiのIO出力追加に使う方法[ledやモーターをたくさん使いたい]

mcp23017out-eyecatch

今回は、MCP23017通称IOエキスパンダについてのご紹介です。

なんだかんだRaspberryPiって入出力端子が豊富に見えて、

いざやりたいことを考えると、端子が足りなくなることありませんか?

そんなときにこのMCP23017があると、

なんと最大128点の入出力端子を増やすことができます。

今回は「出力端子を増やす方法」について詳しく解説していきます。

入力端子を増やす方法については長くなってしまう関係上、

別記事で掲載する予定です。

この記事を読むことでわかること

RaspberryPiでIO出力制御できる本数を増やす方法がわかる。

自己紹介

東証一部上場企業でサラリーマンしてます。

主に工場(生産現場)で使用する検査装置のアプリケーション開発してます。

ヒトの作業を自動化して簡略化するアプリケーションを日々開発中。

転職に成功して現在は超大手企業でシステム系の開発をしています。

Youtubeチャンネルにさまざまな動画を上げています

↓↓↓こちらからYoutubeチャンネルにアクセス!! ↓↓↓

PR

MCP23017とはそもそもなんなのか?

MCP23017
MCP23017

MCP23017はMICRO CHIP社が製造しているIOエキスパンダと呼ばれるICです。

簡単に言うと、RaspberryPiのGPIOピンを増設できます。

こちらはI2C通信で制御しますが、兄弟機種として、MCP23S17という

SPI通信で制御するICもあります。

MCP23S17
MCP23S17今回は使わない。

今回はI2C制御のMCP23017のみご紹介します。

Amazonでも一応購入可能です。↓↓↓

MCP23017とRaspberryPiはどうつなぐ?

続きまして、配線方法です。

今回はGPAの0番にLEDを接続して光らせます。

データシートにも記載されていますが、一応MCP23017のピン配置を載せておきます。

mcp23017-pin
MCP23017のピン配置

切り欠きの向きだけ注意してくださいね。

MCP23017とRaspberryPiをつなげて、LEDを光らせる。

線の本数がそれなりに多くなっているので、配線ミスに注意してください。

今回はI2Cのアドレスが0x20となるように配線しています。

RaspberryPi側でMCP23017を認識してみる。

正しく接続できたら、まずはRaspberryPi側で認識されたかチェックです。

LXターミナルに、

i2cdetect -y 1

と打ち込んでください。

こちらのように20番が表示されたらOKです。

20番に1つだけつながっていることがわかる。これがMCP23017

PythonでMCP23017のピンを出力する方法。

MCP23017のデータシートから必要な情報を調べる。

MCP23017のデータシートはこちらにあります。

まずはダウンロードしておきましょう。※データシートは必ず読みましょう。

http://ww1.microchip.com/downloads/jp/DeviceDoc/20001952C_JP.pdf

必要なところだけ抜粋して紹介しますが、

必要なのは次の3か所です。

  • ハードウェア アドレスデコーダ
  • I/O方向レジスタ IODIRA(ADDR:0x00)
  • ポートレジスタ GPIOA(ADDR:0x12)
mcp23017のデータシートより
データシートより抜粋

ハードウェア アドレスデコーダ

こちらについては、別記事で詳しく書いています。

MCP23017の複数台つなげた場合のアドレスについて書いていますが、

アドレスが決まる原理なども書いてありますので、そちらを参考にしてみてください。

I/O方向レジスタ

こちらは、MCP23017の各IOピンが入力なのか出力なのか

決めてあげるためのレジスタです。

今回はA0しか使用しないので、IODIRAつまり、0x00しか使用しません。

B0~B7まで使用する場合は、別途IODIRB:0x01も定義してあげる必要があります。

具体的に方向を決める方法ですが、

大前提としてのルールは、

  • LEDなど出力させたい場合:0
  • センサなど入力したい場合:1
  • 7番ピンから順に01で並べてhexに変換する。

となっています。

今回の例としては、A0ピンを出力としたいので、

0000000

つまり0x00が適用されます。

同様に、例えば4番ピンだけ入力で、他を出力にしたい場合は、

00010000

上記binをhexに変換すると、0x10となります。

ポートレジスタ

最後にポートレジスタです。

これがピンのON/OFFにかかわるところです。

具体的には、I/O方向レジスタと同様に、こちらのルールがあります。

  • 論理Low(0V):0
  • 論理High(3.3V):1
  • 7番ピンから順に01で並べてhexに変換する。

並べ方はI/O方向レジスタとまったく同じです。

今回の例として、A0ピンをHigh(3.3V)にしたいので、

00000001

つまり0x01です。

例えば7番ピンから5番ピンまでHigh(3.3V)としたい場合は、

11100000

hexになおすと、0xE0になります。

Pythonのソースコード

import smbus
import time

CHANNEL   = 1       # i2c割り当てチャンネル 1 or 0
I2CADDR    = 0x20   # MCP23017のアドレス。この場合はA0~A3までGND接続した場合のアドレス。
REG_IODIRA = 0x00    # 入出力設定レジスタ
REG_GPIOA  = 0x12   # 出力レジスタ

bus = smbus.SMBus(CHANNEL)  #smbusを定義

# ピンの入出力設定
bus.write_byte_data(I2CADDR, REG_IODIRA, 0x00)   #データシートより、0:出力
def loop():
    while True:
        # GPA0をONする
        bus.write_byte_data(I2CADDR, REG_GPIOA, 0x01)
        time.sleep(1)
        # 全出力OFF
        bus.write_byte_data(I2CADDR, REG_GPIOA, 0x00)
        time.sleep(1)
# Ctrl+Cキーで入る。
def destroy():
    print('end')
# main
if __name__ == '__main__':
    print ('Program is starting...' )

    try:
        loop() 
    # ターミナル上でCtrl+Cでloop()を中断
    except KeyboardInterrupt: 
        destroy()

importのsmbusが通らない場合は、

sudo apt install python-smbus

とLXターミナルから打ち込んでおきましょう。

また、今回はMCP23017のI2Cアドレスですが、

A0~A3ピンをすべてGND接続していることを想定しているので、

0x20となります。今後複数台のMCP23017を接続したくなった場合は、

こちらの記事のようにアドレスを変更するように気を付けてください。

ちょっとクセがあるとしたら、

bus.write_bite_dataの時の最後の引数でしょうか。

bit7始まりですから、GPIOのAの0番をHIGHにする場合は0b00000001となり、

7番をHIGHにする場合は、0b10000000となります。

最後にbinをhexに変換する必要があります。

7番だけHIGHにする例だと、0b10000000なので、

0x80ですね。

すべてのピンをHIGHにする場合は、

0b11111111なので、

0xFFとなります。

その計算も関数にしてあげるともっと使いやすくなると思います。

そこらへんをスッキリさせたVer.もそのうち作って公開する予定です。

まとめ

今回はRaspberryPiのGPIOが足りなくなった場合の、

増設方法についてMCP23017を使って説明しました。

最大128点も追加できると考えると、だいぶ心強いですよね。

次回は、入力側を増やす方法について説明していきます。

おそらく今回の内容が理解できていればすぐに理解できるはずです。

コメント

  1. 端山勇斗 より:

    コメント失礼いたします。
    現在、ラズベリーパイ4にてSPI通信の方のMCP23S17を使用していて、こちらのサイトのようにLEDを点滅させるためにPythonコードを参考にさせてもらったのですが、上手くいきませんでした。
    以下が実行させたプログラムになります。ほかのサイトも調べてみたのですが解決すことはできませんでした、どうか力を貸していただきたいです。よろしくお願いいたします。

    import spidev
    import time

    #初期設定
    spi = spidev.SpiDev()
    spi.open(0,0)
    spi.mode = 0
    spi.max_speed_hz = 1000000

    Control_Byte = 0x40
    REG_IODIRA = 0x00 #入出力設定レジスタ
    REG_GPIOA = 0x12 #出力レジスタ

    spi.xfer2([Control_Byte,REG_IODIRA,0x00]) #出力
    # spi.xfer2([Control_Byte,0x05,0xB4]) #出力

    try:
    while True:
    spi.xfer2([Control_Byte,REG_GPIOA,0x01]) #ON
    time.sleep(1)
    spi.xfer2([Control_Byte,REG_GPIOA,0x00]) #OFF
    time.sleep(1)
    except KeyboardInterrupt:
    pass

    • hobbyhappy より:

      コメントありがとうございます。
      mcp23017のSPI通信版ですね。手元にあったはずなので引っ張り出してコード付きで解説記事を作りますので少々お待ちください。

    • hobbyhappy より:

      ご提示していただいたコードでも動作することは確認できました。
      恐らく配線関係の問題が起こっていると推察されます。
      やっていくうちに、I2Cとはアドレスの設定が若干違うところがわかりましたので、
      そちらについても記事にいたします。
      少々お待ちください。

タイトルとURLをコピーしました