PICマイコン
はじめに
Microchipというメーカから出ている超小型CPUで
通常この手の部品は外部クロックや外部メモリなど、
面倒な部分があるがPICはチップによっては+5VとGNDだけで動作可能で
非常に簡単に動作させることができる。
また命令は8ビット単位35種類なので簡単かも?
(逆に簡単な命令しか無いのでプログラムを工夫する必要がある)
種類
ここではよく使っているチップを紹介
・12F675:8ピン、フラッシュメモリ、内部クロック、10ビットADC付き
と何か簡単な事をやるには最適なパッケージとなる
1つ注意はPORTAの名前がGPIOと言う名前に変わっていることくらい
入出力は5ピン(GP3は入力専用)ADCは4ピンとなる
・16F84:16ピンのスタンダードPICとなるが今から使うなら下を使った方が良い
・16F88:16ピンPICのほぼ全機能が入っているPIC
他と比べて値段差もあまり無いので今から使うなら迷わずこれ
内蔵クロックやPWM出力、シリアル入出力など機能は豊富
また上位には18Fという命令が増えたPICやUSB機器として動作するPIC
さらには10BaseTのEthernet機能まである物ある
電源電圧は基本+5Vで端子位置もPICによってバラバラ
(Vdd=+5V Vss=GND 入力端子にはこの範囲外の電圧は×)
実際の使用
12Fや16Fではアセンブラがプログラミングの中心となります
(18FなどはC言語で作った方がライブラリ使えるのでいいかも)
あとPICにプログラムを書き込む必要がありますが
書き込み機自体を自作することも可能です(シリアルPICなどで検索)
しかし自作した場合全てのPICを書き込むのは難しいみたいです
(自作の場合書き込み電圧低下など不定要素もあるので正しくは純正を)
そして、PICのアセンブラではWレジスタというのを駆使してプログラミングしていきます、
(Cで言うとWレジスタという1つの変数だけを使ってどんどん重ねて実行されていく感覚)
Cで慣れている人ははっきり言って面倒ですが、
x86命令を始めアセンブラというのはこう動いている物なので慣れましょう
慣れてくるとパズルを解くような感覚に近くなっていくので、好きな人は好きかも?
様々な機能がありますが、使いたい機能は制御用レジスタで呼び出して使います
その時バンクと言う方式あり、bank0-bank1など同じアドレスでも意味合いが違う場合がある
またプログラムスタックは8段しか無いのでCALLの呼び出しすぎに注意
アセンブラ
ここでは実際に使用する事例で紹介
CBLOCK 0x20 ;変数メモリの初期位置の宣言
TEST ;TESTという変数を宣言
ENDC ;宣言終了
ORG 0x000 ;プログラム開始位置
ORG 0x004 ;割り込み処理開始位置
RETFILE ;割り込みから復帰
;レジスタ内容移動命令系
MOVLW 0xFF ;0xFFをWレジスタに移動
MOVWF TEST ;Wレジスタの内容をTESTに移動
MOVF TEST,W ;TESTの内容をWレジスタに移動
;レジスタ値クリア・セット命令系
CLRF TEST ;TESTレジスタをゼロクリアする
CLRW ;Wレジスタをゼロクリアする
BCF TEST,0 ;TESTレジスタの0ビット目を0にする
BSF TEST,1 ;TESTレジスタの1ビット目を1にする
CLRWDT ;ウォッチドックタイマーをリセットする
;演算命令系
ADDLW 0xF0 ;0xF0とWレジスタの内容を加算する 答えはWレジスタに
ADDWF TEST,W ;TESTレジスタの内容とWレジスタの内容とで加算 答えをWに
SUBLW 0x11 ;0x11からWレジスタ内容分引き算する 答えはWレジスタに
SUBWF TEST,W ;TESTレジスタからWレジスタ内容分引き算する 答えはWに
ANDLW 0x0F ;0x0FとWレジスタの内容とでANDを取る 答えはWレジスタ
ANDWF TEST,W ;TESTレジスタの内容とWレジスタの内容とでAND 答えをWに
IORLW 0x01 ;0x01とWレジスタの内容とでORを取る 答えはWレジスタに
IORWF TEST,W ;TESTレジスタの内容とWレジスタの内容とでOR 答えをWに
XORLW 0x40 ;0x40とWレジスタの内容のXORを取る 答えはWレジスタに
XORWF TEST,W ;TESTレジスタの内容とWレジスタの内容とでXOR 答えはWに
COMF TEST,W ;TESTレジスタの内容を反転(NOT) 答えはWレジスタに
INCF TEST,W ;TESTレジスタのカウントアップ(+1) 答えはWレジスタに
DECF TEST,W ;TESTレジスタのカウントダウン(-1) 答えはWレジスタに
RLF TEST,W ;TESTレジスタの内容を左回転(1ビット) 答えはWレジスタ
RRF TEST,W ;TESTレジスタの内容を右回転(1ビット) 答えはWレジスタ
SWAPF TEST,W ;TESTレジスタの上位4ビットと下位4ビットを入れ替え Wレジスタに
;分岐ジャンプ命令系
BTFSC TEST,0 ;TESTレジスタの0番目が0なら次の命令をスキップ 逆に言うと
;TESTレジスタの0番目が1なら次の命令を実行(スキップしない)
BTFSS TEST,1 ;TESTレジスタの1番目が1なら次の命令をスキップ 逆に言うと
;TESTレジスタの1番目が0なら次の命令を実行(スキップしない)
INCFSZ TEST,W ;TESTレジスタのカウントアップ(+1)し 答えをWに
;また答えが0なら次の命令をスキップ(0以外なら実行)
DECFSZ TEST,W ;TESTレジスタのカウントダウン(-1)し 答えをWに
;また答えが0なら次の命令をスキップ(0以外なら実行)
;ジャンプ命令系
NOP ;何もしないで次の命令に行く
GOTO START ;STARTにジャンプ(ジャンプするだけで戻れない)
CALL START ;STARTにサブルーチンジャンプ (RETURNで復帰)
RETURN ;現在のサブルーチンから無条件復帰
RETLW 0xFF ;0xFFをWレジスタにセットしサブルーチンから復帰
SLEEP ;スリープモードにする(プロセッサ停止)
RETFIE ;割り込みから復帰
以上の命令の組み合わせでなんとかする
ちなみにADDWF TEST,F とすると
結果はTESTに移動される(TEST,Wは全てTEST,Fに変更可能)
また演算結果はSTATUSレジスタにあり、利用できる
具体的には
STATUS,Z=1の場合、直前の演算結果が0の場合を表し
STATUS,C=1では演算結果上位ビットからオーバーフローした場合
または、引き算の場合で結果が正の値C=1となる
ADDLW 0xF0などの数値表現は
D'100':10進数で表現 B'00000001':2進数で表現
A'A':ASCIIで表現 O'123':8進数で表現
など表現出来る
AND、OR、XORの使い方は
AND:1ビットにセットした場所だけ素取り出す事が出来る
OR:1ビットにセットした場所を強制的に1になる
XOR:LED点滅など反転したい場所を1にすると反転する
フラグについて
STATUS,Z:計算や演算結果が0x00→1 逆に言うと
計算結果などが0x00以外の時→0(ビット)
STATUS,DC:計算結果下位4ビットがキャリー(桁あふれ)→1
計算結果下位4ビットに桁あふれしない→0
STATUS,C:計算結果最上位ビットがキャリー(桁あふれ)→1
計算結果最上位ビットが桁あふれしない→0
具体的なケース加算:オーバーフロ→C=1 下位4ビットフロー→DC=1 結果が0→Z=1
それ以外→全て0
具体的なケース減算:結果が正→C=1,Z=0 結果が0→C=1,Z=1
結果が負→C=0,Z=0
左右シフトレジスタ:右シフト→Cのビットを最上位ビットにセット最下位ビットをCに移動
よく使うコードの一例は
A,0ビットの内容をB,1ビットにコピー
BTFSS A,0
BCF B,1
BTFSC A,0
BSF B,1
if(A == B)ならGOTO X
MOVF B,W
XORWF A,W
BTFSC STATUS,Z
GOTO X
if(A < B)ならGOTO X
MOVF B,W
SUBWF A,W
BTFSS STATUS,C
GOTO X
if(A <= B)ならGOTO X
MOVF A,W
SUBWF B,W
BTFSC STATUS,C
GOTO X
あくまで演算は8ビット単位なので例えば16ビット使いたい場合でも
命令の工夫でなんとかするしかないです。
簡単とは行かないけど、組み合わせ方によってはどんなことも出来ます。
最後に TEST,0 ビットなど指定するほかに#defineを用いる方法があり
#define TESTX TEST,0
と宣言しておけばTESTXという名前などを、ビット単位で名前付けられます
デバッグの方法
・ブレークポイント:停止させたい行をダブルクリック
・順に実行:Debug → Animateでゆっくり実行(間隔も指定可能)
・変数チェック:View → File Registersで表示(Symbolicだと名前付き)
・実行時間測定:Debug → StopWatchで表示Debug → Settingsに動作周波数を入れる
計測はブレークからブレーク間の測定(時間はZeroでリセット出来る)
・ロジアナ:View → Simulator Traceで領域指定 View → Logic Analizarで表示画面
Channelsボタンでポート指定
CNT1とCNT2はあらかじめメモリ宣言する(4MHz時で50msecになる予定)
DELAY_50MSEC
MOVLW D'50'
MOVWF CNT1
DELAY_50MSEC_LOOP0 ; ((4*250)+5)*50サイクル = 50250サイクル
MOVLW D'250'
MOVWF CNT2
DELAY_50MSEC_LOOP1 ; 4*250サイクル
NOP ; 1
DECFSZ CNT2, F ; 1(no skip), 2
GOTO DELAY_50MSEC_LOOP1 ; 2
DECFSZ CNT1, F ; 1(no skip), 2
GOTO DELAY_50MSEC_LOOP0 ; 2
RETURN