I2C通信やSPI通信の説明に入る前に、マイコンで通信を行うにはどうすればよいのか、基礎的な概念を解説します。
デジタル通信
実践編で作成した回路図では、マイコンとセンサー・LCDモジュールは次のように2本、または4本の線で接続しています。
データ通信は、この接続線をデジタル制御して行われます。

「データ通信をデジタル制御で行う」というとなんだかすごく難しそうですよね。
この「デジタル制御」というのは、基礎編と応用編で行なったLED制御と同じなんです。
基礎編と応用編では、プログラムでRA5 = 1;
などと書いて、LEDやブザー、スイッチをON/OFF制御しましたよね。
この「ON/OFF」制御は「デジタル制御」と呼ばれます。「デジタル」とは「ONとOFF」や「0と1」のように2つの状態しかないものを指します。
「データ通信をデジタル制御で行う」というのは、実はPICマイコンのピンを0か1か(電圧としては0Vか3.3Vか)の出力制御したり、ピンの電圧値を0か1で読み取ったりする制御方法です。
マイコンとモジュール間のデータ通信は、2本、または4本の接続線を0か1か制御しながら行われているわけです。
とは言っても、回路図では接続線が2本だったり4本だったりしますし、その接続線を0か1か制御して何をどうすればデータ通信ができるのか、さっぱりわかりませんよね。
そこで今回の記事では、デジタル制御によるデータ通信はどのように行われるのか、架空のシステムを作って、考えていきます。
このシステムは、あくまでデジタル制御のデータ通信はどのように考えていけばいいか、ということを説明するものです。
今回の記事内容は、SPI通信やI2C通信そのものの説明ではない点に注意してください。
今回説明するシステムは、デジタル通信の基礎となります。
このシステムが完成したあと、考え方を拡張してSPI通信システムやI2C通信システムを説明します。
ところで、このシステムはこれからいろいろと問題が出てきます。一つ一つ解決していきますので説明が長くなりますが、最後までお付き合いいただければと思います。
(架空の)データ通信システム
これから、次のようなシステムで、どのように制御すれば情報を送ることができるか、つまりデータ通信ができるのかを考えます。

このシステムは、1階のリビングにスイッチがあり、このスイッチで2階の子供部屋にある電球を点滅させることができます。
リビングのスイッチを押すと子供部屋の電球が光り、スイッチを離すと電球は消えます。このようなシステムで、どのようにすればうまく情報が送れるか考えていきます。
なお、このシステムはコンピュータの世界の通信に対応しています。
リビングにあるスイッチはデータ送信を行うためにOFF/ON制御(デジタル制御)を行うことに相当します。
また、子供部屋の電球がONかOFFかを確認することは、OFF/ONを確認して情報を受け取ることに相当します。
ゴール
このシステムで行いたいことは、リビングにいる母親から、子供部屋にいる息子に次の情報を送ることです。
- 友達が来たよ
- 買い物行ってきて
- お風呂できたよ
- 洗濯物たたんで
- おやつあるよ
- ごはんできたよ
- 掃除を手伝って
- ちょっと来て
普通の用事以外に、行かない方がいいものもあるので、息子さんは正確に情報を読み取る必要があるわけです。
このシステムでは言葉はそのまま送れませんので、それぞれの用事を電球の点滅パターンで表すことにします。
電球の点灯を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ビットずつ読み取るようにします。(両方の時計の秒を刻むタイミングは一致しているものとします)
このように決めると、すべての情報は3秒で送信され、1秒目は一桁目、2秒目は二桁目、3秒目は三桁目となるので、お互いに時計の秒針を頼りにスイッチを操作したり、電球の点滅はパターンを読み取れば、正しく情報が送れそうです。
それでは、1秒に1ビットずつパターンを送る、という決まりの元、以下のパターンを読み取ってみましょう。今度は時計付きです。

時計の秒針を見ながら点滅パターンを見ると、2秒間点灯してそのあと消灯しています。
全部で3ビット、3秒ですので、2秒間点灯、1秒間消灯ということで「点灯→点灯→消灯」、つまり「110」であることが判別できるようになりました!
これで大丈夫です!
残りのパターンを送る
今までの考え方で「100」「101」「110」「111」は送れるようになりました。
まだ4種類の情報が残っていますので、残りも早く片付けてしまいましょう。
残りのパターンは「000」「001」「010」「011」です。
それでは、このうちのどれかの情報を送りますので判別して見てください。時計付きですので安心ですよね!

「001」と読み取った方や、もしかして「100」ではないか、と思った方もいますかね。
「010」と送ったつもりなんですが……確かに「001」のような気もしますし、「100」と言われても確かにそう読み取れます。
ということで簡単に片付けるはずが、また問題が出てきてしまいました…
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秒間点灯することで知らせる方法です。
送信開始時に、電球を必ず1秒間点灯させ、そのあとの3秒間で3桁の情報を送る、という方法です。
情報を送る時間は4秒間になってしまいますが、確実に送信開始を知らせることができます。
以下は「010」を送信する点滅パターンです。最初に電球が1秒間点灯しますので、送信が開始された、と認識します。情報はそのあとの3秒間の3ビットです。

1秒間点灯したあとは、1秒間消灯、1秒間点灯、1秒間消灯しています。
最初の点灯は「これからデータを送りますよ」という意味なので、そのあとの点滅が実際のデータになります。
つまり、「010」ということになり、無事データが正しく送信できました。
これで全てのパターンを送ることができるようになりました!
今まで考えてきた通信方法をまとめると、次のようになります。
- 1桁1秒で送信する
- データ送信の開始時に、データに先立って1を送信する
- そのあとに3桁の情報を送る
このようスイッチと電球だけのシステムでも、うまく情報を送るための取り決めをすると、0と1のデータを送れるようなります。
また、このような情報を送るための取り決めを「通信手順」または「プロトコル」と呼びます。
実際の通信方式
今回検討した通信手順は、1つの信号線(1組のスイッチと電球)でデータ通信を行う方式です。この通信方式は、実際にコンピュータ(マイコンやPCなど)で使われています。
1つの信号を使った通信方式としては、例えば、マイコンがサポートしているものでは「UART(シリアル通信)」と呼ばれているものが一般的です。
Arduinoをお使いの方は、Arduino IDEに「シリアル機能」を使ったことがあるかもしれません。この「シリアル機能」は、1つの信号線を使って、Arduino IDEとArduinoボードの間でタイミングを合わせて通信しています。
また、PCでよく利用される通信方式としては「USB」が有名です。
実際にUARTやUSBで使われる通信手順は、次の特徴を持っています。
- 1つの信号線でデータ通信を行う
- 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ピンに変更 |
2025.7.18 | 動画再生されない不具合を修正 |