目次

乱数でイルミネーション

 ArduinoのAPIには、乱数を発生するrandomが
 あります。
 このAPIで、イルミネーションを実現。

 LEDは11個を、電流制限抵抗といっしょに
 ブレッドボードに差し込み。



 回路は、単純。



 電流制限抵抗の値は、VFを2Vとし、Arduinoの
 GPIOピンから5V出力するとして、次のように
 計算し、問題がないことを確認。

    i = (5V-2V)/470(Ω)
      = 3V / 470(Ω)
      = 3V / 500(Ω)
      = 3000mV / 500(Ω)
      = 6mA

 LEDに流れる電流は、7mAまではないので、破損は
 ないでしょう。

 許容電力250mWのカーボン抵抗で、耐えられるかを
 計算してみると、50mAくらいで1/5くらいでOK。

  W = V x i
    = 3V x 6mA
    = 48mA

 LEDを11個使うので、どのピンに接続するのかを
 マクロ定義。

#define LED00 3
#define LED01 4
#define LED02 5
#define LED03 6
#define LED04 7
#define LED05 8
#define LED06 9
#define LED07 10
#define LED08 11
#define LED09 12
#define LED10 14

 Arduino基板には、D13にLEDが接続されている
 ので、そのピンをスキップ。

 回路図から、LEDを接続するピンを初期化する
 関数を定義して、関数setup()内で使えるよう
 にしておきます。

#define OFF 0
#define ON  OFF+1

void init_led_pins()
{
  byte ii ;

  for ( ii = 0 ; ii < 10 ; ii++ ) {
    digitalWrite( LED00 + ii , OFF );
    pinMode( LED00 + ii , OUTPUT );
  }
  digitalWrite( LED10 , OFF );
  pinMode( LED10 , OUTPUT );
}

 ピン番号が連番であれば、for文を利用して
 全部のピンの論理値と入出力を指定できます
 が、LED10だけ番号が飛んでいるので、for文
 の外でコンフィグレーション。

 乱数を生成して、1個のLEDだけ点灯する
 ステートマシンを定義。

#define LCNTMAX 3000

byte lstate ;
byte rd ;
unsigned long lcnt ;

void led_handling()
{
  switch ( lstate ) {
    /* generate random number */
    case 0 :
             rd = random(11);
             lstate = 1 ;
             break ;
    /* turn on target LED and duration */
    case 1 :
             led_on( rd );
             lcnt = millis() + LCNTMAX ;
             lstate = 2 ;
             break ;
    /* delay */
    case 2 :
             lstate = 2 ;
             if ( millis() > lcnt ) { state = 3 ; }
             break ;
    /* return first state */
    case 3 :
             lstate = 0 ;
             break ;
    /* others */
    default :
             break ;
  }
}

 ステートマシンの中で使っているLEDを1個だけ
 点灯する処理関数を定義します。

void led_on(byte x)
{
  byte ii ;
  /* turn off all LEDs */
  for ( ii = 0 ; ii < 10 ; ii++ ) {
    digitalWrite( LED00 + ii , OFF );
  }
  digitalWrite( LED10 , OFF );
  /* turn of target LED */
  if ( x > 9 ) {
    digitalWrite( LED10 , ON ) ;
  } else {
    digitalWrite( LED00 + x , ON ) ;
  }
}

 ステートマシンを動かすためには、状態変数lstateの
 初期化が必要なので、関数init_led_pinsに入れて対応。

void init_led_pins()
{
  byte ii ;

  for ( ii = 0 ; ii < 10 ; ii++ ) {
    digitalWrite( LED00 + ii , OFF );
    pinMode( LED00 + ii , OUTPUT );
  }
  digitalWrite( LED10 , OFF );
  pinMode( LED10 , OUTPUT );
  /* initialize state value */
  lstate = 0 ;
}

 スケッチ作成の部品が揃ったのでまとめ。

#define LED00 3
#define LED01 4
#define LED02 5
#define LED03 6
#define LED04 7
#define LED05 8
#define LED06 9
#define LED07 10
#define LED08 11
#define LED09 12
#define LED10 14

#define OFF 0
#define ON  OFF+1

#define LCNTMAX 3000

byte lstate ;
byte rd ;
unsigned long lcnt ;

void init_led_pins()
{
  byte ii ;

  for ( ii = 0 ; ii < 10 ; ii++ ) {
    digitalWrite( LED00 + ii , OFF );
    pinMode( LED00 + ii , OUTPUT );
  }
  digitalWrite( LED10 , OFF );
  pinMode( LED10 , OUTPUT );
  /* initialize state value */
  lstate = 0 ;
}

void led_on(byte x)
{
  byte ii ;
  /* turn off all LEDs */
  for ( ii = 0 ; ii < 10 ; ii++ ) {
    digitalWrite( LED00 + ii , OFF );
  }
  digitalWrite( LED10 , OFF );
  /* turn of target LED */
  if ( x > 9 ) {
    digitalWrite( LED10 , ON ) ;
  } else {
    digitalWrite( LED00 + x , ON ) ;
  }
}

void led_handling()
{
  switch ( lstate ) {
    /* generate random number */
    case 0 :
             rd = random(11);
             lstate = 1 ;
             break ;
    /* turn on target LED and duration */
    case 1 :
             led_on( rd );
             lcnt = millis() + LCNTMAX ;
             lstate = 2 ;
             break ;
    /* delay */
    case 2 :
             lstate = 2 ;
             if ( millis() > lcnt ) { state = 3 ; }
             break ;
    /* return first state */
    case 3 :
             lstate = 0 ;
             break ;
    /* others */
    default :
             break ;
  }
}

void setup()
{
  init_led_pins();
}

void loop()
{
  led_handling();
}

 イルミネーションごときに、ステートマシンを
 使うことはないだろうと言われましたが、複数
 のLED基板があったなら、ステートマシンを使う
 ことなしに実現したら、バグの嵐で完成しない
 でしょう。

 ArduinoMega2560のように、多数のI/Oピンを
 持つマイコン基板では、次のようにLEDを接続
 すると、初期化と点灯するLEDを指定する関数
 が単純になります。



 初期化は、次のように単純に。

#define OFF 0
#define ON  OFF+1

#define PS0 24

void init_led_pins()
{
  byte ii ;

  for ( ii = 0 ; ii < 11 ; ii++ ) {
    digitalWrite( PS0 + ii , OFF );
    pinMode( PS0 + ii , OUTPUT );
  }
  /* initialize state value */
  lstate = 0 ;
}

 ターゲットとするLEDの点灯は、for文と
 switchを利用して記述。

void led_on(byte x)
{
  byte ii ;
  /* judge */
  if ( x > 10 ) return ;
  /* turn off all LEDs */
  for ( ii = 0 ; ii < 11 ; ii++ ) {
    digitalWrite( PS0 + ii , OFF );
  }
  /* turn of target LED */
  digitalWrite( PS0 + x , ON ) ;
}

 下位の関数を書き換えたので、全体は
 次のソースコードに。

#define OFF 0
#define ON  OFF+1

#define PS0 24

#define LCNTMAX 3000

byte lstate ;
byte rd ;
unsigned long lcnt ;

void init_led_pins()
{
  byte ii ;

  for ( ii = 0 ; ii < 11 ; ii++ ) {
    digitalWrite( PS0 + ii , OFF );
    pinMode( PS0 + ii , OUTPUT );
  }
  /* initialize state value */
  lstate = 0 ;
}

void led_on(byte x)
{
  byte ii ;
  /* judge */
  if ( x > 10 ) return ;
  /* turn off all LEDs */
  for ( ii = 0 ; ii < 11 ; ii++ ) {
    digitalWrite( PS0 + ii , OFF );
  }
  /* turn of target LED */
  digitalWrite( PS0 + x , ON ) ;
}

void led_handling()
{
  switch ( lstate ) {
    /* generate random number */
    case 0 :
             rd = random(11);
             lstate = 1 ;
             break ;
    /* turn on target LED and duration */
    case 1 :
             led_on( rd );
             lcnt = millis() + LCNTMAX ;
             lstate = 2 ;
             break ;
    /* delay */
    case 2 :
             lstate = 2 ;
             if ( millis() > lcnt ) { state = 3 ; }
             break ;
    /* return first state */
    case 3 :
             lstate = 0 ;
             break ;
    /* others */
    default :
             break ;
  }
}

void setup()
{
  init_led_pins();
}

void loop()
{
  led_handling();
}

 下位の関数を書き換えるだけで、上位の
 関数、手続きをかえないで済ませられる
 のが、ポイント。


目次

inserted by FC2 system