Arduinoで複数桁の7セグメントLEDを使う
原理
端子数が…
以前、Arduinoで7セグメントLEDを制御し、数字を表示する実験を行いました。7セグメントLEDは数字を表示するために7つのLED(小数点も表示する場合は8つのLED)を使用しますが、それぞれのLEDをArduinoの出力ポートに接続し、点灯・消灯を行うという簡単な原理でした。
今回は、7セグメントLEDの桁数を増やしてみましょう。1桁分の制御に7ないし8の出力ポートが必要ですが、Arduinoではデジタル入出力端子が14ありますが、一部は通信用端子も兼用しているため、実質的には12程度しか使用できません。しかし7セグメントLEDを2桁使用したい場合は14~16の出力ポートが必要になるため、不足してしまいます。
そこで、必要なデジタル出力端子の数を減らすための工夫が必要となります。
ダイナミック点灯
LEDを制御するのに必要な端子数を減らすための工夫として、今回はダイナミック点灯という手法を使用します。
ダイナミック点灯で7セグメントLEDを4桁制御するには、たとえば数のように接続します。
まず、4つの7セグメントLEDのa~g(小数点を使う場合はdpも)は、同じセグメントごとにArduinoの同じデジタル出力端子につないでしまいます。たとえば4つの7セグメントLEDのa端子はすべて電流制限抵抗Rを経由してArduinoのD2に接続します。
次に、各7セグメントLEDのcommon端子を、それぞれArduinoの別々のデジタル出力端子に接続します。
この配線でD2~D8に表示パターンを出力し(a~gのうち点灯したいセグメントをHIGH)、D9~D12のうちD9のみLOW、他をHIGHにすると、DIG1の7セグメントLEDにのみパターンが表示されます。つまり、D2~D8で表示パターンを設定し、D9~D12で表示する桁を設定できるのです。
これで、DIG1~DIG4のうち1桁ずつの表示ですが、表示桁を高速で切り替えながら繰り返し表示していくと、人間の目には4桁が表示されているように見えるのです。
このような表示方法をダイナミック点灯といいます。
製作・実行
回路
では、具体的な回路を設計しましょう。今回からはR4対応も考え、デジタル出力端子の電流が8mA未満になるように設計します。LEDがちょっと暗くなりそうですが…。
回路は以下のようにしました。原理解説とは違い、桁選択部分にトランジスタを追加しています。
アノード(a~g、dp)側電流制限抵抗
まずD2~D8に接続されている電流制限抵抗ですが、これらの抵抗には一度に最大LED1つ分の電流が流れます。この電流を8mA以下にします。Arduinoのデジタル出力端子のHIGH電圧を5.0V、手元の7セグメントLEDの順方向電圧降下は1.8Vなので、LEDに流れる電流を\(I\)、電流制限抵抗の抵抗値を\(R\)とすると
\[I=\frac{5.0-1.8}{R}<8\times 10^{-3}\]
\[\frac{5.0-1.8}{8\times 10^{-3}}=400< R\]
というわけで抵抗値が400Ωより大きな抵抗が必要になります。今回は安全のため470Ωとしました。
カソード(common)側
問題はカソード側です。カソード側には7つのLEDが接続されるので、最大8×7=56mAが流れる可能性があります。これではArduinoの定格を超えてしまい、破損の恐れがあります。
そこで、トランジスタを使ってスイッチングすることにします。
トランジスタはベース電流が流れるとコレクタ~エミッタ間に電流が流れるようになります。よって、原理の説明の項とは逆に、桁選択端子D9~D12のうちHIGHの桁が表示されるようになります。
使用部品
今回使用した部品は以下の通りです。
7セグメントLED
今回使用したのは、7セグメントLED×4桁の5461ASという製品ですが、特にこのメーカー・この型番にはこだわりがありません。コモンカソード、LED1つあたりIF(標準電流)=10mA、VF(順方向電圧降下)=1.8Vという標準的な仕様なので、似たような4桁7セグメントLEDならだいたい使用できます。
※コモンアノードの場合は回路もプログラムも変更する必要があります。
※IFが違っても暗くなったりするだけで回路はそのまま使えます。
※VFが小さい場合は電流制限抵抗の値を大きくする必要があります。
※違う型番だと端子配置が違うかもしれませんのでデータシートで確認してください。LEDの数は同じなのに16端子あるものなど、端子配置はいろいろあります。
トランジスタ
コモンカソードをArduinoの出力端子に直接接続するとArduinoの端子電流定格を超えてしまうため、スイッチングにトランジスタを使用します。今回は入手しやすい 2SC1815 を使用しました。
2SC1815はNPN型バイポーラトランジスタで、高周波増幅・スイッチング用によく使用されています。最大150mAの電流をスイッチングできるので今回の回路には十分です。放熱も特に必要ありません。
また価格も20本入りパックが100円(1つ5円!)と安価で、入手しやすいです。
※価格は秋月電子通商、2024年7月時点
トランジスタの回路記号は以下の通りです。3つの端子の名前はベース(B)、エミッタ(E)、コレクタ(C)といいます。
ピン配列は以下の通りです。
※このタイプのトランジスタはだいたい同じピン配列です。『向かい合って、左からエクボ(ECB)』とすると憶えやすいです。
抵抗器
これも入手しやすい炭素皮膜抵抗1/4Wのもので大丈夫です。100本パックが100~150円程度と非常に安価です(1本1円!)。
※価格は秋月電子通商、2024年7月時点
配線
配線図
今回はジャンパ線が多いので注意して配線してください。ジャンパ線の色自体には意味はありません。図の上で辿り易いように隣接するジャンパ線を違う色にしているだけです。
作ってからアノード側とカソード側の配線を左右逆にした方が見やすかったかも…と気づきましたが後の祭り(苦笑
実際の配線例
…すみませんグチャグチャです(汗
プログラム
ソースコード
// Arduinoの出力端子指定
int segPin[7]={2,3,4,5,6,7,8};
int digPin[4]={9,10,11,12};
// 数字の点灯パターン
int pattern[10][7]={{HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW}, // 0
{LOW,HIGH,HIGH,LOW,LOW,LOW,LOW}, // 1
{HIGH,HIGH,LOW,HIGH,HIGH,LOW,HIGH}, // 2
{HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}, // 3
{LOW,HIGH,HIGH,LOW,LOW,HIGH,HIGH}, // 4
{HIGH,LOW,HIGH,HIGH,LOW,HIGH,HIGH}, // 5
{HIGH,LOW,HIGH,HIGH,HIGH,HIGH,HIGH}, // 6
{HIGH,HIGH,HIGH,LOW,LOW,LOW,LOW}, // 7
{HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH}, // 8
{HIGH,HIGH,HIGH,HIGH,LOW,HIGH,HIGH}}; // 9
// 表示内容
int text[4]={1,2,3,4};
void setup() {
// 関係する端子をすべて出力に設定、すべてのLEDを消灯
for(int i=0; i<7; i++){
pinMode(segPin[i], OUTPUT);
digitalWrite(segPin[i], LOW);
}
for(int i=0; i<4; i++){
pinMode(digPin[i], OUTPUT);
digitalWrite(digPin[i], LOW);
}
}
void loop() {
for(int i=0; i<4; i++){
// SEG各端子をi桁目の点灯パターンにセット
for(int j=0; j<7; j++){
digitalWrite(segPin[j], pattern[text[i]][j]);
}
// i桁目の7セグメントLEDを点灯
digitalWrite(digPin[i], HIGH);
delay(100);
// i桁目の7セグメントLEDを消灯
digitalWrite(digPin[i], LOW);
}
}
プログラム解説
端子の設定
// Arduinoの出力端子指定
int segPin[7]={2,3,4,5,6,7,8};
int digPin[4]={9,10,11,12};
最初にArduinoのどの端子がどの役割かを設定しています。
配列segPin[]は7セグメントLEDのセグメントa~セグメントgと対応、
配列digPin[]はDIG1(1桁目)~DIG4(4桁目)と対応しています。
数字点灯パターン
// 数字の点灯パターン
int pattern[10][7]={{HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,LOW}, // 0
{LOW,HIGH,HIGH,LOW,LOW,LOW,LOW}, // 1
{HIGH,HIGH,LOW,HIGH,HIGH,LOW,HIGH}, // 2
{HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}, // 3
{LOW,HIGH,HIGH,LOW,LOW,HIGH,HIGH}, // 4
{HIGH,LOW,HIGH,HIGH,LOW,HIGH,HIGH}, // 5
{HIGH,LOW,HIGH,HIGH,HIGH,HIGH,HIGH}, // 6
{HIGH,HIGH,HIGH,LOW,LOW,LOW,LOW}, // 7
{HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH}, // 8
{HIGH,HIGH,HIGH,HIGH,LOW,HIGH,HIGH}}; // 9
数字と7セグメントLEDの各セグメントの点灯パターンとの対応です。HIGHが点灯、LOWが消灯で、セグメントa~セグメントgの順に並んでいます。
表示内容
// 表示内容
int text[4]={1,2,3,4};
7セグメントLEDに表示する内容です。とりあえず『1234』と表示するようにしてあります。
初期設定(setup()関数)
void setup() {
// 関係する端子をすべて出力に設定、すべてのLEDを消灯
for(int i=0; i<7; i++){
pinMode(segPin[i], OUTPUT);
digitalWrite(segPin[i], LOW);
}
for(int i=0; i<4; i++){
pinMode(digPin[i], OUTPUT);
digitalWrite(digPin[i], LOW);
}
}
初期設定では segPin[] および digPin[] で設定された端子をすべて出力モード・LOWを出力(消灯)に設定しています。
表示(loopt()関数)
今回はダイナミック点灯の実験のため、loop()の中でダイナミック点灯のための制御をしています。実用上はタイマ割り込みで制御するようなライブラリを作ることになるでしょう。
1桁目~4桁目を順に点灯
void loop() {
for(int i=0; i<4; i++){
// SEG各端子をi桁目の点灯パターンにセット
for(int j=0; j<7; j++){
digitalWrite(segPin[j], pattern[text[i]][j]);
}
// i桁目の7セグメントLEDを点灯
digitalWrite(digPin[i], HIGH);
delay(100);
// i桁目の7セグメントLEDを消灯
digitalWrite(digPin[i], LOW);
}
}
forループで、1桁目~4桁目について順に処理しています。
void loop() {
for(int i=0; i<4; i++){
// SEG各端子をi桁目の点灯パターンにセット
for(int j=0; j<7; j++){
digitalWrite(segPin[j], pattern[text[i]][j]);
}
// i桁目の7セグメントLEDを点灯
digitalWrite(digPin[i], HIGH);
delay(100);
// i桁目の7セグメントLEDを消灯
digitalWrite(digPin[i], LOW);
}
}
セグメントa~セグメントgに、i桁目の点灯/消灯情報をセットします。
この時点では digPin[] がすべてLOWのため、まだLEDは点灯しません。
1桁の点灯~消灯
void loop() {
for(int i=0; i<4; i++){
// SEG各端子をi桁目の点灯パターンにセット
for(int j=0; j<7; j++){
digitalWrite(segPin[j], pattern[text[i]][j]);
}
// i桁目の7セグメントLEDを点灯
digitalWrite(digPin[i], HIGH);
delay(100);
// i桁目の7セグメントLEDを消灯
digitalWrite(digPin[i], LOW);
}
}
i桁目を点灯し、少し待ってから消灯します。消灯後はループの次の回(次の桁)の処理になります。delay()による待ち時間をどの程度にすればよいかは、次の項で試してみます。
実行結果
待ち時間:100ms
まずは1桁ずつ順次点灯しているという原理がはっきり判るように、delay()の待ち時間を長めの100msに設定してみます。
このスピードだと1桁ずつ順次点灯しているのがはっきり判ります。
待ち時間:10ms
待ち時間を一気に1/10の10msにしました。4桁表示するのに40ms、1秒に25回のループなので、テレビ放送より若干フレームレートが低い程度と考えられるでしょうか。
1桁ずつの点灯を目で追うことは出来ませんが、少々のちらつきが感じられます。
待ち時間:5ms
待ち時間をさらに半分の5msにしました。
動画だと多少のちらつきがありますが、肉眼ではほとんど気にならないレベルです。
待ち時間:2ms
さらに待ち時間を短く、2msにしてみました。
肉眼では完全に4桁が同時に連続点灯しているように見えます。動画でもほぼちらつきが感じられなくなりました。
まとめ
- Arduinoの出力端子では足りないほどのLEDを制御するのに、ダイナミック点灯という方法がある
- 桁制御には大きな電流が流れるので、トランジスタなどのスイッチング素子が必要
コメント