以前にArduinoを使って7セグを表示するプログラムを作成しました。7セグが一つあれば0~9の10通りの数字を表すことができますが、2つ、3つと複数あればより多くの数字を表すことができます。例えば、温度や湿度であれば2つは必要になりますし、時計であれば時分だけでも4つは7セグが必要となります。
そこで、今回は7セグを複数表示する場合の例として、二つの7セグを表示する方法についてご紹介します。
複数の7セグを表示する制御
7セグを表示するには大きく分別してスタティック制御とダイナミック制御を使った表示方法があります。配線の複雑さやマイコンの使用ピン数の削減などを狙いとして分かれています。
スタティック制御
スタティック制御は、7セグの個数分だけ配線をしてそれぞれに対してLEDの点灯・消灯を制御する方式です。直観的でわかりやすいものの7セグの数が増えれば配線も複雑になり、さらにマイコンの使用するポート数が増えます。
例えば、一般的な7セグは下図の通り10ピンあります。この内、7ピン(ドットを含めると8ピン)はArduinoの端子へ接続する必要があります。
7セグが二つになると合計で14ピンをArduinoに接続することになります。
ダイナミック制御
スタティック制御だと圧倒的にマイコンの使用ピンが足りないので、限られたピン数でやりくりする方法としてダイナミック制御があります。これは、高速にLEDが点灯・消灯をしても人間は点灯しているようにしか見えない原理を使っています。
つまり、実際にはひとつの7セグを順番に表示してますが、人の目ではすべての7セグを同時に点灯しているように見えるのです。そのため、スタティック制御と比べてひとつずつ7セグを表示すればよいのでマイコンの使用ピンを大幅に削減することができます。
実際には以下の回路図を見てください。
7セグが2つあるのにも関わらず、Arduinoと7セグのアノードと繋がる線は7本(ドットを合わせて8本)となっています。PD2~PD9からの出力を二つの7セグで共用しています。これにはからくりがあります。
この回路で使用している7セグはカソードコモンを採用しています。それぞれのカソードコモンは1桁目をPD11、2桁目をPD12で制御します。ダイオードですので、カソードコモンの場合はカソード側がLOWになっていなければ電気が流れず、LEDは点灯しません。
そのため、1桁目の7セグのカソードをLOWにして表示し、そのあとHIGHにして非表示にします。続けて2桁目の7セグのカソードをLOWにして表示する流れになります。
カソード側を制御することによって、一つずつ7セグの表示を切り替えているのです。
2つの7セグをダイナミック制御で表示する
ここから2つの7セグをダイナミック制御で表示する回路及びプログラムコードを作成していきます。今回はスイッチを押すと予めプログラムに記述された数値(1と2)を表示・非表示するプログラムとなります。回路の完成図は以下の通りです。
使用した装置及び部品は下表を見てください。
Arduino | 小型コンピュータ搭載のマイコン |
ブレッドボード | 抵抗・ジャンパー線などを使って回路を作る基板 |
7セグ表示器×2 | 0~9の数字を表示できるディスプレイ |
抵抗10kΩ | 電圧を下げる端子 |
抵抗220Ω×8 | 電圧を下げる端子 |
スイッチ | ボタン押下による通電のスイッチ |
ジャンパー線 | 電気を中継する線 |
実際の結線は以下の図を参考にしてください。
プログラムコード
作成したプログラムコードは以下となります。
//ピンの変数宣言
const int pin_SW = 13;//スイッチ
const int pin_disp[] = {2,3,4,5,6,7,8};//7セグ
const int pin_dot = 9;//ドット
const int pin_deg[] = {11,12};//表示する桁位置
//7セグ表示の値
const int disp[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//その他変数
int deg_cnt = 2;//桁数
int disp_num[] = {2,1};//表示する数字
int sw_value;//スイッチの押された状態
int bef_sw_value = 0;//スイッチの押された前回の状態
int disp_status = -1;//ステータス
void setup() {
// put your setup code here, to run once:
//スイッチピンの初期設定
pinMode(pin_SW,INPUT);
//7セグピンの初期設定
for(int i=0;i<7;i++)
{
pinMode(pin_disp[i],OUTPUT);
}
//7セグピンのドットの初期設定
pinMode(pin_dot,OUTPUT);
//表示する桁位置ピンの初期設定
for(int i = 0; i<2;i++)
{
pinMode(pin_deg[i],OUTPUT);
digitalWrite(pin_deg[i],HIGH);//初期値は非表示
}
}
void loop() {
// put your main code here, to run repeatedly:
int loop_value = 0;
//スイッチの押された状態を確認
sw_value = digitalRead(pin_SW);
//スイッチが押された場合
if(bef_sw_value == LOW && sw_value == HIGH)
{
disp_status = disp_status * -1;
delay(100);
}
//スイッチが押されていない場合
else
{
//処理なし
}
bef_sw_value = sw_value;
//スイッチが押されてON状態
if(disp_status > 0){
while(loop_value < deg_cnt)
{
//7セグを描画
for(int i= 0;i < 7;i++)
{
digitalWrite(pin_disp[i],disp[disp_num[loop_value]] & (0x01 << i));
}
digitalWrite(pin_dot,LOW);
//1桁目描画
if(loop_value == 0)
{
digitalWrite(pin_deg[0],LOW);
digitalWrite(pin_deg[1],HIGH);
}
//2桁目描画
else
{
digitalWrite(pin_deg[0],HIGH);
digitalWrite(pin_deg[1],LOW);
}
loop_value++;
delay(5);
}
//スイッチが押されてOFF状態
}else
{
//LEDを非表示
digitalWrite(pin_deg[0],HIGH);
digitalWrite(pin_deg[1],HIGH);
}
}
7セグの表示パターンを16進数で表す
7セグを表示するにはa~gをLOWまたはHIGHにして数字を形成していきます。例えば、「0」を表示するためにはg~aに”0111111″を指定すればいいわけです。(g~aで2進数を並べているのはこの後説明します。)これらを一覧にすると下表になります。
プログラムではdispという配列で予めこれらの16進数が添え字と対応するように宣言しています。
では、実際にどうやって表示しているかというとプログラム中の以下の個所になります。
digitalWrite(pin_disp[i],disp[disp_num[loop_value]] & (0x01 << i));
これは指定した分だけ左にビットシフトし、その数値と表示する数字の積を取っています。例えば、”5″という数字を示したい場合はg~aを表すと”01101101″となります。ここでi = 0の場合は、0x01 << 0 すなわちビットのシフトは発生しませんので”00000001″となります。よって”01101101″ AND “00000001”の結果、1ビット目が1となるため結果はHIGHとなります。
i=1の場合は、0x01 << 1すなわち左に1ビットだけシフトしますので”00000010″となります。よって”01101101″ AND”00000010″の結果、1となるビットは存在しませんので結果はLOWになります。
その他のビットも同様に続きます。
実行結果
実行結果は以下のようになりました。
まとめ
今回は2つの7セグをダイナミック制御で表示する方法をご紹介しました。スタティック制御と比べて配線数が少なくまた、マイコンの使用ピンも少なくて済みます。
しかし、複数の7セグを少ないリソースで表示するために7セグドライバーを使う方法もあります。追々、ご紹介していこうと思います。