2016年3月30日水曜日

Multi-function Shield と超音波距離センサーを使ったラップタイマー(制作編)

1.Multi-function Shieldの取付け注意事項

Multi-function Shield をArduino UNOに装着する場合、4桁セグメントLEDの裏面ピンがArduino UNOのUSBコネクタに接触します。この表示動作時に誤動作を起こしたり、ボード故障の原因になりますので、セグメントLEDのピンは短くカットして、USBコネクタの上面には絶縁テープを貼ってください。


2.超音波距離センサーの取り付け

超音波距離センサー(HCSR04)をMulti function Shieldにスマートに固定するためにシールド左上の7ピンコネクタ(APC220 Bluetooth)を使用します。簡単なソケットボードを制作してシールドに固定してください。

コネクタのピン3-4は、Arduino UNOのシリアルピン0-1に使用されていますので使えません。なので、コネクタピン6-7を使用します。Arduno UNOのピン5-6がシールド右下のコネクタに引き出されていますので、これを使用します。下記のようにArduno UNOのピン5-6が、HC-SR04のEcho, Trigピンつながるように配線してください。



3.ラップライマーのプログラム

ラップライマーとして動作するプログラムソースを下記に添付します。
/*
 * 第一工業大学東京上野キャンパス
 * 木下研究室 3年生プレゼミ教材
 * 2016年4月㏠
 */

#define EchoPin 5   // 超音波距離センサ HC-SR0 ピン 入力
#define TrigPin 6   // 超音波距離センサ HC-SR0 ピン 出力
#define LATCH_DIO 4 // シフトレジスタ 74HC595 ピン OUTPUT
#define CLK_DIO 7   // シフトレジスタ 74HC595 ピン OUTPUT
#define DATA_DIO 8  // シフトレジスタ 74HC595 ピン OUTPUT
#define SW1 A1      // スイッチSW1 A1ピン     :モード切替SW
#define SW2 A2      // スイッチSW1 A1ピン     :ラップタイマーリセット
#define SW3 A3      // スイッチSW1 A1ピン
#define SW3 A3      // スイッチSW1 A1ピン
#define Mode_0 0    // モード0: トラック位置設定
#define Mode_1 1    // モード1: ラップタイマーモード
#define LED1 13     // LED1 ON:トラック位置設定、
#define LED2 12     // LED2 ON: ラップタイマーモード
#define LED3 11     // LED3
#define LED4 10     // LED4
#define ON 0         // LED is on
#define OFF 1       // LED is off
#define SPEAKER 3        // 
int cm;                 // 超音波距離センサー計測値(センチメートル)
int TrackCenter = 15;   // トラック中央値 (デフォルト)
bool DP_on = false;     //2桁目LEDのDPのOn/Off
byte OperationMode = Mode_0;    // 動作モード
bool Sw2IsOn = false;           // スイッチ2が押された
bool LapTimerStart = false;     // ラップライマー制御
bool LapTimerRunning = false;
unsigned long Last_100ms_Count = 0; //100ms カウント最終値
int Count_100ms = 0; // 100ms カウンタ
bool SpeakerOn = false;     //スピーカーをオン用フラグ(オンは0.1秒に固定
unsigned long SpeakerDuration = 0;
void setup ()
{
  Serial.begin(9600);   //シリアルを使用する

  // シフトレジスタ 74HC595初期化
  pinMode(LATCH_DIO, OUTPUT);
  pinMode(CLK_DIO, OUTPUT);
  pinMode(DATA_DIO, OUTPUT);

  // 超音波距離センサピン初期化
  pinMode(TrigPin, OUTPUT);
  pinMode(EchoPin, INPUT);
  digitalWrite(TrigPin, LOW);

  // Speaker 設定(オンオフは方向レジスタで制御)
  pinMode(SPEAKER, INPUT);

  // LED1-4の初期化
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);

  digitalWrite(LED1, ON);  //ON
  digitalWrite(LED2, ON);
  digitalWrite(LED3, ON);
  digitalWrite(LED4, ON);
  delay(1000);
  digitalWrite(LED1, OFF);  //OFF
  delay(100);
  digitalWrite(LED2, OFF);
  delay(100);
  digitalWrite(LED3, OFF);
  pinMode(SPEAKER, OUTPUT);
  delay(100);
  digitalWrite(LED4, OFF);
  pinMode(SPEAKER, INPUT);
}

/* Main program */
void loop()
{
  ReadSwitch();     //SW1, SW2 の読み取り

  // キャリブレーションモード
  if (OperationMode == Mode_0) {
    digitalWrite(LED1, ON);
    digitalWrite(LED2, OFF);
    Display(cm);
    DP_on = false;
    Count_100ms = 0;
    TrackCenter = 2 * cm / 3;
    LapTimerStart = false;
    LapTimerRunning = false;
  }

  // ラップタイマーモード
  if (OperationMode == Mode_1) {
    digitalWrite(LED1, OFF);
    digitalWrite(LED2, ON);
    DP_on = true;
    Display(Count_100ms);

    // ラップタイマーストップ状態でマイコンカーが横切ったらカウントスタート
    if (LapTimerStart == false && cm  < TrackCenter ) {
      LapTimerStart = true;
      TurnSpeakerOn();
    }

    // ラップタイマーラン状態でマイコンカーが横切ったらカウントストップ
    if (LapTimerRunning == true && cm  < TrackCenter ) {
      LapTimerStart = false;
      TurnSpeakerOn();
    }

    // ラップタイマーストップ状態で、SW2を押した場合
    if (Sw2IsOn == true &&  LapTimerStart == false) {
      Count_100ms = 0;              // カウントを0.0秒にリセット
      LapTimerRunning = false;      // ラップタイマー停止
      Sw2IsOn = false;              // SW2 ONクリア
    }
  }
  // 100ms インターバル処理
  if (millis() - Last_100ms_Count > 100) {
    Last_100ms_Count = millis();
    cm = readDistance();        // 距離計測は100msごと

    if (LapTimerStart == true) {
      if (Count_100ms < 9999) {
        Count_100ms++;
        if (Count_100ms > 10 ) LapTimerRunning = true;  // ラップライマーがスタートして1秒間はラン状態にしない。
        else LapTimerRunning = false;
      } else  Count_100ms = 0;
    }
  }

  if (SpeakerOn == true) {     // スピーカーを0.5秒オンする
    if (millis() - SpeakerDuration > 50) {
    SpeakerOn = false;
    pinMode(SPEAKER, INPUT);
    }
  }

}
// SW1, SW2の読み取り, スイッチはアナログ読み
void ReadSwitch(void) {
  static byte Sw1Latch;
  static byte Sw2Latch;
  if ( analogRead(SW1) < 100) {
    if (Sw1Latch == 0) {
      Sw1Latch = 1;
      TurnSpeakerOn();
      if (OperationMode == Mode_0) {
        OperationMode = Mode_1;

      } else {
        OperationMode = Mode_0;
        Sw2IsOn = false;
        LapTimerStart = false;
      }
    }
  } else Sw1Latch = 0;

  if ( analogRead(SW2) < 100) {
    if (Sw2Latch == 0) {
      Sw2Latch = 1;
      Sw2IsOn = true;
      TurnSpeakerOn();
    }
  } else Sw2Latch = 0;

}

void TurnSpeakerOn(void) {
  SpeakerOn = true;
  pinMode(SPEAKER, OUTPUT);
  SpeakerDuration = millis();
}


/*4SEG LEDにNumberを表示する
  loop()関数内に配置すれば、3ms毎にスキャン表示を行いう
  Number: 0-9999 の4桁の整数
  表示間隔: 5ms
*/
void Display(int Number)
{
  static unsigned long Last_ms_Count;
  static byte ScanSeg = 0;
  if (millis() - Last_ms_Count > 3) {
    Last_ms_Count = millis();
    switch (ScanSeg++) {
      case 0:
        WriteNumberToSegment(0 , Number / 1000);
        break;
      case 1:
        WriteNumberToSegment(1 , (Number / 100) % 10);
        break;
      case 2:
        WriteNumberToSegment(2 , (Number / 10) % 10);
        break;
      case 3:
        WriteNumberToSegment(3 , Number % 10);
        break;
      default:
        ScanSeg = 0;
    }
  }
}
/* セグメント表示
    Segment: セグメント位置:0 - 3
     Value:表示する値 : 0 - 9
*/
void WriteNumberToSegment(byte Segment, byte Value)
{
  // セグメント表示パターン:  0 - 9
  const byte SEGMENT_MAP[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0X80, 0X90};  
  const byte SEGMENT_SELECT[] = {0xF1, 0xF2, 0xF4, 0xF8}; // 4-seg LED 選択パターン: 1 to 4
  byte SegPattern;

  if (DP_on == 1 && Segment == 2)           // LED2のDP On/Off判定
    SegPattern = SEGMENT_MAP[Value] & 0x7F;     // DPパターンのマスク
  else
    SegPattern = SEGMENT_MAP[Value];
  digitalWrite(LATCH_DIO, LOW);
  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SegPattern);
  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_SELECT[Segment] );
  digitalWrite(LATCH_DIO, HIGH);
}

// 距離測定:センチメートル
int readDistance(void) {
  long t ;
  int ans ;
  digitalWrite(TrigPin, HIGH) ;         // 超音波センサーに5usのパルスを出力する
  delayMicroseconds(5) ;
  digitalWrite(TrigPin, LOW) ;
  t = pulseIn(EchoPin, HIGH, 5000) ;    // パルス幅の時間を測る
  ans = (t / 29) / 2 ;                  // 往復なので2で割る
  return ans ;                          //cm単位戻す
}

0 件のコメント:

コメントを投稿