I/Oピン書き換えの罠

RA4のオープンドレインが分ってもまだ安心は出来ません。 RA4は更なる罠を隠し持っています。 下の回路図を見てみましょう

オープンドレイン出力のRA4をプルアップして正論理でLEDを光らすというものです。 一見これで何の問題もなさそうです。 ためしに
PORTA = 0x1F;
としてみましょう。(プログラムはCで記述。コンパイラ:HI-TECH C PRO (Lite mode) )
バッチリ全LEDが点灯しました。
次に、30[ms] 後にLED0だけを消灯するために、
PORTA = 0x1F;
__delay_ms(30);
RA0 = 0;
としてみます。

(゜Д゜)!?

そうすると、なぜかLED0だけでなく、LED4も消えます
RA4などいじっていないのに・・・

これは8ビットシリーズのPIC特有の現象です。 AVRマイコンなどではこのようなことは起こりません(使ったことはないけど^^;)
一体何が起こっているのでしょうか

実は、
RA0 = 0;
という文は、一見RA0しか操作していないように見えるのですが、実はPORTAの全てのピンを書き直しています。 8ビットマイコンは1ビット単位の処理はできず、8ビット単位でしか処理できないのです。 一旦PORTAの全ピンを読込み、その値に対して演算してビット0だけを書き換え、またPORTAに戻します。 つまり、この文の実際の動作は、
char temp = PORTA; //PORTAを読込む
temp &= 0xFE; //ビット0だけをクリア
PORTA = temp; //PORTAに書き込む
となります。
この1文目が重要です。PORTAは出力ポートなのにあたかも入力ポートかのように読込んでいます。 この時のRA4ピンの電圧に注目しましょう。 これを説明するためにオープンドレイン出力であるRA4ピンの動作をスイッチで示したのが以下の図になります。

この図でRA4は何Vでしょう?
LEDの電圧降下分である2V弱程度であることが分ります。つまり、"LOW (0) " です!!!
なんということでしょう!
"1"出力しているのに、入力として読む"0"なのです!
つまり、RA0を書き換えるとき、一旦PORTAを読込むが、その時にRA4について実際の出力とは異なる値を読み、 そのまま書き込んでしまうためRA4が書き換わってしまうのです。
ちなみにこれはRA4ピンでなくても出力ピンに低いインピーダンスの負荷をつないでいるときに起こります。

これを防止する最も確実な手段は1ビット単位での書き換えをしないことです。つまり、
RA0 = 0;
という文は使わないこと。代わりにあらかじめ、 PORTA用変数 char latA を用意しておき、 latA を自力で書き換えたあと、最後にPORTAを丸ごと書き換えます。 つまり、上記のプログラムは
char latA;
latA = 0x1F; //一旦latAに書き込む
PORTA = latA; //PORTAを丸ごと書き換える
__delay_ms(30);
//一旦latAを書き換える
latA = (latA & 0xFE) | 0x00; //ビット0に値をセット
PORTA = latA; //PORTAを丸ごと書き換える
とします。ものすごく面倒ですが^^;

ではなぜ8bitシリーズのPIC以外のマイコンではこの現象が起こらないのでしょうか?
PIC以外のマイコンでも8bit単位でしか操作できないというのはどのマイコンも同じです。
実は、PIC以外のマイコンには上記のPORTA用変数 char latA もともとついているのです。 これをDATAラッチといいます。 なので、単に
_LATA0 = 0;
のようにするだけで、上のchar latA を使ったプログラムと同じことをするのです。 つまり、8bitシリーズのPICには Microchipの陰謀により、DATAラッチがないため、このような現象が起こるのです。
(16bitシリーズのPIC (dsPICやPIC24F) にはDATAラッチがあります。)

Top