2001/12/08 【ソフトウエア編TOPに戻る】
今回から具体的なPICのアセンブラプログラム例をご紹介します。第一回は最も簡単な動作で、PIOを使ったデータの入出力動作です。
PIC16Fシリーズには、PORTAからPORTEまでのパラレルポートがあるようですが、PIC16F84AにはPORTAとPORTBまでが付いており、PIC16F873には更にPORTCまでが付いています。16F84AのPORTAはRA0〜RA4までの5ビットで、16F873ではRA0〜RA5までの6ビットと、機種によって若干仕様が異なります。PORTBとPORTCはそれぞれ8ビットあり、他の機能と端子を共用しています。
310−1.16F84Aと16F873のPIOポート
以下に16F84Aと16F876の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ビットを1にしなさいという意味になります。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を使うとどういうプログラムになるのか、についてご紹介します。
改版 2001.12.11 3-10-6.実験風景追記