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

I2C / Arduinoからのデータを受信する

引き続き、シリアル通信 I2C について勉強しています。今回は、送られてきたアドレスが自己アドレスと一致したときだけ ACK を返す回路と、受信したデータを出力する回路を作ってみました。

前回は、とりあえず ACK を返すことで、アドレスに続くデータをコントローラが送るようにしています。それ自体は難しいことではなかったのですが、欲を出して高速モードプラス (1MHz) にしてみて、うーん、もうちょっと回路を考えないとなぁ、と感じたのでした。

高速モードプラスはさておき、アドレスとデータをそれぞれどう取り出そうか、ちょっとばかり悩んでしまいました。こちらも、うーん、もっと回路を工夫しないとなぁ、な気分です。

データ受信のタイミングダイヤグラム

データ受信タイミングダイヤグラム
図1. データ受信タイミングダイヤグラム

図1 は、コントローラ (Arduino) から送られてくる I2C 信号を受信するタイミングダイヤグラムです。クロックをカウントして ACK を送出するまでは、前回と同じです。

スタートコンディションパルス ST から最初のキャリーオーバ CO までの FAD の間がアドレスデータですので、これを検出して自己のアドレスと照合します。アドレスが一致し、RW が 0 (Write モード) ならば ACK を返します。一致しなければ NACK (ACK を返さない) とします。
データはシフトレジスタでパラレルデータに変換します。クロックの初めの 8クロックをシフトレジスタクロックとしてシフトし、最後の 9個目をレジスタクロックとしてストレージレジスタへ出力します。

回路図

各部の回路図です。前回までの回路も再掲してあります。

初期化回路

初期化回路
図2. 初期化回路

初期化回路 (図2)、コントローラ回路 (図3) には変更ありません。前回記事を参照ください。

下のスケッチも変更ありません。転送速度は高速モード (400KHz) としています。
実験では、SDA 側のプルアップ抵抗を 1KΩにすることで高速モードプラス (1MHz) にも対応できました。

コントローラ (Arduino) 回路

コントローラ (Arduino) 回路
図3. コントローラ (Arduino) 回路

コントローラのスケッチ

  1. #include <Wire.h>
  2. void setup() {
  3.   Wire.begin();
  4.   Wire.setClock(400000);
  5. }
  6. void loop() {
  7.   static byte address = 0x54;
  8.   static byte data = 0x00;
  9.   for(data = 0x00; data <= 0xFF; data++) {
  10.     Wire.beginTransmission(address);
  11.     Wire.write(data);
  12.     Wire.endTransmission();
  13.     delay(100);
  14.   }
  15. }

通信中検出回路

通信中検出回路
図4. 通信中検出回路

図4 は、スタートコンディションからストップコンディションまでの間、通信中 BUSY を出力する回路です。基本的には前回と変わりないのですが、NOT と AND で構成していた立ち下がりエッジの検出部を NOR ゲート 74HC02 (U7D) に置き換えました。

カウンタおよび ACK送出回路

カウンタおよび ACK送出回路
図5. カウンタおよび ACK送出回路

図5 は、クロックのカウントを行なうカウンタ回路と、ACK を送出するオープンドレイン回路です。前回と変更ありませんが、今回は否定応答である NACK も利用します。

アドレス検出回路

アドレス検出回路
図6. アドレス検出回路

図6 は今回追加した回路、コントローラから送られてきたペリフェラルのアドレスを検出し、自己のアドレスと一致するかを照合する回路です。一致しないとき NACK は LOW になり、ACK の送出を行ないません。

8回路 Dフリップフロップ U8 (74HC377) は SIPOシフトレジスタを構成しています。ストレージレジスタのないシフトレジスタ (Ex. 74HC164) があればそれでいいのですが、部品箱になかったのでこれを使いました。アドレス 7ビットと RWフラグ 1ビットの 8ビットをパラレル出力し、LED 表示しています。

XOR (74HC86) と OR (74HC32)、NOR (74HC02) の組み合わせ回路は、シフトレジスタから出力された 8ビットデータがアドレス=0x54、RW=0 (0b10101000) であれば、出力 NACK を HIGH にします。
排他的論理和 XOR は入力が不一致ならば 1 を出力します。それをすべて OR しますから、すべてのビットが一致したときだけ 0 が出力されます。が、最後のゲートが NOR なので、NACK は 1 になります。

Dフリップフロップ U9A (74HC74) は、スタートコンディションパルス ST でセットされ、クロックカウンタのキャリーオーバ CO でリセットされる FAD を出力します。FAD はシフトレジスタのクロック入力を有効にして、最初の 8パルス分だけデータを取り出しています。

データ出力回路

データ出力回路
図7. データ出力回路

図7 は、アドレスに続いて送られてくるデータビットを出力する回路です。
クロック SCK の初めの 8クロックをシフトレジスタ U14 (74HC595) のシフトクロック SRCLK として入力し、データ SDT をシフトします。最後の 9クロック目 (CO が HIGH のとき) はレジスタクロック RCLK に切り替え、データをストレージレジスタへ送ります。
アドレスを受けている FAD が LOW の間は、シフトレジスタを停止します。

なお、電源オン時の初期化は CLR を入れているだけなので不規則に点灯する場合があります。

ブレッドボード

I2C 受信回路ブレッドボード
図8. I2C 受信回路ブレッドボード

I2C の受信回路の実験を行なったブレッドボードです。

本来はブロックごとに分けて作ることを原則にしているのですが、今回は IC の空き回路を積極的に使っています。そのために配線の行き戻りが多くなっています。まぁ、そのときの気分なんで。

上部の Arduino Nano Every がコントローラです。I2C 信号を受信すると、中央付近の LEDがアドレスと RW の 8ビットを表示します。
アドレスが一致すれば、下部の LEDがデータを表示します。一致しなければ消灯します。

毎度の、こんなんにしてやりました、ってことで。
ちなみに、Chrome なら画像を右クリックして「新しいタブで開く」と原寸にできますので、お好みでどうぞ。

後記

今回は、Arduino をコントローラとして送信される I2C 信号を受信して、LEDに表示する回路を作りました。が、I2C 通信がどんなものなのかを確かめながらでしたので、なんだかツギハギの回路になったなぁと感じています。

これまでシリアル通信について勉強してきました。SPI はコントローラとペリフェラルとでデータを交換していました。UART はデータを送りっぱなしです。
でも I2C は、コマンドで送信か受信かを選択し、データを受け取ったら ACK を返すというやり取りがあります。なので、受信モードも含めた全体の動きを考えて検討する必要があるよなぁ、って。もしロジックIC でなどと酔狂いうなら、もう一度最初から考えなおそうね。考えなおそう、そのうち、もし、気が向いたらね。

論理回路の勉強をやり始めたのは、もう 1年半前になります。

なんだかんだいろいろやってきましたけど、そろそろ論理回路はおしまいにしようかなと思います。でも、まだまだ知らないこと、わからないことだらけですので、また気が向いたらやりますケド。

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