アフィリエイト広告
アフィリエイト広告

Arduinoからシフトレジスタ 74HC595へ SPIでデータを送る

今回は、SPI (Serial Peripheral Interface) とはどんな通信方式なのかを勉強して、Arduino からシフトレジスタ 74HC595 (SIPO) へ SPI でデータを送る実験をしてみました。

これまで、shiftOut() 関数を利用してシフトレジスタ 74HC595 へデータを送るということは幾度もやってきました。以下の記事などを参照ください。

基本的には同じようなことなのですが、SPI を利用するメリットはなんといっても伝送速度が速いこと。いやぁ伝送速度なんて遅くてもいいよって思っちゃうのですが、いやいや、その時間を別な処理にあてられるでしょって言われると、心が動きます (;´Д`)
shiftOut() の伝送速度は 80KHz 程度、SPI は 8MHz ですから 100倍です。制御信号があるから実質的には数倍ほどでしょうか、それでも 1回の伝送で 100μs は節約できそうです。これを利用しない手はない。

でも、SPI は過去に一度だけ使ったことはありますが、知識はありません。一からの勉強です。

なお、公式サイトのアナウンスに従い、用語の言い換えをしています。新しい用語については以下の表を参照してください。なお、使用した Arduino の端子名は旧称で表示されていますので、一部混用している部分があります。

Controller/peripheral is formerly known as master/slave. Arduino no longer supports the use of this terminology. See the table below to understand the new terminology:

Master/Slave (OLD)Controller/Peripheral (NEW)
Master In Slave Out (MISO)Controller In, Peripheral Out (CIPO)
Master Out Slave In (MOSI)Controller Out Peripheral In (COPI)
Slave Select pin (SS)Chip Select Pin (CS)
Arduino & Serial Peripheral Interface (SPI)

SPI とは

毎度々々ですが、ググってください。詳細な解説をしてくださるグーグル先生がたくさんおられます。

が、詳しすぎてチンプンカンプンわからない。これからやってみようとしている Arduino とシフトレジスタとの通信って、けっきょくどうすればいいんですか?

SPI とは、シフトレジスタ同士のデータの交換です

SPI はコントローラ (Controller) とペリフェラル (Peripheral) の間のデータ交換のしくみです。

図1 に示すように、コントローラとペリフェラルにはそれぞれシフトレジスタがあり、それがループのようにつながっています。それぞれのシフトレジスタは交互にデータを送り合って、最終的にコントローラ側のデータとペリフェラル側のデータが入れ換わる。じつは、それだけの話、なんです。

SPIのしくみのダイヤグラム
図1. SPI のしくみ

SPI はデータを交換するのですから、送信と受信を同時に行ないます。
じゃ、送信だけしたいときはどうするか。コントローラからデータを送信し、ペリフェラルからダミーデータを受けとります。と言うとむずかしく聞こえますが、たとえばコントローラの CIPO を GND につなげば 0x00 が入ってきたことになります。必ずしもペリフェラルがデータを送る必要はありません。
受信だけするときは? コントローラからダミーデータを送ります。すると、ペリフェラルはデータを送ってきます。

Arduino から 74HC595 へデータを送る方法

SPI のしくみがわかりましたので、じっさいにコントローラの Arduino からペリフェラルの 74HC595 へデータを送る方法を考えてみましょう。

Arduinoから74HC595へデータを送る接続図
図2. Arduino から 74HC595 へデータを送る接続図

Arduino では、SPI のコマンドである SPI.transfer(value) で内部のシフトレジスタへデータ value が渡され、COPI をとおして送信が始まります。
74HC595 は、Arduino から送られてくるシリアルクロック SCK に同期してデータを受け取ります。すべてのデータが送信されたら Arduino から CS信号が送られてきますので、ストレージレジスタへデータを渡します。
Arduino の受信入力である CIPO は GND または +5V ラインにつないでおけば、それがダミーデータになりますから、74HC595 につなぐ必要はありません。

Arduinoから74HC595へデータを送るタイミングダイヤグラム
図3. Arduino から74HC595 へデータを送るタイミングダイヤグラム

図3 は、データ送信時のタイミングダイヤグラムです。ここでは SPISetting() を、MSBFIRST、SPI_MODE0 としています。

コントローラ (Arduino) 側では、チップセレクト CS を LOW にすることで通信を開始し、終了したら HIGH にもどす。SPI.transfer() を実行すると、COPI にデータ D7 がセットされ、シリアルクロック SCK が送出される。SCK は 8クロック出力され、それにともなって送信データがシフトする。
データがないとき、COPI は HIGH になっている。

ペリフェラル (74HC595) 側。CS は レジスタクロック RCLK につながっていて、LOW になっても何も起こらない。SCK は シフトクロック SRCLK につながるが、クロックが入ってこなければ何も起こらない。つまり、待機状態。
COPI は シリアル入力 SER につながっているので、Arduino 側でデータ D7 が COPI にセットされると、それが SER に入力される。SCK が入るたびにデータを受けとり、シフトして、8ビットのデータがシフトレジスタから出力される。送信が終了し CS が HIGH になると、それが レジスタクロック RCLK となり、データがストレージレジスタから出力される。

ちなみに、SPI_MODE0 のとき、Arduino 側では SCK の立ち下がりエッジ (Falling) で送信データがシフトされます (Output Edge)。74HC595 側は SCK の立ち上がりエッジ (Rising) でシフトします (Data Capture)。ここ、勘違いしそうなポイントなので要注意です。(*1)

ということで、図2 のように接続すれば、図3 のように動くであろうことがわかりました。

回路図

Arduino から出力される 8ビットデータを受信して、LED でビット列を表示する回路です。

Arduinoから74HC595へデータを送る回路図
図4. Arduino から 74HC595 へデータを送る回路図

Arduino は Nano Every です。使用するピンは、SCK が D13、COPI が D11で UNO や NANO と同じですが、CS は D8 (*2) です。UNO、NANO では D10 (*3) ですので、間違えないように。

CIPO は入力端子ですので、GND もしくは +5V につないでおきます。うっかり出力ポートにしちゃったりすると悲惨な目にあいますので、1kΩ の抵抗を保護のためにつけておきましょう。
電源は USB から供給します。IC の駆動電源として 5V 出力を利用します。

74HC595 のシフトレジスタクリア SRCLR、アウトプットイネーブル OE はそれぞれ +5V、GND につないであります。電源オン時の初期化については考慮していません。出力 QA~QH はそれぞれ LED を取り付け、出力状態を表示させます。

スケッチ

Arduino から SPI で 8ビットカウンタデータを出力するテスト用のスケッチです。

  1. // Sketch for Arduino to 74HC595 SPI-Test 2023.9.8 meyon
  2. #include <SPI.h>
  3. SPISettings mySettings(8000000, MSBFIRST, SPI_MODE0);
  4. void setup() {
  5.   // In Nano Every,SS is pin-D8, Mode setting required
  6.   pinMode(SS, OUTPUT);
  7.   SPI.begin();
  8. }
  9. void loop() {
  10.   for (int value=0; value<=0xFF; value++) {
  11.     SPI.beginTransaction(mySettings);
  12.       digitalWrite(SS, LOW);
  13.       SPI.transfer(value);
  14.       digitalWrite(SS, HIGH);
  15.     SPI.endTransaction();
  16.     delay(50);
  17.   }
  18. }

9行目。Arduino Nano Every では CS のピンモードを設定してやらないとうまく動きません。UNO や NANO では必要ないです。あっても不都合はないようですが、念のため SPI.begin() の前に置いておきましょう。

14行目で、0x00~0xFF のカウンタデータを生成しています。16行目で CS を LOW にし、17行目で送信、18行目で CS を HIGH にもどします。そのトランザクションを 50ms 間隔で繰り返しています。

動作状況

実験中のブレッドボードのようす
図5. 実験中のブレッドボード

図5 は、実験中のブレッドボードです。

右に Arduino Nano Every、中央がシフトレジスタ 74HC595 です。左下はビット表示の LED。

回路図に明記していないのですが、中央下の電解コンデンサ (10μF) は 5V 電源ラインに入っています。ノイズがかなり電源ラインにのりますのであったほうがよいのですが、あまり大きくすると Arduino の電源が心配です。しっかりした別電源を用意するのがベターです。

チップセレクトCSとシリアルクロックSCKの波形
図6. チップセレクト CS とシリアルクロック SCK

図6 は、チップセレクト CS (黄) とシリアルクロック SCK (青) の波形です。

CS を LOW にしてから0.8μs ほどして SCK が送出されます。伝送速度が 8MHz ならば 8ビットで 1μs、その後 CS が HIGH になるまでに 1.9μs、全体で 3.7μs となりました。
ただ、ときどきばらつきます。数μs の delay を入れると安定するようですが、その分伝送時間が延びます。

シリアルクロックSCKとシリアルデータCOPIの波形
図7. シリアルクロック SCK と シリアルデータ COPI

図7 は、シリアルクロック SCK (黄) と シリアルデータ COPI (青) の波形です。

図3 タイミングダイヤグラムで示したように、SCK の立ち下がりエッジで COPI のデータがシフトします。74HC595 では SCK の立ち上がりエッジでデータを読み込みます。したがって、波形から「11010110」と読み取っていることがうかがえます。
残念ながら図5 の LED の表示はこのタイミングではないので、別な値を表示しています (;´Д`)

テスト用のスケッチは、Arduino から 8ビットのカウンタデータを出力しています。74HC595 の出力である LED列が 0b00000000~0b11111111 をカウント表示することを確認できました。

後記

今回は、SPI による伝送について勉強し、Arduino をコントローラ、シフトレジスタ 74HC595 をペリフェラルとして、SPI でデータを伝送するしくみを実験してみました。

冒頭に書いたように、俺は SPI について知識がありませんでした。グーグル先生にいろいろ教えてもらいましたが、トポロジがどうだとか、クロックの極性やら位相やらがどうだとか、最初はチンプンカンプン。でもどこかで、コントローラとペリフェラルでデータが交換されるんだと知って、いっきに理解が進みました。
もう SPI、ばっちりですよ (^_^;)

さて、では次は、ペリフェラルからコントローラへ、データを受信する方法をやってみましょう。しくみはデータの交換ですから、受信も送信と同じように考えればよいはずですが、どうでしょうか。

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