はじめに
センサを買ってきてデータシートを開くと、だいたい最初のページにこう書かれています。
「Interface: I2C」 「Interface: SPI」 「Interface: UART」
そして初心者が最初に思うのが、この疑問です。
「……で、これは何が違うの? どれを選べばいいの?」
Lチカの次にセンサをつなごうとすると、必ずこの壁にぶつかります。温湿度センサは I2C、SDカードは SPI、GPS モジュールは UART。同じ「シリアル通信」なのに、配線の本数もライブラリの書き方も全部違う。
この記事は、その3つを同じ土俵に並べて比較するためのものです。個別の実装方法ではなく、「どういうときにどれを選ぶのか」という判断基準に絞って解説します。
📝 この記事で学べること:
- I2C・SPI・UART の構造的な違い(なぜ線の本数が違うのか)
- 速度・接続台数・配線距離という選定の3軸
- センサや部品を買う前に「これは自分の構成で使えるか」を判断する方法
- オシロスコープで通信波形を見るときの着眼点
Arduino で Lチカ と シリアルモニタでのセンサ値読み取り まで進んだ方を想定しています。マイコンの種類(Arduino / ESP32 / STM32)は問いません。三大通信規格の考え方はどれでも共通です。
🔍 3つの規格をひと目で比較
細かい話に入る前に、結論から並べます。この表だけ持ち帰れば9割は足ります。
| 項目 | UART | I2C | SPI |
|---|---|---|---|
| 信号線の本数 | 2本(TX / RX) | 2本(SDA / SCL) | 4本(SCK / MOSI / MISO / CS) |
| クロック線 | なし(非同期) | あり(SCL) | あり(SCK) |
| 典型的な速度 | 9,600〜115,200 bps | 100k / 400k bps(高速版で 1M〜3.4M) | 数 MHz〜数十 MHz |
| マスタ・スレーブ | 対等(1対1) | マスタ/スレーブ(マルチマスタ可) | マスタ/スレーブ |
| 複数デバイス接続 | ❌ 原則 1対1 | ⭕ アドレスで最大 100 台規模 | △ CS 線をデバイス数だけ増やす |
| 配線距離の目安 | 数 m(TTL レベル) | 〜1 m 程度(基板内が基本) | 〜数十 cm(基板内) |
| 全二重/半二重 | 全二重 | 半二重 | 全二重 |
| 受信確認(ACK) | なし | あり(バイトごと) | なし |
| プルアップ抵抗 | 不要 | 必須 | 不要 |
| 向いている用途 | GPS・無線モジュール・PC とのデバッグ通信 | 温湿度・気圧センサ、GPIO 拡張 IC、EEPROM | SDカード、TFT 液晶、高速 A/D、シフトレジスタ |
3行でまとめると
- 線を減らしたい・センサをたくさんぶら下げたい → I2C
- とにかく速度が欲しい・大量のデータを流したい → SPI
- 相手が「モジュール」で1対1、距離もそこそこ欲しい → UART
以降のセクションでは、この表の各項目が「なぜそうなるのか」を構造から説明していきます。
📡 UART ― 相手と「速さの約束」だけで通じ合う
3つのなかで最もシンプル、かつ最も歴史が古いのが UART(Universal Asynchronous Receiver/Transmitter)です。
クロック線が無い、という最大の特徴
UART にはクロック線がありません。これが I2C・SPI との決定的な違いです。
I2C や SPI では、送信側が「今このタイミングでビットを読んで」とクロック線で教えてくれます。しかし UART にはそれがない。ではどうやってタイミングを合わせるのか。
答えは「事前に速さを約束しておく」です。これが ボーレート(baud rate) の正体です。
Serial.begin(9600); // 「1秒あたり9600ビットで喋ります」という宣言
9,600 bps なら、1ビットあたりの時間は次のように決まります。
T_{bit} = \frac{1}{9600} \approx 104.17\ \mu s受信側は「スタートビットが来たら、そこから 104.17 µs ごとに8回読めばいい」と分かる。つまり時間そのものがクロックの代わりをしています。
シリアルモニタが �������� のような文字化けを起こすとき、原因の9割は送信側と受信側のボーレート設定違いです。Serial.begin() の値と、シリアルモニタ右下の設定を一致させてください。配線を疑う前にまずここです。
1フレームの構造
UART は1バイトごとに「フレーム」という単位で送ります。最も一般的な 8N1(データ8ビット・パリティなし・ストップビット1)の構成はこうです。
| 区間 | ビット数 | レベル | 役割 |
|---|---|---|---|
| アイドル | — | H | 何も送っていない状態 |
| スタートビット | 1 | L | 「今から始めます」の合図 |
| データビット | 8 | 可変 | LSB(下位ビット)から送る |
| パリティビット | 0 or 1 | 可変 | 誤り検出用(省略が主流) |
| ストップビット | 1〜2 | H | 「終わりました」の合図 |
データが LSB ファーストである点は要注意です。0x41(文字 A)を送ると、線の上を流れるのは 1,0,0,0,0,0,1,0 という順序になります。ビット順を意識せずに波形を読むと、必ず混乱します。
1対1でしか使えない、という制約
UART にはアドレスの概念がありません。TX と RX をクロスに繋いだ相手としか通信できない、完全な 1対1 です。
センサを3個ぶら下げたい、という用途には根本的に向いていません。逆に GPS モジュールや Bluetooth モジュールのように「1個の相手と延々データをやり取りする」用途には最適です。
配線距離は TTL レベル(0V / 3.3V or 5V)のままなら数 m が実用上の限界ですが、RS-232 や RS-485 のトランシーバ IC を挟むことで一気に伸ばせます。**「距離が欲しいなら UART 系」**というのが定石なのは、この拡張性があるためです。
🔗 I2C ― 2本の線に何台でもぶら下げる
I2C(Inter-Integrated Circuit)は、SDA(データ)と SCL(クロック)のたった2本で、複数のデバイスを数珠つなぎにできる規格です。
マイコンのピンは有限です。センサを増やすたびにピンが2本ずつ消えていくようでは、すぐに破綻します。I2C はその問題を「全員で同じ2本を共有する」という発想で解決しました。
アドレスで相手を呼び分ける
線を共有するなら、「今から喋る相手は誰か」を指定する必要があります。それが スレーブアドレス(通常7ビット)です。
マスタは通信開始時に「アドレス 0x27 のデバイス、応答して」と呼びかけ、該当するデバイスだけが返事をします。7ビットなので理論上は 128 通り、うち予約アドレスを除いた 112 台程度が接続可能です。
ただし現実には、同じ型番のセンサを2個つなぐとアドレスが衝突するという問題が起きます。そのため多くの IC には、外部ピンの H/L でアドレスの下位ビットを変更できる仕組みが用意されています。MCP23017 の記事 で解説した A0・A1・A2 ピンがまさにこれで、3本のピンで 8 通りのアドレスを作り分け、同じ IC を 8 個まで並べられます。
プルアップ抵抗が「必須」である理由
I2C を初めて触った人が最も高い確率でハマるのが、プルアップ抵抗の付け忘れです。「配線は合っているのに、スキャンしてもデバイスが1台も見つからない」——この症状はほぼプルアップが原因です。
なぜ必須なのか。I2C の出力段は オープンドレイン という構造になっているからです。
各デバイスは「線を GND に引き下げる(L にする)」ことしかできません。H にする能力を誰も持っていないのです。これは複数デバイスが同じ線を共有するうえで必然的な設計で、もし各デバイスが自由に H を出力できると、あるデバイスが H、別のデバイスが L を同時に出した瞬間に電源とGNDが短絡してしまいます。
そこで、外部の抵抗で線を電源電圧に吊り上げておき(プルアップ)、誰も引っ張っていないときは自然に H になるようにします。
下限は「L に引き下げるときに流れる電流が、IC の吸い込み能力(IOL、通常 3mA)を超えないこと」で決まります。
R_{p(min)} = \frac{V_{DD} - V_{OL(max)}}{I_{OL}}3.3V 電源・VOL = 0.4V・IOL = 3mA なら、約 970 Ω が下限です。
上限は「バスの寄生容量を充電しきる速さ」で決まります。
R_{p(max)} = \frac{t_r}{0.8473 \times C_b}標準モード(立ち上がり時間 tr = 1000 ns)でバス容量 Cb = 100 pF なら、約 11.8 kΩ が上限になります。
実用上は、100 kHz なら 4.7 kΩ、400 kHz なら 2.2 kΩ を選んでおけばまず外しません。 抵抗値の計算そのものに不安がある方は オームの法則の記事 を先に読んでください。
なお、多くのセンサモジュール(ブレイクアウト基板)には、すでに基板上にプルアップ抵抗が実装されています。その場合は追加不要です。ただしモジュールを何枚も並列につなぐと、プルアップ抵抗も並列に入って合成抵抗が下がりすぎるという逆の問題が起きます。3枚以上つなぐときは、モジュール上のプルアップをカットする必要が出てくることもあります。
通信の開始と終了を「線の動き方」で表す
I2C には、他の規格には無い独特の作法があります。スタートコンディションとストップコンディションです。
| 条件 | SCL の状態 | SDA の動き | 意味 |
|---|---|---|---|
| スタート | H のまま | H → L に落ちる | 通信開始 |
| ストップ | H のまま | L → H に上がる | 通信終了 |
| データ転送中 | L の間だけ | 変化してよい | 通常のビット送出 |
通常、SDA は SCL が L の間にしか変化しません。「SCL が H なのに SDA が動いた」というルール違反そのものを合図として使うわけです。この仕組みのおかげで、データと制御信号を追加の線なしに区別できています。
ACK ― 届いたかどうかを確認できる唯一の規格
I2C は 8 ビット送るごとに、9 発目のクロックで受信側が SDA を L に引き下げます。これが ACK(肯定応答) です。
3つの規格のなかで、受信側が「受け取った」と返事をする仕組みを持つのは I2C だけです。デバイスが応答しなければ SDA は H のまま(NACK)となり、マスタは「そのアドレスに誰もいない」と即座に判断できます。
I2C スキャナのスケッチが機能するのは、この ACK があるからです。全アドレスに順番に呼びかけて、ACK が返ってきたアドレスだけをリストアップしているに過ぎません。
⚡ SPI ― 速度が欲しいならこれ一択
SPI(Serial Peripheral Interface)は、速度を最優先した規格です。SDカード、TFT 液晶、高速 A/D コンバータなど、大量のデータを流す用途はほぼ SPI が採用されています。
4本の線それぞれの役割
| 信号名 | 別名 | 方向 | 役割 |
|---|---|---|---|
| SCK | SCLK / CLK | マスタ → スレーブ | クロック |
| MOSI | SDO / COPI | マスタ → スレーブ | マスタが送るデータ |
| MISO | SDI / CIPO | スレーブ → マスタ | スレーブが返すデータ |
| CS | SS / NSS | マスタ → スレーブ | このデバイスを選択(通常 L で有効) |
送信線と受信線が独立しているため、送りながら同時に受け取れます(全二重)。I2C は 1 本の SDA を送受信で共有する半二重なので、ここで構造的な差がつきます。
なぜ速いのか
SPI が速い理由は、やらないことが多いからです。
- アドレス指定をしない(CS 線で物理的に選ぶ)
- ACK を返さない(届いたかは確認しない)
- スタート/ストップ条件がない(CS を L にした瞬間から始まる)
- オープンドレインではなくプッシュプル出力(H も L も能動的に駆動する)
プロトコル上のオーバーヘッドがほぼゼロで、しかも出力が能動的に H を駆動するため、I2C のようにプルアップ抵抗と寄生容量で波形が鈍る問題も起きません。結果として数十 MHz が現実的に出せます。
その代償が 線の本数です。デバイスを1台増やすたびに CS 線が1本ずつ必要になります。3台つなげば SCK・MOSI・MISO・CS×3 で計6本。I2C なら何台でも2本のままです。**「SPI は速度をピン数で買っている」**と考えると、選択の基準が整理しやすくなります。
モード0〜3 ― SPI 最大のハマりどころ
SPI には規格として明確に決まっていない部分があります。「クロックのどのエッジでデータを読むか」です。これが CPOL(クロック極性) と CPHA(クロック位相) の組み合わせで4通り存在します。
| モード | CPOL | CPHA | アイドル時の SCK | データを読むエッジ |
|---|---|---|---|---|
| 0 | 0 | 0 | L | 立ち上がり |
| 1 | 0 | 1 | L | 立ち下がり |
| 2 | 1 | 0 | H | 立ち下がり |
| 3 | 1 | 1 | H | 立ち上がり |
モード0 が最も広く使われていますが、デバイスによってはモード3 を要求するものもあります。
SPI デバイスから読んだ値が、全部 0x00 だったり 0xFF だったり、あるいは本来の値が 1 ビットずれたような数値になる場合、モード設定の不一致がまず疑わしいです。データシートのタイミングチャートで、SCK のアイドルレベルとデータ確定タイミングを確認してください。
I2C と違って SPI には ACK が無いため、通信が失敗しても誰もエラーを教えてくれません。 黙って壊れたデータが返ってくるだけです。これは SPI を使ううえで常に意識しておくべき性質です。
レジスタから見た SPI
マイコン側から見ると、SPI は「シフトレジスタを 8 回叩く」だけの単純な回路です。実際、74HC595 シフトレジスタ を shiftOut() で制御するのと、SPI でデータを送るのは、ハードウェアがやっていることがほぼ同じです。
74HC595 の制御を理解している方なら、SPI は「あれをハードウェアが自動でやってくれる版」と考えれば腑に落ちるはずです。ドットマトリクス LED の記事 で扱った転送の考え方も、そのまま応用できます。
レジスタレベルで何が起きているかをもう一段深く知りたい方は、STM32 連載 第4回(ビットの世界 ― レジスタ操作の作法) が参考になります。また、SPI で液晶へ大量の画素データを流すような場面では 第10回の DMA と組み合わせるのが定石です。
📊 波形で理解する
3つの規格の違いは、言葉で説明されるより 波形の形を1度見たほうが早い 部分があります。
以降に載せるのは、各規格の信号がどう並ぶかを整理した タイミングチャート(理想化した図) です。実機の波形はここに立ち上がりの鈍りやノイズが乗りますが、まず「どこを見るべきか」を把握するには図のほうが分かりやすいので、先に図で構造を押さえ、そのあと自分のオシロで実物と見比べる、という順序を想定しています。
自分で測るときの設定
図と同じものを実機で見るための、オシロスコープ側の設定です。
| 項目 | 設定 |
|---|---|
| チャンネル数 | 2ch(1本をクロック、もう1本をデータに割り当てる) |
| プローブ | ×10 で使用(×1 は帯域が足りず波形が鈍る) |
| GND | プローブの GND クリップは測定対象の GND に必ず接続 |
| トリガ | 立ち下がりエッジ・シングルショット |
トリガをシングルショットにするのが重要です。通信は連続的に起きるわけではないので、フリーラン表示では波形が流れて読めません。
UART の波形:0x55 を送る
UART は1本の線だけで観測できるため、最も手軽です。テストデータには 0x55(文字 U)を推奨します。
0x55 は 2 進数で 0101 0101。LSB ファーストで送出されるため、線の上には 1,0,1,0,1,0,1,0 が並び、きれいな方形波になります。ビット境界が目で数えられるので、初めての波形観測に最適です。
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.write(0x55); // 観測用の固定パターン
delay(100);
}
読み取るべきポイントは次の3つです。
- アイドル時が H になっているか — L のままなら TX ピンを間違えています
- 1ビットの幅 — 9,600 bps なら約 104 µs。ここがズレていればボーレート設定の問題
- スタートビット(最初の L)の位置 — ここを起点にビットを数える
タイミングチャート:UART(9,600 bps)で 0x55 を送信したときの1フレーム。スタートビットの立ち下がりから、約104 µs 間隔でビットが並ぶ
相手のモジュールのボーレートが分からないとき、1ビットの幅を実測すれば逆算できます。
\text{baud} = \frac{1}{T_{bit}}1ビットが 8.68 µs なら 115,200 bps、104 µs なら 9,600 bps です。ボーレート不明のモジュールを解析する実用テクニックとして覚えておく価値があります。
I2C の波形:SCL と SDA を同時に見る
I2C は 2 チャンネルをフルに使います。CH1 に SCL、CH2 に SDA を割り当て、SDA の立ち下がりでトリガをかけます。
見どころは3箇所です。
- スタートコンディション — SCL が H のまま SDA が落ちる瞬間。ここが通信の起点
- アドレス部の 7 ビット — 最初の 7 クロック分。ここを読めば「どのデバイスに話しかけているか」が分かる
- 9発目のクロックでの ACK — SDA が L に落ちていれば応答あり、H のままなら NACK
タイミングチャート:I2C の 1 トランザクション。SCL が H のまま SDA が落ちる(スタート)→ アドレス7ビット → 9発目のクロックで SDA が L に落ちる(ACK)
実機で見ると、ここが図と変わる
上の図では信号が垂直に立ち上がっていますが、実際の I2C バスではここが最も鈍ります。
オープンドレイン出力は L に引く力しか持たないため、H への復帰は抵抗と寄生容量による充電に頼っています。したがって実機の SDA・SCL は、立ち上がりが斜めに寝た波形になります。傾きが大きく、三角波のように見えるほど鈍っていたら、プルアップ抵抗が大きすぎるサインです。 受信側が H を H として認識できず、通信が不安定になります。抵抗値を1段小さくする(4.7 kΩ → 2.2 kΩ)と改善します。
この鈍りは図には描かれておらず、実機を測って初めて見えます。 I2C が不安定なときにオシロスコープの価値が最も分かりやすく出るのが、まさにこの場面です。
SPI の波形:2ch では CS まで見られない
SPI は信号線が4本あるため、2チャンネルのオシロでは全体を一度に観測できません。ここは正直に割り切る必要があります。
現実的な運用は次の2通りです。
| 観測したいこと | CH1 | CH2 |
|---|---|---|
| モードの確認(推奨) | SCK | MOSI |
| CS のタイミング確認 | CS | SCK |
まず SCK + MOSI でモード(アイドル時の SCK レベルと、データが確定するエッジ)を確認するのが優先です。トリガは CS の立ち下がりでかけたいところですが、2ch しかない場合は SCK の最初のエッジでトリガをかけて代用します。
タイミングチャート:SPI(モード0)の SCK と MOSI。SCK はアイドル時 L で、立ち上がりエッジでデータが確定する
実機で読み取るべきは以下です。
- アイドル時の SCK が L なら CPOL=0、H なら CPOL=1
- MOSI の値が変化する位置と、SCK のエッジの関係 → CPHA が判別できる
- SPI はプッシュプル出力なので、実機でも波形の角がしっかり立つ。ここが鈍っていたら配線が長すぎるサインです
同じ条件で I2C と SPI を測って並べると、I2C は立ち上がりが寝ていて、SPI は角が立っているという差がはっきり出ます。オープンドレインとプッシュプルの違いが最も分かりやすく現れる比較です。
本サイトでは他にも、サーボモータの PWM 制御をオシロで可視化した記事 や、555 タイマー IC の発振波形を実測した記事 があります。「理論値と実測値がどれくらいズレるのか」という感覚を掴むのに役立ちます。
🧭 結局どれを選べばいいのか
選定は、次の順序で考えると迷いません。
ステップ1:そもそも選択肢があるか確認する
多くの場合、選択の余地はありません。 使いたいセンサが I2C にしか対応していなければ I2C 一択です。まずデータシートを見てください。
選択が発生するのは、次のようなケースです。
- 同じ機能のセンサが I2C 版と SPI 版の両方で売られている
- 自分で回路を設計していて、IC を選ぶところから始められる
- ディスプレイモジュールに両対応のものを選ぼうとしている
ステップ2:4つの質問に答える
| 質問 | Yes なら |
|---|---|
| 相手は 1 台だけ? 距離が 1 m 以上ある? | UART |
| 同じ線に 3 台以上ぶら下げたい? | I2C |
| 1 秒あたり数十 KB 以上を流す?(画像・音声・SDカード) | SPI |
| マイコンの空きピンが 2 本しかない? | I2C |
ステップ3:迷ったら I2C から試す
どれも当てはまらない、というときは I2C を選んでください。 理由は3つあります。
- 配線が 2 本で済むため、ブレッドボード上の配線ミスが起きにくい
- ACK があるため、繋がっていないことがすぐ分かる(SPI は黙って壊れた値を返す)
- I2C スキャナで「デバイスが認識されているか」を数行で確認できる
速度が足りないと分かった時点で SPI に移行すればよく、最初から SPI を選ぶ理由はあまりありません。デバッグのしやすさは、開発速度に直結します。
本サイトの ESP32 ネットワーク時計 では、GPIO を 16 本に拡張するために MCP23017 を I2C で 接続しています。理由は明確で、表示更新の頻度が 1 秒に 1 回程度で、速度が要求されないからです。
一方、ニキシー管時計 のように高電圧のダイナミック点灯を行う場合や、TFT 液晶に画像を描画する場合は、転送量が桁違いになるため SPI が必須になります。
「速度が要るか要らないか」を最初に見積もる——これが規格選定の実質的な判断基準です。
🛠️ トラブルシューティング
| 症状 | 規格 | 主な原因 | 対処 |
|---|---|---|---|
| デバイスが1台も見つからない | I2C | プルアップ抵抗が無い | 4.7 kΩ を SDA・SCL の両方に追加 |
| スキャンで見つかるが値が化ける | I2C | プルアップが大きすぎて波形が鈍っている | 2.2 kΩ に下げる/配線を短くする |
| 2台つないだら両方認識しなくなった | I2C | アドレス衝突 | A0〜A2 ピンでアドレスを変更する |
| 読み値が全部 0x00 / 0xFF | SPI | モード不一致、または CS が動いていない | データシートで CPOL/CPHA を確認 |
| 値が 1 ビットずれている | SPI | CPHA の設定違い | モード 0 ⇔ 3 を入れ替えて試す |
| 文字化けする | UART | ボーレート不一致 | 両側の設定を揃える |
| 何も受信できない | UART | TX と RX が繋がっていない(クロス必須) | TX → RX、RX → TX に接続 |
| 通信は成功するが時々化ける | 共通 | 電源のノイズ、配線が長い | パスコン追加・配線短縮・速度を下げる |
ESP32 や STM32 は 3.3V 系、Arduino UNO は 5V 系です。3.3V のセンサに 5V の信号を直接入れると、センサが破損する可能性があります。
I2C の場合はプルアップ先を 3.3V にすることで解決できるケースもありますが、確実を期すならレベル変換 IC を挟んでください。SPI・UART も同様です。「動いたけれど、しばらくしてセンサが壊れた」という事故の典型パターンです。
✅ まとめ
- UART はクロック線を持たず、ボーレートという「時間の約束」で同期する。1対1専用だが距離を伸ばしやすい
- I2C は 2 本の線を全員で共有し、アドレスで相手を呼び分ける。オープンドレインゆえにプルアップ抵抗が必須。3規格で唯一 ACK を持つ
- SPI はアドレスも ACK も持たない代わりに圧倒的に速い。デバイスを増やすと CS 線が増える。モード0〜3 の不一致が最大のハマりどころ
- 選定は「速度が要るか」「何台つなぐか」「距離はどれくらいか」の3点で決まる
- 迷ったら I2C から試す。ACK があるぶんデバッグが圧倒的に楽
規格の違いを構造から理解しておくと、初めて触るセンサでもデータシートを見た瞬間に必要な配線と注意点が分かるようになります。ここが、Lチカから「自分で回路を組み立てる」段階へ進むための分水嶺です。
よくある質問(FAQ)
Q. I2C と SPI、両方に対応しているセンサはどちらで使うべきですか?
A. 速度が要らないなら I2C を推奨します。配線が2本で済み、ACK があるため接続確認が容易だからです。画面描画やデータロギングのように転送量が多い場合のみ SPI を選んでください。
Q. I2C のプルアップ抵抗は、モジュールに付いていれば追加不要ですか?
A. 1枚だけなら追加不要です。ただし複数のモジュールを並列につなぐと、それぞれのプルアップ抵抗が並列に入って合成抵抗が下がりすぎます。 3枚以上つなぐ場合は、1枚を残して他のモジュール上のプルアップをカットすることを検討してください。
Q. UART で 3 台のモジュールを繋ぐことはできますか?
A. 標準の UART では原則できません。マイコン側に UART が複数系統あればその数だけ繋げます(ESP32 は 3 系統、STM32 は品種により多数)。それでも足りない場合は、そもそも I2C が適した構成である可能性が高いです。
Q. SPI のモードが分からないときはどうすればいいですか?
A. データシートのタイミングチャートで、SCK のアイドルレベル(L なら CPOL=0)と、データが確定するエッジを確認するのが正攻法です。記載が見つからない場合は、モード0 と モード3 を試すと大半のデバイスで通ります。
Q. オシロスコープが無くても通信のデバッグはできますか?
A. I2C ならスキャナスケッチでデバイスの有無が判定でき、UART ならシリアルモニタで受信文字を確認できるため、ある程度までは可能です。ただし「波形が鈍っている」「速度を上げると化ける」といった物理層の問題は、波形を見ないと原因の切り分けができません。ここが測定器の必要になる境界線です。
関連記事
I2C の実装例:
SPI・シフトレジスタの実装例:
UART・シリアル通信の基礎:
マイコン内部から通信を理解する:
- STM32 連載 第4回:ビットの世界 ― レジスタ操作の作法と BSRR の思想
- STM32 連載 第8回:割り込みの仕組みを完全理解
- STM32 連載 第10回:DMA という発想 ― CPU を暇にする転送アーキテクチャ
オシロスコープで波形を実測した記事:
基板設計で通信線を引く: