目次PIC回路集サインボード


サインボード ソフト処理説明




タイトル

;********************************************************
;
;             The signboard control processing
;
;                                 Author : Seiichi Inoue
;********************************************************

    コメント(;)を使用してプログラムのタイトルを書きました。



LIST および INCLUDE疑似命令
        list            p=pic16f84a
        include         p16f84a.inc
    PICの種類を指定するためにLISTコマンド(疑似命令)を使用します。
    PIC16F84Aの標準ラベル定義をINCLUDEコマンドで組み込みます。
    Microchip社で定義している定義ではTRISAおよびTRISBの定義がBank1アドレスになっているので、そのまま使用するとバンク切り替えの警告メッセージが出ます。私は定義ファイルを変更しました。
    定義ファイルはMPLABをインストールしたときにインストールされます。ファイルのインストール先は通常以下の場所にあります。
    c:\Program Files\Mplab\p16f84a.inc
    PCによってはドライブが異なりますので注意して下さい。

    p16f84a.incの内容の変更部分は以下です。
; P16F84A.INC  Standard Header File, Version 2.00'(modify)

TRISA      EQU     H'0085'    ->     H'0005'
TRISB      EQU     H'0086'    ->     H'0006'
    または、ERRORLEVELコマンドで警告メッセージを表示しないようにすることができます。



コンフィギュレーションワード
    CONFIG疑似命令を使用してコンフィギュレーションワードの指定を行っています。
        __config _hs_osc & _wdt_off & _pwrte_on & _cp_off
    コンフィギュレーション・ワードはライターでプログラムを書き込む際に指定できますが、CONFIG疑似命令を使用すると自動的に設定することができます。CONFIGの前のアンダーバーは2つ連続に書かれています。
    ただし、このコマンドのオペランドにラベルを使用する場合には事前にラベルの常数が定義されている必要があります。
    PIC16F84Aの標準ラベルには一通りのラベルが定義されているので、INCLUDEの後にCONFIGを指定すれば問題はありません。

    今回指定したラベルは標準ラベルでは以下のように定義されています。
_CP_OFF        EQU     H'3FFF'
_PWRTE_ON      EQU     H'3FF7'
_WDT_OFF       EQU     H'3FFB'
_HS_OSC        EQU     H'3FFE'
    これらのラベル定義はオペランドでAND(&)指定しているので、CONFIGの設定値は以下のようになります。
_CP_OFF0011 1111 1111 1111(3FFFh)
AND
_PWRTE_ON0011 1111 1111 0111(3FF7h)
AND
_WDT_OFF0011 1111 1111 1011(3FFBh)
AND
_HS_OSC0011 1111 1111 1110(3FFEh)

結果0011 1111 1111 0010(3FF2h)

    CONFIG命令は以下のように書くこともできます。
        __config    h'3ff2'
    設定内容は以下のようになります。

    項目設定内容フィールド名称ビット
    コードプロテクションOFFCP1111111111
    パワーアップタイマーONPWRTE(inv)0
    ウォッチドッグタイマーOFFWDTE0
    クロック発振器指定HSFOSC1およびFOSC010





ラベル定義

;****************  Label Definition  ********************

    処理で使用するラベル常数の定義を行います。PIC16F84Aの標準ラベルはINCLUDEで組み込まれるので、ここで定義する必要はありません。標準ラベルの名称はドキュメントに記載されている名称と異なる場合もありますので、注意が必要です。

    ラベルの内容はメモリ・アドレスの定義と、データサイズなどのようにプログラムが動作する時の値を設定するものがあります。いずれも、EQU疑似命令を使用して定義します。今回のリストではアドレスのEQUとデータ設定のEQUとの分かりやすく分けました。
;************************
;*     Time adjust      *
;************************
;This data decides a scroll speed. Basic rate is 26msec.
tm_adj  equ     0c              ;Time adjust(26msec x 12)


;************************
;*   EEPROM data size   *
;************************
;If the data size is 30 bytes, then simply set d'30'.
e_size  equ    d'32'            ;EEPROM data size


EEPROMデータの設定
;***************  EEPROM Data Definition  ***************
        org     h'2100'
        de      b'11111111'

    今回のソフトでは表示するメッセージの内容をEEPROMに格納しています。
    EEPROMのデータはメモリアドレス h'2100' として指定します。
    アドレス h'2100' はEEPROMメモリでは h'00' になります。アドレスの指定にはORG疑似命令を使用します。
    各ビットは'0'でLED点灯、'1'でLED消灯です。


プログラム開始
;****************  Program Start  ***********************

    電源投入/リセット時はプログラムメモリアドレスは h'0000' からスタートします。また、割り込み処理のスタート番地は h'0004' です。
    goto命令で各処理にジャンプするようにしています。 h'0000' は初期化処理、h'0004' はタイマー割込処理にジャンプします。


初期化処理
;****************  Initial Process  *********************

    電源投入後の初期化処理として以下の処理を行います。
    ポートAおよびBを全て出力ポートに設定
    タイマー割り込みの条件を設定
    タイマー入力に内部クロックを使用TOCS = 0

    プリスケーラをTMR0に使用PSA = 0

    プリスケーラ値 = 256PS2 = 1


    PS1 = 1


    PS0 = 1

    タイマー値 = 0 ( 256カウント )TMR0 = 0

    タイムアウトスキップ回数TM_ADJ = TM_CNT



    EEPROMの条件を設定

    EEPROMアドレスの初期化

    EEPROMデータサイズの設定
    割込機能開始を設定

    タイマーオーバーフロー割込許可指定T0IE = 1

    全割り込みマスク解除指定GIE = 1



LEDスクリーン表示処理
;**************  Screen Load Process  *******************

    128個(8 x 16)のLEDにはメッセージを表示するので、スクリーンと称しています。
    128個のLEDの点滅状態はRAMファイルメモリのに16バイトを確保して制御するようにしています。
    PICでは同時には8個のLEDの点滅しか制御できないので、8個単位の点滅制御を高速で行い、人の目には128個のLEDを同時に制御しているように見せています。制御は一番右端の8個から始まり、1列ずつずらして制御して16回で1周期分です。
    RAMファイルメモリの内容を変更すれば、LEDの点灯状況を変えることができます。
    ポートBには8個のLEDの点滅状態を出力し、ポートAの4ビット(RA0-RA3)には列制御情報をバイナリで出力します。
    列制御情報は外部のデコーダ(74HC154)により16本の制御情報に分けられ、16本の内の1つだけが選択されます。
    高速でスキャンしていますので、ちらつきは無いのですが、1つのLEDの点灯時間は1/16になりますので、少し暗くなります。外部にラッチレジスタ回路を使用すれば点灯時間を長く出来るので、LEDを明るく点灯させることができます。しかし、16個のラッチレジスタが必要なので、今回の回路では省きました。

    この処理のポイントの一つは間接メモリアドレス方式を使っていることです。
    間接メモリアドレス方式の場合、アクセスしたいメモリのアドレスをFSRレジスタに書き込むとINDFレジスタに内容が表示されます。
    PICでの命令は基本的には直接アドレス方式が採られています。この場合、アクセスしたいアドレスは命令コードに直接書かれているので、アクセスアドレスを変えるためには、アドレス毎に命令コードを用意しておく必要があります。すると、プログラムの量が増えてしまいます。
    間接アドレスを使うと、処理をループ状に回して、その都度カウンターでアドレスを加算すれば、順番にメモリにアクセスすることができ、プログラム量を少なくすることができます。

     bcf     intcon,gie      ;Interrupt disable
    
     bsf     intcon,gie      ;Interrupt enable
    もう一つのポイントはスクリーンの書き換えを行っているときには割り込み処理を禁止している点です。
    割り込み処理が発生すると、その時点で実行している処理は中断され、割り込み処理が実行されます。この時、スクリーンの途中まで書き換えた状態でメモリが書き換えられると、スクリーンの表示がずれてしまいます。
    割り込み処理が実行されるのは次のスクリーンの書き換え準備をする4ステップを実行しているときです。スクリーン書き換え中にタイムアウトが発生した場合、割り込みは待ちの状態になります。

    スクリーンデータの書き換え処理で最初にLEDを消すしてから次の列の処理を行っています。これはLEDを消さないで次の列に切り替えると次の列のLEDが前の列のデータで一瞬点灯してしまい、表示に「にじみ」が出てしまいます。デバッグでは気が付かなかったのですが、実際にサインボードを動作させて分かりました。



割り込み処理
;************  Begin Interruption Process  **************

    ハードタイマーがタイムアウトすると割り込みが発生します。割り込みはINTCONレジスタのT0IFビットが'1'になると同時にプログラムの実行番地が強制的に h'0004' になります。また、中断したプログラムへの戻り番地がスタックに記録されます。ですから、割り込み処理を利用する場合には、サブルーチンコールでスタックを全て使用してはいけません。最低1つは余裕を持たせておく必要があります。
    割り込み処理では二重の割り込みが発生しないように自動的にINTCONレジスタのGIEビットが'0'になり割り込みが禁止されます。

    割り込み処理で最初に行うことはレジスタの待避処理です。今回はWレジスタとSTATUSレジスタの待避を行っています。場合によってはPCLATHレジスタを待避させることがあります。
    まず、Wレジスタから待避します。というのはSTATUSレジスタを待避するためにはWレジスタを使う必要があり、Wレジスタの内容が壊されてしまうからです。先にWレジスタの待避を行ってもSTATUSレジスタの内容は変わりません。

    次に割り込みの種類を判断します。今回はタイムアウト割り込みしか発生しないので、特に判定をする必要はないのですが、一応、タイムアウトビット(T0IF)のチェックを行っています。タイムアウトビットが立っていない割り込みが発生した場合には、異常割り込みとして初期化処理にジャンプさせています。初期化処理にジャンプしても異常が直るわけではありませんので、異常動作をしている場合には要因を追求する必要があります。




割り込み終了処理
;************  END of Interruption Process **************
    割り込み処理が終了した場合、元のプログラムに処理を戻します。
    その際に待避したレジスタ類を元の値に設定します。レジスタを戻す順番はSTATUSレジスタを戻してからWレジスタを戻します。
    STATUSレジスタを戻すときにWレジスタを使用するからです。Wレジスタを戻すのには工夫が必要です。単純にmovf命令を使用してWレジスタを設定するとSTATUSレジスタの内容が変わってしまいます。ですから、STATUSレジスタの内容が変わらない方法で戻します。具体的にはswapf命令を使います。swapf命令は上位4ビットと下位4ビットを入れ替える命令で、STATUSの変化はありません。また、処理結果を格納する場所を指定することができます。ですから、swapf命令を二回使用し、二回目の結果をWレジスタに格納すれば、STATUSレジスタの内容を変えることなくWレジスタを戻すことができます。
    最後にretfie命令で元の処理に戻ります。この命令はスタックの内容により元のプログラムに戻ると同時にINTCONレジスタのGIEビットを'1'にして割り込み可能な状態にします。




タイムアウト割り込み処理
;***********  Time-out interruption Process  ************
    ハードタイマーでカウントできる時間はプリスケーラを使用しても10MHzクロックの場合、最大約26_秒です。今回の処理ではタイマーの割り込み処理でメッセージを1列づつ移動するようにしています。26_秒をそのまま使用するとメッセージの移動速度は右端から左端まで16 x 26 = 416_秒になります。この速度では速過ぎます。そのため、割り込みの回数をカウントして26_秒の整数倍にしています。このカウント値はラベル定義の設定値で変えられます。今回の設定は'6'にしているので、メッセージが右端から左端までの時間は16 x 26 x 6 = 2,496_秒(約2.5秒)になります。
    タイムアウト割り込みが発生するとINTCONレジスタのT0IFビットが'1'になります。このビットはソフトウェアで消さないと次の割り込みが発生しません。また、カウント値も設定し直す必要があります。

    TMR0はカウントアップタイマーで、値がFFhから00hになるとタイムアウトになります。ですから、256から希望するタイマー値を引いた値が設定値になります。255(FFh)を設定すると1カウントでタイムアウトします。
    例えば、10MHzのクロックを使った場合、タイマーの1カウント時間は4サイクルですから、0.4μ秒です。プリスケーラを256に設定した場合、TMR0に入力されるパルスの間隔は256 x 0.4 = 102.4μ秒になります。
    TMR0を約20ミリ秒でタイムアウトさせるのには20/0.1024 = 約195カウントです。195カウント後にタイムアウトさせるためには256-195 = 61(3Dh)カウントをTMR0に設定します。
    今回の場合には最大時間を設定したいので、TMR0の設定値は 0 にしています。



スクリーンスクロール処理
;************  Screen data shift Process  ***************
    タイムアウト割り込みが規定の回数発生すると、LED表示を変更する処理が実行されます。
    処理内容は1列分左に移動し、一番右側の列に新しいメッセージの1列を表示することです。
    まず、左の15列分のメッセージを1列移動します。この処理でも間接アドレスを使用しています。FSRレジスタにアドレスを設定するとINDFレジスタに該当するメモリの内容が格納されます。また、その状態でINDFレジスタの内容を変更すれば、RAMメモリの内容を変更することができます。


EEPROMデータ読み出し処理
;**************  New data write Process  ****************
    スクリーンスクロール処理が終わった後、右側の1列にEEPROMからのデータを書き込みます。
    EEPROMの読み出しには特殊な処理ステップが必要です。SFRの中のEEADRレジスタ、EECON1レジスタおよびEEDATAレジスタを使用します。
    まず、EEADRレジスタに読み出したいEEPROMメモリのアドレスを設定します。ここで使用するアドレスはh'00'からh'3f'までの64バイトです。ソースコードで指定したh'2100'の値ではありません。
    次にEECON1レジスタのRDビットを'1'にします。この操作が読み込み開始の指示になります。EEPROMデータの読み出しが完了するとRDビットは自動的に'0'になります。特に'0'になったことを確認する必要はありません。
    読み出されたデータはEEDATAレジスタに格納されています。

      movwf   eeadr           ;Set EEPROM address
      bsf     status,rp0      ;Change to Bank1
      bsf     eecon1,rd       ;Start EEPROM reading
      bcf     status,rp0      ;Change to Bank0
      movf    eedata,w        ;Read EEPROM data

    読み出したデータをLED表示の一番右側の列に設定します。
    以上で、LEDの表示が左に1列分移動しました。

    EEPROMに書かれたデータを最後尾まで読み出すと、また、先頭に戻って読み出しを行います。この動作を繰り返し行い、LEDにはEEPROMのデータが流れるように表示されます。



コーディングの終了
;********************************************************
;          END of signboard control processing
;********************************************************

        end
    コーディングの最後は end命令 で終了します。endが無いとアッセンブラはコーディングの最後を検出できず。エラーになります。