【電子工作】3-1.Arduinoのソースコードを複数ファイルに分けよう

 

最近、どんどんコードが長くなっていますよね。

 

特に、数字を表現する部分は、変更することがないのに

毎回コードが長くて、ファイル全体の可読性を下げてしまっています。

 

できれば、もう変更しない部分を分けてしまいたいですよね。

 

例えば、前回のコードでいうと、

 

何個も出てくる”数字表現”を定義した

//Display function x

の部分です。

 

 

また、Arduinoではなかなかないかもしれませんが、

 

C言語に限らず、規模が大きくなってくると、

1つのプロジェクト複数のメンバーで作成や修正することが増えてきます。

 

しかしながら、

複数のメンバー1つのファイルを同時に編集するのは色々と問題が発生します。

 

 

また、別のプロジェクトに流用するためにも

ファイルを分けちゃいましょう!

 

 

Arduinoの画面には、ひっそりとファイル追加する画面があります。

 

ただ、Arduinoの画面って名称に癖がありますね。

 

◆ファイル分割① ファイルを追加

 

新規タブ と書いていますが、これがファイル追加を意味しています。

 

 

 

このボタンを押すと。。

 

画面を大きくしているとわかりにくいんですが、

以下のような、ファイル名を記入する画面が表示されます。

 

 

なんで画面の下やねん。。。

 

 

好きな名前を入力してOKを押しますよ

 

今回、SAIはDisplayFunctionを別ファイルに分けたいので、

こんな名称にしました。

 

拡張子はひとまず、".h " にしておきましょう。

 

◆ファイル分割② コードの移動

 

続いて、

新しく作成した"DisplayFunction.h"に、移動させたいコード部分を全部移動させましょう。

 

とりあえず、

エラーチェックをしたいので、

何も考えず、DisplayFunction に関連する定義を 全部移動させましょう。

 

 

 

◆ファイル分割③ includeの追加

そして、

最後にメインの関数に、新ファイルをincludeしましょう。

 

 

追加するファイルはローカルヘッダなので、  でくくります。

 

この段階で、一回ビルドしてみてください。

 

 

うまく移動できていたら、

ビルドが成功するはずです!


 

◆ファイル分割④ ソース用のinoファイル追加

 

続けて、ソースコード部分を移植します。

 

Arduinoの追加するソースファイル”ino”である必要があります。

 

①と同様の方法でファイル追加ができますが、

拡張子を指定しなければ、勝手に”ino”になるようです。

 

 

◆ファイル分割⑤ コードの移動

 

続いて、

新しく作成した"DisplayFunction.ino"に、

移動させたいコード部分(作った関数のことです)を全部移動させましょう。

 

C言語と違い、ヘッダファイルにプロトタイプ宣言をする必要はないようです。

 

"DisplayFunction.ino"に、関数を書いたら、

ビルドをしてみましょう。

 

 

どうでしょうか?

 

※サンプルソースを最下部に載せておきます。

 

お試しください。

 

 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

雑談

それにしても、C言語を扱っていた人からすると、

Arduinoはちょっと変わっていますね。

 

C言語の感覚でコードを書くと、よくわからないエラーが出たりします。

 

関数に関しては、どれかのinoファイルに関数を記載しておけば、

リンク時に整合性を撮ってくれるっぽいですね。

 

それに反して、定数は事前にIncludeしていないとエラーになる。

 

最初は、プロトタイプ宣言と定数宣言がうまくいかないので、

考え方が理解不能でした。。


 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

 

それでは、コードです。

 

 

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

★メインのinoファイル

 

/*
 * Author: SAI
 */

/* *** Include *** */
#include <TimerOne.h>
/* 注意
   TimerOne.h を使用するためには、
   スケッチ -> ライブラリのインクルード -> ライブラリの管理
   から、TimerOne をインストールしておく必要があります。
*/

// 7Seg LED 表示Function //
#include "DisplayFunction.h"


/* *** Define 定義 *** */

#if 0
/* 1桁の表示時間 */
const long TIMER_ADJUST = 103;
const long TIMER_DELAY = (5 * 1000) - TIMER_ADJUST;

/* 1秒にかかるカウント数 */
const long TIMER_CNT_SECOUND = ((long)1000 * 1000) /(TIMER_DELAY*4);
#endif

/* 1桁の表示時間 */
const long TIMER_DELAY = (5 * 1000);
/* 1秒にかかるカウント数 */
const long TIMER_CNT_SECOUND = ((long)1000 * 1000) /(TIMER_DELAY);



/* 砂時計用内部カウンター */
long gTimerCounter;

long gDispTime;


/* 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);

  /* タイマー用のカウンターを初期化 */
  // Timer setting  タイマー設定
  Timer1.initialize(TIMER_DELAY); //マイクロ秒単位で設定 
  Timer1.attachInterrupt(timerFire); // コールバック関数設定 
  
  gTimerCounter = 0;
  gDispTime = 0;
}



/* Mail loop 通常処理(繰り返し) */
void loop() {

  delay(1000);

}

/*
 * タイマー割り込み処理
 * 100ms(=100000us)毎にここが呼び出される */
void timerFire() {
  // 時間計測 //
  gTimerCounter++;
  if(gTimerCounter >= (long)10000*1000)
  {
    gTimerCounter = 0;
  }
  /* 100ms単位の時間に変換 */
  int lTime = gTimerCounter / (TIMER_CNT_SECOUND /10 ) ;

  if(gDispTime != lTime)
  {
    gDispTime = lTime;
    /* 桁上がりした時だけ、1msの処理をする */
    delay(1);
  }

  /* 桁切り分け */
  int DispKeta = gTimerCounter % 4 ;
  
  switch(DispKeta)
  {
    case 0:
     /* 1桁を表示 */
      DigitDisp(lTime);
      digitalWrite(DotSeg, LED_OFF);  
      Keta1();
      break;
    case 1:
     /* 2桁を表示 */
      digitalWrite(DotSeg, LED_ON);  
      DigitDisp(lTime/10);
      Keta2();
      break;
    case 2:
     /* 3桁を表示 */
      digitalWrite(DotSeg, LED_OFF);  
      DigitDisp(lTime/100);
      Keta3();
      break;
    case 3:
    default:
     /* 4桁を表示 */
      digitalWrite(DotSeg, LED_OFF);  
      DigitDisp(lTime/1000);
      Keta4();
      break;
  }
}

 

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

DisplayFunction用のinoファイル

//  ヘッダファイルはここでIncludeする必要ないみたい。


//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;
  }
}

 

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

 

// DisplayFunction.hファイル

 

/* *** 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;

 

 

 

 

【電子工作】2-3.Arduinoで割込み処理で精度のたかい砂時計を作ろう

 

さて、前振りが長くなりましたが、

やっと、本題に到達しました。

 

2章で本当に学んでほしいこと。

 

割り込み処理です。

 

ちなみに、今回はタイマー割り込みです。

外部割込みはまた今度。

 


 

割り込み処理とは何か?

 

 

皆さん、作業中にチャイムが鳴ったらどうしますか?

 

今やっている作業を中断して、割り込みを確認しに行きますよね?

 

確認が終わったら、元の作業の続きをしますよね。

 

 

イメージするとこんな感じ。

 

元の処理 = メイン処理

チャイム = 割り込み処理のイメージです。

 

処理をしているところに色を塗ると、こんなイメージです。

 

 

 

Arduinoなどマイコンでも同じで、割り込んだ処理を優先的に作業する機能があります。

 

ただ、マイコンの割り込み処理は、ちょっと面倒で、

レジスタのせっt・・・・ごにょごにょ

<長くなるので省略>


 

 

Arduinoの場合、

「ごにょごにょ・・・」の大変な設定処理はしなくても、

比較的簡単に割り込み処理を実現できるようです。

 

タイマー割り込みの設定で、

5msごとに繰り返しtimerFire()呼び出すように設定すれば、

 

timerFire()の関数を定期的に割り込み呼び出してくれます。

 

マイコンの割り込みは、だいたいマイコンのクロックにより実現するので、

かなり正確に繰り返し呼び出しできますね。

 

こんなイメージです。

 


 

では、この処理はどうすれば実現できるのか?

 

 

SAIとしては、タイマーは苦戦の難関のイメージです。

 

が、Arduinoはかなり簡単です。

 

 

ステップ①

 タイマー機能で一定時間に割り込みで呼び出してくれるように初期設定をする

 ↓ 

 Timer1.initialize(5000); //5ms=5000マイクロ秒単位で設定 

 

ステップ②

 ↓ 

 割り込み処理用の好きな関数を、コールバック関数に設定する)

 Timer1.attachInterrupt(timerFire); // コールバック関数設定 

                  ↑ 割り込み用に好きな関数を設定する

                     timerFire()関数を設定

 

以上!

 

 

 

めちゃ簡単!

 

 

というわけで、

 

◆回路

回路は、前回と全く一緒です。

↓の写真をみて、頑張って接続してください。

 

◆スケッチ(コード)

 ※コードは、日記の最後に書いています。

 デジタル出力は、前回と同様の方法です。

 後で、コードを書き込んでみてね

 

 

 

 

今回は、教科書っぽくなってしまいました、、、

 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

雑談

 

H8で初めて割り込み処理を作成したころは、

紙で作成されていた1000P以上あるマニュアルと睨めっこして、

慣れないアセンブラで1週間以上苦戦しました。

 

3048で引っ掛かり、途中3664に切り替えて

TimerAとかTimerWとかタイマーを動かすので一苦労、

その後に、こちらでやっと割り込み処理成功。

 

超苦戦しました。

 

この壁を乗り越えたら、ラジコンサーボを動かすPWM制御とか

割り込み制御も使えるようになり、

シリアル通信も実装できて、何かが開けました。

 

そういえば、

H8の製造元。

当時は、Renesussではなく、まだHitachiでしたね。

おそらく、倉庫にHitachiと書いたマニュアルが残っています。

 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

 

 

それでは、コードです。

(ちょっとずつ雑になってる・・・)

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

/*
 * Author: SAI
 */

/* *** Include *** */
#include <TimerOne.h>
/* 注意
   TimerOne.h を使用するためには、
   スケッチ -> ライブラリのインクルード -> ライブラリの管理
   から、TimerOne をインストールしておく必要があります。
*/


/* *** 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;


#if 0
/* 1桁の表示時間 */
const long TIMER_ADJUST = 103;
const long TIMER_DELAY = (5 * 1000) - TIMER_ADJUST;

/* 1秒にかかるカウント数 */
const long TIMER_CNT_SECOUND = ((long)1000 * 1000) /(TIMER_DELAY*4);
#endif

/* 1桁の表示時間 */
const long TIMER_DELAY = (5 * 1000);
/* 1秒にかかるカウント数 */
const long TIMER_CNT_SECOUND = ((long)1000 * 1000) /(TIMER_DELAY);



/* 砂時計用内部カウンター */
long gTimerCounter;

long gDispTime;


/* 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);

  /* タイマー用のカウンターを初期化 */
  // Timer setting  タイマー設定
  Timer1.initialize(TIMER_DELAY); //マイクロ秒単位で設定 
  Timer1.attachInterrupt(timerFire); // コールバック関数設定 
  
  gTimerCounter = 0;
  gDispTime = 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() {

  delay(1000);

}

/*
 * タイマー割り込み処理
 * 100ms(=100000us)毎にここが呼び出される */
void timerFire() {
  // 時間計測 //
  gTimerCounter++;
  if(gTimerCounter >= (long)10000*1000)
  {
    gTimerCounter = 0;
  }
  /* 100ms単位の時間に変換 */
  int lTime = gTimerCounter / (TIMER_CNT_SECOUND /10 ) ;

  if(gDispTime != lTime)
  {
    gDispTime = lTime;
    /* 桁上がりした時だけ、1msの処理をする */
    delay(1);
  }

  /* 桁切り分け */
  int DispKeta = gTimerCounter % 4 ;
  
  switch(DispKeta)
  {
    case 0:
     /* 1桁を表示 */
      DigitDisp(lTime);
      digitalWrite(DotSeg, LED_OFF);  
      Keta1();
      break;
    case 1:
     /* 2桁を表示 */
      digitalWrite(DotSeg, LED_ON);  
      DigitDisp(lTime/10);
      Keta2();
      break;
    case 2:
     /* 3桁を表示 */
      digitalWrite(DotSeg, LED_OFF);  
      DigitDisp(lTime/100);
      Keta3();
      break;
    case 3:
    default:
     /* 4桁を表示 */
      digitalWrite(DotSeg, LED_OFF);  
      DigitDisp(lTime/1000);
      Keta4();
      break;
  }
}

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

【電子工作】2-2.Arduinoで少し精度のたかい砂時計を作ろう

 

前回、delay()で待ち時間をしつつ、描画更新をしたら、

毎秒16.6msずつずれていました。

 

これを改善する方法はないのでしょうか?

 

1秒間に16.6msずれているなら、

待ちに使用しているDelayを補正すればいいじゃないという方法です。

 

前回はdelay()を使用していました。

 

この関数では、1ms粒度の調整しかできません。

 

これに対して、もっと粒度の高い街をする関数があります。

 

それは、

delayMicroseconds(us);

 

引数がミリ秒からマイクロ秒に粒度アップです。

 

 

そして、遅延に使用している時間 5ms (5000us)のに対して、

他の処理にかかる時間分だけ引いておく、

 

つまり、5msのTimerDelay用の定数に、補正をかける感じですね。

 

                           // ↓補正用の定数

const long TIMER_DELAY = (5 * 1000) - TIMER_ADJUST;

 

こうすることで、

より正確な5msを稼ぐことができますね!

 

 

※delay()からdelayMicroseconds()に変えたため、

  処理時間も変化しています。

  Adjustにかかる時間は、Try and Goで、何度か微調整が必要です。

 

 

◆スケッチ(コード)

 ※コードは、日記の最後に書いています。

 後で、コードを書き込んでみてね

 

はい、できました!

 

 

 

 

 

ほんとに?

 

本当に無事解決・・・でしょうか?

 

 

 

 

これには盲点があります。

 

1秒に1回ブザーを鳴らすとか、

100msに1回LEDを光らせるなどの、分岐を入れた場合、

その処理にかかる時間が増えてしまいます

 

「100msに一回、特殊な処理をする」というコードにしてみました。

 

すると、こんな感じ。

                                               

                                                

 

 

矢印の箇所で、処理が行われているために、

1msのずれが発生しています。

 

 

結論からすると、

ぐるぐるループ内で時間調整をするのは、

 

基本的には無理なのです

 

 

正確な定期処理を必要とする処理に関しては、

ぐるぐるループ内で調整できないと考えてください。

 

 

 

では、目覚まし時計なんかはどう作るのでしょうか?

 

解決方法は、割り込み処理にあります。

 

 

 

次は、割り込み処理を学習しましょう!

 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

雑談

 

ぐるぐるループ内でカウントが基本的にはできません。

 

”基本的には”です。

 

実はArduinoの場合、SystemTimerを持っていて

micros()でマイクロ秒単位の時間を取得できるようです。

 

delay()で待機する代わりに、micros()で取得した時間が期待の時間より経過した

という方法で計時するほうが確実でしょうね。

iアプリやアンドロイドアプリを作るなら、こっちのほうがいいかもしれません。

 

ただ、組み込みではよくない処理です。

 

そんなことまでやってると先に進まないので、

とっとと割り込みに進みます。

 

晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ晴れ

 

それでは、コードです。

 

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

/*
 * 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 long TIMER_ADJUST = 103;
const long TIMER_DELAY = (5 * 1000) - TIMER_ADJUST;

/* 1秒にかかるカウント数 */
const long TIMER_CNT_SECOUND = ((long)1000 * 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();
  delayMicroseconds(TIMER_DELAY);

  digitalWrite(DotSeg, LED_ON);  
  DigitDisp(lTime/10);
  Keta2();
  delayMicroseconds(TIMER_DELAY);
  
  digitalWrite(DotSeg, LED_OFF);  
  DigitDisp(lTime/100);
  Keta3();
  delayMicroseconds(TIMER_DELAY);
  
  DigitDisp(lTime/1000);
  Keta4();
  delayMicroseconds(TIMER_DELAY);
}

 

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