310.PIOで入出力する(PIC16F84A)


2001/12/08 【ソフトウエア編TOPに戻る】

今回から具体的なPICのアセンブラプログラム例をご紹介します。第一回は最も簡単な動作で、PIOを使ったデータの入出力動作です。

PIC16Fシリーズには、PORTAからPORTEまでのパラレルポートがあるようですが、PIC16F84AにはPORTAとPORTBまでが付いており、PIC16F873には更にPORTCまでが付いています。16F84APORTAはRA0〜RA4までの5ビットで、16F873ではRA0〜RA5までの6ビットと、機種によって若干仕様が異なります。PORTBPORTCはそれぞれ8ビットあり、他の機能と端子を共用しています。


310−1.16F84Aと16F873のPIOポート

以下に16F84A16F876のPIOポートを一覧で示します。

■PIC16F84A 

pin PORTA 説 明 pin PORTB 説 明
17 RA0 RA0専用端子 6 RB0 INTと共用
18 RA1 RA1専用端子 7 RB1 RB1専用端子
1 RA2 RA2専用端子 8 RB2 RB2専用端子
2 RA3 RA3専用端子 9 RB3 RB3専用端子
3 RA4 T0CK1と共用 10 RB4 RB4専用端子
--- --- --- 11 RB5 RB5専用端子
--- --- --- 12 BR6 RB6専用端子
--- --- --- 13 RB7 RB7専用端子

ポートアドレス : 05h

ポートアドレス : 06h

設定レジスタTRISA : 85h

設定レジスタTRISB : 86h

■PIC16F873 

pin PORTA 説 明 pin PORTB 説 明 pin PORTB 説 明
2 RA0 AN0と共用 21 RB0 INTと共用 11 RC0 T1OS0/T1CK1と共用
3 RA1 AN1と共用 22 RB1 RB1専用端子 12 RC1 T1OS1/CCP2と共用
4 RA2 AN2/Vref-と共用 23 RB2 RB2専用端子 13 RC2 CCP1と共用
5 RA3 AN3/Vref+と共用 24 RB3 PGMと共用 14 RC3 SCK/SCLと共用
6 RA4 T0CK1と共用 25 RB4 RB4専用端子 15 RC4 SDI/SDAと共用
7 RA5

AN4/SSと共用

26 RB5 RB5専用端子 16 RC5 RC5/SDOと共用
--- --- --- 27 BR6 PGCと共用 17 RC6 TX/CKと共用
--- --- --- 28 RB7 PGDと共用 18 RC7 RX/DTと共用

ポートアドレス : 05h

ポートアドレス : 06h

ポートアドレス : 07h

設定レジスタTRISA : 85h

設定レジスタTRISA : 86h

設定レジスタTRISA : 87h

各ポートとも、他の機能と端子を共用している様子が分かりますか。16F84Aは比較的端子の共用が少なく、16F873はほとんど共用しています。この端子の共用が思わぬ悪さをしますので、関連する設定レジスタをしっかりと確認しないと、悩みの種になったりします。

TRISA、TRISB、TRISCの各設定レジスタで、各ポートの入出力をビットごとに設定することができます。

このほか、PORTBはOPTION_REGレジスタの設定によって、プルアップ設定を行なうこともできますが、詳しくは後ほどご説明します。

それぞれのポートは、電気的な特性にも個別の特徴があります。詳しくはデータシートを参照して下さい。

【先頭に戻る】


310−2.PIC16F84AのPIO入出力プログラム piotes1A.asm

では早速、PIC16F84AでPIOの入出力機能を使ったプログラム例 piotes1A.asm をご紹介しましょう。このプログラムは、PORTAに接続したスイッチから入力したデータを、PORTBに接続したLEDに出力します。つまり、スイッチのON/OFF状態が、そのまんまLEDに表示されます。ハードウエア環境は、PIC実験用ボード簡易型実験用I/Oボードを使って準備しています。

以下にアセンブラプログラムのソースをご紹介します。プログラムはここをクリックするとダウンロードできます。piotes1A.asm

 

;**********************************************************************
;PIOTEST1                                                    2001.11.30
;DEVICE : PIC16F84A
;CLOCK  : 20MHz
;PORT-Aの入力データをPORT-Bに出力する
;**********************************************************************
list p=16F84A
#include <p16F84A.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC
;**********************************************************************
       ORG     00H             ; processor reset vector
       GOTO    MAIN            ; go to beginning of program

MAIN   BSF     STATUS,RP0      ;メモリーバンクを1にセット
       MOVLW   0FFH            ;WレジスタにFFHをセット
       MOVWF   TRISA           ;TRISAにFFHをセットPORT-Aを入力にセット
       CLRF    TRISB           ;TRISBをクリア PORT-Bを出力にセット
       MOVLW   080H            ;Wレジスタに80Hをセット
       MOVWF   OPTION_REG      ;OPTION_REGに80Hをセット PORT-B PULL UPなし
       BCF     STATUS,RP0      ;メモリーバンクを0にセット
;***********************************************************************
;PORT-Aの入力データをPORT-Bに出力
;***********************************************************************
LOOP
       MOVF    PORTA,W         ;WレジスタにPORTAのデータ取り込む
       MOVWF   PORTB           ;PORTBにPORTAのデータを出力する
       GOTO    LOOP            ;ラベルLOOPにジャンプ

       END

 【先頭に戻る】


310−3.PIC16F84AのPIO入出力プログラム piotes1A.asmの説明

piotes1A.asmは、PICの最も簡単なアセンブラプログラムの例です。処理の内容はコメント部分に書いてある通りですが、今回がはじめてのご紹介なのでちょっと細かく説明したいと思います。PICのアセンブラ命令一覧を参照しながら見てください。

■コメント文

;(セミコロン)以降の文字は、改行されるまではコメント文として扱われます。コメント文はプログラムに影響を与えませんので、後々のために処理内容の記入などをしておきます。

■list文によるプロセッサ指定(擬似命令)

list p=16F84A では、プロセッサを16F84Aに指定しています。list文は直接PICを動作させるアセンブラ命令ではなく、アセンブラソフト(アセンブラ言語を機械語に翻訳するソフト)に対して指示を出す擬似命令文とよばれるもののひとつです。擬似命令には色々な種類のものがあり、便利に利用することでアセンブラ言語でのプログラミングの助けになります。

list文そのものはアセンブル結果(機械語への翻訳結果)のリスト(拡張子.LSTのファイル)を出力するという指示ですが、p=16F84A というオプション設定を行なうことによって、16F84Aのプロセッサに最適化するように働きます。

■#include文(擬似命令)

#include <p16F84A.inc> では、p16F84A.inc というインクルードファイルを読み込む指定を行なっています。p16F84A.incとは何だ?というところですが、このファイルにはPIC16F84Aの各レジスタ名とそのアドレスが関連付けて定義されていたり、各レジスタの各ビット番号とビット名称などが定義されているファイルです。C言語のヘッダファイルと同じ役割をします。

このインクルードファイルを読み込むことによって、プログラム中でレジスタを参照する時に、わざわざ分かりずらいアドレスで指定せず、分かりやすいレジスタ名称で指定することが出来るようになります。インクルードファイルは、MPLABがインストールされているフォルダに入っています。一度テキストエディタで覗いてみて下さい。

■__CONFIG設定(擬似命令)

PICにはコンフィグレーションビットという1ワード(14ビット)の動作設定用の特殊なメモリー領域があり、ここでの設定はPICの基本動作に影響を与えます。このコンフィグレーションビットはプログラム上からは読み書きできず、プログラムライターソフト上で設定を行なって書き込みます。

PIC16F84Aの場合は、以下の基本動作設定が可能です。

ビット名 選択肢 説 明
FOSC RC/HS/XT/LP PICに使用している発振回路を指定する。
WDTE ENABLE/DISABLE ウォッチドックタイマを利用するかしないかを指定する。
PWRTE DISABLE/ENABLE 電源投入直後の72mS期間のリセット動作をするかしないかを指定する。
CP DISABLE/ALL コードプロテクトをするかしないかを指定する。

これらの設定はプログラム書き込み時に、ライタソフト上で指定して同時に書き込むことができますが、プログラム中に__CONFIG文のオプションとして記述すれば、ライタソフトの設定を自動化することができます。今回の例では

__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC

としてありますので、上の表の太線赤字のように自動設定されます。

ちなみに、FOSC(発振回路指定)の部分は、以下を参考にモードを選択します。

モード 説 明 発振周波数の範囲 備 考
LP 低電力/水晶発振 200KHz以下 極低消費電力動作が可能
XT 水晶/セラミック発振 4MHz以下 標準的な用途
HS 高周波水晶/セラミック発振 4MHz〜20MHz 高速動作が可能
RC RC発振 約1MHz以下 抵抗とコンデンサで組める安価

■ORG (擬似命令)

ORG命令は、プログラムメモリの番地をセットします。

      ORG        00H
      GOTO      MAIN

とすると、プログラムメモリの00H番地に「GOTO  MAIN」という命令文を書き込みます。PICはリセット後に00H番地の命令から実行を開始するため、リセット後に実行させたい命令の番地(ラベル)を指定しておくという意味になります。ここでは、リセット後にはMAINというラベルにジャンプします。

ちなみに00H番地とは、16進数でゼロ番地のことです。0x00と記入してもOKです。

■GOTO(ジャンプ命令)

GOTO  MAIN は、MAINというラベルの行(本当はMAINという名前が付けられたメモリ番地)にジャンプして、そこの命令から実行を継続します。GOTOはアセンブラの擬似命令ではなく、直接PICのプロセッサを動作させるアセンブラ命令です。

■BSF(レジスタのビットを1にする命令)

MAIN   BSF        STATUS,RP0      ;メモリーバンクを1にセット

ここに記載されているMAINがラベルです。GOTO命令からのジャンプ先であるという意味です。

ここでの主役はBSF命令です。この行では、STATUSレジスタのRP0ビットをにしなさいという意味になります。STATUSレジスタってなに?という感じですが、以下の機能を持つレジスタです。

STATUSレジスタの機能

7 6 5 4 3 2 1 0
(IRP) (RP1) RP0 TO PD Z DC C

IRP:関節アドレス指定の際、レジスタバンクを選択します。16F84Aでは未使用です。

RP1:PR0:レジスタのバンク切り替えを行ないます。RP1は16F84Aでは未使用です。

       RP0 = 0 → BANK0 、 RP0 = 1 → BANK1

TO:タイムアウトビット

       1 = 電源ON後、CLRWT命令またはSLEEP命令の実行後。

       0 = WDT(ウォッチドックタイマー)のタイムアウト発生。

PD:パワーダウンビット

       1 = 電源ON後またはCLRWDT命令による。

       0 = SLEEP命令の実行による。

Z:ゼロビット

       1 = 計算またはロジック演算の結果がゼロ。

       0 = 計算又はロジック演算の結果がゼロではない。

DC:デジットキャリー

       1 = 結果により下位4ビット目からキャリーが発生した。

       0 = 結果により下位4ビット目からキャリーが発生しなかった。

C:キャリー

       1 = 結果により最上位ビットからキャリーが発生した。

       0 = 結果により最上位ビットからキャリーが発生しなかった。

※ボロービットについては説明を省略します...。

つまり、BSF   STATUS,RP0 は、レジスタBANKを1に切り替える操作ということになります。これは、BANK1にあるTRISAレジスタ、TRISBレジスタそしてOPTION_REGレジスタを操作するための準備に他なりません。

ところで、BSFは、B(ビット)S(セット)F(レジスタァイル)と憶えましょう。

 

■MOVLW(Wレジスタに任意の定数を書き込む命令)

■MOVWF(指定のレジスタにWレジスタの値を書き込む命令)

今回のプログラムでは、PIOポートのPORTAを入力に設定したいと思ってます。PORTAの入出力設定は、TRISAレジスタで行ないます。

TRISAレジスタの機能

7 6 5 4 3 2 1 0
- - (TRISA5) TRISA4 TRISA3 TRISA2 TRISA1 TRISA0

     1 = 指定のビットを入力ポートに設定する。

     0 = 指定のビットを出力ポートに設定する。

TRISA0から5の各ビットは、PORTAの各ビットに対応しています。TRISA5ビットは、16F84Aでは未使用です。

今回はPORTAの全てのビットを入力に設定するので、TRISAレジスタにFFHをセットすることにします。ところが、任意のレジスタに直接任意のデータ(定数)をセットするアセンブラ命令はありません。なので、この場合以下の手順を辿ります。

 1.W(ワーキング)レジスタに任意のデータ(定数)を書き込む。MOVLW命令

 2.Wレジスタのデータを指定のレジスタ(ここではTRISA)に書き込む。MOVWF命令

Wレジスタとは、多くのアセンブラ命令でメモリー上のデータをやり取りする際の仲介役として活躍するレジスタです。任意のデータを指定のレジスタに書き込む際には、このWレジスタを通して行ないます。実際のプログラム例では、以下の記述で行なっています。

          MOVLW   0FFH
          MOVWF   TRISA  

MOVLW   0FFH では、WレジスタにFFHというデータ(16進数でFF)を書き込みます。

MOV(動く[MOVE])  L(定数リテラル)→ W(Wレジスタ) と憶えると憶えやすいですね。

 ここで、MOVLW  FFH とすると、なぜかアセンブル時にアラーとなります。FFH ではなく OFFHとしないとダメみたいです。また、16F84AではTRISAレジスタは5ビット分までしか有効でないため、01FHとしてもOKです。ちなみに、MOVLW  1FHならアセンブル時にはエラーになりません...。

MOVWF  TRISA では、Wレジスタのデータを指定のレジスタ(ここではTRISA)に書き込みます。

MOV(動く[MOVE]) W(Wレジスタ)→F(レジスタァイル)と憶えると楽ですね。

この2段構えのデータセットは、一番頻繁に使用しますので、是非憶えて置いてください。

 

■CLRF(指定のレジスタをゼロクリアする命令)

今回のプログラムでは、PIOポートのPORTBを出力に設定したいと思ってます。PORTBの入出力設定は、TRISBレジスタで行ないます。

TRISBレジスタの機能

7 6 5 4 3 2 1 0
TRISB7 TRISB6 TRISB5 TRISB4 TRISB3 TRISB2 TRISB1 TRISB0

     1 = 指定のビットを入力ポートに設定する。

     0 = 指定のビットを出力ポートに設定する。

TRISBの各ビットは、PORTBの各ビットに対応しています。

今回はPORTBの全てのビットを出力に設定するので、TRISBレジスタに00Hをセットすることにします。00Hをセットするこいうことは、レジスタをゼロにクリアするということなので、以下の命令を実行しています。

          CLRF      TRISB

CLRF   TRISB では、TRISBレジスタをゼロクリア(00Hに設定)しています。

CLR(クリア)→F(レジスタァイル)と憶えましょう。

          MOVLW   00H
          MOVWF   TRISB

を実行しても同じ結果となります。

  

■OPTION_REGレジスタの操作

次に行なっている以下の命令は、何をしているかもうお分かりですね。

          MOVLW   080H 
          MOVWF   OPTION_REG 

そう、OPTION_REGレジスタに080Hを書き込んでいます。OPTION_REGレジスタとは、以下のようなもので、主に割り込み設定やタイマー設定などの一部を行ないます。

OPTION_REGジレスタの機能

7 6 5 4 3 2 1 0
RBPU INTEDG T0CS T0SE PSA PS2 PS1 PS0

RBPU:PORTBプルアップイネーブルビット

     1 = PORTBを内部プルアップしない。(出力設定時に使用)

     0 = PORTBを内部プルアップする。(入力設定時に使用)

INTEDG:割り込みエッジ選択ビット

     1 = RB0/INT端子の立ち上がりエッジで割り込み発生

     0 = RBO/INT端子の立下りエッジで割り込み発生

T0CS:TMR0(タイマー0チャンネル)クロックソース選択ビット

     1 = RA4/T0CK1端子の入力をタイマークロックとする。

     0 = 内部命令サイクル(φ/4)をタイマークロックとする。

T0SE:TMR0(タイマー0チャンネル)ソースエッジ選択ビット

     1 = RA4/T0CK1端子の立下りタイミングでインクリメント(カウントアップ)

     0 = RA4/T0CK1端子の立上がりタイミングでインクリメント

PSA:プリスケーラ割り当てビット

     1 = PS2〜0で指定するプリスケーラをWDT(ウォッチドックタイマー)に割り当てる。

     0 = PS2〜0で指定するプリスケーラをTMR0(タイマー0チャンネル)に割り当てる。

PS2〜0:プリスケーラ選択ビット。

PS2,1,0 TMR0の場合 WDTの場合
0 0 0 1:2 1:1
0 0 1 1:4 1:2
0 1 0 1:8 1:4
0 1 1 1:16 1:8
1 0 0 1:32 1:16
1 0 1 1:64 1:32
1 1 0 1:128 1:64
1 1 1 1:256 1:128

 

つまり、OPTION_REGレジスタに080Hを書き込むということは、PORTBの内部プルアップを行なわない設定にしているということがわかります。

 

BCF(レジスタのビットを0にする命令)

BANK1にあるレジスタの設定が終わったら、BANKを0(ゼロ)に戻しておきます。ここでは、BCF命令を使って、指定の指定のレジスタ(STATUSレジスタ)の指定のビット(RP0ビット)を0にクリアしています。

         BCF        STATUS,RP0

これで、STATUSレジスタのRP0ビットが0にクリアされます。つまり、BANK0に切り替わります。

B(ビット)C(クリア)F(レジスタァイル)と憶えましょう。

 

■いよいよメインの処理

いままでダラダラとご紹介してきたのは、PICを動かすための設定でした。ここからが、ようやくメインになる処理となります。

LOOP
             MOVF      PORTA,W          ;WレジスタにPORTAのデータ取り込む
             MOVWF    PORTB             ;PORTBにPORTAのデータを出力する
GOTO    LOOP                             ;ラベルLOOPにジャンプ

コメント文にもあるように、メインの処理で行なっているのは、PORTAのデータをWレジスタに取り込み、それをPORTBに転送するという作業をループによって繰り返しているだけです。

ここで新しいアセンブル命令が出てきましたので、簡単に説明しましょう。MOVF命令です。

MOVF   PORTA,W では、指定のレジスタのデータをWレジスタに書き込んでいます。

MOV(動く[MOVE])F(レジスタファイル)と憶えましょう...ん? MOVFWではないの???と思ったりもしますが、MOVFです!この命令では書き込み先を自分自身に指定できたりするため、Wは付きません。

メインとなる処理はこれだけです。

 

■END文(擬似命令)

ソースコードの終わりにはEND文を付けます。これはアセンブラソフト(翻訳ソフト)に対してソースコードはこれで終わりですよ、と教えてあげているもので、PICのプロセッサを動作させるものでは有りません。ソースコードの最後には必ず付けます。

【先頭に戻る】


310−5.ちょっとまとめ。

プログラムは全然大したことないのですが、初めてのPICということで説明が長くなって、要点が絞れなくなったので、ちょっとまとめてみます。

■使った擬似命令

list p=16F84A → リストファイルの出力指定。プロセッサの指定

#include <p16F84A.inc> → インクルードファイルの読み込み

__CONFIG → ライタソフトへのコンフィグレーションビット自動設定

ORG  → プログラムメモリの番地セット

END → ソースコードの終わり

■使ったアセンブラ命令

GOTO  k  → 指定のラベル(アドレス)へのジャンプ命令

BSF    f,b → 指定のレジスタの指定のビットを1にセットする命令

BCF    f,b → 指定のレジスタの指定のビットを0にクリアする命令

MOVLW   k → 任意の定数データをWレジスタに書き込む命令

MOVWF   f → Wレジスタのデータを任意のレジスタに書き込む命令

CLRF      f → 指定のレジスタをゼロクリアする命令

MOVF     f,d → 指定のレジスタのデータをWレジスタ(か自分自身)に書き込むデータ

■使ったレジスタ

STATUSレジスタ → 今回はレジスタ操作のためにメモリーバンクの切り替えをした。

TRISAレジスタ → PORTAの入出力設定を行なった。

TRISBレジスタ → PORTBの入出力設定を行なった。

PORTAレジスタ → 外部からの信号取り込みに使った。

PORTBレジスタ → 外部への信号出力(LED点灯)に使った。

OPTION_REGレジスタ → PORTBのプルアップ設定をOFFにした。

【先頭に戻る】


3−10−6.実験風景

以下が実験風景の写真です。

実験風景写真 左側がPIC16F84Aを載せた実験基板で、右がテスト用の簡易I/O基板です。

右側の基板の下の方で、LEDが5ビット分点灯しているのが分かりますか?その部分が同じ基板についているディップスイッチの状態で点灯/消灯します。5ビット分しか点灯していないのは、PIC16F84AのPORTAが5ビットまでしかないためです。


初めてのPICプログラミングはいかがでしたか?

C言語などになれていると、好きな変数(レジスタ)に好きなデータを直接書き込めない、などといった制約があってちょっと不便に感じるかもしれませんが、すぐになれます。何よりも、限られた基本的な命令を組み合わせてプログラミングを行なう楽しさ、つまり、マイコンのハードウエアをひとつひとつ順に動かしていく、といった楽しさが実感できると思います。是非、実際に試してみてください。

次回は、PIC16F873を使うとどういうプログラムになるのか、についてご紹介します。

 

【ソフトウエア編TOPに戻る】


改版 2001.12.11  3-10-6.実験風景追記


【表紙に戻る】