7セグメントLEDを使った数値の表示

7セグメントLEDといわれる数値を表示するためのLEDを使ってみます。

 

7セグメントLEDで数値を表示する原理や桁数を増やすダイナミック点灯の制御方法について。

ポートの数を減らしたり、配線を少なくする工夫などで3桁の数値を表示する


7セグメントLEDを使う

ワンセグというのが流行(はやり)ですが、こちらは7セグです
 一般の、あのワンセグとは何の関係もありません)

7segmentLED
棒状のLEDが7コ、 8の数字に配置された、数値を表示するための表示器 です。

 

この7本の棒状LEDの、どれかを点灯させ、どれかは点灯させない ことで 数値の形を作り出す表示器です。

(このタイプの表示を街中で見かけはじめた初期の頃は、数値に違和感がありましたが、慣れるとこの角ばった数値はもう当たり前に受け入れられていますネ)

 

今やLCDの液晶表示器が安価になったので、数値だけの表示でもこれが使われるここが多いです。できるなら配線が少ないのでLCDを使いたいところです^^

それでも7セグLEDを使う理由として

 

やはりLEDで作り出す文字は、なんとなくイイ!
バックライト付きのLCDを使っても、7セグ表示の感じはなんか違っていて、
数値の表示 : 時計、温度、回転数など
数値の表示はやっぱりこれにしたい!と思ってしまいます。

 

LCD液晶 も 7セグLEDも同じ、数値が表示できる表示器ですが、マイコンなどで表示器として利用を考えると一長一短です

 

●LCD液晶

【長所】
字もアルファベットもいっぱい表示できる。
配線が簡単
表示器に外部回路も込みになっているので簡単
【短所】
文字が小さい、見にくい
最初の表示のルーチンを作るまで労力がかかる。

 

●●7セグメントLED

【長所】
長所が少ないんですが、
やっぱり数値はこれでないと
IOポートの簡単な処理だけで数値表示できる。
かなり大きな表示もできる
(大きな7セグ表示器はあるので)
数値が発光するので遠くからでも見やすい
【短所】
ほとんど数字だけしか表示できない
配線が大変、外部回路もなかなか作るの大変。
(外部回路込みの7セグもありますが、あまりみかけません)
7セグ1つで1桁の表示(何桁かつながった7セグもありますが)

ネットでもあちこちに解説記事があり、今更という感じですがH8を使い7セグで数値表示をしました。

 

基本はLEDを点灯、消灯させる操作なので、いままでで実験済みですが、配線やピンを減らす工夫などの方法を使っています。

 

7セグLED

7segmentLED2

7セグLEDは 単に棒状のLEDが7本(ついでに小数点の .(DF) が付いていたりもする)を点灯、消灯させるだけです。

 

共通端子が 電源部かGND部かで
アノードコモン、カソードコモンといわれるタイプがあります。

 

図のA~G 7本全部を点灯させれば、8 の数値になる、 
各ピンと各部LEDをつなぎ、いくつかを点灯させれば数値に見えるのでLEDの点灯操作と同じです。

 

ただ、そのままやると
1桁で7本の I/Oピンが必要。。。2桁になると14本 、 3桁で・・・・・

 

H8/3664F、3694F などはマイコンとしてはPICなどよりIOピン数が多い方ですが、数値の表示だけにこれだけのピンを取られるとキビシいです
1桁ぐらいなら7本なのでなんとか、、、でも
数値3桁ぐらいの表示は通常必要なので 7本×3桁= 21本ちかくのピンが。。。

 

こんなピン数を使った配線でやることは実際はそうないです、そこで以下の方法でマイコンからのピン数を減らす工夫をします。

 

★ ピンを減らす工夫 ★

7本を4本に減らす デコーダIC

1桁は9までなので、それを2進数で表すと、4桁の2進数になります
   つまり  4桁 → 4ビット → 4本のIOピン使用

 

4ビットで0~9までの数値が表せるので、マイコンでは4本のIOピンを使いH,Lの出力をだし、途中で、デコーダICを使い0~9までの数値用に変換して、7セグを光らせる各ピンの信号にするという方法です。

 

2進数→10進数に変換することをデコード(その逆がエンコード)と呼ばれるので、デコーダICを使用します。
74LS47を使用しました。

(デコードと難しそうですが、、実際はピン節約するだけなので 4ビットのH,Lの組み合わせで表示に必要な7本のLEDのどれかを光らせるH,L信号になったらいいんです。PICとかでも、4ビットの入力を受けて足から7ビットH,L出力するだけなので出来ます)

 

  • アノードコモンの7セグでは 74LS47、247のようなIC
  • カソードコモンでは4511 のようなICが使われることが多いです。

 

★ 桁数での工夫 ★

ICを間に使うと、1つの7セグで4本(4ビット)のピンで数値が出来るようになりました。
でも、桁数が増えると 4×桁数で なかなかの数のピン数が必要になります。

 

そこで 桁数が増えても、IOピンを減らす工夫として

 

ダイナミック点灯

ダイナミック点灯 といわれる方法がよく使われています。
これは全部の桁表示器をつないでしまい、いっぺんに同じ数値を表示させる方法です。

 

ダイナミック点灯の説明

表示器を全部横につないでしまうと、全桁 同じ数値が表示されます

全部の桁 同じ数値を表示してどうするんだ? と思いますが、

例えば
”21” という2桁の数値なら
それぞれ、 2 1 と 各桁違う表示でなく、表示器を全部つなげているので 

まずを表示させると 全桁 同じ数値 
1,1 と全部の桁が表示になる。
そこで、通電で 最初の桁しか表示しないように、1桁目だけ表示されるようにします

 

2桁目 1桁目

次に を表示させると 全桁 同じ数値 
2,2 と全部の桁が表示になるが、2桁目だけを表示させる


すると  

2桁目 1桁目

これを瞬時に高速で切り替えて表示すると 
2桁目 1桁目

連続した数値に見える という残像の表示方法です。

 

これだと、全桁つながっているので、数値の表示には デコーダICで節約して4本
そして、各桁を表示させられるように、各桁の通電のON、OFF制御に 1本 ×桁数
4本+桁数 だけのI/Oピン数だけで7セグでの数値ができます。(3桁だと 4+3で7本)
このダイナミック点灯は、桁数が増えるとピン数がドンと増えてくるので、必要度が高い方法です。

 

でも、途中のデコーダICで 7本→4本にへりましたが、3本減ってる(節約できた)だけですね。 (デコーダIC使わなくても 7本+桁数 だけのI/Oピン数でいける)

 

この 途中のデコーダIC回路を作るコト と 3本のピンが減らせるコト  天秤にかける必要があります
(もちろん、このICにも ちょっとした7セグ表示用の付加機能はありますが)


IOピンに余裕があるなら、デコーダICで数本だけ減らす回路は無くてもいいかもしれません

 

回路

LCD表示は、一度作れば多桁の数値なんて簡単に表示できるのに較べ、
さすがに配線作業がとても大変でした。

7segmentLED点灯回路

 

アノードコモンの7セグ
デコーダICに 74LS47
各桁通電ON,OFFに Tr 1085 を使用した回路

Trの通電切り替えは作ったテストボードで使用できるIOポートの関係から、とびとびの違うポートになってしまってます。

本来 入力の A0~A3 などは5k~10kΩ程度でプルアップすべきです。(お行儀よく、しておきましょう)

 

プログラム

まず、テストに簡単に数値を流すプログラム

FQ_7seg_TmA



/*タイマAの割り込み関数による 7セグLED点灯

  タイマAの設定値を変えることで
 
      TA.TMA.BYTE=0x09;    低速切替え  
      TA.TMA.BYTE=0x0B;    中速切替え
      TA.TMA.BYTE=0x07;    高速切替え
  ダイナミック点灯の切り替え速度体感
  
*/

#include <3664.h>

int f;

void int_timera (void){ 

  switch(f){

    case 0 :  //1桁目通電 表示
              IO.PDR2.BYTE = 0x00;   //#0   →LOW吸い込み通電   0000 0000
              //2桁目以降 非表示
              IO.PDR1.BYTE = 0x30;   //#4-5 →HIGH              0011 0000
              f+=1;            
             break;
   case 1 :  //2桁目通電 非表示
              IO.PDR2.BYTE = 0x01;   //#0   →HIGH              0000 0001
               //2桁目 表示
              IO.PDR1.BYTE = 0x20;   //#4   →LOW吸い込み通電   0010 0000
              f+=1; 
             break;
    case 2 :  //3桁目通電 非表示
              IO.PDR2.BYTE = 0x01;   //#0   →HIGH              0000 0001
              //2桁目 表示
              IO.PDR1.BYTE = 0x10;   //#5   →LOW吸い込み通電   0001 0000
              f=0; 
             break;           
  }
        IRR1.BIT.IRRTA=0; // 検知フラグを戻して再開 
}



int main(){

  IO.PCR8 =0xFF;     // ポート出力に設定(#0-3だけ使用) 0000 1111
  IO.PCR1 =0xFF;     // ポート出力に設定(#4-5だけ使用) 0011 0000
  IO.PCR2 =0xFF;     // ポート出力に設定(#0だけ使用) 0000 0001

  TA.TMA.BYTE=0x09;     /* 低速切替え   時計用クロック 時間0.5s   0000 1001 */
//  TA.TMA.BYTE=0x0B;   /* 中速切替え   時計用クロック 時間0.31s  0000 1011 */
//  TA.TMA.BYTE=0x07;   /* 高速切替え   高速クロック 時間φ/8        0000 0111 */

  IRR1.BIT.IRRTA=0; /* タイマーA割込みフラグのリセット */
  IENR1.BIT.IENTA=1; /* タイマーA割込みを利用可能にする */  
  
//数値 
  IO.PDR8.BYTE = 0x03;

   f=0; //case値 初期化

 EI;    //割り込み許可


   while (1) ;

}


       

 

同じ数値を各桁ごとにタイマーAの割り込みを使い、0.5秒ごとに流れる表示
(タイマーAの設定については 以前のタイマーALED点灯記事を参照してください)

 

単純ですが、数字が順に流れる・・・これだけでなんか楽しい! 
数値表示というより、光りモノ工作なところが楽しめます。LCD液晶表示でこんなことをしてもおもしろいと感じませんが、これがLEDなところかもしれません。

わかりやすくcase分岐を使って0~2で、各桁の7セグの通電ON、OFFを切り替え、表示と非表示にしました。

【改良実験】

切り替え速度を早め

タイマAの時間設定を 0.5s → 0.3125S 
TA.TMA.BYTE=0x0B; /* 時計用クロック 時間0.3125s 0000 1011 */
にすると表示がチラつきますが、ほぼ連続した数値になって見えるのがわかります。

 

さらにもっと高速に

高速クロック使用 φ/8 にすると
TA.TMA.BYTE=0x07; /* 高速クロック 時間φ/8  0000 0111 */
ちらつき無く表示されているのがわかります。

少しずつ切り替え速度を上げると、ダイナミック点灯がよくわかります。

 

3桁数値の表示

3桁の任意の数値を表示してみます。

Q_7seg_NumTmA



/*タイマAの割り込み関数による7セグLED点滅

  _7seg_out(数値)で入力された  3桁の数値を 
  _7seg_out関数で各桁に分解し 各桁の数値を strtemp[0-2]へ入力
  タイマーAのcase分岐0-2で 各桁をダイナミック点灯表示する
  
  2桁目、3桁目の表示には 頭に不要なゼロがあるとき非表示にする処理
  
*/

#include <3664.h>

int f;
unsigned char strtemp[3];               //    各桁格納配列
unsigned char num[10];                  //    7seg数値データ変数

    
void _7seg_out( short data )            // 数値データを各桁にする関数)
{
    unsigned char temp;                //     格納変数を定義

    int i;                         
    for(i=0;i<4;i++){ strtemp[i]=0; }  //    各桁格納配列初期化
    i=0;  
      do {
          temp = data % 10;             //     下位の桁から数字を抽出
          strtemp[i++] = temp;          //    配列へ格納
      } while (( data /= 10 ) != 0);    //     数値の桁数までループ
}

void int_timera (void){ 

  switch(f){

    case 0 :
          //数値 
              IO.PDR8.BYTE = num[ strtemp[f] ];
              //1桁目 表示
              IO.PDR2.BYTE = 0x00;   //#0   →LOW吸い込み通電   0000 0000
              //2桁目以降 非表示
              IO.PDR1.BYTE = 0x30;   //#4-5 →HIGH              0011 0000
              f+=1;            
             break;
             
   case 1 :   //数値 
              IO.PDR8.BYTE = num[ strtemp[f] ];
              //1桁目 非表示
              IO.PDR2.BYTE = 0x01;   //#0   →HIGH              0000 0001
              //2桁目 表示
              if(  (strtemp[f+1]==0) && (strtemp[f] ==0)  ){ IO.PDR1.BYTE = 0x30;} 
                                                         //#4,5  → HIGH  頭のゼロ 非表示
              else{ IO.PDR1.BYTE = 0x20; }               //#4  →LOW吸い込み通電   0010 0000
              f+=1; 
             break;
             
    case 2 :  //数値 
              IO.PDR8.BYTE = num[ strtemp[f] ];
              //1桁目通電 非表示
              IO.PDR2.BYTE = 0x01;   //#0   →HIGH              0000 0001
              //3桁目 表示
              if(strtemp[f] ==0 ){   IO.PDR1.BYTE = 0x30;}
                                           //#4,5  → HIGH  頭のゼロ 非表示
              else{ IO.PDR1.BYTE = 0x10; } //#5    → LOW吸い込み通電        0001 0000
              f=0; 
             break;           
  }
  IRR1.BIT.IRRTA=0; // 検知フラグを戻して再開 
}



int main(){

  long testI;
    
	IO.PCR8 =0x0F;     // ポート出力に設定(#0-3だけ使用) 0000 1111
	IO.PCR1 =0x30;     // ポート出力に設定(#4-5だけ使用) 0011 0000
  IO.PCR2 =0x01;     // ポート出力に設定(#0だけ使用) 0000 0001

  TA.TMA.BYTE=0x07; /* 高速クロック 時間φ/8        0000 0111 */

  IRR1.BIT.IRRTA=0; /* タイマーA割込みフラグのリセット */
  IENR1.BIT.IENTA=1; /* タイマーA割込みを利用可能にする */  
  

  f=0;                //case値 初期化
  
  num[0] =  0x00;     //数値データ
  num[1] =  0x01; 
  num[2] =  0x02;
  num[3] =  0x03;
  num[4] =  0x04;
  num[5] =  0x05; 
  num[6] =  0x06;
  num[7] =  0x07;
  num[8] =  0x08;
  num[9] =  0x09;

 EI;    //割り込み許可
   
//表示数値 
    _7seg_out(719);
for(testI=0; testI<800000; testI++);  //しばらく待つ

     _7seg_out(3);
for(testI=1; testI<800000; testI++);

     _7seg_out(90);
for(testI=1; testI<800000; testI++);

     _7seg_out(361);
for(testI=1; testI<800000; testI++);
     _7seg_out(842);

     
 EI;    //割り込み許可


   while (1) ;

}


       

 

7seg_out(719) の部分に表示する数値を入れます
各桁に分解して配列に入れ、通電on,off の操作をしています。

num[0] = 0x00; //数値データ
は16進数にしていますが、普通に10進数でも大丈夫

 

頭に不要なゼロがある場合

003 030 のような場合
003 → 3
030 → 30  のように
頭のゼロを非表示にする処理を加えてあります。

 

実行はテスト用に

_7seg_out(719);
for(testI=0; testI<800000; testI++); //しばらく待つ
_7seg_out(3);
 ・
 ・

と、違う数値をしばらく表示して、いくつかの数値が切り替わって表示されるようになってます。

 

スポンサーリンク
  • facebook
  • twtter
  • google+
  • hatena