I2CやSPI通信の説明に入る前に、コンピュータの世界の通信とはどういうものか、具体的に考えてみます。
マイコンとセンサやLCDモジュール間の通信
実践編で設計した回路図では、マイコンとセンサやLCDモジュールは以下のように2本、または4本の線で接続しています。データ通信は、この接続線をデジタル制御して行われます。
「データ通信はデジタル制御で行う」というとなんだか難しそうですよね。
この「デジタル制御」ですが、基礎編と応用編で行なったLED制御と同じなんです。
タイマーのプログラムでは、LEDやブザー、スイッチをデジタル制御しましたよね。デジタルのデータ通信制御はその方法と同じです。PICマイコンのピンを0か1か(電圧としては0Vか3.3Vか)出力制御したり、ピンの電圧値を0か1で読み取ったりする制御方法です。
マイコンと周辺モジュール間のデータ通信は、2本、または4本の接続線を0か1か制御しながら行われているわけです。
とは言っても、回路図では接続線が2本だったり4本だったりしますし、その接続線を0か1か制御して何をどうすればデータ通信ができるのか、さっぱりわかりませんよね。
そこで、データ通信を検討するための架空のシステムを作って、どのようにすればデータ通信ができるか考えてみます。このシステムは、あくまでコンピュータのデータ通信はどのように考えていけばいいか、ということを説明するものです。SPI通信やI2C通信そのものの説明ではありません。このシステムが完成したあと、考え方を拡張してSPI通信システムやI2C通信システムを説明します。
ところで、このシステムはこれからいろいろと問題が出てきます。一つ一つ解決していきますが、説明を読み進める前に、できるだけご自分で解決策を考えてみてください。
データ通信システム
これから、以下のようなシステムでどのように制御すれば情報を送ることができるか、つまりデータ通信ができるのかを考えます。
このシステムは、1階のリビングにスイッチがあり、このスイッチで2階の子供部屋にある電球を点滅させることができます。リビングのスイッチを押すと子供部屋の電球が光り、スイッチを離すと電球は消えます。このようなシステムで、どのようにすればうまく情報が送れるか考えていきます。
なお、このシステムはコンピュータの世界の通信に対応しています。リビングにあるスイッチはデータ送信を行うためにOFF/ON制御(0/1制御)を行うことに相当します。また、子供部屋の電球がONかOFFかを確認することは、OFF/ONを確認して(0/1を確認して)情報を受け取ることに相当します。
ゴール
このシステムで行いたいことは、リビングにいる母親から、子供部屋にいる息子に以下の情報を送ることです。
- 友達が来たよ
- 買い物行ってきて
- お風呂できたよ
- 洗濯物たたんで
- おやつあるよ
- ごはんできたよ
- 掃除を手伝って
- ちょっと来て
普通の用事以外に、行かない方がいいものもあるので、息子さんは正確に情報を読み取る必要があるわけです。
このシステムでは言葉はそのまま送れませんので、それぞれの用事を電球の点滅パターンで表すことにします。電球の点灯を1、消灯を0と表し、点滅パターンを割り当てます。用事は8種類ありますので、以下のように点滅パターンを割り当てます。
点滅パターン | 用事 |
---|---|
000 | 友達が来たよ |
001 | 買い物行ってきて |
010 | お風呂できたよ |
011 | 洗濯物たたんで |
100 | おやつあるよ |
101 | ごはんできたよ |
110 | 掃除を手伝って |
111 | ちょっと来て |
例えば「ごはんできたよ」という情報を送りたい場合、点滅パターンは「101」に割り当てていますので、電球を「点灯 → 消灯 → 点灯」となるようにスイッチをパチパチやればいいわけです。母親と息子は上の点滅パターン表を手元に置いておき、母親はこの表に従ってスイッチを操作し、息子は電球の点滅パターンを見て送られてきたパターンを読み取ることによって、これらの情報を正確に送ろうというわけです。
なお、送る情報を2進数と見た場合、3ビットの情報を送るシステムになっています。実際のコンピュータの世界のデータ通信は、このビット数は8ビットや9ビットなど、もっと増えますが、考え方は同じです。
とりあえずやってみよう!
送りたい情報のパターン通りにスイッチを操作すればいいわけですから、ずいぶん簡単そうですよね。いろいろと考える前に、とりあえずやってみましょう!
まずは先ほどの表の「ごはんできたよ」という情報を送ってみましょう。以下の画像をクリックすると子供部屋の電球が点滅しますので、3ビットの情報が受け取れるか確認してみてください。
これは、誰がみても「点灯 → 消灯 → 点灯」ですので、「101」、つまり「ごはんできたよ」という情報ですよね。もしかして「点灯 → 消灯 → 点灯 → 消灯」ではないのか? と思われた方もいるかもしれません。今回の情報は全て3ビットでやり取りすることにしていますので、この場合は「点灯 → 消灯 → 点灯」と読み取ることになります。
この調子で全部行けそうな気もしますので、次は「おやつあるよ」を送ってみましょう。点滅パターンは「100」、つまり「点灯 → 消灯 → 消灯」です。
「点灯 → 消灯 → 消灯」と読み取れましたので、「100」つまり「おやつあるよ」が受信できたようです。
それではここで他の情報を読み取ってみましょう。次の画像の点滅パターンは何か判別してみてください。
なんだかちょっと怪しくなってきてませんか? 「110」のような気もしますが、「100」とも読み取れるような気がします。さらには、もしかしたら「111」かもしれません。これは「110」を送ったつもりなんですが…
よくよく考えてみると、「100」「110」「111」は、電球の点滅状態を見ると、すべてが「しばらく点灯 → 消灯」というパターンです。
これらの情報を読み間違えると、おやつのつもりが掃除を手伝わされたり、さらには得体の知れない「ちょっときて」だったりしますので、なんとしてでも正確に読み取る必要があります。
「100」「110」「111」を区別するにはどうすればよいか、次の説明を読む前に、まずはどうすれば解決できるか、考えてみてください。
「100」「110」「111」を正確に送るには?
問題は、「100」「110」「111」のいずれも、電球の点滅状態は「電球が光って→消える」というパターンになってしまうために、1がいくつ連続しているのか読み取ることが困難になっていることです。
「100」「110」「111」ともに電球が光って→消える、というパターンである以上、電球が光っている状態が「1」なのか「11」なのか「111」なのか判別する必要があります。
ここで、電球が点灯している時間に注目してみます。「100」と「110」では電球が点灯している時間は「110」の方が長いはずですよね。ところが、母親は「110」のつもりで情報を送っても、息子は「100」「110」「111」の判別が困難です。例えば、母親は0.5秒おきに1ビットずつ送ったつもりでも、息子は1秒に1ビットのつもりでパターンを読み取ってしまっては正しく情報を送ることができません。
このように考えていくと、母親と息子の1ビットの時間感覚が異なることに原因がありそうです。
この問題を解決するためには、時間感覚を合わせればうまく判別できるようになるのではないでしょうか。ということで、母親と息子はそれぞれ時計を見ることにします。秒針付きの時計です。この時計の秒針をみながら、母親は1秒に1ビットずつスイッチを操作することにします。また息子は情報が送られてきたら1秒に1ビットずつ読み取るようにします。
このように決めると、すべての情報は3秒で送信され、1秒目は1ビット目、2秒目は2ビット目、3秒目は3ビット目となるので、お互いに時計の秒針を頼りにスイッチを操作したり、電球の点滅はパターンを読み取れば、正しく情報が送れそうです。
それでは、1秒に1ビットずつパターンを送る、という決まりの元、以下のパターンを読み取ってみましょう。今度は時計付きです。
時計の秒針を見ながら点滅パターンを見ると、2秒間点灯してそのあと消灯しています。全部で3ビット、3秒ですので、2秒間点灯、1秒間消灯ということで「点灯→点灯→消灯」、つまり「110」であることが判別できるようになりました。
これで大丈夫ですよね!
残りのパターンを送る
今までの考え方で「100」「101」「110」「111」は送れるようになりました。まだ4種類の情報が残っていますので、残りも早く片付けてしまいましょう。
残りのパターンは「000」「001」「010」「011」です。それでは、このうちのどれかの情報を送りますので判別して見てください。時計付きですので安心です!
「001」と読み取った方や、もしかして「100」ではないか、と思った方もいましたでしょうか。「010」と送ったつもりなんですが……確かに「001」のような気もしますし、「100」と言われても確かにそう読み取れます。
ということで簡単に片付けるはずが、また問題が出てきてしまいました。1秒ごとに1ビット送るという取り決めをしたところまではよかったのですが、以下の区別がつきません!
「001」と「010」と「100」→ いずれも1秒間点灯し、他の時間は消灯
「110」と「011」→ いずれも2秒間点灯し、他の時間は消灯
ということで、追加でこれらの信号が区別する方法を考える必要が出てきてしまいました…。すみませんが考えてみてください。「100」はおやつ、「010」はお風呂で問題ないんですが、「001」の時は行きたくないんです。
「100」「010」「001」を正確に送るには?
「100」「010」「001」の情報が読み取れない原因は、点滅パターンの始まりがどこかわからない、というところにあります。
解決策として思いつくのは、お互い持っている時計を使って、決まった時間に情報を送るという方法あたりでしょうか。例えば、毎時00分に情報を送る、という方法です。
でもこのようにしてしまうと、1時間に1回しか情報が送れません。また、母親から送る情報がない場合でも、息子は毎時00分に3秒間の3ビット情報を受け取ろうとします。毎時00分から3秒間、電球が点灯しない場合は「000」と読み取れてしまいます。さらに、そもそもお互いが持っている時計がずれてくる可能性もあります。電波時計やスマホは基準となる時間に合わせていますのでいつでも正確ですが、一般的な時計は1ヶ月に15秒〜20秒程度ずれてしまいます。決まった時間に情報を送る、という方法は解決策にならさそうです。
なんだか解決策はなさそうですが、、、一ついい方法があります。
それは、送信が始まることを、1秒間点灯することで知らせる方法です。送信開始時に、電球を必ず1秒間点灯させ、そのあとの3秒間で3ビットの情報を送る、という方法です。情報を送る時間は4秒間になってしまいますが、確実に送信開始を知らせることができます。
以下は「010」を送信する点滅パターンです。最初に電球が1秒間点灯しますので、送信が開始された、と認識します。情報はそのあとの3秒間の3ビットです。
1秒間点灯したあとは、1秒間消灯、1秒間点灯、1秒間消灯ですので、無事「010」が送信できました。
これで全てのパターンを送ることができるようになりました!
今まで考えてきた通信方法をまとめると、以下のようになります。
- 1ビット1秒で送信する
- データ送信の開始時に、データに先立って1を送信する
- そのあとに3ビットの情報を送る
このようスイッチと電球だけのシステムでも、うまく情報を送るための取り決めをすると、0と1のデータを送れるようなります。このように、情報を送るための取り決めを「通信手順」と呼びます。
実際の通信方式
今回検討した通信手順は、1つの信号(1組のスイッチと電球)でデータ通信を行う方式です。この方式は、実際にコンピュータ(マイコンやPCなど)で使われています。
1つの信号を使った通信方式としては、例えば、マイコンがサポートしているものでは「UART」と呼ばれているものが一般的です。また、PCがサポートしている通信方式としては「USB」が有名です。
実際に使われる通信手順は、以下の特徴を持っています。
- 1つの信号でデータ通信を行う
- 1秒間に何ビット送信するか、あらかじめ決めておく。つまり1ビットを送る時間を決めておく
- データ送信の開始を知らせるビットを送る(「スタートビット」と呼ばれています)
- 1回に送るデータの長さ(例えば8ビット送る、など)を決めておく
- データ送信の終わりを知らせるビットを送る(「ストップビット」と呼ばれています)
UARTでもUSBでも、この考え方で通信が行われています(信号線の回路と制御方法はもっと複雑ですが…)。
例えばUSBはバージョン2.0や3.0などがあり、それぞれの規格で通信スピードが決められていますよね。それは、1ビットを送る時間をあらかじめ決めておくためです。
また、この記事で考えたシステムでは1秒間に1ビットという非常にゆっくりしたスピードでデータ送信していますが、UARTやUSBでは1秒間に数千〜数十億ビットと、非常に短い時間で1ビットを送るため、データ送信の終わりも確認しながら送信しています。
SPI通信とI2C通信
先ほどの例で出てきたUARTやUSBは、1つの信号を使ってデータ通信を行う方法です。
次回から説明するSPI通信やI2C通信はこの方法とは異なり、2つの信号や4つの信号を使ってデータ通信を行います。
1つの信号でもデータ通信ができることを考えると、なぜ複数の信号でデータ通信をやり取りするか、ちょっと不思議ですよね。その理由ですが、SPI通信とI2C通信は、データを送る方も受け取る方もお互いに時計を持たずに通信しているからなんです。
とはいっても、時計を持たずにどのように通信するか不思議ですよね。そこで、今回検討したシステムを拡張していくことにより、お互いに時計を見なくてもデータ通信ができる方法を考えていきます。
更新履歴
日付 | 内容 |
---|---|
2018.4.11 | 新規投稿 |
2018.12.9 | 回路図のPICkitコネクタを5ピンに変更 |