目次
本記事で使用するもの
以下のリンクのスターターキットを購入した場合、上記で述べた使用するものは、PC以外すべて入手することができます。
Arduinoをまだ購入していないという方やArduinoで動かすことができるたくさんのパーツが欲しいという方は、購入を検討してみてください。
7セグメントLEDの説明
7セグメントLEDは、以下の画像のような見た目をした部品で、英数字を表示させるときなどに使用されます。
7セグメントLEDは、7個のLED(ドット表示を入れると8個のLED)を1つの部品にまとめたものであり、それらのLEDの点灯を制御することにより、英数字を表示させることができます。
7セグメントLEDのピンは、それぞれ各LEDと共通で使用される線に繋がっています。
ここで、線の繋がり方は、LEDのカソード側(マイナス側)が共通となっている「カソードコモン」、アノード側(プラス側)が共通となっている「アノードコモン」の2種類があるので注意が必要となります。
本記事では、上記で紹介したスターターキットの中に、入っている「カソードコモン」の7セグメントLEDを使用して説明をしていきたいと思います。
「アノードコモン」の7セグメントLEDをお使いになる方は、これから説明する回路やスケッチを、少し訂正する必要があるので、注意をしてください。
7セグメントLEDを試す
まず初めに、以下の動画のように、7セグメントLEDに0~9の数字とドット( . )を表示させる方法について説明したいと思います。
空のスケッチを書き込む
回路を作成する前に、空のスケッチ(「ファイル」タブの「New Sketch」をクリックしたときに出てくる何の処理も書かれていないスケッチ)を書き込みます。
そうすることにより、前に書き込んだスケッチが、新しく作成しようとしている回路に影響を及ぼすことを防げます。
新しい回路を作成するときは、いつもこの作業をやっておくと、安全に回路を作成することができます。
回路を作成する
以下の回路を作成してください。
上記の回路は「カソードコモン」の7セグメントLEDを使用した場合のものです。
「アノードコモン」のものを使用する場合は、共通の線に繋がるピンを「GNDピン」ではなく、「5Vピン」に接続します。
また、同じ1桁表示の7セグメントLEDでも、ピンの配置が異なる場合がございますので、仕様書などを確認して、それぞれの接続の対応を確認して回路を作成してください。
抵抗器の電気抵抗の高さは、LEDの順電圧と順電流から計算で求めます。
以下に、直列に繋げる抵抗器の電気抵抗の高さを計算するツールを用意しましたので、ご活用ください。
回路で使用する抵抗器は、上記のツールで求めた電気抵抗よりも少し高い電気抵抗のものを使用します。
上記のツールが行っている電気抵抗の計算方法については、以下のリンク先の記事で説明していますので、気になる方はご覧になってください。
ここで、電気抵抗の計算が行えない場合は、電気抵抗が高いもの(大体1[kΩ])から順番に接続していき、ちょうど良い明るさになるものを探していきます。
その際、電気抵抗を低いものにすれば、その分点灯が明るくなるのですが、電気抵抗が低すぎるもの(大体100[Ω]を下回るくらい)の場合、LEDの寿命を縮めてしまったり、破壊してしまったりすることがあるので注意してください。
今回、私は220[Ω]の抵抗器を使用しています。
スケッチを書き込む
回路の作成が終わりましたら、以下のスケッチを書き込んでください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
//LEDに接続しているピン番号 int LED_pin[8]={2,3,4,5,6,7,8,9}; //数字の表示とピンの出力についての関係(0:LOW 1:HIGH) bool Output_0[8]={1,1,1,1,1,1,0,0}; // 0 bool Output_1[8]={0,1,1,0,0,0,0,0}; // 1 bool Output_2[8]={1,1,0,1,1,0,1,0}; // 2 bool Output_3[8]={1,1,1,1,0,0,1,0}; // 3 bool Output_4[8]={0,1,1,0,0,1,1,0}; // 4 bool Output_5[8]={1,0,1,1,0,1,1,0}; // 5 bool Output_6[8]={1,0,1,1,1,1,1,0}; // 6 bool Output_7[8]={1,1,1,0,0,0,0,0}; // 7 bool Output_8[8]={1,1,1,1,1,1,1,0}; // 8 bool Output_9[8]={1,1,1,1,0,1,1,0}; // 9 bool Output_dot[8]={0,0,0,0,0,0,0,1}; // . void setup() { //LEDに繋いだピン(2~9)を出力ピンとして設定する for(int i=0;i<8;i++){ pinMode(LED_pin[i],OUTPUT); } } void loop() { //0を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_0[i]); } delay(500); //1を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_1[i]); } delay(500); //2を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_2[i]); } delay(500); //3を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_3[i]); } delay(500); //4を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_4[i]); } delay(500); //5を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_5[i]); } delay(500); //6を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_6[i]); } delay(500); //7を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_7[i]); } delay(500); //8を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_8[i]); } delay(500); //9を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_9[i]); } delay(500); //ドット(.)を表示 for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_dot[i]); } delay(500); } |
上記のスケッチは「カソードコモン」の7セグメントLEDを使用した場合のものです。
「アノードコモン」のものを使用する場合は、LEDの点灯、消灯と出力の「HIGH」と「LOW」の関係が逆となるため、「bool Output_~[]={~}」の{ }内の「0」と「1」を全て反転させる必要があります。
例:「bool Output_0[]={1,1,1,1,1,1,0,0}」を、「bool Output_0[]={0,0,0,0,0,0,1,1}」のように変更する。
もしくは、「digitalWrite()」の中の「Output_~[i]」の前に「!」を追加し反転させるという方法もあります。
例:「digitalWrite(LED_pin[i],Output_0[i])」を、「digitalWrite(LED_pin[i],!Output_0[i])」のように変更する。
スケッチと回路が正しければ、先程の動画のように、0~9の数字とドット( . )が、一定の間隔で表示されていくのが確認できます。
スケッチの解説
今回行っている処理は、「digitalWrite()」でLEDの点灯を制御しているだけなので、LEDの制御を行ったことがある方にとっては、それほど難しいものではありません。
ただし、スケッチをコンパクトで見やすいものにするために、「配列」というものを使用していますので、その辺りについて、説明していきたいと思います。
ここで、LEDの制御を行ったことが無いという方は、以下のリンク先の記事で、LEDを制御する方法を説明していますので、是非ご覧になってください。
では、今回スケッチで使用した配列について、説明をしていきたいと思います。
「配列」というのは同じ型の要素(変数など)をまとめたものです。
例えば、2行目に記述している「int LED_pin[8]={2,3,4,5,6,7,8,9}」は「int型」の要素(変数)を8個まとめたものとなっています。
宣言した配列の要素には、0から順に番号が割り振られており、読み書きを行う際に割り振られた番号を指定します。
ここで、今回のスケッチの「void setup()」を見てみると、以下のような文が記述されています。
20 21 22 |
for(int i=0;i<8;i++){ pinMode(LED_pin[i],OUTPUT); } |
これは、「for文」と配列を利用して、「LED_pin」に入れた8個の番号のピンを出力ピンとして設定をしています。
上記の文の処理の流れとしては、以下のようになります。
次に「void loop()」内にある、各数字を表示させる文について、説明をしたいと思います。
スケッチの28行目から30行目を見ると以下のような文が記述されています。
1 2 3 |
for(int i=0;i<8;i++){ digitalWrite(LED_pin[i],Output_0[i]); } |
こちらも、「for文」と配列を使うことにより、各ピンの出力を制御しています。
「digitalWrite()」の2番目の引数は、「LOW」、「HIGH」という文字以外にも、「0」、「1」や「false」、「true」などを入れて出力を制御することができます。
今回のスケッチでは、「bool型」の「Output_~[]」という配列を用意して、表示させたい数字に対応するように出力を制御しています。
表示される数字 | 7セグメントLEDの対応 | A | B | C | D | E | F | G | DP |
for文の変数 i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
LED_pin[8] | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
0 | Output_0[8] | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
1 | Output_1[8] | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
2 | Output_2[8] | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 |
3 | Output_3[8] | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 |
4 | Output_4[8] | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 |
5 | Output_5[8] | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 |
6 | Output_6[8] | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 0 |
7 | Output_7[8] | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
8 | Output_8[8] | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
9 | Output_9[8] | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
. | Output_dot[8] | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
よって、「1」から「9」までの数字と「 . 」が、間隔を空けながら順番に表示されるということになります。
シフトレジスタ(74HC595)の説明
次は、シフトレジスタ(74HC595)を使って、7セグメントLEDを制御する方法について説明したいと思います。
シフトレジスタ(74HC595)は、以下の画像のような見た目をした部品で、マイコン側で使用する出力ピンの数を節約したいときなどに使用されます。
シフトレジスタ(74HC595)には、データを受け取るためのピンと出力をするためのピンがあり、受け取ったデータに応じて出力を制御します。
その際、マイコン側は3個の出力で、データを送信することで、8個の出力を制御するといったことができるため、マイコン側は出力ピンの節約ができるということになります。
シフトレジスタ(74HC595)の各ピンの役割は以下のようになっています。
ピンの名称 | ピンの役割 |
VCC | 電源の+(今回は5V) |
GND | 電源の-(GND) |
QA~QH | 出力ピン |
QH‘ | シフトレジスタの最上位ビットの状態を出力(今回は使用しない) |
OE | HIGH:出力を無効 LOW:出力を有効 (今回は出力を常に有効にするためGNDに接続) |
RCLK | 出力の状態を切り替える際に使用するクロック信号を入力 |
SER | 出力を制御するためのデータを入力 |
SRCLK | データを取り込むタイミングを制御するためのクロック信号を入力 |
SRCLR | HIGH:データを保持する LOW:データをクリアする (今回はデータを常に保持するため5Vに接続) |
今回は、Arduinoで3個の出力ピンを制御することにより、シフトレジスタの8個の出力を制御します。
これから行おうと思っているデータの送信と出力の流れは、以下のような感じになります。
ここで、「SER」と「SRCLK」のデータ送信は、「shiftOut()」という関数を使うことにより、簡単に行うことができます。
よって、今回スケッチで行うのは、「shiftOut()」を使った「SER」と「SRCLK」への出力と「digitalWrite」を使った「RCLK」への出力の制御ということになります。
74HC595で7セグメントLEDを制御する
では、以下の動画のようにシフトレジスタ(74HC595)を使って、7セグメントLEDに0~9の数字とドット( . )を表示させる方法について説明したいと思います。
空のスケッチを書き込む
回路を作成する前に、Arduinoに差し込んでいるピンを抜いた状態で、空のスケッチ(「ファイル」タブの「New Sketch」をクリックしたときに出てくる何の処理も書かれていないスケッチ)を書き込みます。
そうすることにより、前に書き込んだスケッチが、新しく作成しようとしている回路に影響を及ぼすことを防げます。
新しい回路を作成するときは、いつもこの作業をやっておくと、安全に回路を作成することができます。
回路を作成する
以下の回路を作成してください。
上記の回路は「カソードコモン」の7セグメントLEDを使用した場合のものです。
「アノードコモン」のものを使用する場合は、共通の線に繋がるピンを「GNDピン」ではなく、「5Vピン」に接続します。
スケッチを書き込む
以下のスケッチを書き込んでください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//SERピンに接続しているピンの番号 int SER=2; //RCLKピンに接続しているピンの番号 int RCLK=3; //SRCLKピンに接続しているピンの番号 int SRCLK=4; //数字の表示とピンの出力についての関係(0:LOW 1:HIGH) byte Output_Num[11]={ B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110, // 8 B11110110, // 9 B00000001 // . }; void setup() { //シフトレジスタに繋いだピンを出力ピンとして設定する pinMode(SER,OUTPUT); pinMode(RCLK,OUTPUT); pinMode(SRCLK,OUTPUT); } void loop() { //0~9の数字とドットを順番に表示する for(int i=0;i<11;i++){ digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[i]); digitalWrite(RCLK,HIGH); delay(500); } } |
上記のスケッチは「カソードコモン」の7セグメントLEDを使用した場合のものです。
「アノードコモン」のものを使用する場合は、LEDの点灯、消灯と出力の「HIGH」と「LOW」の関係が逆となるため、「byte Output_Num[11]」内の「0」と「1」を全て反転させる必要があります。
例:「B11111100」を、「B00000011」のように変更する。
もしくは、「byte Output_Num[11]」内の「B~」の前に「~」を追加し、反転させるという方法もあります。
例:「B11111100」を、「~B11111100」のように変更する。
「~」はビット演算に使用される記号で、全てのビット(「0」と「1」)を反転させることができます。
スケッチと回路が正しければ、先程と同様に、0~9の数字とドット( . )が、一定の間隔で表示されていくのが確認できます。
スケッチの解説
7セグメントに対しての出力は、先程のスケッチと同様ですが、シフトレジスタ(74HC595)を介しているので、出力を制御する方法が異なります。
では、シフトレジスタ(74HC595)の出力を制御している部分について説明したいと思います。
37行目から39行目を見ると以下のような文が記述されています。
37 38 39 |
digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[i]); digitalWrite(RCLK,HIGH); |
これが、上記で説明をした、データの送信と出力の切り替えを行っている部分となります。
処理の内容としては、まず、「RCLK」に接続しているピンの出力を「LOW」にして、その後、「shiftOut()」という関数を使うことで、出力に関わるデータを「SER」、「SRCRK」で送信しています。
そして、最後に、「RCLK」に接続しているピンの出力を「HIGH」にすることによって、出力の切り替えを行い、各数字を表示させているという流れになります。
ここで、「shiftOut()」について、もう少し説明をしたいと思います。
「shiftOut()」の引数は4つあり、それぞれ以下のように指定をします。
今回のスケッチでは、1番目の引数を「SER」、2番目の引数を「SRCRK」に接続したピン番号としています。
また、4番目の引数は配列「Output_Num[i]」とすることにより、繰り返しの回数に応じた1バイト(8ビット)のデータを送信しています。
ここで、3番目の引数は、「LSBFIRST」としています。
3番目の引数は、データを送信する順番を指定するためのもので、今回の場合、送る順番が異なるとシフトレジスタの出力結果が異なります。
「LSBFIRST」でデータを送信した場合と、「MSBFIRST」で送った場合の出力の違いを図にまとめると以下のようになります。
このように、データを送る順番によって、受け取る側が認識するデータは異なってきます。
よって、データを送る順番は、受け取る側の仕様を理解した上で決める必要があるので注意してください。
4桁の7セグメントLEDの説明
続いて、以下の画像のような、4桁の7セグメントLEDを制御する方法について、説明したいと思います。
この7セグメントLEDは、見た目の通り、各LEDを制御することで、4つの英数字を表示させることができます。
よって、使用されるLEDは、8×4で32個なのですが、ピンの数が12本しかありません。
(ピンの数が異なるものの場合は、以下で説明する方法では動作しないと思われますのでご注意ください。)
では、どのようにして、32個のLEDを12本で制御するのか説明したいと思います。
まず、この7セグメントLEDの線の繋がりを確認すると以下のようになっています。
なんと、各桁の「A」~「G」と「D.P.」のLEDがすべて繋がっています。
これでは、一番左の桁に「0」と表示させようとしたときに、他の桁も「0」と表示されてしまうと思われる方もいらっしゃるかもしれませんが、大丈夫です。
各桁の共通の線である「DIG~」を出力ピンに接続することによって、各桁のLEDの点灯を制御することができます。
でも、「1234」のように、別々の数字を同時に表示させるにはどうすれば良いのだろうと思われる方がいらっしゃるかもしれません。
結論を先に述べると、4桁で異なる数字を同時に表示させることはできません。
しかし、4桁で異なる数字を同時に表示させているかのように見せることは可能です。
以下で、4桁の7セグメントLEDを制御する方法と4桁で異なる数字を同時に表示させているかのように見せる方法について、説明をしていきたいと思います。
本記事では、上記で紹介したスターターキットの中に、入っている「カソードコモン」の7セグメントLEDを使用して説明をしていきたいと思います。
「アノードコモン」の7セグメントLEDをお使いになる方は、これから説明するスケッチを、少し訂正する必要があるので、注意をしてください。
「アノードコモン」の場合は、以下のような線の繋がりになっています。
4桁の7セグメントLEDを制御する
では、以下の動画のように、4桁の7セグメントLEDの表示を制御する方法について説明したいと思います。
回路を作成する
以下の回路を作成してください。
ダイナミック点灯を行う4桁の7セグメントは、共通の線も出力ピンに接続して、出力の制御をするため、「カソードコモン」、「アノードコモン」のどちらの場合も同じ回路になります。
ただし、同じ4桁の7セグメントLEDでも内部の配線の仕方が異なる場合がございますので、仕様書などを確認し、上記で説明した配線と一致しているかを確認してください。
ピンの数が異なるものなどは、今回説明する回路やスケッチでは動作しないと思われますので、ご注意ください。
スケッチを書き込む
以下のスケッチを書き込んでください。
ここで、配列「Output_Num」に全ての出力を「LOW」にするための要素を追加しているので、注意してください。
配列の要素を追加する際、要素数の変更や「カンマ( , )」の追加を忘れないように注意してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
//SERピンに接続しているピンの番号 int SER=2; //RCLKピンに接続しているピンの番号 int RCLK=3; //SRCLKピンに接続しているピンの番号 int SRCLK=4; //各桁のLEDの共通の線に接続しているピンの番号 int DIG_1=8; int DIG_2=9; int DIG_3=10; int DIG_4=11; //数字の表示とピンの出力についての関係(0:LOW 1:HIGH) byte Output_Num[12]={ B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110, // 8 B11110110, // 9 B00000001, // . B00000000 // OFF }; void setup() { //シフトレジスタに繋いだピンを出力ピンとして設定する pinMode(SER,OUTPUT); pinMode(RCLK,OUTPUT); pinMode(SRCLK,OUTPUT); //各桁のLEDの共通の線に接続しているピンを出力ピンとして設定する pinMode(DIG_1,OUTPUT); pinMode(DIG_2,OUTPUT); pinMode(DIG_3,OUTPUT); pinMode(DIG_4,OUTPUT); } void loop() { //左の数字から順番に表示を行っていくのを繰り返す for(int i=1;i<=500;i++){ //左から1番目のLEDに1を表示 digitalWrite(DIG_1,LOW); digitalWrite(DIG_2,HIGH); digitalWrite(DIG_3,HIGH); digitalWrite(DIG_4,HIGH); digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[1]); digitalWrite(RCLK,HIGH); delay(2000/i/i+1); //繰り返した回数に応じて待機時間を短くする //切り替えを行う際にLEDを消灯させる digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[11]); digitalWrite(RCLK,HIGH); //左から2番目のLEDに2を表示 digitalWrite(DIG_1,HIGH); digitalWrite(DIG_2,LOW); digitalWrite(DIG_3,HIGH); digitalWrite(DIG_4,HIGH); digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[2]); digitalWrite(RCLK,HIGH); delay(2000/i/i+1); //繰り返した回数に応じて待機時間を短くする //切り替えを行う際にLEDを消灯させる digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[11]); digitalWrite(RCLK,HIGH); //左から3番目のLEDに3を表示 digitalWrite(DIG_1,HIGH); digitalWrite(DIG_2,HIGH); digitalWrite(DIG_3,LOW); digitalWrite(DIG_4,HIGH); digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[3]); digitalWrite(RCLK,HIGH); delay(2000/i/i+1); //繰り返した回数に応じて待機時間を短くする //切り替えを行う際にLEDを消灯させる digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[11]); digitalWrite(RCLK,HIGH); //左から4番目のLEDに4を表示 digitalWrite(DIG_1,HIGH); digitalWrite(DIG_2,HIGH); digitalWrite(DIG_3,HIGH); digitalWrite(DIG_4,LOW); digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[4]); digitalWrite(RCLK,HIGH); delay(2000/i/i+1); //繰り返した回数に応じて待機時間を短くする //切り替えを行う際にLEDを消灯させる digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[11]); digitalWrite(RCLK,HIGH); } } |
上記のスケッチは「カソードコモン」の7セグメントLEDを使用した場合のものです。
「アノードコモン」のものを使用する場合は、LEDの点灯、消灯と出力の「HIGH」と「LOW」の関係が逆となるため、先程と同様に「byte Output_Num[12]」内の「0」と「1」を全て反転させる必要があります。
また、「DIG_~」の「HIGH」と「LOW」についても全て逆になるので、注意してください。
例:「digitalWrite(DIG_1,LOW)」を「digitalWrite(DIG_1,HIGH)」のように変更する。
スケッチと回路が正しければ、先程の動画のように、1~4の数字が、間隔を空けながら表示されていき、最後には4つの数字が同時に表示されているように見えるのが確認できます。
スケッチの解説
今回のスケッチでは、先程のスケッチのような各LEDに対しての出力だけではなく、各桁の共通の線に対しての出力も追加で制御しています。
各桁に数字を表示させる流れは以下の図のようになります。
ここで、各桁のLEDを点灯させる間隔は、「delay(2000/i/i+1)」によって制御しており、「for文」による繰り返し回数が多くなると待機時間は短くなっていきます。
ここで、「2000/i/i」の部分は「int型」なので、計算結果が「1」を下回ると値は「0」となり、「+1」の部分により、「delay(1)」となります。
繰り返した回数と待機時間の関係をグラフにすると以下のようになります。
ここで、後半部分の「1234」が同時に表示されている部分というのは、「delay(1)」の状態で繰り返されている部分になります。
実は、各桁の点灯を切り替えるスピードが速すぎると、人間はそれを目で追うことができなくなります。
よって、待機時間がある値より短くなると、各桁の数字が同時に表示されているように見えるということになります。
カウントした値を4桁の7セグメントLEDで表示する
上記までの説明で、4桁の7セグメントLEDに数字を表示させる方法については、理解していただけたかと思います。
次は、以下の動画のように、4桁の7セグメントLEDに表示させている数値を、時間に応じて変化させる方法について説明したいと思います。
実は、先程説明したダイナミック点灯には、大きな弱点があります。
それは、常にLEDを点灯させる処理を行い続けなければ、4桁の表示を行うことができないというところです。
例えば、1秒ごとに表示されている数値を変化させていくような処理をしようと思い、「void loop()」の中に、delay(1000)などを入れると、LEDの表示が止まってしまうという結果になってしまいます。
また、ダイナミック点灯を行っている速いループの中で、数値を変化させた場合、数値の変化を目で追うことができず、数字が重なって見える現象が生じてしまうので、ある時間以上の間隔を空けながら数値を変化させる必要がでてきます。
(数値の変化が速すぎる場合、先程の動画の1桁目のような感じになります。)
よって、ダイナミック点灯を使用しつつ、数値を変化させるような処理をしたい場合は、タイマ割り込みなどを利用して、4桁の表示を行う処理を邪魔しないように、数値を変化させていく必要があります。
スケッチを書き込む
今回は、「MsTimer2」ライブラリを利用して、0.01秒ごとに表示されている数値を1増やすようなスケッチを、作成します。
「MsTimer2」のインストール方法や使い方については、以下のリンク先の記事で説明していますので、「MsTimer2」を使用したことがないという方は、先に以下のリンク先の記事をご覧になってください。
以下のスケッチを書き込んでください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
//ライブラリの読みこみ #include <MsTimer2.h> //SERピンに接続しているピンの番号 int SER=2; //RCLKピンに接続しているピンの番号 int RCLK=3; //SRCLKピンに接続しているピンの番号 int SRCLK=4; //各桁のLEDの共通の線に接続しているピンの番号 int DIG_1=8; int DIG_2=9; int DIG_3=10; int DIG_4=11; //明るさ調節のdelay()に使用する待機時間 int delay_time=1; //タイマ割り込みが発生するたびに1増える変数 int count=0; //4桁までの数値を4つの数字に分けていれるための配列 volatile int8_t Count_Num[4]; //数字の表示とピンの出力についての関係(0:LOW 1:HIGH) byte Output_Num[12]={ B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110, // 8 B11110110, // 9 B00000001, // . B00000000 // OFF }; void setup() { //シフトレジスタに繋いだピンを出力ピンとして設定する pinMode(SER,OUTPUT); pinMode(RCLK,OUTPUT); pinMode(SRCLK,OUTPUT); //各桁のLEDの共通の線に接続しているピンを出力ピンとして設定する pinMode(DIG_1,OUTPUT); pinMode(DIG_2,OUTPUT); pinMode(DIG_3,OUTPUT); pinMode(DIG_4,OUTPUT); //0.01秒ごとにCount_Upが実行されるように、タイマ割り込みの設定をする MsTimer2::set(10,Count_Up); //タイマ割り込みを開始する MsTimer2::start(); } void loop() { //左から1番目のLEDにcountの4桁目の数字を表示 digitalWrite(DIG_1,LOW); digitalWrite(DIG_2,HIGH); digitalWrite(DIG_3,HIGH); digitalWrite(DIG_4,HIGH); digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[Count_Num[3]]); digitalWrite(RCLK,HIGH); delay(delay_time); //明るさ調節のための待機 //切り替えを行う際にLEDを消灯させる digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[11]); digitalWrite(RCLK,HIGH); //左から2番目のLEDにcountの3桁目の数字を表示 digitalWrite(DIG_1,HIGH); digitalWrite(DIG_2,LOW); digitalWrite(DIG_3,HIGH); digitalWrite(DIG_4,HIGH); digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[Count_Num[2]]); digitalWrite(RCLK,HIGH); delay(delay_time); //明るさ調節のための待機 //切り替えを行う際にLEDを消灯させる digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[11]); digitalWrite(RCLK,HIGH); //左から3番目のLEDにcountの2桁目の数字を表示 digitalWrite(DIG_1,HIGH); digitalWrite(DIG_2,HIGH); digitalWrite(DIG_3,LOW); digitalWrite(DIG_4,HIGH); digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[Count_Num[1]]); digitalWrite(RCLK,HIGH); delay(delay_time); //明るさ調節のための待機 //切り替えを行う際にLEDを消灯させる digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[11]); digitalWrite(RCLK,HIGH); //左から4番目のLEDにcountの1桁目の数字を表示 digitalWrite(DIG_1,HIGH); digitalWrite(DIG_2,HIGH); digitalWrite(DIG_3,HIGH); digitalWrite(DIG_4,LOW); digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[Count_Num[0]]); digitalWrite(RCLK,HIGH); delay(delay_time); //明るさ調節のための待機 //切り替えを行う際にLEDを消灯させる digitalWrite(RCLK,LOW); shiftOut(SER,SRCLK,LSBFIRST,Output_Num[11]); digitalWrite(RCLK,HIGH); } //countの値を1増やし、 void Count_Up(){ //countを1増やす count++; if(count>9999){ count=0; } //countの数値を4つの数字に分けて配列に格納する Count_Num[0]=(count%10); Count_Num[1]=(count/10%10); Count_Num[2]=(count/100%10); Count_Num[3]=(count/1000%10); } |
上記のスケッチは「カソードコモン」の7セグメントLEDを使用した場合のものです。
「アノードコモン」のものを使用する場合は、LEDの点灯、消灯と出力の「HIGH」と「LOW」の関係が逆となるため、先程と同様に「byte Output_Num[12]」内の「0」と「1」を全て反転させる必要があります。
また、「DIG_~」の「HIGH」と「LOW」についても全て逆になるので、注意してください。
スケッチが正しければ、先程の動画のように、一番右の数字は目で追うことができず、数字が重なって見えていますが、表示されている数値が増えていくのが確認できます。
スケッチの解説
「void loop()」内にあるLEDの点灯を制御する部分については、基本的に先程のスケッチと同じです。
明るさ調節のために「delay()」を入れていますが、無くても表示は行うことができます。
ただし、「delay()」が無い場合、LEDが点灯している時間が相対的に短くなるため、LEDの明るさは「delay()」があるときと比べて、若干暗くなります。
「delay()」での待機時間が、長い方がLEDの明るさは明るくなるはずですが、長くしすぎると今度は点滅が気になります。
私の体感ですが、「delay()」と点滅の認識の関係は以下のような感じになります。
どうしても、LEDの明るさが気になる場合は、電気抵抗の小さい抵抗器に変えるなど、抵抗器を調節するほうが良いかもしれません。
ただし、電気抵抗を小さくしすぎて、LEDを破壊しないように注意してください。
表示されている数値は、「MsTimer2」を使い、0.01秒ごとに「Count_Up()」という関数が実行させ、countを1増やしていくことにより変化をさせています。
ただし、countの値を表示させる際には、1桁の数字に分解していく必要があります。
1桁ずつに分解しているのは、145~148行目の以下の文になります。
1 2 3 4 |
Count_Num[0]=(count%10); Count_Num[1]=(count/10%10); Count_Num[2]=(count/100%10); Count_Num[3]=(count/1000%10); |
上記の文は、「count」の値を、1桁ずつ分解して、配列「Count_Num[0]」に格納するという処理を行っています。
処理内容をまとめると以下のようになります。
そして、配列の要素に格納した値を、「void loop()」内にある「Output_Num[]」の要素指定を行う際に利用することにより、「count」に応じた数値を表示させているということになります。
終わりに
皆さん上手く数字を表示させることはできたでしょうか。
今回の最後のスケッチでは、時間に応じて変化する数値の表示を行いましたが、測定にかかる処理時間が短いものであれば、割り込み処理時に呼び出される関数「Count_Up()」の中身を変更することで、一定間隔ごとに、何かを測定して表示させるといったことも可能です。
ただし、一番右の数値は変化が速すぎるせいで、目で追うことができず、数字が重なって見える現象が生じています。
また、右から2番目の目の数値は、目で追うことはできますが、少し読みづらいです。
よって、何かの測定結果を、4桁の7セグメントで表示させる際には、状況によりますが、0.1秒以上は間を空けて、数値を変化させたほうが、良いと考えられます。
数値を変化させるタイミングは、58行目の「MsTimer2::set(10,Count_Up)」の数値を変えることで、変更することができるので、色々と試してみてください。
次回の記事では「チルトスイッチ」の使い方について説明したいと思います。
本記事はここまでです。ご清覧ありがとうございました。
広告
楽天モーションウィジェットとGoogleアドセンス広告です。
気になる商品がございましたら、チェックをしてみてください。