Arduino - ポート操作

3つの異なるレジスタ(DDR、PORT、PIN)を使ってArduinoのピンを制御する方法を学びます。


LAST REVISION: 2024/01/04 19:18


ポートレジスタ

ポートレジスタは、Arduino基盤上のマイクロコントローラのI/Oピンに対する低レベルの操作を提供し、また、高速に操作することができる。Arduinoボードに搭載されているチップ(ATmega8とATmega168)は、3つのポートを持っている。

  • B (デジタルピンの8番から13番)
  • C (アナログ入力ピン)
  • D (デジタルピンの0番から7番)

それぞれのポートは3つのレジスタによって制御できる。各レジスタは、Arduino言語の変数としても定義されている。DDRレジスタは、ピンがINPUT(入力)なのかOUTPUT(出力)なのかを決定する。PORTレジスタはピンがHIGHなのかLOWなのかを制御する。PINレジスタは、pinMode()により入力に設定された入力ピンの状態を読み取る。Atmega8とAtmega16のピン配置にポートが示されている。新しいAtmega328pは、Atmega168のピン配置と同じである。

DDRレジスタとPORTレジスタは双方とも読み書き可能である。PINレジスタは入力の状態に結びついているので読み込み専用である。

PORTDは、Arduinoのデジタルピンの0番から7番に対応する。

  • DDRD: ポートDデータ転送方向レジスタ 読み込み/書き出し
  • PORTD: ポートDデータレジスタ 読み込み/書き出し
  • PIND: ポートD入力ピンレジスタ 読み込み専用

PORTBは、Arduinoのデジタルピンの8番から13番に対応する。2つの上位ビット(6と7)は、水晶ピンに対応しているので利用できない。

  • DDRB: ポートBデータ転送方向レジスタ 読み込み/書き出し
  • PORTB: ポートBデータレジスタ 読み込み/書き出し
  • PINB: ポートB入力ピンレジスタ 読み込み専用

PORTCは、Arduinoのアナログピンの0番から5番に対応している。Arduino Miniでは6番ピンと7番ピンを利用可能である。

  • DDRC: ポートCデータ転送方向レジスタ 読み込み/書き出し
  • PORTC: ポートCデータレジスタ 読み込み/書き出し
  • PINC: ポートC入力ピンレジスタ 読み込み専用

これらのレジスタの各ビットは一つのピンに対応する。例えば、DDRBとPORTB、PINBの最下位ビットはPB0(デジタルピンの8番)を参照する。Arduinoのピンとポートのビットとの完全な対応づけは、それぞれのチップのピン配置を参照すること(ATmega8ATmega168)。ポートのいくつかのビットはI/O以外の物に対応しているので、それらに関連するレジスタのビットの値を変更しないように注意すること。

使用例

上記のピン配置を参照すると、PORTDレジスタはArduinoのデジタルピンの0番から7番を制御することがわかる。

しかし、0番ピンと1番ピンとは通常、Arduinoのプログラミングやデバグのために使われるので、これらのピンの値を変更することは、シリアル入力や出力に必要でない限り避けるべきである。プログラムの転送(ArduinoソフトウェアからArduinoへのアップロード)やデバグにも影響があるので注意すること。

DDRDは、ポートD(Arduinoのデジタルピンの0番から7番)のデータの転送方向を制御するためのレジスタである。このレジスタの各ビットがPORTDの各ピンを入力にするのか出力にするのかを設定する。

1
2
3
DDRD = B11111110;  // sets Arduino pins 1 to 7 as outputs, pin 0 as input
DDRD = DDRD | B11111100;  // this is safer as it sets pins 2 to 7 as outputs
	                  // without changing the value of pins 0 & 1, which are RX & TX 

PORTBは、出力の状態を表すレジスタである。

1
PORTD = B10101000; // sets digital pins 7,5,3 HIGH 

DDRDかpinMode()を使って出力に設定してあれば、これらのピンに5Vが出力される。

PINBは入力用のレジスタで、全てのデジタル入力ピンの値を同時に読み取る。

なぜポート操作を使うのか?

一般的にはこの種の操作はいいことではない。なぜか?以下にいくつか理由を挙げる。

  • コードのデバグや維持管理が難しくなる。また、他の人がコードを理解するのが難しくなる。プロセッサがそのコードを実行するのは数マイクロ秒だが、なぜそのコードが正しく動かないのかを見つけたりや修正したりするには何時間もかかるかもしれない。通常コードをもっともわかりやすく書くのがよりよい方法である。
  • コードの可搬性が失われる。digitalRead()とdigitalWrite()を使えば、全てのAtmelのマイクロコントローラ上で動作するプログラム記述するのはやさしいが、レジスタはマイクロコントローラの種類によって異なっている。
  • ポートに直接アクセスすると意図しない欠陥を起こしやすい。DDRD =B11111110;というコードは、0番ピンを入力のままにする。ピン0はシリアルポートの受信用である。ピン0を誤って出力ピンにして、シリアルポートの動作を止めてしまうことは容易である。突然シリアルデータを受信できなくなると混乱してしまう。

この機能をなぜ使う必要があるのかを自問するといい。ポートアクセスが有効に働く場合をいくつか挙げておく。

  • 1マイクロ秒以下というとても短い時間でピンのオン・オフを行う必要があるとき。lib/targets/arduino/wiring.c(訳者註: 実際には、wiring_digital.c)を見ると、digitalRead()やdigitalWrite()にはかなりの行数のコードが書かれていることがわかる。これらはとても多くのマシン命令にコンパイルされる。それぞれのマシン命令の実行には、16MHzで1クロックを要し、短時間で行わなければならないアプリケーションでは問題になる。ポートへの直接操作はより少ないクロック数で同じことを行うことができる。
  • 完全に同時に複数の出力ピンを設定する必要があるとき。digitalWrite(10,HIGH);を呼んだあと、digitlWrite(11, HIGH);を呼ぶと、10番ピンがHIGHになってから数マイクロ秒後に11番ピンがHIGHになる。リアルタイム性の高い外部のデジタル回路を使った時に問題になることがある。PORTB |= B1100;を使えば、完全に同時に両方のピンをHIGHにすることができる。
  • プログラム用のメモリが少ないときに、この使い方をすればコード量を削減することができる。それぞれのピンにfor文を使って順に書き込むよりも、ポートレジスタを使うと非常に少ないメモリしか必要としない。フラッシュメモリに載るか載らないかが変わるくらいの差があるときもある。

もっと読む

オリジナルのページ

https://docs.arduino.cc/hacking/software/PortManipulation

最終更新日

January 5, 2024

inserted by FC2 system