NeoPixel カラーピッカー
NeoPixel 楽しいんだけども
狙った色が出なくて RGB値を変更しては書き込みを繰り返したりとか、ありがちです。割とどうでもいいところなのに時間がかかります。
書き込む前に光らせて確認してみよう
というわけで NeoPixel を指定した RGB値 で光らせるだけのモノです。色合いを保ったまま明るさを変えて…とかできるように HSV値での設定もできるようにしました。
ハード
SODIAL(R)キーパッド シールド ボード ブルー バックライト Arduinoロボット LCD 1602 1280 2560 UNO US用品
- 出版社/メーカー: SODIAL
- メディア: エレクトロニクス
- この商品を含むブログを見る
NeoPixel は WS2812B
改良の余地
NeoPixel には、今回使った WS2812B の他にも、赤緑青白の4色の素子の入った SK6812 もあります。そちらはまたちょっと色合いが変わってくるので両方対応できるといいかも。
スケッチ
#define ITEM "ColorPicker" #define VER "180124" #include <Adafruit_NeoPixel.h> #define PIN_PIXELS A1 #define PIXELS_N 9 Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXELS_N, PIN_PIXELS, NEO_GRB + NEO_KHZ800); int hue = 0, // 色相 sat = 255, // 彩度 val = 128, // 明度 red = 128, // 赤 grn = 0, // 青 blu = 0; // 緑 int sp = 0, // selected position 設定項目 ap = 1; // active pixels 点灯数 #include <LiquidCrystal.h> LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // LCDへの表示位置 #define LCD_H_T (0,0) // hue title #define LCD_H_V (1,0) // hue value #define LCD_S_T (6,0) // sat title #define LCD_S_V (7,0) // sat value #define LCD_V_T (12,0) // val title #define LCD_V_V (13,0) // val value #define LCD_R_T (0,1) // red title #define LCD_R_V (1,1) // red value #define LCD_G_T (6,1) // grn title #define LCD_G_V (7,1) // grn value #define LCD_B_T (12,1) // blu title #define LCD_B_V (13,1) // blu value #define btnRIGHT 0 #define btnUP 1 #define btnDOWN 2 #define btnLEFT 3 #define btnSELECT 4 #define btnNONE 5 void setup() { lcd.begin(16, 2); pixels.begin(); opening(); change_value(0); pixels_set(); lcd.clear(); set_lcd_title(); set_lcd_value(); lcd.cursor(); lcd.blink(); change_sp(0); // カーソル移動 } void loop() { load_key(); delay(10); // test_ad_value(); // キー入力デバッグ用 // delay(100); } void opening() { lcd.clear(); lcd.print(ITEM); lcd.setCursor(0, 1); lcd.print(VER); int pix[] = {0, 1, 2, 5, 8, 7, 6, 3}; // NeoPixelを点灯させる順番 for (int n = 0; n < sizeof(pix) / sizeof(pix[0]); n++) { hsv_to_rgb(n * 40 - 3, 255, 128); pixels.setPixelColor(pix[n], pixels.Color(red, grn, blu)); pixels.show(); delay(200); } hsv_to_rgb(0, 0, 128); pixels.setPixelColor(4, pixels.Color(red, grn, blu)); pixels.show(); delay(500); } void change_sp(int i) { sp = sp + i; if (sp > 5) sp = 0; if (sp < 0) sp = 5; switch (sp) { case 0: lcd.setCursor LCD_H_T; break; case 1: lcd.setCursor LCD_S_T; break; case 2: lcd.setCursor LCD_V_T; break; case 3: lcd.setCursor LCD_R_T; break; case 4: lcd.setCursor LCD_G_T; break; case 5: lcd.setCursor LCD_B_T; break; } } void change_value(int i) { int h = hue, s = sat, v = val, r = red, g = grn, b = blu; switch (sp) { case 0: h = h + i; if (h < 0) h = h + 360; if (h >= 360) h = h - 360; hsv_to_rgb(h, s, v); hue = h; break; case 1: s = s + i; if (s > 255) s = 255; if (s < 0) s = 0; hsv_to_rgb(h, s, v); sat = s; break; case 2: v = v + i; if (v > 255) v = 255; if (v < 0) v = 0; hsv_to_rgb(h, s, v); val = v; break; case 3: r = r + i; if (r > 255) r = 255; if (r < 0) r = 0; rgb_to_hsv(r, g, b); red = r; break; case 4: g = g + i; if (g > 255) g = 255; if (g < 0) g = 0; rgb_to_hsv(r, g, b); grn = g; break; case 5: b = b + i; if (b > 255) b = 255; if (b < 0) b = 0; rgb_to_hsv(r, g, b); blu = b; break; } } /*---------------------------------------- LCD FUNCTIONS ----------------------------------------*/ void set_lcd_title() { lcd.setCursor LCD_H_T; lcd.print("H"); lcd.setCursor LCD_S_T; lcd.print("S"); lcd.setCursor LCD_V_T; lcd.print("V"); lcd.setCursor LCD_R_T; lcd.print("R"); lcd.setCursor LCD_G_T; lcd.print("G"); lcd.setCursor LCD_B_T; lcd.print("B"); } void set_lcd_value() { lcd.setCursor LCD_H_V; aline3(hue); lcd.setCursor LCD_S_V; aline3(sat); lcd.setCursor LCD_V_V; aline3(val); lcd.setCursor LCD_R_V; aline3(red); lcd.setCursor LCD_G_V; aline3(grn); lcd.setCursor LCD_B_V; aline3(blu); } void aline3(int num) { if (num < 100) lcd.print(" "); if (num < 10) lcd.print(" "); lcd.print(num); } /*---------------------------------------- KEY FUNCTIONS ----------------------------------------*/ void load_key() { static int prev_key = btnNONE, prev2_key = btnNONE; static unsigned long on_time = millis(); unsigned long now = millis(); int key = read_LCD_buttons(); if (prev_key == btnNONE && key != btnNONE) on_time = millis(); // UP/DOWN用 有効判定 boolean valid = prev_key == btnNONE && key != btnNONE; valid = valid || now - on_time > 500; switch (key) { case btnRIGHT: // if (prev_key == btnNONE) delay(100); if (prev_key == key && prev2_key == btnNONE) { change_sp(1); } break; case btnLEFT: // if (prev_key == btnNONE) delay(100); if (prev_key == key && prev2_key == btnNONE) { change_sp(-1); } break; case btnUP: if (valid) { change_value(1); set_lcd_value(); change_sp(0); pixels_set(); } break; case btnDOWN: if (valid) { change_value(-1); set_lcd_value(); change_sp(0); pixels_set(); } break; case btnSELECT: // if (prev_key == btnNONE) delay(100); if (prev_key == key && prev2_key == btnNONE) { ap++; if (ap > 4) ap = 0; pixels_set(); } break; case btnNONE: break; } prev2_key = prev_key; prev_key = key; } // read the buttons int read_LCD_buttons() { int adc_key_in = analogRead(0); // キー入力のAD値 読み込み if (adc_key_in > 1000) return btnNONE; if (adc_key_in < 10) return btnRIGHT; // AD実測 0 if (111 < adc_key_in && adc_key_in < 141) return btnUP; // AD実測 131 if (297 < adc_key_in && adc_key_in < 317) return btnDOWN; // AD実測 307 if (469 < adc_key_in && adc_key_in < 489) return btnLEFT; // AD実測 479 if (711 < adc_key_in && adc_key_in < 731) return btnSELECT; // AD実測 721 return btnNONE; // どれにも該当しなかったら何も押されてないものとする } /*---------------------------------------- COLOR FUNCTIONS ----------------------------------------*/ void rgb_to_hsv(int r, int g, int b) { if (r > 255) r = 255; if (r < 0) r = 0; if (g > 255) g = 255; if (g < 0) g = 0; if (b > 255) b = 255; if (b < 0) b = 0; float h, s, v; // r,g,b の最大値と最小値を求める float ma = max(r, g); ma = max(ma, b); float mi = min(r, g); mi = min(mi, b); if (r == g && r == b) { h = 0; } else if (r >= g && r >= b) { h = 60.0 * (g - b) / (ma - mi); } else if (g >= r && g >= b) { h = 60.0 * (b - r) / (ma - mi) + 120.0; } else if (b >= r && b >= g) { h = 60.0 * (r - g) / (ma - mi) + 240.0; } if (h < 0) h = h + 360.0; hue = h + 0.5; if (hue >= 360) hue = hue - 360; s = (ma - mi) / ma * 255.0; v = ma; sat = s + 0.5; val = v + 0.5; } void hsv_to_rgb(float h, float s, float v) { while (h < 0) h += 360.0; while (h >= 360) h -= 360.0; float ma = v; float mi = ma - (s / 255.0 * ma); float r, g, b; switch ((int)h / 60) { case 0: r = ma; g = (h / 60.0) * (ma - mi) + mi; b = mi; break; case 1: r = ((120.0 - h) / 60.0) * (ma - mi) + mi; g = ma; b = mi; break; case 2: r = mi; g = ma; b = ((h - 120.0) / 60.0) * (ma - mi) + mi; break; case 3: r = mi; g = ((240.0 - h) / 60.0) * (ma - mi) + mi; b = ma; break; case 4: r = ((h - 240.0) / 60.0) * (ma - mi) + mi; g = mi; b = ma; break; case 5: r = ma; g = mi; b = ((360.0 - h) / 60.0) * (ma - mi) + mi; break; } // 四捨五入してグローバル変数に返す red = r + 0.5; grn = g + 0.5; blu = b + 0.5; } /*---------------------------------------- NEOPIXEL FUNCTIONS ----------------------------------------*/ void pixels_off() { for (int n = 0; n < PIXELS_N; n++) { pixels.setPixelColor(n, pixels.Color(0, 0, 0)); } pixels.show(); } void pixels_set() { switch (ap) { case 0: pixels_off(); break; case 1: for (int n = 0; n < PIXELS_N; n++) { switch (n) { case 4: pixels.setPixelColor(n, pixels.Color(red, grn, blu)); break; default: pixels.setPixelColor(n, pixels.Color(0, 0, 0)); } } break; case 2: for (int n = 0; n < PIXELS_N; n++) { switch (n) { case 4: case 5: pixels.setPixelColor(n, pixels.Color(red, grn, blu)); break; default: pixels.setPixelColor(n, pixels.Color(0, 0, 0)); } } break; case 3: for (int n = 0; n < PIXELS_N; n++) { switch (n) { case 4: case 5: case 7: case 8: pixels.setPixelColor(n, pixels.Color(red, grn, blu)); break; default: pixels.setPixelColor(n, pixels.Color(0, 0, 0)); } } break; case 4: for (int n = 0; n < PIXELS_N; n++) { pixels.setPixelColor(n, pixels.Color(red, grn, blu)); } break; } pixels.show(); } /*---------------------------------------- TEST FUNCTIONS ----------------------------------------*/ void test_ad_value() { lcd.clear(); lcd.print(analogRead(A0)); }