【電子工作】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);

}

宇宙人しっぽ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人からだ宇宙人あたま