目次

Go/Stop装置

 Go/Stop装置は、タイムトライアル競技の
 スタートの合図を送ります。



 装置の動作を、状態遷移図で示すと、以下。



 ランプが4個必要なので、Arduinoのピン14、15、16、17に
 接続しておきます。



 スタートスイッチを押すと、順番にLEDを点灯していくので
 次のコードで順番に点灯していけばよいはず。

  /* LED_3 */
  PORTC |= (1 << 3);
  /* delay */
  PORTC = 0;
  /* LED_2 */
  PORTC |= (1 << 2);
  /* delay */
  PORTC = 0;
  /* LED_1 */
  PORTC |= (1 << 1);
  /* delay */
  PORTC = 0;
  /* LED_0 */
  PORTC |= (1 << 0);
  /* delay */
  PORTC = 0;

 音も必要なので、PWM波形を出力できる9ピンを使います。
 音を簡単に出力するには、tone関数を使っていきます。

  tone(SOUND_BIT,440,1000);

  tone(SOUND_BIT,880,1000);

 最後だけ高い周波数にし、持続時間を追加して
 LEDの点灯とともに使えば、一関数だけで動作を
 エミュレート可能。

void perform_state()
{
  /* LED_3 */
  PORTC |= (1 << 3);
  tone(SOUND_BIT,440,1000);
  PORTC = 0;
  /* LED_2 */
  PORTC |= (1 << 2);
  tone(SOUND_BIT,440,1000);
  PORTC = 0;
  /* LED_1 */
  PORTC |= (1 << 1);
  tone(SOUND_BIT,440,1000);
  PORTC = 0;
  /* LED_0 */
  PORTC |= (1 << 0);
  tone(SOUND_BIT,880,1000);
  PORTC = 0;
}

 似たような処理をしているので、反復で対応します。

void perform_state()
{
  word f;
  int  i;
  /* default */
  f = 440 ;
  /* repeat */
  for ( i = 3 ; i > -1 ; i-- ) {
    /* turn on target LED */
    PORTC |= (1 << i);
    /* judge */
    if ( i == 0 ) { f = 880 ; }
    /* send sound */
    tone(SOUND_BIT,f,1000);
    /* turn off all LED */
    PORTC = 0;
  }
}

 プッシュスイッチを押されたことは、シフトレジスタを
 用意して、次のように判定。

    /* shift */
    sft <<= 1 ;
    /* mask */
    sft &= 3 ;
    /* get switch state */
    if ( PINB & ON ) { sft |= ON ; }
    /* judge */
    if ( sft == 1 ) { state = MODE_RUN ; }

 シフトレジスタを使うときは、時間差が必要なので
 タイマー割込みを利用して、フラグで時間経過通知
 してもらいます。

  if ( tflag == ON ) {
    /* clear */
    tflag = OFF ;
    /* shift */
    sft <<= 1 ;
    /* mask */
    sft &= 3 ;
    /* get switch state */
    if ( PINB & ON ) { sft |= ON ; }
    /* judge */
    if ( sft == 1 ) { state = MODE_RUN ; }
  }

 LEDと音でスタートまでの合図を送るために
 状態変数stateを用意して、loopの中で処理
 すればよいでしょう。

void loop(void)
{
  /* shift register */
  if ( tflag == ON ) {
    /* clear */
    tflag = OFF ;
    /* shift */
    sft <<= 1 ;
    /* mask */
    sft &= 3 ;
    /* get switch state */
    if ( PINB & ON ) { sft |= ON ; }
    /* judge */
    if ( sft == 1 ) { state = MODE_RUN ; }
  }
  /* execute */
  if ( state == MODE_RUN ) {
    /* perform */
    perform_state();
    /* return */
    state = MODE_IDLE ;
  }
}

 イベント通知のフラグを扱う関数を初期化するには
 次のコードを利用。

  /* 500ms period */
  MsTimer2::set(500,update_trigger);
  /* enable */ 
  MsTimer2::start();

 イベント通知のハンドラに相当する関数を定義。

void  update_trigger(void)
{
  /* flash LED */
  send_led( xcnt & ON );
  /* update counter */
  xcnt++ ;
  /* set flag */
  tflag = ON ;
}

 Arduinoが動作していることがわかるように
 13ピンに接続したLEDを点灯します。
 これは、Arduino基板上にあるので、そのまま
 トグルで論理値を出力するだけで対応できます。

void  send_led(byte x)
{
  if ( x ) { PORTD |=  (1 << LED_BIT) ; }
  else     { PORTD &= ~(1 << LED_BIT) ; }
}

 まとめると以下。

#include <MsTimer2.h>

#define OFF 0
#define ON  OFF+1

#define MODE_IDLE 0
#define MODE_RUN  1

#define LED_BIT   7
#define SOUND_BIT 9

byte state;
byte sft;
byte xcnt;
boolean tflag;

void  send_led(byte x)
{
  if ( x ) { PORTD |=  (1 << LED_BIT) ; }
  else     { PORTD &= ~(1 << LED_BIT) ; }
}

void  update_trigger(void)
{
  /* flash LED */
  send_led( xcnt & ON );
  /* update counter */
  xcnt++ ;
  /* set flag */
  tflag = ON ;
}

void perform_state()
{
  word f;
  int  i;
  /* default */
  f = 440 ;
  /* repeat */
  for ( i = 3 ; i > -1 ; i-- ) {
    /* turn on target LED */
    PORTC |= (1 << i);
    /* judge */
    if ( i == 0 ) { f = 880 ; }
    /* send sound */
    tone(SOUND_BIT,f,1000);
    /* turn off all LED */
    PORTC = 0;
  }
}

void  setup(void)
{
  /* set I/O values */
  PORTD = 0x01 ;
  PORTB = 0x01 ;
  PORTC = 0x00 ;
  /* set port directions */
  DDRD = 0xfe ;
  DDRB = 0xfe ;
  DDRC = 0xff ; 
  /* clear flag */
  tflag = OFF ;
  /* set others */
  xcnt = 0 ;
  sft  = 0 ;
  state = MODE_IDLE ;
  /* 500ms period */
  MsTimer2::set(500,update_trigger);
  /* enable */ 
  MsTimer2::start();
}

void loop(void)
{
  /* shift register */
  if ( tflag == ON ) {
    /* clear */
    tflag = OFF ;
    /* shift */
    sft <<= 1 ;
    /* mask */
    sft &= 3 ;
    /* get switch state */
    if ( PINB & ON ) { sft |= ON ; }
    /* judge */
    if ( sft == 1 ) { state = MODE_RUN ; }
  }
  /* execute */
  if ( state == MODE_RUN ) {
    /* perform */
    perform_state();
    /* return */
    state = MODE_IDLE ;
  }
}

 LEDを4個使うので、デジタルピンの指定をして
 処理することもできます。setupの内容は、次の
 ように記述できるでしょう。

#define PSHB 8

#define LED_M 13
#define LED_0 14
#define LED_1 15
#define LED_2 16
#define LED_3 17

#define SOUND_BIT 9

void  setup(void)
{
  /* set I/O values */
  digitalWrite(LED_0,LOW);
  digitalWrite(LED_1,LOW);
  digitalWrite(LED_2,LOW);
  digitalWrite(LED_3,LOW);
  digitalWrite(SOUND_BIT,LOW);
  /* set port directions */
  pinMode(PSHB ,INPUT);
  pinMode(LED_0,OUTPUT);
  pinMode(LED_1,OUTPUT);
  pinMode(LED_2,OUTPUT);
  pinMode(LED_3,OUTPUT);
  pinMode(LED_M,OUTPUT);
  pinMode(SOUND_BIT,OUTPUT);
  /* clear flag */
  tflag = OFF ;
  /* set others */
  xcnt = 0 ;
  sft  = 0 ;
  state = MODE_IDLE ;
  /* 500ms period */
  MsTimer2::set(500,update_trigger);
  /* enable */ 
  MsTimer2::start();
}

 ピンの入出力と論理値を決めてしまえば
 LEDの点灯と音出力を担当する関数は次
 のように記述できます。

void perform_state()
{
  word xf ;
  word xt ;
  /* default */
  xf = 440 ;
  xt = 1000 ;
  /* LED_3 */
  digitalWrite(LED_3,HIGH);
  tone(SOUND_BIT,xf,xt);
  digitalWrite(LED_3,LOW);
  /* LED_2 */
  digitalWrite(LED_2,HIGH);
  tone(SOUND_BIT,xf,xt);
  digitalWrite(LED_2,LOW);
  /* LED_1 */
  digitalWrite(LED_1,HIGH);
  tone(SOUND_BIT,xf,xt);
  digitalWrite(LED_1,LOW);
  /* LED_0 */
  xf = 880 ;
  digitalWrite(LED_0,HIGH);
  tone(SOUND_BIT,xf,xt);
  digitalWrite(LED_0,LOW);
}

 こちらの方が状態遷移図を、そのまま
 プログラムにしたように見えます。

 全体は、以下。

#include <MsTimer2.h>

#define OFF 0
#define ON  OFF+1

#define MODE_IDLE 0
#define MODE_RUN  1

#define PSHB 8

#define LED_M 13
#define LED_0 14
#define LED_1 15
#define LED_2 16
#define LED_3 17

#define SOUND_BIT 9

byte state;
byte sft;
byte xcnt;
boolean tflag;

void  send_led(byte x)
{
  if ( x ) { digitalWrite(LED_M,HIGH); }
  else     { digitalWrite(LED_M,LOW ); }
}

void  update_trigger(void)
{
  /* flash LED */
  send_led( xcnt & ON );
  /* update counter */
  xcnt++ ;
  /* set flag */
  tflag = ON ;
}

void perform_state()
{
  word xf ;
  word xt ;
  /* default */
  xf = 440 ;
  xt = 1000 ;
  /* LED_3 */
  digitalWrite(LED_3,HIGH);
  tone(SOUND_BIT,xf,xt);
  digitalWrite(LED_3,LOW);
  /* LED_2 */
  digitalWrite(LED_2,HIGH);
  tone(SOUND_BIT,xf,xt);
  digitalWrite(LED_2,LOW);
  /* LED_1 */
  digitalWrite(LED_1,HIGH);
  tone(SOUND_BIT,xf,xt);
  digitalWrite(LED_1,LOW);
  /* LED_0 */
  xf = 880 ;
  digitalWrite(LED_0,HIGH);
  tone(SOUND_BIT,xf,xt);
  digitalWrite(LED_0,LOW);
}

void  setup(void)
{
  /* set I/O values */
  digitalWrite(LED_0,LOW);
  digitalWrite(LED_1,LOW);
  digitalWrite(LED_2,LOW);
  digitalWrite(LED_3,LOW);
  digitalWrite(SOUND_BIT,LOW);
  /* set port directions */
  pinMode(PSHB ,INPUT);
  pinMode(LED_0,OUTPUT);
  pinMode(LED_1,OUTPUT);
  pinMode(LED_2,OUTPUT);
  pinMode(LED_3,OUTPUT);
  pinMode(LED_M,OUTPUT);
  pinMode(SOUND_BIT,OUTPUT);
  /* clear flag */
  tflag = OFF ;
  /* set others */
  xcnt = 0 ;
  sft  = 0 ;
  state = MODE_IDLE ;
  /* 500ms period */
  MsTimer2::set(500,update_trigger);
  /* enable */ 
  MsTimer2::start();
}

void loop(void)
{
  /* shift register */
  if ( tflag == ON ) {
    /* clear */
    tflag = OFF ;
    /* shift */
    sft <<= 1 ;
    /* mask */
    sft &= 3 ;
    /* get switch state */
    if ( digitalRead(PSHB) == HIGH ) { sft |= ON ; }
    /* judge */
    if ( sft == 1 ) { state = MODE_RUN ; }
  }
  /* execute */
  if ( state == MODE_RUN ) {
    /* perform */
    perform_state();
    /* return */
    state = MODE_IDLE ;
  }
}


目次

inserted by FC2 system