• 公開日:2019年10月24日
  • | 更新日:2022年12月01日

化学出身者がマイコンボードでしゃべる挨拶時計をつくってみた(3)~7セグLED~

前回までのあらすじ

 

挨拶時計の仕様が決まり、BeagleBone Black(BBB)のOSとIDEの準備も終わりました。

その後、必要な部品を秋葉原駅周辺で購入し、製作実習の準備が整いました。

それでは7セグLEDを使って時計の表示部分をつくっていきます!

 

時計部分の仕様

 

時計部分の回路図は以下のようになりました。

回路図

7セグデコーダ(TC4511BP)は、使用するBBBのGPIOピンを少なくするために使用しました。

この時、使用したピンは

VDD, LT, BI:P9_03

GND:P9_01

LE:P8_11

A:P8_12

B:P8_13

C:P8_14

D:P8_15

です。

また、トランジスタアレイ(TD62083APG)は基板実装の際にトランジスタをすっきりさせるためと、コレクタ電流を増幅させるために使用しました。この時、使用したピンは

I1:P9_21

I2:P9_22

I3:P9_23

I4:P9_24

です。

今回、カソードコモンLEDを使用しているので、アノードがHighかつカソードがLowになった時LEDが光ります。つまり私の回路では、各数字に対応したセグメントにHighを送り、光らせたい桁のトランジスタがGNDと導通する(Lowになる)ことで7セグLEDが光ります。トランジスタをLowにするためには、トランジスタのベース端子をHighにしてトランジスタをON状態とします。

 

まずは1桁目を表示させよう!

 

まずはプログラミングや配線、各部品の動作確認のために7セグLEDを1桁だけ光らせます。

回路図を見ながらブレッドボード上に各部品を載せ、配線していきます。7セグLEDと7セグデコーダ、トランジスタアレイのピンを間違えないように注意しましょう。私は何度も配線を間違えました。

ボード実装が完成したら、いよいよプログラミングです。動作確認のためカウントアップで数字を表示していきます。数字を表示するために7セグデコーダの真理値表を確認しながらGPIOのHigh / Lowを設定します。

 

引用:https://www.marutsu.co.jp/contents/shop/marutsu/datasheet/TC4511B.pdf

 

BonescriptにはPinMode()やDigitalWrite()などの関数があるので、使用するピンの設定やHigh / Lowの設定は簡単に行えます。これらを使ってプログラムを書いてはデバッグを行い、表示させる各数字のプログラムを書き、カウントアップのプログラムを完成させました。ミスをしつつも、設計通りにどう挿し完成した時は達成感を味わえました。

 

ダイナミック点灯

 

さあ!4桁で動かします!ダイナミック点灯で動かします!

いきなり出てきたダイナミック点灯ってなんだ?ということで説明します。

ダイナミック点灯とは、点灯しているLEDを一定周期で高速に点滅させ、複数の7セグLEDを常時点灯しているように見せる方法です。以下の図で示すように、1桁目だけを点灯させる→すべて消灯→2桁目を点灯→すべて消灯→3桁目…、と桁を変えながら点滅を繰り返します。この方法で1周期(1桁目点灯~4桁目消灯)を10 ms以下で行うことにより、人間の目にはLEDが常に点灯しているように見えます。

 

 

1桁ずつ光らせるためにはトランジスタを使って制御します。光らせたい桁のトランジスタをON状態にし、それ以外はOFF状態にします。トランジスタのON / OFFの切り替えを高速で繰り返すことによりダイナミック点灯を制御することできます。

 

 

さあ4桁で動かすぞ!

 

1桁で組んだ回路を4桁用に組みなおし、プログラミングもダイナミック点灯用に書き直します。

回路を組みながら思ったことが、「配線が多い…。基板実装になったらうまくできるのか?」ということです。実際の配線がこちら。↓↓↓

 

 

7セグLEDの周りがぐちゃぐちゃしてます。配線を間違えていた時に直すのが大変でした。

回路が終わり、プログラムを書きます。ダイナミック点灯を行うので「LEDを点けて消して、桁をずらす」をループさせます。点灯→消灯までの時間を短くしすぎると、LEDがはっきりと光りません。なので“SetInterval()”を使って点灯状態を10 ms程キープしてから消灯に移りました。これも時間がかかりましたがなんとか終了。

しかし問題が発生しました。LEDの表示がちらつきます!原因を調べるためにオシロスコープを使って7セグデコーダの出力波形を測定しました。すると至る所にノイズが入っていました。(10 msほどHighになっているところが本来出力したい波形です。)

 

 

電源からのノイズが原因と考え、パスコンを付け加えましたがノイズは消えません。デバイスの故障も考慮し、新しいものに変えましたがノイズはなくなりませんでした。仕方なく7セグデコーダを諦めてBBBから直接7セグLEDに信号を送ることにしました。その結果、ノイズの入っていないきれいな波形が出力され、ちらつきも無くなりました。

一安心したところでSetInterval()の間隔を短くして、1周期10 ms以下になるようにしました。

そしたらまたまた問題が発生しました…

どれだけSetInterval()の時間を短くしてもLED表示がちらついてダイナミック点灯になりません。

 

SetInterval()ではだめだと思い、delay()を代わりに組み込んでみました。

その時のソースコードが以下です。

 


main.js

var b = require(‘bonescript’);

//7seg初期設定
var MOS1 = ‘P9_21’;
var MOS2 = ‘P9_22’;
var MOS3 = ‘P9_23’;
var MOS4 = ‘P9_24’;
var segA = ‘P8_11’;
var segB = ‘P8_12’;
var segC = ‘P8_13’;
var segD = ‘P8_14’;
var segE = ‘P8_15’;
var segF = ‘P8_16’;
var segG = ‘P8_17’;

var i = 0;
var cathode = [MOS1, MOS2, MOS3, MOS4];
var anode = [segA, segB, segC, segD, segE, segF, segG];
var counts = [1, 1, 2, 3];

//7segダイナミック点灯
for(var x in cathode) { //cathodeをすべてLOWにする(LED消灯)
b.pinMode(cathode[x], b.OUTPUT);
b.digitalWrite(cathode[x], b.LOW);
}

for(var y in anode){ //anodeの表示をBlankにする
b.pinMode(anode[y], b.OUTPUT);
b.digitalWrite(anode[y], b.LOW);
}

//数字の設定
var number0 = function(){
b.digitalWrite(segA, b.HIGH);
b.digitalWrite(segB, b.HIGH);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.HIGH);
b.digitalWrite(segE, b.HIGH);
b.digitalWrite(segF, b.HIGH);
b.digitalWrite(segG, b.LOW);
};

var number1 = function(){
b.digitalWrite(segA, b.LOW);
b.digitalWrite(segB, b.HIGH);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.LOW);
b.digitalWrite(segE, b.LOW);
b.digitalWrite(segF, b.LOW);
b.digitalWrite(segG, b.LOW);
};

var number2 = function(){
b.digitalWrite(segA, b.HIGH);
b.digitalWrite(segB, b.HIGH);
b.digitalWrite(segC, b.LOW);
b.digitalWrite(segD, b.HIGH);
b.digitalWrite(segE, b.HIGH);
b.digitalWrite(segF, b.LOW);
b.digitalWrite(segG, b.HIGH);
};

var number3 = function(){
b.digitalWrite(segA, b.HIGH);
b.digitalWrite(segB, b.HIGH);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.HIGH);
b.digitalWrite(segE, b.LOW);
b.digitalWrite(segF, b.LOW);
b.digitalWrite(segG, b.HIGH);
};

var number4 = function(){
b.digitalWrite(segA, b.LOW);
b.digitalWrite(segB, b.HIGH);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.LOW);
b.digitalWrite(segE, b.LOW);
b.digitalWrite(segF, b.HIGH);
b.digitalWrite(segG, b.HIGH);
};

var number5 = function(){
b.digitalWrite(segA, b.HIGH);
b.digitalWrite(segB, b.LOW);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.HIGH);
b.digitalWrite(segE, b.LOW);
b.digitalWrite(segF, b.HIGH);
b.digitalWrite(segG, b.HIGH);
};

var number6 = function(){
b.digitalWrite(segA, b.HIGH);
b.digitalWrite(segB, b.LOW);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.HIGH);
b.digitalWrite(segE, b.HIGH);
b.digitalWrite(segF, b.HIGH);
b.digitalWrite(segG, b.HIGH);
};

var number7 = function(){
b.digitalWrite(segA, b.HIGH);
b.digitalWrite(segB, b.HIGH);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.LOW);
b.digitalWrite(segE, b.LOW);
b.digitalWrite(segF, b.HIGH);
b.digitalWrite(segG, b.LOW);
};

var number8 = function(){
b.digitalWrite(segA, b.HIGH);
b.digitalWrite(segB, b.HIGH);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.HIGH);
b.digitalWrite(segE, b.HIGH);
b.digitalWrite(segF, b.HIGH);
b.digitalWrite(segG, b.HIGH);
};

var number9 = function(){
b.digitalWrite(segA, b.HIGH);
b.digitalWrite(segB, b.HIGH);
b.digitalWrite(segC, b.HIGH);
b.digitalWrite(segD, b.HIGH);
b.digitalWrite(segE, b.LOW);
b.digitalWrite(segF, b.HIGH);
b.digitalWrite(segG, b.HIGH);
};

//関数設定
//delay関数
function delay(delay_ms){
var nowtime = Date.now();
var timeout = nowtime + delay_ms;
while(nowtime < timeout){
nowtime = Date.now();
}
}

//main関数
main();

function main(){
while(true){
display_number();
delay(2);
ledOff();
}
}

//ダイナミック点灯関数
function display_number(l){ //表示する数字のanodeをHIGHにする
l = n(i);
b.digitalWrite(cathode[l], b.HIGH); //表示する桁のcathodeをHIGHにする
if (counts[l] == 0){
number0();
}else if(counts[l] == 1){
number1();
}else if(counts[l] == 2){
number2();
}else if(counts[l] == 3){
number3();
}else if(counts[l] == 4){
number4();
}else if(counts[l] == 5){
number5();
}else if(counts[l] == 6){
number6();
}else if(counts[l] == 7){
number7();
}else if(counts[l] == 8){
number8();
}else {
number9();
}
}

function ledOff(){
for(var x in cathode) { //cathodeをすべてLOWにする(LED消灯)
b.digitalWrite(cathode[x], b.LOW);
}
for(var y in anode){ //anodeの表示をBlankにする
b.digitalWrite(anode[y], b.LOW);
}
i++; if(i > 3) i = 0; //表示する桁を変更する
};

function n(i){
if(i >= cathode.length) return 0;
else return i;
}

 

頑張ってプログラミングしたのに、これでも早くならない(泣)

動画を撮ってみましたが、こんな感じです。

 

オシロを使って、信号がどのようになっているのか確認します。BBBの出力波形を確認したかったのでトランジスタを取り除き、BBBと7セグLED(13, 14番ピン)を直接つないで出力波形を測定したところ、HighからLowへの切り換わる間隔がバラバラです(この時SetIntervalは1 msに設定)。しかも設定した時間よりはるかに長くなっています。

 

 

この原因はWebブラウザ上でBonescript(Javascript)を実行しているためです。C言語とJavascriptの動作速度を比較した記事があり、この記事によると1000万回の単純for文ループの実行処理時間がC++では38 msだったのに対し、Webブラウザ上でJavascriptを実行した場合では10735 msもかかっています。Javascriptがダイナミック点灯に向いていないことが分かります。

この事実を知るのが遅すぎました。7セグLEDに時間をかけすぎたため、いまからC言語で書く時間がありません。ちらつきは我慢してこれで完成とし、他の機能に移ることにしました。

 

おわりに

 

一から勉強してBonescriptで書くのはとても難しいです。デバッグしては失敗の繰り返しで時間がかかり、やっとつくった時計は表示がちらつく結果になりました。製作実習の期間内にはC言語で書き直すことは難しいので、これは実習後の宿題にしたいと思います。次はRTCに取り掛かります!