Arduino 日本語リファレンス


ポート操作

原文

ポート・レジスタを通じて、ArduinoボードのIOピンを高速かつ細部に至るまで操作できます。Arduinoボードで使われているマイコン(ATmega168/328P)は次の3つのポートを持っています。

ポートB (デジタルピン8から13)
ポートC (アナログピン)
ポートD (デジタルピン0から7)

各ポートはArduino言語で定義されている3つのレジスタでコントロールされます。レジスタDDRは、ピンがINPUTかOUTPUTかを決定します。PORTレジスタはピンのHIGH/LOWを制御し、PINレジスタでINPUTピンの状態を読み取ります。
レジスタの各ビットは1本のピンに対応づけられています。たとえば、DDRB、PORTB、PINBの最下位ビットは、PB0(デジタルピン8)です。

DDRとPORTレジスタは読み書き両方が可能です。PINレジスタは読み取り専用です。

以下はレジスタを表す変数の名前のリストです。

DDRD: ポートD方向レジスタ
PORTD: ポートDデータレジスタ
PIND: ポートD入力レジスタ(読み取り専用)

DDRB: ポートB方向レジスタ
PORTB: ポートBデータレジスタ
PINB: ポートB入力レジスタ(読み取り専用)

DDRC: ポートC方向レジスタ
PORTC: ポートCデータレジスタ
PINC: ポートC入力レジスタ(読み取り専用)

PORTBはArduinoボードのデジタルピン8から13の6本に割り当てられています。上位2ビット(6と7)には水晶発振器が接続されているので使用できません。
PORTCはArduinoボードのアナログ0から5です。6と7のピンは(QFPタイプのATmega168を使っている)Arduino Miniでのみアクセス可能です。




【例】

ポートDのレジスタは、デジタルピン0〜7をコントロールします。

注意が必要なのは、Arduinoのピン0と1はシリアル通信に使用されている点です。もしこのピンを変更すると、シリアル通信が必要であっても、受信や送信の機能が無効になってしまいます。また、このピンはプログラムのダウンロードやデバッグの際にも使用されることを覚えておいてください。

DDRDはポートDの方向レジスタです。このレジスタの各ビットはポートDの各ピンが入力と出力のどちらに使用されるかを決定します。

DDRD = B11111110;  // ピン1〜7を出力, ピン0は入力

// より安全な方法: RXとTX(ピン0と1)は変更せず、2〜7を出力に設定
DDRD = DDRD | B11111100;

PORTDは出力の状態を設定するレジスタです。

PORTD = B10101000; // デジタルピン7,5,3をHIGHに

DDRDかpinMode命令によってピンが出力に設定されているとき、上の例のようにすると、指定されたピンだけに5Vが生じます。

PINDは入力レジスタです。すべてのピンのデジタル入力を同時に読み取ることができます。

【補足】

なぜ、ポート操作を使うのでしょうか?

一般的に、このやり方はあまりいいアイデアとは言えません。なぜ良くないか、いくつかの理由があります。

・コードのデバッグやメンテナンスがずっと難しくなります。また、他の人が理解しにくくなるでしょう。数マイクロ秒の実行時間を節約したために、うまく動かなかったときには数時間が必要になるかもしれません。あなたの時間は貴重ですよね? いっぽう、コンピュータの時間はチープです。ふつうは、わかりやすいコードを書く方がいいのです。

・移植しにくいコードになります。digitalReadとdigitalWriteを使ってコードを書けば、他のAtmelのマイコンすべてで動くようにすることも容易です。

・ポートを直接アクセスすると、不意のトラブルが発生しやすくなります。DDRD = B11111110というコードはどうでしょう。ピン0はシリアル通信の受信ライン(RX)であり、入力でなくてはなりません。うっかり、このピンを出力に設定してしまうと、シリアル通信が突然使えなくなり、あなたはとても混乱することでしょう。

それでもポートを直接アクセスしたいと思う人がいるのは、ポジティブな側面もあるからです。

・プログラムメモリが少ないとき、このトリックを使ってコードを小さくすることができます。ループを使って個々のピンをセットするのに比べて、レジスタを使うとコンパイル後のコードがかなり小さくなります。場合によっては、あなたのプログラムがFlashメモリに収まるか収まらないかを決める要因になるでしょう。

・複数のピンを同時にセットしたいときがあるかもしれません。
digitalWrite(10,HIGH);
digitalWrite(11,HIGH);
このプログラムでは、ピン10がHIGHになってからピン11がHIGHになるまで、数マイクロ秒の間があくはずです。これでは、時間に敏感な外部回路を接続している場合に困ります。かわりに、PORTB |= B1100;とすれば、両方のピンが完全に同じタイミングでHIGHになります。

・1マイクロ秒未満の速さでピンをオンオフする必要が生じるかもしれません。ソースファイルlib/targets/arduino/wiring.cを見ると、digitalRead()やdigitalWrite()は10行以上のコードからなっていて、コンパイルすると少なからぬ量のマシン語になります。各マシン語は16MHzのクロックの1サイクルを消費します。直接ポートにアクセスすることによって、より少ないクロックサイクルで同じ仕事をこなすことができます。



[目次へ戻る]

Creative Commons Attribution-ShareAlike 3.0 License.
このドキュメントはArduino Teamにより執筆され、Takumi Funadaが翻訳し、一部加筆修正したものです
ご意見はtf at musashinodenpa.comまでお送りください [Arduino wiki]