8pinoでSoftwareSerialを使う その2
以前の投稿
で
ただ、あまりUART経由で指示を出すと、電子工作の勉強からは外れてしまうので、それほど深堀しない予定です。
と言ったはずですが、ソフト屋さんとしては、ちょっとだけ、パチコチやりたくなってしまうわけです。
と言うわけで
まずは対話型のインターフェースの基礎をテストすべく、Neopixelの制御を実装してみました。
動画はこちら
仕様は下記の通り
- r → 赤く光る
- g → 緑色に光る
- b → 青く光る
- 8 → 七色に光る
- x → 消灯
ターミナル上はこんな感じ。
うん、想定通り動いています。
※ コードは一番下に記載。
もう一個くらい、デモしたい
せっかくベースを作ったので、他の例も試してみたいです。
この間
とかのシリーズで、圧電スピーカーを制覇したので、これを応用してみたい!
そんな前提で辺りを見回すと、こんなものがありました。
子供向け(おもちゃ)のピアノ絵本です。
これを作ってみましょう。
キーボードに対して、白鍵・黒鍵をこのようにマッピングします。
そして、結果
できました。
今回も音階に合わせて、LED光らせています。
ピアノを習っている六歳児に渡すと、それなりに弾ける様でした。
ターミナルの様子。
考察
ピアノ絵本は楽天価格で、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 ); } }