Arduino と NeoPixel で作る ミニ電光掲示板
手のひらサイズの電光掲示板
Arduino + NeoPixelシールドで作るミニ電光掲示板
よく見たら「&」が鏡文字になってた....。 まぁいいや。
NeoPixel 楽しいです
NeoPixelはコントローラの入ったフルカラーLEDです。信号線は数珠つなぎにすれば良いので使用するマイコンのポートは1本のみ。一直線に連なったテープ状のもの、マトリックス状に並べたディスプレーのようなもの、リング状のもあります。もちろん1個ずつの単品も。今回使う部品はマイコンボード Arduino UNO とそれに簡単に接続できる NeoPixelシールド。40個の NeoPixel が 5×8のマトリックスに並んでいます。
Duinofun NeoPixel Shield for Arduino - 5x8=40 RGB LED Pixel Matrix
- 出版社/メーカー: WONDER ELECTRONICS
- メディア: その他
- この商品を含むブログを見る
改良の余地
PCのシリアルコンソールから入力した文字列をリピート表示できたら、ちょっとは使い道ありそうでしょうか。 アルファベット大文字小文字・数字・記号 だけならできるかも。
スケッチ
#include <math.h> #include <Adafruit_NeoPixel.h> #define PIN_PIXELS 6 #define NUM_PIXELS 40 #define NUM_PIXELS_H 5 #define NUM_PIXELS_W 8 #define PIXELS_BRIGHT 16 // NEOPIXELを点灯させる明るさ 0~255 Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_PIXELS, PIN_PIXELS, NEO_GRB + NEO_KHZ800); void setup() { pixels.begin(); } void loop() { show_message(); show_count(0, 99); } void show_message() { int sh = 5; // 表示内容の高さピクセル int sw = 62; // 表示内容の幅ピクセル int dh = NUM_PIXELS_H; // ディスプレーの高さピクセル int dw = NUM_PIXELS_W; // ディスプレーの幅ピクセル int r, g, b; // red green blue boolean str[sh][sw] = { {0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,1,0,0}, {0,0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0}, {0,0,1,1,0,0,0,0,0,1,0,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,1,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0}, {0,1,0,1,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0}, {0,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0} }; for (int c = 0; c < sw + dw; c++) { // スクロール for (int h = 0; h < dh; h++) { // 上の行から for (int w = 0; w < dw; w++) { // 左の列から if ((c + w < dw) || (c + w >= dw + sw)) { // 表示範囲外 continue; } else if (str[h][w - dw + c] == 1) { // 表示位置の データが 1 のとき r = PIXELS_BRIGHT; g = PIXELS_BRIGHT; b = PIXELS_BRIGHT; } else { // 表示位置のデータが 0 のとき r = 0; g = 0; b = 0; } pixels.setPixelColor(h * dw + w, pixels.Color(r, g, b)); } } pixels.show(); delay(100); // スクロール速度の設定 } } void show_count(int from, int to) { int chr_h = 5; int chr_w = 3; boolean chr[10][chr_h][chr_w] = { // 5x3で数字を描く // 0 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, // 1 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // 2 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, // 3 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, // 4 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, // 5 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, // 6 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, // 7 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, // 8 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, // 9 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, }; for (int c = from; c <= to; c++) { // c: count pixels_clear(); int pos; int rgbhsv[] = {c * 5, 255, PIXELS_BRIGHT}; hsv_to_rgb(rgbhsv); if (c < 10) { // 1桁のみ表示 pos = 3; for (int h = 0; h < chr_h; h++) { for (int w = 0; w < chr_w; w++) { if (chr[c][h][w] == 1) { pixels.setPixelColor(NUM_PIXELS_W * h + w + pos, pixels.Color(rgbhsv[0], rgbhsv[1], rgbhsv[2])); } } } } else { // 2桁以上の表示 pos = 1; // 10の位 for (int h = 0; h < chr_h; h++) { for (int w = 0; w < chr_w; w++) { if (chr[c / 10][h][w] == 1) { pixels.setPixelColor(NUM_PIXELS_W * h + w + pos, pixels.Color(rgbhsv[0], rgbhsv[1], rgbhsv[2])); } } } pos = 5; // 10の位 for (int h = 0; h < chr_h; h++) { for (int w = 0; w < chr_w; w++) { if (chr[c % 10][h][w] == 1) { pixels.setPixelColor(NUM_PIXELS_W * h + w + pos, pixels.Color(rgbhsv[0], rgbhsv[1], rgbhsv[2])); } } } } pixels.show(); delay(200); } } void pixels_clear() { // 全ピクセル消灯 for (int n = 0; n < NUM_PIXELS; n++) { pixels.setPixelColor(n, pixels.Color(0, 0, 0)); } } /*---------------------------------------- COLOR FUNCTIONS ----------------------------------------*/ void rgb_to_hsv(int rgbhsv[3]) { // RGB を HSV に変換 float r = rgbhsv[0], g = rgbhsv[1], b = rgbhsv[2]; float h, s, v; 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; if (h >= 360) h = h - 360.0; s = (ma - mi) / ma * 255.0; v = ma; rgbhsv[0] = (int)(h + 0.5); rgbhsv[1] = (int)(s + 0.5); rgbhsv[2] = (int)(v + 0.5); } void hsv_to_rgb(int rgbhsv[3]) { // HSV を RGB に変換 float h = (float)rgbhsv[0], s = (float)rgbhsv[1], v = (float)rgbhsv[2]; float ma = v; float mi = ma - (s / 255.0 * ma); float r, g, b; h = fmod(h, 360.0); 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; } rgbhsv[0] = (int)(r + 0.5); rgbhsv[1] = (int)(g + 0.5); rgbhsv[2] = (int)(b + 0.5); }
1 と 0 で点灯するピクセルを指定しています。
テキストエディタから 1, を検索してこんな感じにマーカーを付ければ出来上がりが見やすいし、上書きモードで書き換えていけば編集も楽です。