[PIC]HI-TECH Cで7セグ4桁のLEDをダイナミック点灯させる

7セグ4桁のLEDを、HI-TECH Cでダイナミック点灯させるプログラムを作成しました。

ダイナミック点灯の仕組みですが、簡単で短い周期で順番に1桁づつ点灯させていくだけです。
どの桁を点灯させるかは7セグのコモン側のピンを操作する事で決定します。BQ-N516RDはカソードコモンなので、点灯したい桁のコモンをLowにすればOKです。

表示の周期ですが、60Hzぐらい(毎秒60回)まで速くしてあげれば、人間の目だと残像で全桁がずっとつきっぱなしになっていると錯覚してしまうようです。低めの周波数だとチラツキを感じる事も有るので、可能なら気持ち速めほうが良いかもしれません。

ネットで見た情報だと、表示桁を移る前に一瞬、全桁非表示になるタイミングを作ったほうが良いような内容もありましたが、そのような細工をしなくても問題なく表示されていました。


PICの周辺回路についてはこちらの記事を参考にしてください。



今回作ったプログラムは以下の通りです。

#include <stdio.h>
#include <htc.h>
 
#define TMR0_INTERVAL (255-250) // TMRモジュールのカウント初期値
#define PRESCALER 4
int data = 0;
 
void main( void )
{
    __CONFIG ( FOSC_HS & WDTE_OFF & PWRTE_ON & CP_OFF );
    TRISB = 0;
 
    TMR0   = TMR0_INTERVAL;     // カウントアップタイマー値を初期化
 
    OPTION_REGbits.T0CS  = 0;           // タイマモードとして実行
    OPTION_REGbits.PS    = PRESCALER;   // プリスケーラ値(4:32倍, 6:128倍)
    OPTION_REGbits.PSA   = 0;           // プリスケーラをTMRモジュールで使用する
 
    INTCONbits.T0IE   = 1;      // TMR0   interruptを有効にする
    INTCONbits.GIE    = 1;      // Grobal interruptを有効にする
 
    // 無限ループに入る
    while ( 1 ) {
        NOP();
    }
}
 
// 割り込み処理(10msec周期)
static void interrupt intr( void )
{
    static int i;
    static int intr_counter;
 
    //--------------------------------
    // 一定周期でインクリメントする
    //--------------------------------
    intr_counter++;
    if ( intr_counter >= 50 ) {
        data++;         // 300msec周期で加算する
        intr_counter = 0;
    }
 
 
    //--------------------------------
    // 各桁の値をダイナミック点灯する
    //--------------------------------
    i++;
    switch ( i % 4 ) { 
        case 0:
            PORTB = data % 10;
            PORTB |= 0b11100000;
            break;
        case 1:
            PORTB = ( data / 10 ) % 10;
            PORTB |= 0b11010000;
            break;
        case 2:
            PORTB = ( data / 100 ) % 10;
            PORTB |= 0b10110000;
            break;
        case 3:
            PORTB = ( data / 1000 ) % 10;
            PORTB |= 0b01110000;
            break;
        default:
            PORTB = 0x00;
            break;
    }
 
 
    if ( data > 9999 ) {
        data = 0;
    }
 
    // 割り込みの再設定
    TMR0 = TMR0_INTERVAL;
    T0IF = 0;
}



main()関数は、割り込み処理の定義だけして直ぐに無限ループに入ってしまいます。
※割り込みについては以前書いたので、詳しく知りたい人はこちらの記事を参考にしてください。
今回の動作確認はPICを8MHzのクロックで動作させており、計算すると約5msec周期で割り込みが入る事になります。


一定周期でやってくる割り込み処理が、intr()関数です。
ここでは、表示すべきデータを変数”data”で管理しているのですが、割り込みが入るたびに加算していると分かり辛いので50回ごと(0.25秒毎)にインクリメントします。

次にLEDの出力処理で、これはswitch文のところで行っています。

    i++;
    switch ( i % 4 ) { 
        case 0:
            PORTB = data % 10;
            PORTB |= 0b11100000;
            break;
        case 1:
            PORTB = ( data / 10 ) % 10;
            PORTB |= 0b11010000;
            break;
        case 2:
            PORTB = ( data / 100 ) % 10;
            PORTB |= 0b10110000;
            break;
        case 3:
            PORTB = ( data / 1000 ) % 10;
            PORTB |= 0b01110000;
            break;
        default:
            PORTB = 0x00;
            break;
    }


今回はpicのPORTBに、LEDからの回路を接続しました。下位4ビットが表示すべき値で、上位4ビットが表示桁になっています。この為、割り込みが来るたびに上位ビットが”0001″, “0010”, “0100”, “1000”と、毎回1桁ずれるようにしています。
これで一回20msec、50Hzでの表示でしたが、見た感じではチラツキは特に気にならなかったです。

また、そのうちiがオーバーフローするのでは?と懸念されるかもしれませんが、仮にオーバーフローしても8bitのintでは128から-127に代わった時でもi%4の剰余は周期が代わるわけではないので特に問題ないです(確信犯的にクリアせずほったらかしにしています)。


作成したプログラムを実行した結果です。

関連記事

コメントを残す

メールアドレスが公開されることはありません。