チラシのうら

レゴとか、工作とか。

8pinoでSoftwareSerialを使う その2

以前の投稿

ただ、あまりUART経由で指示を出すと、電子工作の勉強からは外れてしまうので、それほど深堀しない予定です。

と言ったはずですが、ソフト屋さんとしては、ちょっとだけ、パチコチやりたくなってしまうわけです。

と言うわけで

まずは対話型のインターフェースの基礎をテストすべく、Neopixelの制御を実装してみました。

動画はこちら

仕様は下記の通り

  • r → 赤く光る
  • g → 緑色に光る
  • b → 青く光る
  • 8 → 七色に光る
  • x → 消灯

ターミナル上はこんな感じ。 f:id:tetunori_lego:20150602070055j:plain
うん、想定通り動いています。
※ コードは一番下に記載。

もう一個くらい、デモしたい

せっかくベースを作ったので、他の例も試してみたいです。

この間 とかのシリーズで、圧電スピーカーを制覇したので、これを応用してみたい!
そんな前提で辺りを見回すと、こんなものがありました。 f:id:tetunori_lego:20150602074521j:plain
子供向け(おもちゃ)のピアノ絵本です。
これを作ってみましょう。

キーボードに対して、白鍵・黒鍵をこのようにマッピングします。 f:id:tetunori_lego:20150602074656j:plain

そして、結果

できました。

今回も音階に合わせて、LED光らせています。

ピアノを習っている六歳児に渡すと、それなりに弾ける様でした。

ターミナルの様子。
f:id:tetunori_lego:20150602075847j:plain

考察

ピアノ絵本は楽天価格で、2000円以上するみたいなので、わりとリーズナブルに同程度の環境が構築出来たことになります。

だから、何?

後、やっぱり、出来そうなことをやって、
結果、出来ても、成長はしないですね。
次回は電子工作寄りの話に戻します。

LEDのコードはこちら。

/*
  Software serial test
  Control Adafruit Neopixel Ring
 */

#include <SoftwareSerial.h>

/*************************************************
* For Adafruit NeoPixel
*************************************************/
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
 #include <avr/power.h>
#endif

#define NEOPIXEL_IN_PIN 0
#define NUM_OF_PIXELS 16

Adafruit_NeoPixel pixels = Adafruit_NeoPixel( NUM_OF_PIXELS, NEOPIXEL_IN_PIN );

#define _8PINO_SOFTWARE_SERIAL_PIN_RX ( 1 ) 
#define _8PINO_SOFTWARE_SERIAL_PIN_TX ( 2 ) 

#define _8PINO_PRINT_NEOPIXEL_RING_CONTROL ( "\r\n  Neopixel Ring -> " )

#define _8PINO_PROMPT_STRING ( "\r\n8pino > " )

SoftwareSerial mySerial( _8PINO_SOFTWARE_SERIAL_PIN_RX, _8PINO_SOFTWARE_SERIAL_PIN_TX );

void setup()  
{
  
  pinMode( NEOPIXEL_IN_PIN, OUTPUT );
  
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
  if( F_CPU == 16000000 ) clock_prescale_set( clock_div_1 );
#endif
  pixels.begin();
  pixels.setBrightness(30);
  pixels.show(); // Initialize all pixels to "off"
  
  // set the data rate for the SoftwareSerial port
  mySerial.begin(4800);
  mySerial.println("");
  mySerial.println("--- Hello! from 8pino... ---");
  mySerial.write( _8PINO_PROMPT_STRING );
  
}

void loop() // run over and over
{
  
  int tmp_char = 0;
  int i = 0;
  
  if ( mySerial.available() ){
    tmp_char = mySerial.read();
    if( tmp_char == '\r' ){
      mySerial.write( _8PINO_PROMPT_STRING );
    }else if( tmp_char == 'r' ){
      mySerial.write( tmp_char );
      mySerial.write( _8PINO_PRINT_NEOPIXEL_RING_CONTROL);
      mySerial.write( "Red!" );
      for( i = 0; i < NUM_OF_PIXELS; i++ ){
        pixels.setPixelColor( i, 255, 0, 0 );
      }
      pixels.show();
      mySerial.write( _8PINO_PROMPT_STRING );
    }else if( tmp_char == 'g' ){
      mySerial.write( tmp_char );
      mySerial.write( _8PINO_PRINT_NEOPIXEL_RING_CONTROL);
      mySerial.write( "Green!" );
      for( i = 0; i < NUM_OF_PIXELS; i++ ){
        pixels.setPixelColor( i, 0, 255, 0 );
      }
      pixels.show();
      mySerial.write( _8PINO_PROMPT_STRING );
    }else if( tmp_char == 'b' ){
      mySerial.write( tmp_char );
      mySerial.write( _8PINO_PRINT_NEOPIXEL_RING_CONTROL);
      mySerial.write( "Blue!" );
      for( i = 0; i < NUM_OF_PIXELS; i++ ){
        pixels.setPixelColor( i, 0, 0, 255 );
      }
      pixels.show();
      mySerial.write( _8PINO_PROMPT_STRING );
    }else if( tmp_char == '8' ){
      mySerial.write( tmp_char );
      mySerial.write( _8PINO_PRINT_NEOPIXEL_RING_CONTROL);
      mySerial.write( "Rainbow!" );
      for( i = 0; i < NUM_OF_PIXELS; i++ ){
        pixels.setPixelColor( i, Wheel( ( i * 256 / pixels.numPixels() ) & 255 ) );
      }
      pixels.show();
      mySerial.write( _8PINO_PROMPT_STRING );
    }else if( tmp_char == 'x' ){
      mySerial.write( tmp_char );
      mySerial.write( _8PINO_PRINT_NEOPIXEL_RING_CONTROL);
      mySerial.write( "Off!" );
      for( i = 0; i < NUM_OF_PIXELS; i++ ){
        pixels.setPixelColor( i, 0, 0, 0 );
      }
      pixels.show();
      mySerial.write( _8PINO_PROMPT_STRING );
    }else{
      mySerial.write( tmp_char );
    }
  }
  
}

uint32_t Wheel(byte WheelPos) {
  
  if(WheelPos < 85) {
   return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  
}

ピアノのコードはこちら。

/*
  Software serial test
  Control Buzzer
 */

#include <SoftwareSerial.h>

/*************************************************
* For Adafruit NeoPixel
*************************************************/
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
 #include <avr/power.h>
#endif

#define NEOPIXEL_IN_PIN 0
#define NUM_OF_PIXELS 16

Adafruit_NeoPixel pixels = Adafruit_NeoPixel( NUM_OF_PIXELS, NEOPIXEL_IN_PIN );

#define _8PINO_SOFTWARE_SERIAL_PIN_RX ( 1 ) 
#define _8PINO_SOFTWARE_SERIAL_PIN_TX ( 2 ) 

#define _8PINO_PROMPT_STRING ( "\r\n8pino > " )

SoftwareSerial mySerial( _8PINO_SOFTWARE_SERIAL_PIN_RX, _8PINO_SOFTWARE_SERIAL_PIN_TX );

#define _8PINO_TONE_DELAY_TIME  ( 150 )

#define _8PINO_TONE_SPEAKER_PIN_1 ( 1 )
#define _8PINO_TONE_SPEAKER_PIN_2 ( 4 )

#define _8PINO_TONE_START ( 0x00 )
#define _8PINO_TONE_STOP  ( 0x01 )

#define _8PINO_TONE_NOT_USED ( 0 )

#define _8PINO_TONE_DO_2    ( 238 )
#define _8PINO_TONE_RE_2    ( 212 )
#define _8PINO_TONE_MI_2    ( 189 )
#define _8PINO_TONE_FA_2    ( 178 )
#define _8PINO_TONE_FA_SH_2 ( 168 )
#define _8PINO_TONE_SO_2    ( 158 )
#define _8PINO_TONE_SO_SH_2 ( 150 )
#define _8PINO_TONE_RA_2    ( 141 )
#define _8PINO_TONE_SI_FL_2 ( 133 )
#define _8PINO_TONE_SI_2    ( 126 )
#define _8PINO_TONE_DO_3    ( 118 )
#define _8PINO_TONE_DO_SH_3 ( 112 )
#define _8PINO_TONE_RE_3    ( 106 )
#define _8PINO_TONE_RE_SH_3 (  99 )
#define _8PINO_TONE_MI_3    (  94 )
#define _8PINO_TONE_FA_3    (  89 )
#define _8PINO_TONE_FA_SH_3 (  83 )
#define _8PINO_TONE_SO_3    (  79 )
#define _8PINO_TONE_SO_SH_3 (  74 )
#define _8PINO_TONE_RA_3    (  70 )
#define _8PINO_TONE_SI_FL_3 (  66 )
#define _8PINO_TONE_SI_3    (  62 )
#define _8PINO_TONE_DO_4    (  59 )
#define _8PINO_TONE_DO_SH_4 (  55 )
#define _8PINO_TONE_RE_4    (  52 )
#define _8PINO_TONE_MI_4    (  46 )
#define _8PINO_TONE_FA_4    (  44 )
#define _8PINO_TONE_SO_4    (  39 )
#define _8PINO_TONE_RA_4    (  34 )

void setup()  
{
  
  pinMode( NEOPIXEL_IN_PIN, OUTPUT );
  pinMode( _8PINO_TONE_SPEAKER_PIN_2, OUTPUT );
  
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
  if( F_CPU == 16000000 ) clock_prescale_set( clock_div_1 );
#endif
  pixels.begin();
  pixels.setBrightness(15);
  pixels.show(); // Initialize all pixels to "off"
  
  // Configure Registers for PWM of PB4(PIN No.4)
  //  1. Comparator A Mode -> Set the OC1A output line.
  //  2. Time/Counter1 Prescale Select -> 8MHz/256 = 32KHz.
  //  3. Enable Pulse Width Modulator B.
  //  4. Comparator B Mode -> Set the OC1B output line
  TCCR1 = _BV (COM1A1) | _BV (COM1A0) | 
             _BV (CS13) | _BV (CS10);
  GTCCR = _BV (PWM1B) | _BV (COM1B1) | _BV (COM1B0);
  
  // set the data rate for the SoftwareSerial port
  mySerial.begin(4800);
  // mySerial.println("");
  // mySerial.println("--- Hello! from 8pino... ---");
  mySerial.write( _8PINO_PROMPT_STRING );
  
}

void loop() // run over and over
{
  
  int tmp_char = 0;
  int i = 0;
  int note = 0;
  int light_index = 0;
  
  if ( mySerial.available() ){
    tmp_char = mySerial.read();
    if( tmp_char == '\r' ){
      mySerial.write( _8PINO_PROMPT_STRING );
    }else{
      mySerial.write( tmp_char );
      mySerial.write( "\r\n " );
      switch( tmp_char ){
        case 'q':
          mySerial.write( "FA# 2" );
          note = _8PINO_TONE_FA_SH_2;
          light_index = 1;
          break;
        case 'a':
          mySerial.write( "SO 2" );
          note = _8PINO_TONE_SO_2;
          light_index = 2;
          break;
        case 'w':
          mySerial.write( "SO# 2" );
          note = _8PINO_TONE_SO_SH_2;
          light_index = 2;
          break;
        case 's':
          mySerial.write( "RA 2" );
          note = _8PINO_TONE_RA_2;
          light_index = 3;
          break;
        case 'e':
          mySerial.write( "SIb 2" );
          note = _8PINO_TONE_SI_FL_2;
          light_index = 3;
          break;
        case 'd':
          mySerial.write( "SI 2" );
          note = _8PINO_TONE_SI_2;
          light_index = 4;
          break;
        case 'f':
          mySerial.write( "DO 3" );
          note = _8PINO_TONE_DO_3;
          light_index = 5;
          break;
        case 't':
          mySerial.write( "DO# 3" );
          note = _8PINO_TONE_DO_SH_3;
          light_index = 5;
          break;
        case 'g':
          mySerial.write( "RE 3" );
          note = _8PINO_TONE_RE_3;
          light_index = 6;
          break;
        case 'y':
          mySerial.write( "RE# 3" );
          note = _8PINO_TONE_RE_SH_3;
          light_index = 6;
          break;
        case 'h':
          mySerial.write( "MI 3" );
          note = _8PINO_TONE_MI_3;
          light_index = 7;
          break;
        case 'j':
          mySerial.write( "FA 3" );
          note = _8PINO_TONE_FA_3;
          light_index = 8;
          break;
        case 'i':
          mySerial.write( "FA# 3" );
          note = _8PINO_TONE_FA_SH_3;
          light_index = 8;
          break;
        case 'k':
          mySerial.write( "SO 3" );
          note = _8PINO_TONE_SO_3;
          light_index = 9;
          break;
        case 'o':
          mySerial.write( "SO# 3" );
          note = _8PINO_TONE_SO_SH_3;
          light_index = 9;
          break;
        case 'l':
          mySerial.write( "RA 3" );
          note = _8PINO_TONE_RA_3;
          light_index = 10;
          break;
        case 'p':
          mySerial.write( "SIb 3" );
          note = _8PINO_TONE_SI_FL_3;
          light_index = 10;
          break;
        case ';':
          mySerial.write( "SI 3" );
          note = _8PINO_TONE_SI_3;
          light_index = 11;
          break;
        case ':':
          mySerial.write( "DO 4" );
          note = _8PINO_TONE_DO_4;
          light_index = 12;
          break;
        case '[':
          mySerial.write( "DO# 4" );
          note = _8PINO_TONE_DO_SH_4;
          light_index = 12;
          break;
        case ']':
          mySerial.write( "RE 4" );
          note = _8PINO_TONE_RE_4;
          light_index = 13;
          break;
        default : 
          mySerial.write( tmp_char );
          return;
      }
      
      _8pinoTone( _8PINO_TONE_SPEAKER_PIN_2, note, _8PINO_TONE_START );
      for( i = 0; i < light_index; i++ ){
        pixels.setPixelColor( i, 255, 255, 255 );
      }
      pixels.show();
      delay( _8PINO_TONE_DELAY_TIME );
      _8pinoTone( _8PINO_TONE_SPEAKER_PIN_2, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP );
      for( i = 0; i < NUM_OF_PIXELS; i++ ){
        pixels.setPixelColor( i, 0, 0, 0 );
      }
      pixels.show();
      mySerial.write( _8PINO_PROMPT_STRING );
      
    }
    
  }
  
}

void _8pinoTone( int pin_speaker, uint8_t freq, uint8_t startstop ){
  if( startstop == _8PINO_TONE_START ){
    pinMode( pin_speaker, OUTPUT );
    // if( pin_speaker == _8PINO_TONE_SPEAKER_PIN_1 ){
    //   OCR0A = freq;
    //   OCR0B = OCR0A - 1;
    // }else{
      OCR1C = freq;
      OCR1B = OCR1C - 1;
    // }
  }else{
     pinMode( pin_speaker, INPUT );
  }
}