できること

第8回 Arduinoで作る簡易百葉箱(その2)。電光掲示板(7セグメントLED)を使って数値を表示。

DSC_0043
今回は前回に引き続き簡易百葉箱を作るその2です。前回は温度センサーを使って気温を取得することができました。
ここでいったん、これから作っていく百葉箱の全体像を把握するため、百葉箱の全体的な仕様をおさらいしてみたいと思います。本来であれば、「作る前に考える」が基本となりますが、Arduinoの場合、手を動かし色々な部品を触りながら拡張していく楽しさもあります。ある程度色々なセンサーが扱えるようになってから「目的のあるものを作成する」という取り組み方もお勧めです。
では、さっそく百葉箱の仕様を考えてみましょう。

今回の電子工作レシピ

完成までの時間目安:60分
必要なパーツ

 

百葉箱の仕様を考える

百葉箱、改めてwikipediaで調べてみます。

百葉箱
百葉箱(ひゃくようそう、ひゃくようばこ)とは、温度計や湿度計を入れ、正確な気温を計測するために設置された(屋根付きの)箱の事である。(引用:wikipedia)

これを見ると一般的に温度計と湿度計が最低限そろっていれば「百葉箱」と言って問題ないようですね。前回で温度センサーは扱えるようになりました。基本的な機能として、あとは湿度計を扱うことができればとりあえず胸を張って「百葉箱作りました!」と言えますね(笑)

では、ここから具体的な完成形をもうちょっとイメージしてみましょう。

どのような百葉箱だと作った時に面白いか?自分がうれしいのか、だれがうれしくなるのか。イメージする百葉箱に今自分が足りないスキルや道具はないか?などを考えながら完成予想図を描いていくと、具体的なイメージが固まってきます。

何か一つ作り上げていく際には、この繰り返しを行っていくことで、作品がどんどんブラッシュアップされていきます。

まず、「どんな百葉箱にしたいか」イメージする時の使い勝手を考えてみます。

 plan
イメージして仕様を固めてみる

 

  1. インターネットを通じてPC上からいつでも数値を確認したい
  2. 色々な所に置きやすいようにPCにつなげなくても独立して動くようにしたい
  3. さらに百葉箱につなぐ線もできるだけ減らしたい(可能であれば全ての線をなくしたい)
  4. PCだけでなく直接数値を確認したい
  5. サイズをコンパクトにしたい

私がこんな百葉箱だと使いやすいと思うのはこんなところでしょうか。
では、上記を実現する為にはどのような実装が必要か考えてみます。

  1. インターネットを通じてPC上からいつでも数値を確認したい
    →イーサネットモジュールなどを利用してLANで百葉箱をつなぐ
  2. 色々な所に置きやすいようにPCにつなげなくても独立して動くようにしたい
    →Arduinoの給電をUSBではなくDCアダプターや電池での給電に変更
  3. さらに百葉箱につなぐ線もできるだけ減らしたい(可能であれば全ての線をなくしたい)
    →上記2の方法で電源コードを減らす、LANケーブルを無線LAN化するなどしてケーブルフリーにする等
  4. PCだけでなく直接数値を確認したい、PC上ではグラフとかで推移を確認したい
    →ディスプレイをつけて本体に数値を表示する等
  5. サイズをコンパクトにしたい
    →ブレッドボードではなく基板に半田付けしてサイズを小さくする、もっと小さいサイズのArdinoを利用する等

という解決策が出てきます。
これまでの連載で既に習得したものと、そうでないものがあるので、一つずつクリアしていきます。

上記項目1は前回で習得しましたね。2と3は、まだやってないので、勉強する必要がありますね。4「PCだけでなく直接数値を確認したい」は、前回ちょっと触れた7セグメントLEDを利用すればできそうですね。「PC上ではグラフとかで推移を確認したい」は、Arduinoよりもどちらかというと、ブラウザ上でどのように表現の課題なので、HTMLなどの知識が必要になりそうですね。
とまあ、製作したいものが決まったら、それに対して一歩一歩仕様を詰めて、計画を立て取り組んでいくことで、より具体的に完成が見えてきます。
今回は、上記の中で4「PCだけでなく直接数値を確認する」の7セグメントLEDの使い方を覚えたいと思います。

7セグメントLEDとは?

Arduino上でアナログ入力の数値などのデータを表示させる方法はいくつかあります。今回は前回触れた7セグメントLEDについてちょっと詳しく見ていきます。

2014-08-29 05.10.12
7セグメントLED

7セグLED裏面
7セグメントLEDの裏側

7セグメントLED(以下「7セグLED」)は、数値のパネルに基づいてLEDが配置している部品です。数値を表現する7つのLEDとドットを表現するための1つのLED合計 8つのLEDがあります。今回は1桁のものを組み合わせて利用しますが、2桁や4桁等、複数組み合ったものもあります。7セグLEDは、身近なところだと自販機等でよく見るのではないでしょうか?(最近全てタッチパネルの自販機が増えてきていますが・・・汗)7セグLEDは、表示がわかりやすい、部品の耐久性が高いことから悪条件でも比較的安定して利用することができます。

7セグメントLEDの構成

7セグLEDは、「アノードコモン」と「カソードコモン」の2種類のタイプがあります。それぞれの違いは、アノード(+極)が共通(コモン=common)のもの、カソード(-極/GND側)が共通のものになります。LEDには向きがありますのでアノード、カソードを間違って配線すると表示されません。

今回は「カソードコモン」タイプの7セグLEDを利用します。

7セグメントLEDの構造・仕様
7セグメントLEDの構成

 

0から9までを表現するために

部品はa〜gそしてドットのDPからなるLEDで構成されていることが上の図でわかります。このLEDを光らせたり消したりすることで数値などを表現することができます。0から9まで表示する場合の見取り図を表です。表の数字は「1」は、電流を流す「0」は、電流を流さないという意味です。この表はあとでプログラムでも利用します。

7セグLEDで数字を表現
0から9までの7セグメントLEDのオン1/オフ0の表

例として「1」を表現する場合は、下記のようにb,cに対して電流を流してやることで表現ができます。

11を表現する場合

7セグLEDはその名の通りLEDなので抵抗器を回路の途中に挟みます。
Arduinoで利用する場合は、下記のような回路となります。

n_01

//
// 7セグメントLEDで1を光らせるプログラム
//
void setup(){
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
}
void loop(){
digitalWrite(2,HIGH);
digitalWrite(3,HIGH);
delay(200);
digitalWrite(2,LOW);
digitalWrite(3,LOW);
delay(200);
}

これで何となく使い方がわかってきましたでしょうか?
次に7セグLEDで0から9までを表示する回路を作ります。かなり配線が多くなってしまいますね。

7segmentLEDSingle010から9までを表示する為の回路

デジタルアウト28番ピンそれぞれを制御することで指定のLEDを光らせることができます。実際は、Arduinoで利用する場合はちょっと使いにくいので、0から9までカウントアップしたプログラムを考えてみます。

void loop(){
//0
digitalWrite(2,HIGH);
digitalWrite(3,HIGH);
digitalWrite(4,HIGH);
digitalWrite(5,HIGH);
digitalWrite(6,HIGH);
digitalWrite(7,HIGH);
//一旦全てオフ
digitalWrite(2,LOW);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,LOW);
digitalWrite(8,LOW);
//1
digitalWrite(3,HIGH);
digitalWrite(4,HIGH);
//一旦全てオフ
digitalWrite(2,LOW);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,LOW);
digitalWrite(8,LOW);
….

0から9までカウントするだけでもloop処理の中が、とても長いプログラムになってしまいますね。これをもう少し短いコードにしたいです。数字を渡すと7セグLEDに表示されるような使い方が、できる関数を用意すると手軽ですよね。

NumPrint(数字を指定); //7セグメントLEDに指定した数字を表示

先ほどの表を使って便利な関数を作成してみます。

//数値表示用の配列を定義
boolean Num_Array[10][7]={
{1,1,1,1,1,1,0}, //0
{0,1,1,0,0,0,0}, //1
{1,1,0,1,1,0,1}, //2
{1,1,1,1,0,0,1}, //3
{0,1,1,0,0,1,1}, //4
{1,0,1,1,0,1,1}, //5
{1,0,1,1,1,1,1}, //6
{1,1,1,0,0,1,0}, //7
{1,1,1,1,1,1,1}, //8
{1,1,1,1,0,1,1} //9
};
//LED表示関数を定義
void NumPrint(int Number){
for (int w=0; w<=7; w++){
digitalWrite(w+2,-Num_Array[Number][w]);
}
}

NumPrint関数はNum_Arrayに数値のパターンを全て定義しています。この定義に基づいて、7セグLEDの7個のLEDを制御して数値を手軽に表示することができます。
この関数を使ったプログラムの例が以下になります。0から9までカウントアップしていきます。

 

//
// 7セグメントLEDで0から9までを光らせるプログラム
//
void setup(){
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
}
//LEDレイアウトを定義
boolean Num_Array[10][7]={
{1,1,1,1,1,1,0}, //0
{0,1,1,0,0,0,0}, //1
{1,1,0,1,1,0,1}, //2
{1,1,1,1,0,0,1}, //3
{0,1,1,0,0,1,1}, //4
{1,0,1,1,0,1,1}, //5
{1,0,1,1,1,1,1}, //6
{1,1,1,0,0,1,0}, //7
{1,1,1,1,1,1,1}, //8
{1,1,1,1,0,1,1} //9
};
//LED表示関数を定義
void NumPrint(int Number){
for (int w=0; w<=7; w++){
digitalWrite(w+2,-Num_Array[Number][w]);
}
}
//全てのLEDを非表示にする
void off7SegLED(){
digitalWrite(2,LOW);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,LOW);
digitalWrite(8,LOW);
}
void loop(){
NumPrint(0);
delay(2000);
off7SegLED();
delay(50);
NumPrint(1);
delay(2000);
off7SegLED();
delay(50);
NumPrint(2);
delay(2000);
off7SegLED();
delay(50);
NumPrint(3);
delay(2000);
off7SegLED();
delay(50);
NumPrint(4);
delay(2000);
off7SegLED();
delay(50);
NumPrint(5);
delay(2000);
off7SegLED();
delay(50);
NumPrint(6);
delay(2000);
off7SegLED();
delay(50);
NumPrint(7);
delay(2000);
off7SegLED();
delay(50);
NumPrint(8);
delay(2000);
off7SegLED();
delay(50);
NumPrint(9);
delay(2000);
off7SegLED();
delay(50);
}

0から9まで光りました!
このプログラム、まだちょっと同じような記述がだらだらと続いている感じがします。loop()内の処理が単純に0から9まで増えて、また戻るような処理なので、for文を使ってまとめることができます。さらに、setup()内のデジタル出力ピンの宣言とLEDを非表示にするoff7SegLED()の処理も一緒にまとめてしまいます。

//
// 7セグメントLEDで0から9までを光らせるプログラム
//
void setup(){
//for文で2番ピンから8番ピンまでを利用宣言
 for(int i=2;i<9;i++){
 pinMode(i,OUTPUT);
 }
}
//LEDレイアウトを定義
boolean Num_Array[10][7]={
{1,1,1,1,1,1,0}, //0
{0,1,1,0,0,0,0}, //1
{1,1,0,1,1,0,1}, //2
{1,1,1,1,0,0,1}, //3
{0,1,1,0,0,1,1}, //4
{1,0,1,1,0,1,1}, //5
{1,0,1,1,1,1,1}, //6
{1,1,1,0,0,1,0}, //7
{1,1,1,1,1,1,1}, //8
{1,1,1,1,0,1,1} //9
};
//LED表示関数を定義
void NumPrint(int Number){
for (int w=0; w<=7; w++){
digitalWrite(w+2,-Num_Array[Number][w]);
}
}
//全てのLEDを非表示にする
void off7SegLED(){
//for文で2番ピンから8番ピンまでをLOWにする
 for(int i=2;i<9;i++){
 digitalWrite(i,LOW);
 }
}
void loop(){
//for文で0から9までをカウント
 for(int i=0;i<10;i++){
 NumPrint(i);
 delay(2000);
 off7SegLED();
 delay(50);
 }
}

これでだいぶプログラムがすっきりしましたね!

カウントアップの速度を上げたい場合、長いままのプログラムだと複数箇所のdelayの数値を修正が必要です。for文でまとめると一カ所変更するだけで可能になります。このようにプログラムをまとめていく処理は、今後も重要になっていきますので、できる限り癖をつけるようにするのがお勧めです。

 

2桁の表示をしてみる

1桁の表示についてはこれでできるようになりました。次は2桁の表示をします。単純に考えると、1桁の表示では2〜8番ピンを利用したので、2桁の表示はもう1つ同じように回路を作成して残りのピン(0,1,9,10,11,12,13)を利用すれば実装することが可能です。

ただ、その場合だと、1桁でも配線が多くなってしまったので、さらに配線が増えてしますのが目に見えていますね(苦笑)。そこで、電子工作の工夫とでもいいますか、先人の知恵とでもいいますか、人間の目の錯覚を利用します。

人間の目はものすごく早く点滅するものを連続した映像として感じます。テレビや映画などは1秒間に30枚、24枚の画像が連続して切り替わることで一連の動きのある映像として認識しています。この目のしくみを利用して2桁の表示では、交互に高速で表示を切り替えることで手軽に表示を行うことができます。

回路の方はどうでしょうか?1桁の回路に比較的簡単に手を加えることで2桁の表示もできます。

7segmentLEDDouble17
2桁の為の表示回路

 

1桁の時と違い、もう一つ7セグLEDが増えたので、抵抗器から2つの7セグLEDに同じように配線を行います。さらに、もう一つ違うのがGNDの接続箇所です。1桁の時はArduinoのGNDに接続していましたが、今回11番、13番ピンに接続していますね。あれ?これって大丈夫なの?と思われるかもしれません。ちょっと頭が混乱しますが、改めてデジタル出力のHIGHとLOWについて考えてみます。

HIGHの状態は、Arduinoから5Vの電圧の電気が流れます。ではLOWはというと、0Vの電圧の電気が流れます。0V?この0Vというのは実質電気が流れていない状態=GNDと同じ状態なのです。

今回2桁の表示を行うために、11番、13番ピンを交互をオン・オフすることで表示の切り替えを行います。

//
// 2桁の7セグメントLEDを光らせるプログラム
//
int _cnt = 0; //
int _number = 0; //
boolean _flg = false;
void setup(){
Serial.begin(9600);
//2~8番ピン デジタル出力へセット
for (int i=2; i<=8; i++){
pinMode(i,OUTPUT);
}
pinMode(13,OUTPUT);
pinMode(11,OUTPUT);
}
//LEDレイアウトを定義
boolean Num_Array[10][7]={
{1,1,1,1,1,1,0}, //0
{0,1,1,0,0,0,0}, //1
{1,1,0,1,1,0,1}, //2
{1,1,1,1,0,0,1}, //3
{0,1,1,0,0,1,1}, //4
{1,0,1,1,0,1,1}, //5
{1,0,1,1,1,1,1}, //6
{1,1,1,0,0,1,0}, //7
{1,1,1,1,1,1,1}, //8
{1,1,1,1,0,1,1} //9
};
//LED表示関数を定義
void NumPrint(int Number){
for (int w=0; w<=7; w++){
digitalWrite(w+2,-Num_Array[Number][w]);
}
}
//2桁をそれぞれの桁で分解する関数
int NumParse(int Number,int s){
if(s == 1){
return Number % 10; //10で割ったあまり = 一桁目の値
}
else if(s == 2){
return Number / 10; //10で割った値を整数にする = 二桁目の値
}
return 0;
}
void loop(){
if(_number >= 100){
_number = 0;
}
//flg変数をtrue / falseを切り替えることで11番13番ピンの出力を交互に切り替える
if(_flg){
digitalWrite(11,LOW);
digitalWrite(13,HIGH);
_flg = false;
NumPrint(NumParse(_number,1)); //1桁目の表示
}
else{
digitalWrite(11,HIGH);
digitalWrite(13,LOW);
_flg = true;
NumPrint(NumParse(_number,2)); //2桁目の表示
}
//100まで行ったら表示する数値(_number)を1つ足す(実質delayの10×100で1秒に1カウント)
if(_cnt >= 100){
_number++;
_cnt = 0;
Serial.print("NUMBER:");
Serial.println(_number);
}
_cnt++;
delay(10);
}

これで2桁の表示もできましたね!

プログラムではいくつか関数が増えていますが、基本的に使っている処理は簡単な演算を元にしています。2桁の数値からそれぞれの桁数の数値を抜き出す処理は、今回紹介した方法以外にも色々ありますので、興味のある方は検索して調べてみてください。

記事の最初の方で決めた仕様に関して、まだ触っていない湿度センサーの使い方と、残りは2,3の項目をクリアすることができればあとはケースなどを含めて外装の5を経て簡易百葉箱が完成できそうです。

  1. インターネットを通じてPC上からいつでも数値を確認したい
  2. 色々な所に置きやすいようにPCにつなげなくても独立して動くようにしたい
  3. さらに百葉箱につなぐ線もできるだけ減らしたい(可能であれば全ての線をなくしたい)
  4. PCだけでなく直接数値を確認したい
  5. サイズをコンパクトにしたい

次回は、これまでPCに接続しているArduinoを電池やDCアダプターを使って動かし、湿度センサーの使い方を学んで一気に完成へ進みたいと思います!

 

アバター画像

電子工作や新しいデバイスをこよなく愛するエンジニア。日常生活のちょっとしたことを電子工作で作って試して、おもしろく過ごしたいと日々考えています。

高専ロボコン2019出場ロボット解剖計画