Youtubeでも活動中

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

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

RaspberryPiでMCP23S17を使いこなす。【SPI通信】

raspberrypi-mcp23s17-spi-eyecatch

以前からMCP23017(i2c通信)と一緒に購入した、
MCP23S17(SPI通信)を使ってテストする予定が、
ずるずると…

今回はコメントでやってほしいという依頼もありまして、
ようやくMCP23S17とRaspberryPiをつなげて、
LEDを点灯させます。

MCP23S17はIOエクスパンダというもので、
単純に言うと、このチップに命令を出すと、
それぞれの足がHighになったり、Lowになったりできる。

という便利なものです。
もちろんピンの数にも限りがありますが、
Aのほうで0~7
Bのほうで0~7
なので合計16本GPIOピンが増えるようなイメージです。

I2Cのほうはすで記事にしていますから、
MCP23017のほうを使ってみたい方は
こちらの記事を確認してみてください。

MCP23017をRaspberryPiで使った時の記事
この記事を読むことでわかること

自己紹介

サラリーマンしてます。

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

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

2022年5月に転職。現役バリバリの技術者です。
現在は超大手企業の新規事業分野で装置の研究・開発をしています。

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

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

注意

本ブログはアフィリエイトを用いた広告を掲載しています。

今回やったことを実行するとこんな感じでLEDが点灯します。

raspberrypi400を使ってMCP23S17(SPI通信の方のIOエキスパンダ)でLED光らせてみた。 #programming #python #raspberrypi
実際にMCP23S17を使って7segの一部を光らせている動画

今回使用した道具たち

今回使用したのは写真のように、
主役のMCP23S17と、7セグ、抵抗、RaspberryPi400です。

今回の主役。MCP23S17
ブレッドボードに載せた7セグLEDと抵抗たち
RaspberryPi400あんまり使ってなかったし、VNC接続メインなのでタイピングもあまりしない…

今回紹介しているのは7セグですが、7セグである必要はありません。
もちろんただのLED1本、抵抗1本でまったく問題ないです。

わたしの場合は、すでにブレッドボードに7セグがくっついていたので、
外すのが面倒だったのでそのままにしました。

そういう意味では、ブレッドボードと
ジャンパーワイヤーも用意しておいてください。

今回使用しているのは、以前シフトレジスタや、MCP23017の時に使用したままの状態だったかな???

とりあえず、アノードコモンのタイプです。
写真の紫の線に+3.3Vを入れた状態で、
各ピンをGNDに落としてあげるとLEDが光るという仕組みですね。

もう少し詳しく解説した記事が以前のものであるので、
気になったら読んでみてください。

これらの部品は基本Amazonや通信販売でも取り扱いされています。
近くに実物を販売している店舗がない場合は、
通販を使うのもオススメです。

↓RaspberryPi400

↓MCP23S17

↓アノードコモンの7セグLED

↓ブレッドボードとか小物類のセット

RaspberryPiとPythonの開発環境について

開発環境はそろえておいたほうがよいので、
今回使用した開発環境についてご紹介しておきます。

  • OSのVer.は11.6
  • pythonのVer.は3.9.2 32-bit
  • このあと紹介するSPI用のライブラリ(spidev)のVer.は3.5
  • エディターはVSCodeを使用

一応執筆時点でほぼほぼ最新にした状態で検証しています。


一部でpython3では実行できないなんて話も出ていましたが、
この状態でできたので、わざわざVer.ダウンはしなくてよさそうです。

RaspberryPiとMCP23S17と7セグLEDを接続する

次に配線ですね。
MCP23S17は先述の通り、SPI通信を使用します。
RaspberryPiのほうもSPI通信のピンを使用しますが、
対応するピンがあらかじめ決まっていますので、間違えないように注意が必要です。

配線はこんな感じです。↓↓↓

raspberryPi-mcp23017
RaspberryPiとMCP23S17を接続した状態。7セグはアノードコモン。

繰り返しになりますが、
LEDは7segのLEDを使用する必要はありません。

砲弾型の普通のLEDを使用したい場合は、
オレンジ線にLEDのアノード(足の長い方)を接続して、
カソードを抵抗のうちどちらかにつなげてあげればいいです。

それから、I2C通信Ver.のMCP23017では重要だったアドレスについてですが、
これは今はあまり気にしなくていいです。
というのも、別記事で解説する予定のためです。
とにかく今回はこちらのように配線してもらえればLEDは光ります。

MCP23S17をRaspberryPiとPythonで制御するには

配線は完了したので、
ここからはRaspberryPiで実際に操作をしていきます。
RaspberryPi側で初期設定が必要ですので、
いったん確認しておきましょう。

RaspberryPiでSPI通信ができるようになっているか確認

RaspberryPiはOSを書き込んだ初期の状態だと、
SPI通信をしてくれない状態です。

ですので、SPI通信ができるように、
設定を変更してあげる必要があります。

具体的にはここを見てあげればいいです。
RaspberryPiの設定のところですね。

Raspberry Pi setting
RaspberryPiの設定画面の出し方。UIがしっかりしているので違和感なく使えますね。

上から3つ目のRaspberry Piの設定をクリックしましょう。
するとこんな画面が出てきますので、インターフェイスのタブを選択します。

Raspberry Pi interface tab
Raspberry Piの設定画面。インターフェイスのタブを選択した状態。

ここで確認するのが、上から3つ目のSPIというところです。
これに濃いグレーの色がついていれば、使えるということになります。

もし、ここに色がついていなければ、
クリックをしてSPIを有効化しましょう。

また、このSPIに限らない話ですが、
ここらへんの設定を変更したら、必ず再起動(reboot)しましょう。

再起動しないと、設定が反映されません。
これ結構重要です。

RaspberryPiでSPIを使うための準備

さて、SPIの機能をONにしたところで、
次にやることは、pythonでSPI通信をするために必要なライブラリの取得です。

ライブラリの取得とは言ってもそんなに大変な作業ではありません。
いわゆるpipです。

ちなみに初期状態でSPIのライブラリはインストールされているとの情報もありますが、
なんどpipをやっても特に問題はありません。

念のため実行しておくことをオススメします。

使用するライブラリの名前は、spidevというものです。
具体的にpipのコマンドを書いておくと、

sudo pip3 install spidev

このようにLXterminal上で打ち込むと、
spidevすなわち、pythonを使ったRaspberryPiのSPI通信用のライブラリがインストールできます。

冒頭でご紹介した開発環境の紹介のところでも書きましたが、
このspidevのVer.は3.5で実行しています。

ご自分のspidevのver.が知りたい方は、
LXterminalで、次のコマンドを打てばVer.の一覧が出てきます。

pip3 list

pythonのコードを書く

さて、ライブラリも準備できたところで、
いよいよコードを書きます。

まずはコードの全体を掲載していきましょう。

import spidev
import time

# 初期設定
spi = spidev.SpiDev()
# ここの引数は、(bus,CE0orCE1)。今回はCE0に配線しているので0。
spi.open(0,0)
spi.mode = 0
# 1MHzで設定。MCP23S17はデータシート上だと10MHzが最高らしい。
spi.max_speed_hz = 1000000

# CHも含めたアドレス関係をまとめた文字列。
Control_Byte = 0x40
# IOの向き(入力or出力)を決めるレジスタのアドレス。
REG_IODIRA = 0x00 
# GPIOAの入出力指令を出すためのレジスタのアドレス。
REG_GPIOA = 0x12 

# 今回はGPA0~A7まで全て出力に指定。出力:0,入力:1
spi.xfer2([Control_Byte,REG_IODIRA,0x00]) 
# whileの無限ループを中断するための退避用の関数。
def destroy():
    print("end")
try:
   # ここから無限ループ
    while True:
       # 0x03つまり、00000011となり、GPIOAの0と1をONする指令。
        spi.xfer2([Control_Byte,REG_GPIOA,0x03]) #ON
        time.sleep(1)
       # 0x00 つまり、すべての出力指示をOFF。
        spi.xfer2([Control_Byte,REG_GPIOA,0x00]) #OFF
        time.sleep(1)
# Ctrl + Cでここに入る。
except KeyboardInterrupt:
        destroy()

こんな感じです。

これでとりあえず動くはずです。
ただ、引っ掛かるポイントはいくつかあると思いますので、詳しく解説していきます。

spi.open(0,0)はこれ意外に設定方法がないか?

こちらは、コード上にコメントを入れていますが、
引数は取り合えず今回紹介した配線通りになっていればそのまま使えます。

もし、複数のMCP23S17を使用したい。
もしくは、他のSPI通信を使用する機器を増設したい。

そんなときは、
その機器をRaspberryPi上のCE1のピンにCSピンをつなげてあげればいいです。
その後、spi.open(0,1)とすれば接続できます。

ここは理論ではそうなるはずなのですが、
実際に試してみないと納得できないですよね。
そのうちMCP23S17を2つにして接続してみる予定です。

spi.modeは0でいいのか?

spiモードは、0~4ありますが、
一般的なSPI通信のモジュールは0で動くようになっているようです。

もちろんデータシートを確認したうえで決定してくださいね。
ここら辺の決め方は、詳しく解説している記事がありましたので
ご紹介しておきます。

SPIモードについて詳しく解説している記事

Control_Byteはなぜ0x40なの?

ここは少し説明が長くなりますが、
ちゃんと説明します。

以前のi2c版のIOエキスパンダーMCP23017の時は、A0~A2をGNDにつなげるか、
Vddにつなげるかでアドレスが変わる。とお話しました。

具体的には、A0~A2をGNDにつなげると、アドレスが、
0b010 0000で0x20になる。

A0~A2をVddにつなげるとbitが立って、
0b010 0111で0x27でアドレスをずらすことで最大8本つなげられる。

という論理でした。

では今回3本ともGNDに入れているから、0x20じゃないの?
と思いましたか?鋭いですね。

実は私も勘違いしていました。ですから、最初は0x20として「あれ、光らない…」
なんてやってました。

ここで重要になるのが、アドレスを決めた後のビットです。
データシートで確認しましょう。

MCP23S17のデータシートより。

こちらを見てもらうとわかる通り、R/Wのビットが最後に入ります。

つまり、0x20の最後に0or1が入ります。
今回はwriteしたいので、0が入ります。

というわけで、0b0010 0000となるわけです。
同様に、A0~A2をVddに入れると、0b0100 1110で、4Eになります。

なので、今回0x40を最初のコマンドとしているというわけです。

REG_〇〇はどこで決めているの?

REGは、レジスタの略です。
レジスタとは、簡単に言うと、あらかじめ決まっている機能の番地のようなものです。

この番地を指定して、その機能に合った信号を送ると思い通りに設定できますよ。
ということです。

これは、i2c通信Ver.のMCP23017でも解説しています。
今回のMCP23S17も確認してもらえればほぼ一緒であることがわかってもらえると思います。

どこで決めているかという疑問の答えは、
ズバリ…データシートですね。

データシートに詳しく記載がありますので、
データシートを参考にしてみてください。
きっと、0x00がIOの向き、0x12が入出力指令であるとわかってもらえるはずです。

spi.xfer2()は何をしているの?

spi.xfer2()←こちらは、実際にMCP23S17にコマンドを送っています。

引数()のなかに必要なコマンドを入れて実行します。
引数は必ず配列[]で渡します。
今回のMCP23S17の場合は、(アドレス+W/R+レジスタアドレス+コマンド)
という引数になっています。

これはMCP23S17のデータシート通りに送る場合の決まったフォーマットになります。
つなげて送る場合、引数の中でカンマ(,)を入れることで続けてコマンドが送られます。

具体的に1つ目のGPIOの向きを設定するところを例にして解説しましょう。

spi.xfer2([Control_Byte,REG_IODIRA,0x00]) 

さて、Control_Byteは、先ほど解説した通り、0x40です。


次に、REG_IODIRAは0x00です。
こちらはデータシートでレジスタのアドレスを確認すればOKのはずです。

最後に0x00は、GPIOAの0~7のピンをすべて出力(:0)に設定しています。

わかってしまえばそんなに難しくないですよね??
やりたいことがあれば少し変えるだけでいけそうです。

例えば、Aだけでなく、Bも使いたい…となれば、
IODIRBのアドレスをデータシートで確認すればいいですし、
GPIOAの0番だけ入力にしたいのであれば、
3つ目の0x00を0b00000001 = 0x01とすればOK。

ここからは、次回につながるMCP23017と異なるところ…

さて、ここまでで動作確認ができましたかね。
じつは、重要なことを説明せずにここまで来ました…
いちおうこれで目的の動きはできるはずですが、
もし2個目、3個目とMCP23S17を追加しようとすると必ずぶつかる壁があります。

それがCH設定です。

A0~A2までGNDに落としていますが、
じつは、このA0~A2、Vddに入れても動作するんです!
CHが0x20じゃなくなるじゃないか!でも動作するんですね。
試していただければすぐにわかります。

さてなんででしょうか?
このおはなしを次回の記事にする予定です。

今回のまとめ

今回はSPI通信を使用するIOエキスパンダ
MCP23S17をRaspberryPi400で制御してみました。

まともにSPI通信をしたことが無かったので、
今回の内容でだいぶ勉強になりました。

MSP23S17に限る話ではありませんが、
データシートの確認が重要であることを再確認しました。

ぜひこの記事を読んでSPI通信にチャレンジしてみてくださいね!

コメント

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