LoginSignup
1
3

More than 5 years have passed since last update.

LCD KEYPAD SHIELD試してみた

Last updated at Posted at 2017-07-27

P_20170724_215323.jpg

参考にしたページ

お手軽にいろんなことが試せそうだなと思って買ってみました。
すでにネット上で得られる情報で十分なのですが、いろいろ試してみたら意外とうまくいったので書いてみました。
何かのお役にたてば。

こんなプログラムにしたい

このシールドはスイッチがA0に結線されていて、電圧を読んでどのスイッチか判別する必要があります。
多分使う時は、

  • A0を読んで -> 平滑化して -> どのキーか判別して -> キーに応じて何かする
  • ちょっと待つ
  • 最初に戻る

という流れになるかと思います。
なのでとりあえずloopをこんな風にしてみました。

void loop() {
 // キーに応じて何かする <- どのキーか判別して <- 平滑化して <- A0を読んで
    actionByKey(         aKeyFromData(      smoothData( analogRead( A0 ) ) ) );
    delay( 1 );
}

まだ何にも決めていませんが、それっぽい名前をつけた関数を並べてみました。
これに合うように関数を作っていきたいと思います。

関数をどうするか

smoothData,aKeyFromData,actionByKeyと三つの関数を作ります。

  • 引数は整数がひとつだけ。
  • 返り値は整数。

ということにすればうまくいきそうです。
関数を作るときには他にも引数が必要になることもあるので、そこは部分適用で対応することにします。
補足記事:部分適用っておいしいの? on Arduino

まず、平滑化する関数。

auto smoothF ( 
  []( const long RATE = 20 ){
    long previousValue ( 0 );
    return [=]( const long CURRENT_VALUE ) mutable -> long {       
      return previousValue = (RATE * CURRENT_VALUE + (100 - RATE) * previousValue  ) / 100;
    };
  } 
);
auto smoothData ( smoothF( 50 ) );

直前値と現在値の加重平均を返します。
ほかのスケッチで使用したものの使い回しです。
ただし、反応がのろい感じがしたので加重平均の比率を上げてみました。

キーを判別する関数。

auto aKeyFromDataF (
  [](const int NO_KEY, const int NEITHER ){
      int previousValue ( NO_KEY );
      int confirmedValue ( NO_KEY );
      return [=]( const int DATA ) mutable -> int {
        const int CURRENT_VALUE ( whichKey( DATA ) );
        if( previousValue == NEITHER || CURRENT_VALUE == NEITHER ) {
          previousValue = CURRENT_VALUE;
          return confirmedValue;
        }
        if(  CURRENT_VALUE == previousValue ) return confirmedValue = CURRENT_VALUE;
        previousValue = CURRENT_VALUE;
        return confirmedValue;
      };
    }
 );
 auto aKeyFromData ( aKeyFromDataF( NO_KEY, NEITHER ) );

まだキーの値をどうするかとか決めてないのですが、とりあえず、なにか整数値で、

  • NO_KEYは何も押してない時の値
  • NEITHERはどのキーにもあてはまらない時の値

です。

whichKeyという関数を作って、データがどのキーにあたるか判別しています。
ただし、変動の途中でたまたまそのキーの値になってしまったということもあるので、

  • 直前値と現在値がともにNEITHER以外でかつ等しい場合、現在値を確定値に代入して返す
  • そうでなければ、現在値を直前値に代入し、確定値を返す

二つ同じキー値が続いたら新しいキー値として確定する、というようにしました。
whichKeyはこんな感じです。

auto whichKeyF (
  []( const int NO_KEY, const int SELECT_KEY, const int LEFT_KEY
    , const int DOWN_KEY, const int UP_KEY, const int RIGHT_KEY, const int NEITHER
  ){

    return [=] ( const int DATA ) mutable -> int {
      if( isInRange(     NO_KEY, DATA ) )  return  NO_KEY;
      if( isInRange( SELECT_KEY, DATA ) )  return  SELECT_KEY;
      if( isInRange(   LEFT_KEY, DATA ) )  return  LEFT_KEY;
      if( isInRange(   DOWN_KEY, DATA ) )  return  DOWN_KEY;
      if( isInRange(     UP_KEY, DATA ) )  return  UP_KEY;
      if( isInRange(  RIGHT_KEY, DATA ) )  return  RIGHT_KEY;
      return NEITHER;
    };
  }
);
auto whichKey ( whichKeyF( NO_KEY, SELECT_KEY, LEFT_KEY
                         , DOWN_KEY, UP_KEY, RIGHT_KEY, NEITHER ) );

データがどのキーか判別します。どれでもなかったらNEITHERを返します。
isInRangeという関数を作って、キーの範囲にデータがあるか判別しています。
キーの値をどうするか決めてませんが、後述のactionByKeyと同じものを使っていれば大丈夫だろう、という作戦です。
isInRangeはこんな感じです。

auto isInRangeF (
  [](const int KEY_RANGE ){
    return [=](const int KEY, const int DATA ) mutable -> bool {
      return DATA > KEY - KEY_RANGE && DATA < KEY + KEY_RANGE;
    };
  }
);
auto isInRange ( isInRangeF( KEY_RANGE ) );

( KEY - KEY_RANGE, KEY + KEY_RANGE ) の範囲内に DATA が入っているかを返します。

キーに応じて何かする関数。

auto actionByKeyF (
  []( const int NO_KEY, const int SELECT_KEY, const int LEFT_KEY
    , const int DOWN_KEY, const int UP_KEY, const int RIGHT_KEY
  ){
    return [=]( const int KEY ) mutable -> int {
       //Serial.println( KEY );
      if( KEY == NO_KEY ) return KEY;
      if( KEY == SELECT_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "SELECT_KEY" );
        return KEY;
      }
      if( KEY == LEFT_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "LEFT_KEY  " );
        return KEY;
      }
      if( KEY == DOWN_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "DOWN_KEY  " );
        return KEY;
      }
      if( KEY == UP_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "UP_KEY    " );
        return KEY;
      }
      if( KEY == RIGHT_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "RIGHT_KEY " );
        return KEY;
      }
      return KEY;
    };
  }
);
auto actionByKey ( actionByKeyF( NO_KEY, SELECT_KEY, LEFT_KEY
                               , DOWN_KEY, UP_KEY, RIGHT_KEY ) );

参考ページと同様に、とりあえずキーの名前を表示してみました。何か他のことをさせたいときはここを書き換えればOK。
用途によってはまだ使うかも知れないので、一応、引数をそのまま返り値にしています。

デバッグ用の関数。

auto sPrint( const int DATA ) -> int {
  Serial.print( DATA );
  Serial.print(",");
  return DATA;                 
};
auto sPrintln( const int DATA ) -> int {
  Serial.println(",");
  return DATA;                 
};

データの流れがどうなっているか見たかったので作ってみました。
引数をそのまま返しつつ、シリアルに出力します。
こんな風に見たいところに挟みこんで使います。便利。

  sPrintln( actionByKey( sPrint( aKeyFromData( 
    sPrint( smoothData( sPrint( analogRead( A0 ) 
    ) ) ) ) ) ) );

A0を読む -> シリアルに出力 -> 平滑化する -> シリアルに出力 -> キー値に変換 -> シリアルに出力 -> キーによって何かする -> シリアルを改行
という意味です。

プロッタに出してみたところ。
スクリーンショット 2017-07-26 18.25.12.png
青が生データ、赤が平滑化したもの、緑がキー値です。

キーの値は、0,1,2など別途IDを振ってもいいのですが、もろもろ簡単になるので 平滑化した値を実測したものにしました。IDイコール判断基準値ということです。
この流れでいくと、NEITHERは0から1023以外ならいいということになり、とりあえず-1ということにしました。

ここまで書いてきて、actionByKeyじゃないじゃん! actionByNewKeyじゃん!と気がつきました。
大概の場合、新しいキーが押された時だけ何かする、という方が使いでがあるようです。
使うこともあるかも知れないのでactionByKeyの方は処理の部分だけコメントアウトして残し、あらたにactionByNewKeyというのを加えました。といってもほとんど同じで、直前値と現在値が同じなら引数を返すだけで何もしない、というのが加わっただけです。

auto actionByKeyF (
  []( const int NO_KEY, const int SELECT_KEY, const int LEFT_KEY
    , const int DOWN_KEY, const int UP_KEY, const int RIGHT_KEY
  ){
    return [=]( const int KEY ) mutable -> int {
      if( KEY == NO_KEY ) return KEY;
      if( KEY == SELECT_KEY ){
//        lcd.setCursor( 0,1 );
//        lcd.print( "SELECT_KEY" );
        return KEY;
      }
      if( KEY == LEFT_KEY ){
//        lcd.setCursor( 0,1 );
//        lcd.print( "LEFT_KEY  " );
        return KEY;
      }
      if( KEY == DOWN_KEY ){
//        lcd.setCursor( 0,1 );
//        lcd.print( "DOWN_KEY  " );
        return KEY;
      }
      if( KEY == UP_KEY ){
//        lcd.setCursor( 0,1 );
//        lcd.print( "UP_KEY    " );
        return KEY;
      }
      if( KEY == RIGHT_KEY ){
//        lcd.setCursor( 0,1 );
//        lcd.print( "RIGHT_KEY " );
        return KEY;
      }
      return KEY;
    };
  }
);
auto actionByKey ( actionByKeyF( NO_KEY, SELECT_KEY, LEFT_KEY
                               , DOWN_KEY, UP_KEY, RIGHT_KEY ) );

auto actionByNewKeyF (
  []( const int NO_KEY, const int SELECT_KEY, const int LEFT_KEY
    , const int DOWN_KEY, const int UP_KEY, const int RIGHT_KEY
  ){
    int previousKey ( NO_KEY );
    return [=]( const int KEY ) mutable -> int {
      if( KEY == previousKey ) return KEY;
      if( KEY == NO_KEY ) return previousKey = KEY;
      if( KEY == SELECT_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "SELECT_KEY" );
        return previousKey = KEY;
      }
      if( KEY == LEFT_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "LEFT_KEY  " );
        return previousKey = KEY;
      }
      if( KEY == DOWN_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "DOWN_KEY  " );
        return previousKey = KEY;
      }
      if( KEY == UP_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "UP_KEY    " );
        return previousKey = KEY;
      }
      if( KEY == RIGHT_KEY ){
        lcd.setCursor( 0,1 );
        lcd.print( "RIGHT_KEY " );
        return previousKey = KEY;
      }
      return previousKey = KEY;
    };
  }
);
auto actionByNewKey ( actionByNewKeyF( NO_KEY, SELECT_KEY, LEFT_KEY
                               , DOWN_KEY, UP_KEY, RIGHT_KEY ) );

loopはこんな感じになりました。

void loop() {
  sPrintln( actionByNewKey( actionByKey( sPrint( aKeyFromData( 
    sPrint( smoothData( sPrint( analogRead( A0 ) 
    ) ) ) ) ) ) ) );
  delay( 1 );
}

最初のように言葉で書けば

  • A0を読む -> シリアルに出力 -> 平滑化する -> シリアルに出力 -> キー値に変換 -> シリアルに出力 -> キーによって何かする -> 新しいキーによって何かする -> シリアルを改行
  • ちょっと待つ
  • 最初に戻る

という流れです。

スケッチの全体はこちらからどうぞ。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3