Arduinoを用いた7seg(7セグメント)
超大型表示器の制御器

価格の低下とともに、フルカラーで画素数の多い液晶パネルが全盛となりました。 しかしながら、デジタル時計や電光掲示板、電卓などの数字のみを表示する 用途には7セグと呼ばれる7つのセグメントかならる液晶/LED表示器が幅広く 使われています。ここでは、ゲームセンターにある7ケタの超大型表示器の 廃品を活用した、距離測定表示器を試作します。マイコンによる A/D変換とダイナミック方式の7セグ制御の参考になれば幸いです。

表示器

7セグメントの表示器はヤフーオークションに出品されていた 超大型(文字高さは76.2mm,パネル高さは110 mm)のものを購入いたしました。 7桁と配線付きで1000円程度という良心的な価格でした。 ブラックジャックというセガのアーケードゲーム機(メダルゲームのようです)から 取り外した中古品ですが、壊れるものではないと考え購入いたしました。 実際に点灯チェックをしてみたのが下の図です。7セグメントのうち一つだけに15Vを 接続して点灯させた例です。文字の高さは110mmもあり、目が良い人ならば50 m程度の 距離からも数字が読めそうです。 大型の7セグ表示器に関しては こちらのサイト(テクノミューコン)で 販売されています。 これを7ケタも用意すると、かなりの価格となってしまいますが。
7セグメント表示器。
上側の紫の半透明アクリルで覆うことで、コントラストが強くなる。


一つのセグメントにLEDが6個直列×2列並列に接続されています。
写真は15 Vで点灯させた様子。数字用のセグメントが7つ、ドットとコンマ用に2つ、
これに共通のCathode(Cathode common:カソードコモン)があります。
つまり、一つの数字盤に10個の電極がついています。

商品が届いてから、7セグ表示器の型番がLTS-30801であることが 判明しました。ネット上でデータシートを見つけることができました。 数字部のセグメントは一つあたり6*2=12個の赤色LEDです。 ドットとコンマは2*2=4個のLEDでした。 それぞれのLEDのしきい値は2V程度であり、一般的に使用されるものでした。 ですから、数字セグメント部は約12-15V程度で駆動し、ドット部分は4-5V程度で良いことがわかります。より正確には抵抗をつけて、おおよその電流値が40 mAとなるように 制御しました。

購入した7ケタの表示機では、 7つの7セグが等価に、並列に接続され、桁の選択をCommon cathodeで 行う制御方式となっています。つまり、マイコンでは

  1. カソード選択
  2. 数字表示用のセグメントの選択
  3. off
  4. 別の桁のカソード選択
  5. 数字表示用のセグメントの選択

を7ケタ分スキャンすれば良いことがわかります。 電極の番号をデータシートから抜粋します(下)。8番ピンが共通の アノードですから、ある桁のアノードを選び、15Vを印加し、 点灯させたいカソードをグランドに 落とせば良いことが分かります。

LTS-30801
Pin No. / connection

  1. segment E Cathode
  2. segment D Cathode
  3. Comma Cathode
  4. Dot Cathode
  5. segment C Cathode
  6. segment B Cathode
  7. segment A Cathode
  8. Common Anode
  9. segment G Cathode
  10. segment F Cathode


セグメントの記号(A,B,C,D,E,F,G), LTS-30801データシートより抜粋。


7セグ表示器内でのLEDの配線。8で表示させたい桁を選択。
それ以外でセグメントの点灯を制御する。

制御回路
セグメントに対応するカソードの選択

数字を表示させるときに、適切なセグメントを選択する機能は マイコン(Arduino)で行うことといたしました。表示 させたい数字と点灯させるセグメントの関係は以下の通りです。 アルファベットが記入されているところが選択すべきカソードとなります。 "-"は選択肢ないカソード(off)を示します。

表示させたい数字/点灯させるセグメント

0/ abcdef-
1/ -bc----
2/ ab-de-g
3/ abcd--g
4/ -bc--fg
5/ a-cd-fg
6/ a-cdefg
7/ abc--f-
8/ abcdefg
9/ abcd-fg

上の図と見比べれば簡単にわかると思います。全点灯が8です。 1はbとcだけを点灯します。 つまり、7bitのデジタル出力を用意して、 上の位からabcdefgと接続します。そこで以下を出力すれば 数字が表示されることになります。ArduinoではDitital OutのD端子を用いることとします。

0/ 1111110
1/ 0110000
2/ 1101101
3/ 1111001
4/ 0110011
5/ 1011011
6/ 1011111
7/ 1110010
8/ 1111111
9/ 1111011

ご存知の方には簡単すぎて申し訳ありません。 今回は一つのセグメントに15V,40mAというマイコンの Ditital Out直接では扱いにくい電圧、電流を制御し、 さらに、これが7セグメント×7桁必要でした。 そこで、セグメント選択用のカソードにはトランジスタ アレイTD62083APを用いることとしました。これは カソードをGNDに落とす時に、使用する7つのトランジスタを 一つにまとめたものです。正確には一つのICに8つのトランジスタが 入っています。余った一つのトランジスタはドット用に使用することも できますが、電圧が違ってイレギュラーなので、未使用としました。TD62083APは秋月電子で購入しました。データシートにあるように、1-8の電極にHIGHが入ると、 その反対側の20−13の電極がGNDに落とされるような仕組みとなっています。 ですから、以下の図のような配線でセグメントの選択制御が可能となります。


トランジスタアレイTD62083APへの接続

それぞれのカソードに47Ωの抵抗を介してトランジスタアレイに接続していますが、 この抵抗値は以下のように計算しました。 一つのセグメントに40 mAですから、 一列に20 mAの電流を流せば良いことになります。 以下に示されるLEDのデータシートを見ると、20 mAの電流には 一つのLEDに2.0 Vの電圧が印加されれば良いことがわかります。 これが6個直列に並んだ時には12Vです。 15Vの電源を接続したときに15-12=3 Vの過剰の電圧が印加されます。 たかが3V÷6=0.5Vといえども、LEDの非線形性は強く、2+0.5=2.5 V が印加された場合に100 mAの(過剰な)電流が流れることがわかります。 この3 Vを消費するために、抵抗を一つ入れると、V=IRから 3 V=40 mA×Rとなり、R=75Ωが必要であることが分かります。 手元には100Ωと47Ωの抵抗がありましたが、 コモンアノードを制御する素子(後述)でも電圧降下があると考え、47Ωを選択しました。 また、15 Vの電圧に関しては、可変電圧として、これを14-15 V程度で制御して セグメントの明るさを調整することとしました。 一つのセグメントには40 mAが流れますので 抵抗での消費電力はI^2×R=40 mA 40 mA×47Ω=0.04×0.04×47mW=0.075W程度となります。 通常の1/4 W抵抗で全く問題ありません。端子9とGNDの 間に一つの抵抗だけで済ませたらいいような気がしますが、 エミッタ接地とならないために、動作しなくなる可能性もありますし、 大きい容量の抵抗が必要となるので、お勧めできません。7個程度なら 半田づけもそれほど面倒ではないですよね。素子がきれいに並ぶのは 気持が良いですし。


単独のLEDのデータシート

数字の桁に対応するアノードの選択

ここまでで、セグメントの選択は終わりました。 では、複数の桁を表示する場合の桁の選択を行う回路を作りたいと思います。 ダイナミックな制御ですので、この桁を数m秒ごとにスキャンすることが 表示の本質となります。 コモンアノードに流れる電流は以下のように計算しました。 単独のセグメントが7つ並列につながっていますので 最大で(数字の8を表示するときに)40 mA×7=280 mAです。 これは電子工作ではやや扱いにくい大きめの電流となります。 しかも、アノードですので、カソードで選択したエミッタ接地のPNPダイオードを 使用することもできません。そこで今回はフォトモスリレーのHSR312を用いることといたしました。 切り替え速度が2-3msec程度でやや遅いことが心配でしたが、プレッドボードで 動作させてみると特に問題なく表示できることがわかりました。最大電流も 320 mAですので、セグメントの常時全点灯(実際には桁の数で割った平均電流となり、 もう少し小さい容量でもOKです。)でも問題は生じないことがわかります。 HSR312 (フォトモスリレー)

接続は以下の通りです。7ケタですので7回路用意したいところですが、 ArduinoのDitital OUT のBは6bitしかありませんので、6ケタ分を用いました。 R1は以下のように決定しました。 HSR312の1-2端子間が1.2 V 3 mA程度のダイオード入力であるため、 ArduinoのDigital HIGH状態の5 Vを使用した時に残りの3.8 Vを3 mAで 消費するために1 kΩとなります。少しぐらい違っていても問題は生じません。 流れる電流がわずかであるため、私は6ケタ分のHSR312の 2端子を一つの1 KΩ抵抗に接続してGNDに落としました。


アノードへの接続。ArduinoのDigital Out B8-B13とCommon Anode1-6桁の 接続方法。

以上でハードウェアは整いました。配線が多くなりますが、 下の写真のような構成です。


動作確認の状況。HSR312(白)がアノードに接続されています。
TD62083AP(黒)がカソード側です。
HSR312は桁の数だけ必要ですが、TD62083APは一個だけとなります。
ダイナミック制御のいいところですね。


ボード上に組み込んだ状態。図のような端子台を用いると、
間違った接続を修正できるため便利です。
複雑そうに見えますが、配線はアノードとカソードの2パターンしかありません。
左に精密可変抵抗と電源IC(後述)が見えます。
画面の中央やや右のコンデンサは電源の平滑用です。

制御プログラム(Arduinoのスケッチ)

作成したArduinoのスケッチは以下の通りです。 portBが6bitですので、6ケタの表示を行うコードとしました。 少し分かりにくくなって申し訳ありませんが、 デジタル出力のための値をbitで表記しております。 こちらのほうがコードが短くできますし、 慣れると早く間違いを見分けられるようになります。 "//"マークの後はコメントですので、プログラムのコンパイルでは読み取られません。


宣言部(端子の出力や変数が小数点を含むか、整数か、などを定義する。)

int Digit1=0;  //Digit1(1桁目の数字)をinteger(整数)として定義。
int Digit2=0;  //Digit2(2桁目の数字)
int Digit3=0;  //Digit3(3桁目の数字)
int Digit4=0;  //Digit4(4桁目の数字)
int Digit5=0;  //Digit5(5桁目の数字)
int Digit6=0;  //Digit6(6桁目の数字)
int DigitNow=0;  //DigitNow(Dynamic制御で点灯したい桁の数字)

long TimeMeasure=0;  //特定の時刻を記録するための変数TimeMeasureを長整数として定義。
long RealLength=777; //cm単位の長さをTimeMeasureを長整数として定義(int型でも可)。
long InputVal=1;     //アナログ電圧の代わりにチェック用に使用するinputvalを長整数として定義。
double ReadVoltage=777.77;  //読み取ったアナログ電圧(ReadVoltage)を倍精度浮動小数点型の変数として定義。


void setup(){   //プログラムの前に記述するsetup関数(電源onやreset時に一度だけ実行する)
 pinMode(1, OUTPUT); // pin 1 (D端子の1番ピン)をoutputに指定
 pinMode(2, OUTPUT); // pin 2 (D端子の2番)をoutputに指定
 pinMode(3, OUTPUT); // pin 3 (D端子の3番)をoutputに指定
 pinMode(4, OUTPUT); // pin 4 (D端子の4番)をoutputに指定
 pinMode(5, OUTPUT); // pin 5 (D端子の5番)をoutputに指定
 pinMode(6, OUTPUT); // pin 6 (D端子の6番)をoutputに指定
 pinMode(7, OUTPUT); // pin 7 (D端子の7番)をoutputに指定
 pinMode(8, OUTPUT); // pin 8 (B端子の0番)をoutputに指定
 pinMode(9, OUTPUT); // pin 9 (B端子の1番)をoutputに指定
 pinMode(10, OUTPUT); // pin 10 (B端子の2番)をoutputに指定
 pinMode(11, OUTPUT); // pin 11 (B端子の3番)をoutputに指定
 pinMode(12, OUTPUT); // pin 12 (B端子の4番)をoutputに指定
 pinMode(13, OUTPUT); // pin 13 (B端子の5番)をoutputに指定
}

関数部1 DigitChange(数字=セグメント(カソード)の選択)

void DigitChange(){ //Dynamic制御で点灯させるセグメントを選択する関数
  switch(DigitNow){ //switchでDigitNowの値が0から9の場合による場合分け。
  case 0: OutPut0(); break; //DigitNow=0の時に、OutPut0()を呼び出して終わる。
  case 1: OutPut1(); break; //DigitNow=1の時に、OutPut1()を呼び出して終わる。
  case 2: OutPut2(); break; //DigitNow=2の時に、OutPut2()を呼び出して終わる。
  case 3: OutPut3(); break; //DigitNow=3の時に、OutPut3()を呼び出して終わる。
  case 4: OutPut4(); break; //DigitNow=4の時に、OutPut4()を呼び出して終わる。
  case 5: OutPut5(); break; //DigitNow=5の時に、OutPut5()を呼び出して終わる。
  case 6: OutPut6(); break; //DigitNow=6の時に、OutPut6()を呼び出して終わる。
  case 7: OutPut7(); break; //DigitNow=7の時に、OutPut7()を呼び出して終わる。
  case 8: OutPut8(); break; //DigitNow=8の時に、OutPut8()を呼び出して終わる。
  case 9: OutPut9(); break; //DigitNow=9の時に、OutPut9()を呼び出して終わる。
  }
}

関数部2=セグメントを指定する関数。(関数部1で呼び出される。)
カソード(D端子,Port D)を選択する。

void OutPut0(){PORTD=B11111100;} // "0"に対応するセグメントを点灯。PortDをB(bit)で指定して7端子から0端子まで11111100(H/H/H/H/H/H/L/L)とする。
void OutPut1(){PORTD=B01100000;} // "1"に対応するセグメントを点灯。(左端からセグメントa,b,c,d,e,f,gに対応)
void OutPut2(){PORTD=B11011010;} // "2" 同上。
void OutPut3(){PORTD=B11110010;}
void OutPut4(){PORTD=B01100110;}
void OutPut5(){PORTD=B10110110;}
void OutPut6(){PORTD=B10111110;}
void OutPut7(){PORTD=B11100100;}
void OutPut8(){PORTD=B11111110;}
void OutPut9(){PORTD=B11110110;}

void NoOutPut(){  //表示を消したいときの関数。
  PORTD=B00000000; //全て消灯
  delayMicroseconds(500);// 500 usec(0.5 msec)待つ。
}

関数部3=桁を指定する関数。
アノード(B端子,Port B)の選択)

void keta1(){   //keta1()という関数。1桁目を選択的に表示するときに呼び出す。
  PORTD=B00000000;  //PortDを全てoff(Low状態)とする。全消灯。
  PORTB=B100000; //PortBの13番のみon。13に接続するアノード(桁)のみを通電可能とする。
  delayMicroseconds(500); // 500usec(0.5 msec)待つ。
}

void keta2(){ //keta2()という関数。
  PORTD=B00000000;
  PORTB=B010000; //PortBの12番(2桁目)を選択。
  delayMicroseconds(500);
}

void keta3(){
  PORTD=B00000000;
  PORTB=B001000; //PortBの3桁目を選択。
  delayMicroseconds(500);
}

void keta4(){
  PORTD=B00000000;
  PORTB=B000100; //PortBの4桁目を選択。
  delayMicroseconds(500);
}

void keta5(){
  PORTD=B00000000;
  PORTB=B000010; //PortBの5桁目を選択。
  delayMicroseconds(500);
}

void keta6(){
  PORTD=B00000000;
  PORTB=B000001; //PortBの6桁目を選択。
  delayMicroseconds(500);
}

ループ部(プログラム本体,6ケタ表示の例)

void loop(){
  if(millis()> TimeMeasure+100){  //100 msecごとに表示値を再定義。
  InputVal=138;  //表示するための数字を与える。ここでanalog readとすれば値を更新できる。
 
  //以下のプログラムで
  Digit6=int(InputVal/100000);     //6桁目の数字を求める。int()は整数部分を取り出す
  InputVal=InputVal-Digit6*100000; //6桁目を除いて5ケタの数字に直す。
  Digit5=int(InputVal/10000);      //5桁目の数字を求める。int()は整数部分を取り出す
  InputVal=InputVal-Digit5*10000;  //5桁目を除いて4ケタの数字に直す。
  Digit4=int(InputVal/1000);       //4桁目の数字を求める。
  InputVal=InputVal-Digit4*1000;   //4桁目を除いて3ケタの数字に直す。
  Digit3=int(InputVal/100);        //3桁目の数字を求める。
  InputVal=InputVal-Digit3*100;    //3桁目を除いて2ケタの数字に直す。
  Digit2=int(InputVal/10);         //2桁目の数字を求める。
  InputVal=InputVal-Digit2*10;     //2桁目を除いて1ケタの数字に直す。
  Digit1=InputVal;                 //1桁目の数字を求める。
  TimeMeasure=millis();            //時間を更新
  }        //値の再定義の終了
  
  ///これより下で数字を表示。
  
  keta6();                         //6桁目を選択(消灯して6桁目を点灯させる準備)
  DigitNow=Digit6;                 //DigitNow(表示させたい数字)を入力(ここでは6桁目の数字)
  DigitChange();                   //数字を変更して点灯させる。
  delayMicroseconds(6000);         //6000usec=6msec待つ。
  
  keta5();                         
  DigitNow=Digit5;                
  DigitChange();                  
  delayMicroseconds(6000);     
  
  keta4();                     
  DigitNow=Digit4;                
  DigitChange();                 
  delayMicroseconds(6000);      
  
  keta3();                       
  DigitNow=Digit3;                
  DigitChange();                  
  delayMicroseconds(6000);      
  
  keta2();                    
  DigitNow=Digit2;               
  DigitChange();                
  delayMicroseconds(6000);     
  
  keta1();                    
  DigitNow=Digit1;              
  DigitChange();                  
  delayMicroseconds(6000);         

}

以上です。宣言部、関数部、プログラム本体を つなげてArduinoのスケッチとしてコピーすれば動くと思います。 待ち時間(delayMicroseconds)などの数値は、素子や回路に依存して最適値を 探す必要があるかもしれません。その時には
long WaitMicroSec=6000; //と宣言しておいて
delayMicroseconds(WaitMicroSec) //などと定義するのが良いかもしれません。
関数1と2はまとめて、
case 0: PORTD=B11111100; break;
("0"を表示したい時に、PortDを11111100の出力状態として終わる) などと記述するほうが理解しやすいかもしれません。

15 V電圧(可変三端子レギューレータ)

電源のことを記載し忘れていました。全点灯で40 mA*7*7=2 A程度の 大きな電流が流れますので、少し高い可変の三端子レギュレーターを 選択しました。用いた素子は LM338 (5A 可変レギューレータ)です。 回路はデーターシートに記載された基本回路をそのまま使いました。 R1=1 KΩ,R2=0-10KΩ(可変)とし、入力側に0.1 uFのセラミックコンデンサ、 出力側に大きい(1000 uF)のアルミ電解コンデンサを用いました。 R2の調整で2.5から13.5 V程度を制御できます。15 Vに調整したい場合には R2に直列に4.7 KΩを接続しておけばよいと思います。より安全ですし。 出力側は100 uFで十分な気がしますが、手元に残っていたものを使いました。 電源として16 VのACアダプタを用いました。

距離測定モジュール

最初は単純に時間などを表示する時計やストップウォッチとしての 使用を考えておりました。これですと、Arduinoの時間を表示するだけです。 少し発展性を持たせるために、アナログ入力の 値を表示するシステムに変更いたしました。 今回はシャープの距離測定モジュール GP2Y0A710K0Fを用いて、1〜5 m程度の距離をcm単位で3ケタで表示することとしました。精度はそれほど高くないと考えてみましたが、1 cm単位でほぼ正確に 距離が測定でき、非常に驚きました。高い素子だけのことはあります。 データシートには明記されていませんが、出力された電圧Voutに対して、
y=150/(Vout-1)
によりcm単位の距離が求められます。すなわち、

   ReadVoltage=5.0*double(analogRead(0))/1024.0; 
   //↑analogRead(0端子)を電圧に換算。(5 Vが10bitに分解されていることに注意)
   RealLength=long(150.0/(ReadVoltage-1.0)); 
   //↑上で読んだ電圧を距離(cm単位)に換算。

以上の結果、 センサーから対抗する物体(大きいものである必要があります)までの 距離をリアルタイム(0.1秒ごと)に読み取って大型表示器に表示するシステムが完成いたしました。 16 VのACアダプタで点灯させていますが、単三電池12本で動作することも確認いたしました。


"071 cm"を表示した例。アクリルの半透明パネルをつけると、 非点灯のセグメントは見えなくなるためクリアに数字だけが読み取れます。 写真を撮り忘れてしまいました。すみません。

大型ストップウォッチ(時間表示器、計測器)への改造

Arduinoのプログラムを変更することで、 ストップウォッチに改造して東京マラソンの応援に行きました。 delayMicrosecondsを用いるとタイマーの時間がずれますので 全てdelayのみで書き直しました。 明るいところではあまり目立たなかったようで、来年は 超高輝度のLEDを使ってパネルから自作することを目標にします。 2010年3月7日更新。

宣伝

戸田システムウェア
ここで公開するアイデア/装置は安全性を保障しておりません。 用途に応じた設計を行い、十分な安全検査を行ってからご利用ください。 本サイトの情報の営利目的での利用はご遠慮ください。 本サイトの内容の無断転載を禁じます。© 2009, 2011 TYK