目次>9章 PIC18F1320編 > (06)PORTレジスタとLATレジスタ
PORTレジスタとLATレジスタ
更新日2008.11.22
PICには、入出力ポートを制御するためにPORTレジスタ(PORTA/PORTBなど)があります。これはPIC16もPIC18も共通です。
PIC18では、これに加えてLATレジスタ(LATA/LATBなど)が追加されました。
PIC18を始めて使う時に疑問になる事の一つが、このLATレジスタだと思います。(必要性とか使い方とか)
今回は、このLATレジスタについて、実験をしながら有効性を確認します。
実験回路
|
・ |
過去3回の実験で使った回路と同様に、2つのLEDをRB0/RB1に接続します。
今回の違いは、RB0/RB1に0.01uFのコンデンサを追加している点です。
通常はこのような回路は組みませんが、ある事象を発生させるために意図的にこのようにしています。これが今回の実験の肝になります。
-
| |
680Ωの抵抗2本は、300Ω〜1KΩ程度の範囲であれば何でもOKです。
回路図にはパスコンがありませんが、PICのVddとGND間に0.01uF程度のコンデンサを入れて下さい。
|
- こちらは、ブレッドボードに仮組みした状態です。
-
| |
右上の6ピンヘッダ周りはICSP用で、回路図にはありません。
|
|
過去3回のプログラムで動作させるとどうなるか?
|
|
- 過去3回で、以下のクロック動作を確認しました。
いずれも、RB0/RB1のLEDを交互に点滅させるプログラムです。
- ・40MHz動作(HSPLL)
- ・10MHz動作(HS)
- ・1MHz動作(内部クロック)
この3つのプログラムを今回の回路で動かして見て下さい。
そのままのプログラムで動作可能です。
どんな動きになりましたか?
- 私の環境では以下のようになりました。
-
クロック | RB0のLED | RB1のLED
| 40MHz | 点滅しない | 前回同様に点滅
| 10MHz | 点滅しない | 前回同様に点滅
| 1MHz | 前回同様に点滅 | 前回同様に点滅
|
クロックが速いとRB0のLEDが点滅しなくなる、と言う結果になりました。
|
なぜそうなるのか?
|
|
なぜこのような動作になるのでしょう。
過去3回のプログラムのメインルーチンを以下に引用しました。
-
main | | |
| | BSF | | PORTB,RB0 | | ;(1)
| | BCF | | PORTB,RB1 | | ;(2)
| | CALL | | wait1s | | ;(3)
| | BCF | | PORTB,RB0 | | ;(4)
| | BSF | | PORTB,RB1 | | ;(5)
| | CALL | | wait1s | | ;(6)
| | GOTO | | main | | ;(7)
|
(1)(2)および(4)(5)に何かがありそうです。
まず始めに、BSF/BCF命令の動きを確認しましょう。
BSF/BCF命令などのレジスタ(SFR,GPR)を変更する命令は全て、1命令で以下の動作が行われます。
(下図ではPORTBレジスタを例にしています。)
-
例えば、
BSF PORTB,0
を実行すると以下の内部動作が行われます。
-
これだけであれば問題なく動作しそうです。
続いて、PORTレジスタと入出力ピンの関係です。
下のイメージ図のようにPORTレジスタと入出力ポートは直結しています。
もっと感覚的に表現すると、入出力ポートそのものがPORTレジスタであると言えます。
-
今回の実験回路では出力ポートにコンデンサを接続しました。
この状態でRB0を0から1に変更すると以下のように変化します。
-
直前までの状態 | BSF PORTB,RB0 を実行
| |
| | RB0の電圧変化 RB0に1をセットしてもコンデンサに 充電している間はHレベルにならない
|
逆にRB0を1から0に変更すると以下のように変化します。
-
直前までの状態 | BCF PORTB,RB0 を実行
| |
| | RB0の電圧変化 RB0に0をセットしてもコンデンサが 放電している間はLレベルにならない
|
このように、出力ポートに容量性の負荷(コンデンサ)が接続されていると、BSF/BCF命令の結果が反映されるまでに時間がかかります。
動作1、動作2から以下の命令の結果を見てみます。
-
| BSF | | PORTB,RB0 | | ;(1)
| | BCF | | PORTB,RB1 | | ;(2)
|
2つの命令の内部動作を表したものが下図です。
-
命令 | 内部動作
| BSF PORTB,RB0
| PORTB | 00000010 |
| | ↓ |
| 内部メモリ | 00000010 |
| | ↓ |
| 内部メモリ | 00000011 |
| | ↓ |
| PORTB | 00000010 | (1)RB0はすぐには1にならない
|
| BCF PORTB,RB1
| PORTB | 00000010 | (2)RB0が1になる前に次の命令で読み込み
| | ↓ |
| 内部メモリ | 00000010 |
| | ↓ |
| 内部メモリ | 00000000 |
| | ↓ |
| PORTB | 00000000 | (3)
|
|
上の(3)もRB1は遅れて0になりますが、この命令の直後でPORTBを使っていませんので結果的に正しく機能します。
また、クロックが遅い場合は、(2)の命令実行時にはRB0が1になっているため、意図した動作になります。
このような動作が行われるため、RB0のLEDだけ点滅しなくなりました。
この動きはPIC16ファミリーでも同じです。
|
解決策としてのLATレジスタ
|
|
PIC16であれば、NOP命令を入れて処理を遅延させるような事を行います。
一方PIC18では、PORTレジスタに加えLATレジスタが追加されました。
LATレジスタは出力ポートの制御に使いますが、下のイメージ図のように出力ポートの影響を受けないような構成になっています。
-
それではメインルーチンのPORTBをLATBに変更して動かして見ましょう。
-
main | | |
| | BSF | | LATB,RB0 | | ;(1)
| | BCF | | LATB,RB1 | | ;(2)
| | CALL | | wait1s | | ;(3)
| | BCF | | LATB,RB0 | | ;(4)
| | BSF | | LATB,RB1 | | ;(5)
| | CALL | | wait1s | | ;(6)
| | GOTO | | main | | ;(7)
|
どうなりましたか?
クロックが速くても、以前の回路で動かした時と同じようにLEDが点滅すると思います。
|
PIC18の勧め(Vol.5)
|
|
- その6. LATレジスタにより出力ポートの状態を意識せず意図通りに制御できる
- PIC18ではPORTレジスタに加えLATレジスタが追加されました。
LATレジスタは出力ポートを制御するレジスタですが、出力ポートの影響を受けないレジスタであり、出力ポートの状態に依存せず意図した通りに制御できます。
|