【電子工作】2-1.Arduinoで砂時計を作ろう
これまでの学習の結果、
前回の1-5で、4桁の7セグLEDを使えるようになりました。
今回は、さらに応用して砂時計を作ってみたいと思います。
砂時計と、大それたことを書いていますが、
砂時計を作るには、時間の計算方法を学習する必要があります。
今回2-1では、1-5で学習した7セグ表示方法が
実用処理としては使い物にならない
ということを学んでください。
今回も使用する回路は1-5と同じです。
L1-5で作成したコードのメインループはこんな感じでした。
※主要部抜粋
// delay(ms) /
const int TIMER_DELAY = 5;
/* Mail loop 通常処理(繰り返し) */
void loop() {
/* TIMER_DELAYごとに各桁を表示 */
zero();
Keta1();
delay(TIMER_DELAY); // 5ms wait
one();
Keta2();
delay(TIMER_DELAY); // 5ms wait
two();
Keta3();
delay(TIMER_DELAY); // 5ms wait
three();
Keta4();
delay(TIMER_DELAY); // 5ms wait
}
1桁を、5msdelay()による待ち処理 を行うことで表示させています(黄色背景の箇所)
loop() 内では、4桁を表示をさせるために4回のdelay()による待ち処理 を行っています。
というわけで、
1ループするためには、20msかかっている ことになります。
そうすると、
ループを5回行うことで100ms
ループを50回表示させたら、1秒になりますね。
何だ簡単!
というわけで、
loop内でカウンター(変数)を数えてあげれば、砂時計ができちゃいますね!
ついでなので、小数点を付けて、100ms単位を表示してみましょう
◆回路
回路は、前回1-5と全く一緒です。
↓の写真をみて、頑張って接続してください。
◆スケッチ(コード)
※コードは、日記の最後に書いています。
デジタル出力は、前回と同様の方法です。
後で、コードを書き込んでみてね
それでは、Arduinoに書き込んで動かしてみましょう。
数字の 0.1の桁 に、100msの時間を表示 して 、5ms待機
(小数点を表示)
数字の 1の桁 に、1000msの時間を表示 して 、5ms待機
(小数点を非表示)
数字の 10の桁 に、10000msの時間を表示 して 、5ms待機
数字の 100の桁 に、100000msの時間を表示 して 、5ms待機
どうでしょうか?
人間の見た目では、
0.1秒単位で表示ができていますね。
か~んたん!
本当?
よく見てください。
本当に1秒ずつカウントできていますか?
じつは、この時計はあまり正確ではありません。
これは人間の感覚では、
ダイタイ0.1秒 単位で砂時計表示できている
なのです。
厳密には、0.1秒ではない 時間で砂時計をカウントしていることになります。
証拠ですが、
7セグの桁を切り替え表示するために使っているD0~D3の切り替わるタイミングを
ロジックアナライザー で、正確な時間を計測してみましょう。
10回分の設計値として200ms 相当にかかっている時間は、203.3ms であり、
1秒 間に直すと、誤差として16.66ms ずつずれているのです。
なぜでしょうか?
原因は、先ほど記載した処理のうち、
以下の紫 の処理にかかっている時間です。
(もっと厳密には、loop()外の時間とかもあると思います。)
------------------------------------------------
数字の 0.1の桁 に、100msの時間を表示 して 、5ms待機
(小数点を表示)
数字の 1の桁 に、1000msの時間を表示 して 、5ms待機
(小数点を非表示)
数字の 10の桁 に、10000msの時間を表示 して 、5ms待機
数字の 100の桁 に、100000msの時間を表示 して 、5ms待機
------------------------------------------------
待ち時間の合計は確かに20msですが、実処理は20.33ms消費してるのですね。
というわけで、砂時計失敗です。
次回、別の方法を記載します。
次回は、delayMicroseconds()を使ってみましょう。
雑談
学生が良く書いてしまうコードですね。
何気に、RTOSを使用した組み込みでも
非同期 x 秒呼び出し処理でも、
何気に呼び出し前の処理に時間食ったあげくに、
秒が更新周期(FPS)が落ちているという不具合を見つけたことがあります。
エクセルとか、パソコン上で使うおもちゃやゲームなら描画処理が遅いとかで済みますが、
組み込み系でこんなことされたら、最悪ウォッチドグが弾けます。
SAIは、OSなしのマイコンで割り込み処理を使ったロボットで遊んでたので、
遊びの延長で覚えました。
通常の学生さんって、どこで覚えるんでしょうね。。
SAIでした。
それでは、最後にコードです。
今回は、さらに定義が増えるので、結構長いですよ。
/*
* Author: SAI
*/
/* *** Define 定義 *** */
// A
// ----
// F | G |B
// ----
// E | |C
// ---- . Dot
// D
const int ASeg = 13;
const int BSeg = 12;
const int CSeg = 11;
const int DSeg = 10;
const int ESeg = 9;
const int FSeg = 8;
const int GSeg = 7;
const int DotSeg = 6;
const int Keta1Seg = 5;
const int Keta2Seg = 4;
const int Keta3Seg = 3;
const int Keta4Seg = 2;
const int LED_ON = LOW;
const int LED_OFF = HIGH;
const int LED_KETA_ON = HIGH;
const int LED_KETA_OFF = LOW;
/* 1桁の表示時間 */
const int TIMER_DELAY = 5;
/* 1秒にかかるカウント数 */
const int TIMER_CNT_SECOUND = 1000/(TIMER_DELAY*4);
/* 砂時計用内部カウンター */
long gTimerCounter;
/* initial setting 初期設定 */
void setup() {
/* IO output setting IO出力設定 7Seg用端子を出力 */
pinMode(ASeg, OUTPUT);
pinMode(BSeg, OUTPUT);
pinMode(CSeg, OUTPUT);
pinMode(DSeg, OUTPUT);
pinMode(ESeg, OUTPUT);
pinMode(FSeg, OUTPUT);
pinMode(GSeg, OUTPUT);
pinMode(DotSeg, OUTPUT);
pinMode(Keta1Seg, OUTPUT);
pinMode(Keta2Seg, OUTPUT);
pinMode(Keta3Seg, OUTPUT);
pinMode(Keta4Seg, OUTPUT);
digitalWrite(Keta1Seg, LED_KETA_OFF);
digitalWrite(Keta2Seg, LED_KETA_OFF);
digitalWrite(Keta3Seg, LED_KETA_OFF);
digitalWrite(Keta4Seg, LED_KETA_OFF);
/* タイマー用のカウンターを初期化 */
gTimerCounter = 0;
}
//Display function 0
void zero() {
digitalWrite(ASeg, LED_ON);
digitalWrite(BSeg, LED_ON);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_ON);
digitalWrite(ESeg, LED_ON);
digitalWrite(FSeg, LED_ON);
digitalWrite(GSeg, LED_OFF);
}
//Display function 1
void one() {
digitalWrite(ASeg, LED_OFF);
digitalWrite(BSeg, LED_ON);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_OFF);
digitalWrite(ESeg, LED_OFF);
digitalWrite(FSeg, LED_OFF);
digitalWrite(GSeg, LED_OFF);
}
//Display function 2
void two() {
digitalWrite(ASeg, LED_ON);
digitalWrite(BSeg, LED_ON);
digitalWrite(CSeg, LED_OFF);
digitalWrite(DSeg, LED_ON);
digitalWrite(ESeg, LED_ON);
digitalWrite(FSeg, LED_OFF);
digitalWrite(GSeg, LED_ON);
}
//Display function 3
void three() {
digitalWrite(ASeg, LED_ON);
digitalWrite(BSeg, LED_ON);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_ON);
digitalWrite(ESeg, LED_OFF);
digitalWrite(FSeg, LED_OFF);
digitalWrite(GSeg, LED_ON);
}
//Display function 4
void four() {
digitalWrite(ASeg, LED_OFF);
digitalWrite(BSeg, LED_ON);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_OFF);
digitalWrite(ESeg, LED_OFF);
digitalWrite(FSeg, LED_ON);
digitalWrite(GSeg, LED_ON);
}
//Display function 5
void five() {
digitalWrite(ASeg, LED_ON);
digitalWrite(BSeg, LED_OFF);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_ON);
digitalWrite(ESeg, LED_OFF);
digitalWrite(FSeg, LED_ON);
digitalWrite(GSeg, LED_ON);
}
//Display function 6
void six() {
digitalWrite(ASeg, LED_ON);
digitalWrite(BSeg, LED_OFF);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_ON);
digitalWrite(ESeg, LED_ON);
digitalWrite(FSeg, LED_ON);
digitalWrite(GSeg, LED_ON);
}
//Display function 7
void seven() {
digitalWrite(ASeg, LED_ON);
digitalWrite(BSeg, LED_ON);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_OFF);
digitalWrite(ESeg, LED_OFF);
digitalWrite(FSeg, LED_OFF);
digitalWrite(GSeg, LED_OFF);
}
//Display function 8
void eight() {
digitalWrite(ASeg, LED_ON);
digitalWrite(BSeg, LED_ON);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_ON);
digitalWrite(ESeg, LED_ON);
digitalWrite(FSeg, LED_ON);
digitalWrite(GSeg, LED_ON);
}
//Display function 9
void nine() {
digitalWrite(ASeg, LED_ON);
digitalWrite(BSeg, LED_ON);
digitalWrite(CSeg, LED_ON);
digitalWrite(DSeg, LED_ON);
digitalWrite(ESeg, LED_OFF);
digitalWrite(FSeg, LED_ON);
digitalWrite(GSeg, LED_ON);
}
//Display function Keta1
void Keta1() {
digitalWrite(Keta1Seg, LED_KETA_ON);
digitalWrite(Keta2Seg, LED_KETA_OFF);
digitalWrite(Keta3Seg, LED_KETA_OFF);
digitalWrite(Keta4Seg, LED_KETA_OFF);
}
//Display function Keta2
void Keta2() {
digitalWrite(Keta1Seg, LED_KETA_OFF);
digitalWrite(Keta2Seg, LED_KETA_ON);
digitalWrite(Keta3Seg, LED_KETA_OFF);
digitalWrite(Keta4Seg, LED_KETA_OFF);
}
//Display function Keta3
void Keta3() {
digitalWrite(Keta1Seg, LED_KETA_OFF);
digitalWrite(Keta2Seg, LED_KETA_OFF);
digitalWrite(Keta3Seg, LED_KETA_ON);
digitalWrite(Keta4Seg, LED_KETA_OFF);
}
//Display function Keta4
void Keta4() {
digitalWrite(Keta1Seg, LED_KETA_OFF);
digitalWrite(Keta2Seg, LED_KETA_OFF);
digitalWrite(Keta3Seg, LED_KETA_OFF);
digitalWrite(Keta4Seg, LED_KETA_ON);
}
// 数字振り分け .
void DigitDisp(int aNum)
{
int lDigit = aNum % 10;
switch(lDigit)
{
case 1:
one();
break;
case 2:
two();
break;
case 3:
three();
break;
case 4:
four();
break;
case 5:
five();
break;
case 6:
six();
break;
case 7:
seven();
break;
case 8:
eight();
break;
case 9:
nine();
break;
case 0:
default:
zero();
break;
}
}
/* Mail loop 通常処理(繰り返し) */
void loop() {
gTimerCounter++;
if(gTimerCounter >= (long)10000*1000)
{
gTimerCounter = 0;
}
/* 100ms単位の時間に変換 */
int lTime = gTimerCounter / (TIMER_CNT_SECOUND /10 ) ;
/* TIMER_DELAYごとに各桁を表示 */
DigitDisp(lTime);
Keta1();
delay(TIMER_DELAY);
digitalWrite(DotSeg, LED_ON);
DigitDisp(lTime/10);
Keta2();
delay(TIMER_DELAY);
digitalWrite(DotSeg, LED_OFF);
DigitDisp(lTime/100);
Keta3();
delay(TIMER_DELAY);
DigitDisp(lTime/1000);
Keta4();
delay(TIMER_DELAY);
}