NEC ELECTRONICS NEC ELECTRONICS
NEC electronics NEC electronics NEC
ホーム
アプリケーション
製品情報
先端技術
サポート
WEBショップ
ニュース&イベント
会社案内
header
GO
詳細検索機能/特性検索
サイトマップ お問い合わせ

LEDのダイナミック表示方法(78K0/Kx2,78K0S/Kx1+)

目次

    
FAQ-ID = led2-nnnn
0001: LEDのダイナミック表示方法(78K0/Kx2,78K0S/Kx1+)
led2
-0001
LEDのダイナミック表示方法(78K0/Kx2,78K0S/Kx1+)
[はじめに]
多くの情報を表示する場合には一般にダイナミック表示を行ないます。FAQの「ダイナミック動作とスタティック(Dynamic Operation and Static)」も参照ください。
ここでは、FAQの「LEDのドライブ方法」の「LEDのマトリクス接続の例」に掲載された回路を対象にしたダイナミック表示方法について説明します。
LEDは以下の表に示すポート構成によりグループを選択、その中から対象を選択します。


[表示のしかた]
ここではL1〜L4、L5〜L8、L9〜L12、L13〜L16の4つのLEDから構成された4つのグループに分けて表示することにします。P44〜P47で点灯したいLEDのグループに対応したポートに0それ以外は1に設定、表示したいLEDをP40〜P43で指定することで表示を行ないます。下図の表示のしかたに示すようにP44から順にP45、P46、P47、またP44と0を設定してポートからロウレベルを出力します。これに合わせて、P40〜P43に対応したLEDの点灯パターンを出力します。


表示は2.5m秒で切り替え、10m秒(100Hz)で全てのLEDの点灯を完了するものとします。このために、システム・クロックとして高速内蔵発振器の8MHzを1/2分周した4MHzを使用します。これを1/64分周したクロックで8ビット・タイマを駆動し、1/156分周することで約400Hzのインターバル割り込みを発生させます。このインターバル割り込みの中で表示を切り替えます。

[プログラム例1]
ここではアセンブラ言語で記述したプログラム例を示します。C言語記述についてはプログラム例2で説明します。
表示の指定は、点灯するLEDに対応した2つ(LEDSTATUS1とLEDSTATUS2)の8ビットの変数(LEDステータス)を準備して、そこに表示データを設定しておきます。タイマ割り込み処理では、点灯したいLEDに対応したビットから4個のLEDに対応したデータを抽出します。そのデータと表示グループの指定データを組み合わせてポート4に出力することでLEDを点灯します。これを4回繰り返すことで完全な表示となります。

・表示データの作成
LEDステータスの情報を4つのグループに分けて点灯するため、何回目の表示かの情報を元にLEDステータスから表示データパターンを抽出します。ここでは、どのグループかの情報をXレジスタ、どのLEDかの情報をAレジスタで作成し、2つを合成して表示データを作ります。処理時間を短くするために、グループを示す情報と、その中の点灯するLEDの情報を並行して処理し、最後に結合します。下記のプログラム例では、主にXレジスタでグループの選択情報、Aレジスタでグループ中の点灯するLEDの情報を処理しています。
DATWORK         DSEG    SADDR
NEXTDATA:       DS      1               ; 次の表示データ格納用
LEDSTATUS1:     DS      1               ; LED1〜8の点灯情報(1で点灯)
LEDSTATUS2:     DS      1               ; LED9〜16の点灯情報(1で点灯)
COUNT:          DS      1               ; 何回目の表示か(0−3)

GETLED:
                MOV     A,LEDSTATUS1    ; LED1〜8のステータスを読み出す
                MOV     X,#11101111b    ; LED1〜4の選択信号
                BF      COUNT.1,$NEXT1  ; LED1〜8の表示なら次へ
                MOV     A,LEDSTATUS2    ; そうでなければLED9〜16を
                MOV     X,#10111111b    ; LED9〜12の選択信号
NEXT1:
                BF      COUNT.0,$NEXT2  ; LED1〜4/9〜12なら分岐
                ROR     A,1             ; 有効LEDビットを下位4ビットに
                ROR     A,1
                ROR     A,1
                ROR     A,1
                XCH     A,X             ; グループ選択信号をAレジスタへ
                ROL     A,1             ; 選択信号を次のグループに
                XCH     A,X             ; A:LEDステータス、X:グループ情報
NEXT2:
                OR      A,#11110000b    ; グループ情報をマスク
                AND     A,X             ; 表示データを合成
                MOV     NEXTDATA,A      ; 次の表示データを保存
                RET
・データの表示(タイマ割り込み処理)
2.5m秒ごとの割り込みでLEDをグループごとに点灯させます。表示するためのデータ生成は上記のサブルーチンを用いています。
ここでは、まず表示を消したあとで、前回計算しておいたデータをポートに出力することで表示を行ないます。その後、次のグループの選択し、その表示データを準備します。
前回計算しておいたデータを使用するのはできるだけ時間のばらつきの影響をなくすためです。
TMH1INT:
                PUSH    AX
                MOV     A,NEXTDATA      ; 表示データ情報を読み出す。
                MOV     P4,#11110000b   ; LEDを全て消灯
                MOV     P4,A            ; 新しいデータを表示
                INC     COUNT           ; 次のグループを選択
                MOV     A,#00000011b    ; 表示グループ数のマスク
                AND     A,COUNT         ; 全ての桁が終了していれば
                MOV     COUNT,A         ; 次のグループをセット
                CALL    !GETLED         ; 次の表示データを作成
                        :
        ここに他に必要な処理を記述する
                        :
                POP     AX
DUMMY:          RETI                    ; 割り込み処理終了
・初期化処理
初期化処理では、スタックポインタの設定、電源の立ち上がり待ち、メモリや使用する内蔵周辺のハードウェアを初期化します。その後にタイマを起動し、割り込みのマスクを解除し、その後は他の処理を行ないます。タイマ割り込みが発生すると、LED表示を開始します。
なお、リセット・ベクタや割り込みベクタは以下のようにしておきます。ここで、使用しない割り込みには何もしないでRETI命令で戻るためのダミーのベクタを設定しておきます。
RSTVECT CSEG    AT      0
                DW      START           ;00:リセットスタート処理のベクタ
                DW      DUMMY           ;02:
                DW      DUMMY           ;04:
                DW      DUMMY           ;06:INTLVI
                DW      DUMMY           ;08:INTP0
                DW      DUMMY           ;0A:INTP1
                DW      TMH1INT         ;0C:INTTMH1
                DW      DUMMY           ;0E:INTTM000
                DW      DUMMY           ;10:INTTM010
                DW      DUMMY           ;12:INTAD
                CSEG
START:          MOVW    AX,#STACKP
                MOVW    SP,AX
                CALL    !POWERON        ; 電源の立ち上がりを待つ
                CALL    !INITIO         ; ハードの初期化
                CALL    !INITRAM        ; RAMの初期化
                        :
                        :
                SET1    TMHE1           ; タイマをスタート
                CLR1    TMMKH1          ; タイマ割り込みマスク解除
                EI
                        :
        ここには他にやりたい処理を記述する。
                        :

;
;       電源の立ち上がり待ち(2.7V以上になるのを待つ)
;
POWERON:
                DI
                MOV     LVIS,#00000111b ; VLI=2.7V
                MOV     LVIM,#10000000b ; 低電圧検出開始
                MOV     PCC,#00         ; CPU clock is fx/4
                MOV     WDTM,#01110000b ; WDTを停止
                SET1    LSRSTOP         ; 低速発振器停止
                MOV     A,#50
PONLOOP:
                DEC     A
                BNZ     $PONLOOP        ; 0.2m秒待つ

PONLOOP2:
                BT      LVIF,$PONLOOP2  ; 電圧が2.7V以上まで待つ
                MOV     PPCC,#01        ; CPU clock is fx/2
                RET
;
;       RAMの初期化
;
INITRAM:
                MOV     COUNT,#3
                MOV     LEDSTATUS1,#0
                MOV     LEDSTATUS2,#0
                MOV     NEXTDATA,#11110000b
                RET
;
;       タイマH1やポート4等ハードウェアの初期設定
;
INITIO:
                MOV     P4,#11110000b           ; 初期値(LED全消灯)
                MOV     PM4,#00                 ; ポート4は全て出力に
                MOV     TMHMD1,#00110000b       ; タイマモード設定
;                                |||++-----   インターバルタイマモード
;                                +++-------   カウントクロックfXP/64
                MOV     CMP01,#155              ; インターバル時間を設定
                MOV     IF0,#00                 ; 割り込みクリア
                        :
        ここには他で必要な初期化処理を記述する
                        :
                RET

[プログラム例2]
ここではC言語で記述したLED表示プログラム例について説明します。この例では、表示パターンを約1秒ごとに+1するような処理も追加しています。

・宣言部分
このプログラムでは内蔵周辺I/Oの操作以外に、割り込み制御を行なうので、プログラムの先頭で以下のような#pragma指令の宣言を行ないます。割り込み処理を行なう関数としてはGETLEDをプロトタイプ宣言しています。

コーヒーブレーク

78Kシリーズ用のC言語では標準的なC言語に対して組み込み用途で使用するために機能が拡張されています。この拡張機能を使用するためには宣言が必要となります。主な宣言としては、ここで使用している内蔵周辺I/Oをキーワードとして使用するための「#pragma SFR」、CPUのもついくつかの命令をC言語で使用するための「#pragma EI」や「#pragma NOP」等の指定、CPUのベクタ割り込み(ここではINTTMH1)と実際の処理関数(ここではGETLED)を結びつけるための「#pragma INTERRUPT INTTMH1 GETLED」があります。

それ以外ではハードウェアの初期化を行なうためのhdwinitもプロトタイプ宣言しています。
変数としてはLEDSTATUSが点灯するLEDの情報で、ここでは16ビットの変数として処理しています。SECTIMERは1秒の時間をカウントするために使用します。NEXTDATAやCOUNTはアセンブラ記述のプログラムと同じ意味で使用しています。
#pragma SFR
#pragma EI
#pragma DI
#pragma NOP
#pragma INTERRUPT INTTMH1 GETLED

unsigned int LEDSTATUS,SECTIMER;
unsigned char NEXTDATA,COUNT;

__interrupt void        GETLED(void);
void    hdwinit(void);

・初期化処理部
78KのC言語では内蔵周辺I/Oの初期化処理をプログラム本体の実行開始前に実行できるようになっています。そのために、専用の関数(hdwinit)が予約されています。早目に実行させたい内容はhdwinit関数に記述します。

コーヒーブレーク

78KのAll Flashマイコンでは、CPUが起動するとオプションバイトの確認によるハードウェア構成の決定が行なわれます。その後にリセット・ベクタ(0番地と1番地)に格納されているアドレスから実行がスタートします。アセンブラ記述のプログラムでは、リセット・ベクタもプログラムとして記述しますが、C言語記述の場合にはスタートアップ・ルーチンがスタートします。スタートアップ・ルーチンについてはFAQの「最初に実行する内容について」を参照してください。
スタートアップ・ルーチンがスタックポインターの設定やCのプログラムを実行するために必要な処理を行ないます。その中にhdwinit関数の呼び出しが含まれています。一連の処理が完了したら、スタートアップ・ルーチンはC言語で記述されたmain関数を呼び出すことで、C言語記述のプログラムを実行します。

以下に示すhdwinit関数では、ウォッチドッグタイマを停止した後で、低電圧検出機能を用いて、電源電圧の立ち上がりを待っています。低電圧検出機能は起動してから0.2m秒待たないと、正常な結果が得られないので、そこはソフトウェア・タイマで待ちます。電源電圧が2.7V以上になったら、CPUの動作クロックを4MHzに設定して使用するポートやタイマ等の初期化を行っています。
void    hdwinit(void){
        unsigned char work1;

        LVIS = 0b00000111;              /* select VLI=2.7V        */
        LVIM = 0b10000000;              /* Start VLI detection    */
        PCC = 0x00;                     /* CPU clock is fx/4      */
        WDTM = 0b01110000;              /* Stop WDT               */
        LSRSTOP = 1;                    /* Stop Low speed OSC     */

/*
        wait for 0.2m秒
*/
        for (work1 = 0; work1 < 10; work1++){
                NOP();
        }

        while ( LVIF ){
                NOP();
        }                               /* wait VDD > 2.7V         */

        PPCC = 0b00000001;              /* CPU clock is fx/2       */
        P4 = 0b11110000;                /* Clear All LED           */
        PM4 = 0x00;                     /* Port 4 is Output        */

        TMHMD1 = 0b00110000;            /* set interval timer mode */
        CMP01 = 155;                    /* Interval = 2.5m秒       */
        IF0 = 0x00;
}

・本体処理部
main関数では、各種の変数に初期値を設定します。その後は、タイマを起動して、1秒の時間をカウントする変数(SECTIMER)が0になるのを待ちます。1秒経過したら、表示データ(LEDSTATUS)の値を+1します。変数SECTIMERはmain関数と割り込み関数の両方から書き込まれるので、本来は排他制御を行なうことが考えられます。しかし、ここでは、割り込み間隔(2.5m秒)以内に処理は完了してしまうことから排他制御(この場合には割り込みの禁止/許可)は行いません。
void    main(void){
        COUNT = 3;
        NEXTDATA = 0b1111000;
        LEDSTATUS = 1;
        SECTIMER = 400;
        TMHE1 = 1;
        TMMKH1 = 0;
        EI();
        while(1){
                while(SECTIMER){
                NOP();
                }
                SECTIMER = 400;
                LEDSTATUS++;
        }
}
・割り込み処理部
タイマH1による2.5m秒ごとの割り込みにより起動され、実行されます。そのため、関数の頭で割り込み処理関数であることを示す「__interrupt」が宣言されています。これ以外は通常の引数や戻り値をもたない関数と同じです。
処理の殆どは表示のためのポートに出力するデータパターンの生成です。これは2つの処理から構成されています。一つは、表示するグループに対応したグループの選択信号を生成です。これはswitch文により、変数COUNTに応じた値をNEXTDADAにセットすることにより実現しています。2つ目は、表示データの抽出です。これは表示したいデータ(LEDSTATUS)を必要な回数だけ右シフトして、下位4ビット以外はマスクすることで実現しています。このようにして得られた2つのデータを結合して、次の表示のためのデータパターンとします。
その他の処理としては、最初に前回作成したデータパターンを実際にポートに出力や、次回のための表示グループの更新や1秒を得るためのカウントです。
__interrupt     void    GETLED(void){
        unsigned int work1;
        unsigned char work2;
        P4 = 0b11110000;                /* Clear LED         */
        P4 = NEXTDATA;                  /* Turn on specified LED */
        work1 = COUNT;                  /* Get Display Group Number */
        switch(work1){
                case 0:
                                NEXTDATA = 0b11100000;
                                break;
                case 1:
                                NEXTDATA = 0b11010000;
                                break;
                case 2:
                                NEXTDATA = 0b10110000;
                                break;
                case 3:
                                NEXTDATA = 0b01110000;
        }
        work1 *= 4;
        work2 = LEDSTATUS >> work1;
        work2 &= 0b00001111;
        work1 = (unsigned char) work2;
        NEXTDATA |= work1;
        COUNT = (COUNT+1) & 0b00000011;
        SECTIMER--;
}

(2006/04)

この情報はお役にたちましたか?
back to top  
(2006/04)









































 ご利用にあたって  個人情報保護について  RSS       © 1995-2008  NEC Electronics Corporation