SSブログ

Maruduino(Arduino)で簡易的なストップウオッチの製作 またかよ編 [アプリケーション]

Img_2043.jpgまたかよぅ、と言った感じですが、、、

今までの方式で最大の問題は、計測時間が正確ではなかった点です。
今までの時間の取得は50ms+内部処理時間周期でSW1の状態を監視していたので、ワーストケースでは50ms+LCD表示など内部処理に掛かる時間だけ実際のスイッチの変化から遅れて計測がスタート、ストップしていました。
これを解消するためには、スイッチの変化に対して即座に反応し、計測の開始時間や終了時間を記憶する必要があります。

そこで、Arduinoのライブラリの中のattachInterruptと言う割り込みハンドラの登録機能を利用します。
これは、スイッチの状態の変化が検出されると通常のloop処理以外の流れ(コンテキスト)にマイコンの処理を切り替え、そこで必要な処理を行おうというものです。
必要な処理はユーザーが自分で作成し、登録します。

つまりこのユーザーが登録した別のコンテキストの先頭で変化を検出した時間を記録しておき、その値を計測時間として利用します。
また、同時にチャタリング?対策もここで行ってしまいます。

※厳密に言えばこの方法でもスイッチの変化から割り込みハンドラが起動して時間が記録されるまでに数十とか数百μsくらいの遅延は発生しているのですが、10msの精度から見れば十分に許容範囲内です。

ただしattachInterruptで利用できる端子は限定されており、DIGITAL2またはDIGITAL3のみです。その為、Hello Worldで利用しているLCD端子の移動が必要です。
以下に掲載するスケッチのコメント部にも具体的な割付を書きましたが、DIGITAL2をLCDの制御線から移動し、代わりにSW1からの入力に利用しています。

と言う訳で、スケッチをここに掲載しておきます。
/*
  LiquidCrystal Library - Hello World
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
  The circuit:
 * LCD RS pin to digital pin 8
 * LCD Enable pin to digital pin 9
 * LCD D4 pin to digital pin 4
 * LCD D5 pin to digital pin 5
 * LCD D6 pin to digital pin 6
 * LCD D7 pin to digital pin 7

 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 
 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe
 modified 25 July 2009
 by David A. Mellis
 
 
 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 */

// include the library code:
#include <LiquidCrystal.h>
int mode;  /*初期状態は0(計測スタート待ち)*/
  /*初期状態→計測中→停止中→初期状態に戻る  の状態遷移を行う*/
int int_count;
unsigned long passed_time,latest_time;
unsigned long int_time,guard_time;

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup() {
  // set up the LCD's number of rows and columns: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Play Stopwatch.");
  attachInterrupt(0, sw1_int_handler, RISING);
}

void loop() {
  static int count;

  if( count != int_count )  /*割り込みカウントと不一致が検出された時*/
  {
    count = int_count;  /*更新*/

    switch ( mode )
    {
      case 0 :  /*初期状態から計測中に遷移*/
        passed_time = int_time;  /*計測開始時刻*/
        mode = 1;
        break;
      case 1 :
        latest_time = int_time;  /*計測停止時刻*/
        mode = 2;
        break;
      default :
        lcd.setCursor(0, 1);
        lcd.print("                ");  /*表示クリア*/
        mode = 0;
        break;
    }
  }

  lcd.setCursor(0, 1);
  if( mode == 1 )
    lcd.print((double)(millis() - passed_time) / 1000.0);  /*0.1秒単位で出力*/
  else if( mode == 2 )
    lcd.print((double)(latest_time - passed_time) / 1000.0);  /*計測完了*/
  else
    lcd.print(0.0);  /*表示を0に戻す*/

  delay( 50 );  /*表示更新時間*/
}

void sw1_int_handler()
{
  if( millis() > guard_time )  /*現在時刻がガードタイムを越した時のみ有効とする*/
  {
    int_count++;  /*有効割り込み数*/
    int_time = millis();
    guard_time = int_time + 500UL;  /*不感帯時間の再設定*/
  }
}


nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。