LIST および INCLUDE疑似命令
list p=pic16f873
include p16f873.inc
PICの種類を指定するためにLISTコマンド(疑似命令)を使用します。
PIC16F873の標準ラベル定義をINCLUDEコマンドで組み込みます。
コンフィギュレーションワード
CONFIG疑似命令を使用してコンフィギュレーションワードの指定を行っています。
__config _hs_osc & _wdt_off & _pwrte_on & _lvp_off
コンフィギュレーション・ワードはライターでプログラムを書き込む際にも指定できますが、CONFIG疑似命令を使用すると自動的に設定することができます。
コンフィグレーションワードとして以下を指定しています。
発振器の種類 | : | HS |
ウォッチドッグタイマー | : | OFF |
パワーアップタイマー | : | 使用する |
低電圧プログラミング | : |
OFF
(これをOFFにしないとRB3を入出力ポートに使用できません) |
結果は3F72hです。
PIC16F873では上記以外の項目も含まれています。通常は上記の疑似命令でOKです。
バンク確認メッセージン非表示
errorlevel -302 ;Suppress bank warning
PIC16F873ではSFRを4つのバンクに分けています。全バンク共通のSFRもありますが、バンク固有のSFRもあります。バンクの指定はSTATUSレジスタのRP0ビットおよびRP1ビットで行います。STATUSレジスタに対するバンクの指定処理を正常に行っても、バンク指定の確認のためのメッセージが表示されます。
例
Message[302] C:\MPLAB\PROJECT\MOTOR_~2\MOTOR.ASM 32 : Register in operand not in bank 0.
Ensure that bank bits are correct.
上記の例の場合、ソースコード32行目で指定しているTRISAレジスタ(バンク1)に対する注意メッセージです。
「オペランドで指定しているレジスタはバンク0ではありません。バンク指定ビットが正しいかどうか確認しなさい。」
ちなみに、32行目は以下のような内容です。
032 movwf trisa ;Set TRISA register
30行目でバンク指定を正常に設定していてもこのメッセージは表示されます。たとえ、直前の31行目でバンク設定をしても表示されという余計なお世話メッセージです。そこで、メッセージ(302)を表示しないようにするために、 errorlevel 指定をしています。p16f873.inc でのバンク指定を変更する方法もあります。
ラベル定義
;**************** Label Definition ********************
今回のソフトでは3つのラベル定義をしています。
speed は基準速度値で制御電圧入力回路で発生した電圧をA/D変換した値と speed で指定する値が等しくなるように制御します。 5Vを256分割した値に speed で指定した値を掛けたものが基準速度電圧になります。今回は8を指定しているので、5*8/256=0.156Vが基準速度電圧になります。speed で指定する値を大きくすれば、基準速度電圧は高くなります。モータの回転数を検出する回路の出力電圧により、speed の設定値を変える必要があります。
change はモータの制御電流を変化させる速さを指定します。モータの回転速度の検出は10ミリ秒毎に行われます。制御電圧入力回路の電圧と基準速度電圧に差がある場合、PWMのデューティを change で指定された値で加算または減算します。PWMのデューティ指定はCCPR1レジスタで行われます。CCPR1は8ビットなので0から255までの256段階のデューティ指定ができます。CCPR1の値が255の場合はモータ駆動電流は停止し、値が0の場合は最大電流で駆動されます。change で1を設定すると10ミリ秒毎にCCPR1の値が1だけ加算または減算されます。例えば、モータ停止状態(CCPR1=255)からモータ最大駆動(CCPR1=0)になるまでの時間は10ms×256=2.56秒です。5V変化するのに2.56秒かかるので、change の値が1に対する値は約2mV/msとみなせます。要はchangeの値を大きくすると10ミリ秒毎の制御値の変化が大きくなるということです。使用するモータの特性によりスムーズな制御ができない場合にはこの値を変えてみます。
led は制御状況モニタ用のLEDを点灯させるためのデューティ値一時保存エリアです。20h番地にしています。
プログラム開始
;**************** Program Start ***********************
電源投入/リセット時はプログラムメモリアドレスは h'0000' からスタートします。また、割り込み処理のスタート番地は h'0004' です。goto命令で各処理にジャンプするようにしています。 h'0000' は初期化処理、h'0004' はタイマー割込処理にジャンプします。
初期化処理
;**************** Initial Process *********************
電源投入後の初期化処理として以下の処理を行います。
ポートA、BおよびCのモード初期化 |
|
ポートAの0番をアナログ入力に使用しています。他のAポートは全て出力モードにしました。関係無いかもしれませんが、入力の影響を避けるためです。
BポートはLEDの点灯制御用で、全て出力モードにします。
CポートはCCPの出力をするため、全て出力モードにします。 |
|
A/Dコンバータの初期化 |
|
PICのクロックに10MHzを使ったので、A/D変換クロックをFosc/32にします。
入力チャネルはAN0です。 A/DコンバータをONにして使用できるようにします。
変換結果は上位の8ビットを使用するために右寄せにします。
アナログ入力ポート構成指定は0ポートのみアナログのパターンを選択しています。 |
|
PWMの初期化 |
|
CCP1をPWMモードで使用します。
念のためにタイマー2のカウンタおよびデューティ設定をクリアしています。
出力パルスの周期は1638.4μ秒(約610Hz)にしています。プリスケーラは1:16です。 タイマー2が使えるようにONにします。 |
|
コンペアモードの初期化 |
|
CCP2をコンペアモードで使用し、周期的に割り込み起動がかかるようにします。
割り込み周期は10ミリ秒にしています。タイマー1を内部クロックでカウントさせます。
タイマー1のプリスケーラを1:1にし、タイマー1が使えるようにON状態にします。
CCP2でタイマー1が規定値(10ミリ秒)になったときに割り込みを発生させると同時にA/Dコンバータをスタートするようにします。 |
|
割り込みの初期化 |
| CCP2の割り込み可能ビットを設定します。 グローバル割り込み可能ビット、周辺機器割り込み可能ビットも設定します。 |
以上で初期化処理が終了しました。後は割り込みを待つだけなので、メイン処理としては同じアドレスを繰り返し実行させているだけです。オペランドの'$'は自分のアドレスを意味しています。'$+1'は自分のアドレスの次のアドレスを意味します。
割り込み処理
;*************** Interruption Process *****************
割り込みフラッグのクリア |
| CCP2により10ミリ秒毎に割り込みが発生します。最初にCCP2の割り込みフラッグをクリアします。これをしないと次の割り込みが所定の時間を待たずに発生してしまいます。 |
|
A/Dコンバータの変換待ち |
| CCP2の割り込みと同時にA/Dコンバータの変換がスタートしています。ですから、変換完了(ADCON0のGOビットが0になる)まで待ちます。今回の場合、アナログチャネルは0チャネルだけなので、変換電圧取り込み時間(約 20μ秒)は必要ありません。複数のチャネルを切り替えながらA/D変換する場合にはチャネル切り替え後、A/D変換開始まで待ち時間を設ける必要があります。 |
|
基準速度電圧との比較 |
|
変換が終了したら、変換結果の上位8ビットを規定速度値と比較します。変換結果は10ビット出ますが、今回の回路では1024分割も必要ないので、上位の8ビットだけを使用し、256分割にしています。
制御電圧入力回路の電圧をA/D変換した値と基準速度値(speed)との比較をし、モータの回転数が規定値より速いか遅いかを判断します。 |
|
速度低下処理 |
| 基準速度よりモータの回転が速い場合、デューティ比を大きくしてモータ駆動電流を抑えます。変化させる値は change で指定された値だけデューティ比を大きくします。 |
|
速度上昇処理 |
| 基準速度よりモータの回転が遅い場合、デューティ比を小さくしてモータ駆動電流を増やします。変化させる値は change で指定された値だけデューティ比を小さくします。 |
|
LED点灯制御 |
|
モータの駆動状況を確認するためにLEDレベルメータを使用しました。今回使用したLEDレベルメータは7つのLEDが配列されています。最初は何故8つではないのかと思いましたが、この処理を作ってみて納得できました。今回はCCPR1の上位3ビットを使用してレベルメータの制御をしています。3ビットで表せる状態は000から111まで8種類あります。ということで、最初はLEDが8つ必要と思ったわけです。各種類毎にLEDを1個点灯させる場合には8つのLEDが必要です。しかし、レベルメータはLEDを一つずつ点けるのではなく、レベルが上がるにつれて点灯するLEDの数を増やしていきます。ということは000は全LED消灯状態になるわけです。ですから、LEDは7つでよいわけです。
CCPR1のビットは駆動停止のときは00000000、最大駆動のときは11111111にしています。ということはこの情報をレベルメータ制御に使う場合には0と1を反転する必要があります。comf 命令はそのためです。LEDを点灯させる状態は反転されたCCPR1のデータの上位3ビットのみを使います。それぞれの状態に応じてLEDの点灯制御をします。回路ではRB0からRB7までの8ポートを用意してしまったので、RB0の制御は上位から4ビット目を使用しました。でも、ここにはLEDを接続しないので、RB0の制御は意味はありません。 |
割り込み終了処理
;************ END of Interruption Process **************
割り込み終了割り命令(RETFIE)を実行し、次の割り込みを可能な状態にします。
割り込み時にレジスタ類の待避もしていないので他に何もすることはありません。
RETFIE命令の実行に先だって、Bポートの制御を行っています。これはLED処理で設定したデータをここで集中してPORTBレジスタに書いたほうがステップが少なくなるためです。
コーディングの終了
;********************************************************
; END of signboard control processing
;********************************************************
end
コーディングの最後は end命令 で終了します。endが無いとアッセンブラはコーディングの最後を検出できず。エラーになります。
|