HOME  >>  LED電子工作集 > PICマイコンとC言語の勉強  P-7 3桁の数字を表示させる

PICマイコンとC言語の勉強  P-7 3桁の数字を表示させる

■ はじめに

 今、PICマイコンとC言語の勉強に挑戦している。 そのいきさつは、鉄道模型工作実験室 の別室ブログ 「レイアウトに速度計を設置しよう」 ( 2019/2/22 )にて紹介しているので参照ください。

 学習の第2ステップとして、測定データを表示させるための7セグメントLEDと、新しくPIC16F1827 マイコンの取り扱い方を学ぶことにする。 今回は、セグメントに3桁の数字を表示させよう。

 

■ 7セグメントLEDの注意点

 使用している7セグメントLED C-533SR-A の回路図はカタログより抜粋して下記に示す。

 この回路からも分かるように、一度の全部のセグメントを点灯させると大きな電流が必要となり、PICマイコンの許容電流を大きく上回ってしまうのだ。 ひと桁の表示であれば対応できるのだが、3桁では無理なので、それぞれ個別に素早く順番に点灯させるのである。 これをダイナミック点灯方式と呼ぶそうである。

 点灯するセグメントを制御するには、上記のカソードコモン方式であれば、それぞれのカソードの回路をON/OFF制御すれば良いのである。 多数のLEDから流れた来た大きな電流を一つのスイッチでON/OFF させるために、トランジスタを使用してスイッチとしています。 このための回路を下に示す。

 

/*****************************************
*     7segLED Test 3
*           2019/2/28
*           PIC16F1827   MPLAB X   XC8
******************************************/

 ( 途中省略 )

int ct;        //表示する数の更新間隔
long val;      //表示する数の値
int digit;     //表示する桁位置
int segment_data[]= {0xDE,0x42,0x5D,0x57,0xC3,0x97,0x9F,0xD2,0xDF,0xD7};
               //表示する数字のパターンの行列
char st[3];    //表示する桁の数字、3個の行列


void main()
{
    OSCCON = 0b01110010;  //内部クロックを8MHzに設定
    ANSELA = 0b00000000;  //全てデジタルI/O
    ANSELB = 0b00000000;  //全てデジタルI/O
    TRISA  = 0b00000000;  //全て出力
    TRISB  = 0b00000000;  //全て出力
    PORTA  = 0b00000000;  //出力ピンをすべてLOWにする
    PORTB  = 0b00000000;  //出力ピンをすべてLOWにする
    
    digit=0;      //初期値の設定
    ct=1;
    val=0;
    
    while(1){     //ループ処理
        
        ct --;             //更新間隔をカウントダウン
        if(ct == 0){             //表示桁への振り分け
            st[2]=val/100;           //100の位の数字
            st[1]=val/10-st[2]*10;   //10の位の数字
            st[0]=val%10;            //1の位の数字
            
            val ++;        //表示する数をカウントアップ
            if(val==1000) val=0; //999以上になったら0にする
            ct=20;               //更新間隔をリセット
        }
        
        if(digit==2){         //100の位の数字を表示させる
            PORTA = segment_data[st[2]]; //出力ポートに指示
            RB1 = 1;
            __delay_ms(5);            //5msec表示
            RB1 = 0;                  //表示を消す
            __delay_us(100);
        }
        
        if(digit==1){       //10の位の数字を表示させる
            PORTA = segment_data[st[1]];
            RB2= 1;
            __delay_ms(5);
            RB2 = 0;
            __delay_us(100);
        }
        
        if(digit==0){         //1の位の数字を表示させる
            PORTA = segment_data[st[0]];
            RB3 = 1;
            __delay_ms(5);
            RB3 = 0;
            __delay_us(100);
        }
        
        digit ++;           //表示する桁をカウントアップ
        if(digit ==3)  digit=0;   //3になったら0に戻す
    }
}

■ プログラムの作成

 今回は、「Maicommon.ciao.jp TOP」/「自学のページ」/PIC入門/表示回路/数字3桁表示のページを参考にしました。 さる大学のゼミに使用されていた資料と推察する。 使用しているPICマイコンも異なるし、コンパイラも CCS C であったので記述方法がかなり異なっていました。

 しかし、記述の考え方は理解出来たので、小生が使用している状態に書き換えて記述し直しました。 実行している内容は同じであり、変数も同じ記号を使用しています。

 

● ロジックのポイント

 表示する数字の表示パターン
先回の実験に使用したデータを使用し、それを行列として定義しておく。 即ち0から9までの表示パターンを示す16進数を segmennto_data[ ]に 収めておく。
 
 表示桁への振り分け
表示させる数を各桁ごとの数字に分解しておく必要がある。 例えば、365 と言う数値に対して、1の桁は5で、10の桁は6で、100の桁は3であるとのように指示する必要がある。 このロジックはそっくり利用させていただきました。
 
表示桁の指定
一度に表示出来るのは一つのセグメントだけなので表示する桁を指定して、順繰りに表示するループを構成する。 一つのループではどれか一つの桁しか表示しておらず、このループを素早く実施して、目の残像効果によって、すべて点灯しているように見せるのである。
表示はわずか5msec 間点灯するようにしており、すぐに消してしまう処理を実施ている。 これは、点灯セグメントが重複しないようにしているのだが、忘れて失敗することの多い処理なのだ。
 
 使用する変数
色々なループを構成しているので、そのループ回数をカウントして処理を判断している。 どこでカウントアップ、あるいはカウントダウンしして、どこで判断し、そしてどこでクリアーしているのか、参考にさせて頂きました。

 作成したプログラムを右に示す。 コンフィグ等の設定は先回と同じなので省略しています。

 

◆ お詫びと訂正

 プログラムの一部に間違いがありました。 点灯させるLEDの指定方法がトライ時に実施したままのデータを流用してしまいました。

 実際には右の様に修正ずみです。 お詫びして訂正いたします。

 

 

■ 動作状態

 ブレッドボードに構成した回路状態と動作状況を紹介します。

 ジャンパー線がジャングルの様になってしまいました。 動作状態を動画で紹介します。

 電源は5ボルトのACアダプタから供給しています。 表示はスムースの実行されていますが、セロの数字が先頭にくる場合は表示しないように工夫する必要がありますね。

 これで数字の表示方法まで学習しましたので、次は最大の難関である時間計測に取り掛かります。 以前に報告した「レイアウトに速度計を設置する」では、Arduino を使用しましたが、その場合では、

     t1 = millis();
     while (slit2 == HIGH) {
         slit2 = digitalRead(SLIT2_PIN) ;
     }
     t2 = millis();
     tt = t2 - t1 ;
     V =108000 / tt ;

これだけの記述で、二つのスリットを通過する時間を計測し、スケールスピード V を計算することが出来たのですが・・・・・・・・。