勝手な電子工作・・

勝手なオリジナル電子工作に関する記事を書きます

LEDテープで大ディスプレイを! (LEDテープその3)

f:id:a-tomi:20210818170901j:plain

お馴染みピクトグラムArduinoが次々に描きます。このディスプレイは安価なLED配列フィルムですが、Arduinoから1ワイヤで高速に描画できます。

これまでに書いたLEDテープ記事の続編ですが、前の2つの記事のリンクは次です。

カラーLEDテープ照明を自由にコントロール - 勝手な電子工作・・

LEDテープを使ったディスプレイの実験(Arduino-Unoで) - 勝手な電子工作・・

 

次のような大型、といっても8x32で256個のLEDが配列された柔らかいシートが売られているのを見つけました。AliExpressで1枚約800円でしたが、注文したら珍しく翌週にサッと到着。LEDテープというよりLEDシートというべきかもしれません。

f:id:a-tomi:20210818172350j:plain

しめしめ、これを3段つなげば32x24ドットができるぞ!

毎度ながら簡単・迅速に作りたいですし、また、後で部品に戻せるようにしたいもの。ここでは両面テープでプラバンに貼り付け、裏から配線することにします。

f:id:a-tomi:20210818172537j:plain

真ん中は電源供給ラインを並列につなぎます。信号線は最初の入り口は左上に(信号線とグランドのみ)が入り、右上から出た最後を真ん中左へ(信号線のみ1本でOK、グランドは電源側で接続されているわけなので)と配線。同じく中右から出た最後を左したへと配線して終わり。じつに単純ですね^^ 動かないようにセロテープで止めて出来上がり。電源は5V2AのACアダプターで十分でした。

32x24とはいえ、24x32と見る方が分かりやすい。とはいってもLEDの接続順序は表から見ると次のように少し複雑になります。これをXY座標として扱って、プログラム論理でこれにあうようにすればよいだけです。

f:id:a-tomi:20210818173422j:plain

柔らかいシートとはいっても、両面テープは時間が経つと、次の写真のようにジワリと剥がれて浮くところが少しでます。強力両面テープを使えばこうはなりませんが、後で分解しいやすくするためには、この程度ですかね。

f:id:a-tomi:20210818173939j:plain

見易さを兼ねて、たまたま手元にある薄黒い半透明アクリル板をこの上に重ねて使ってみます。なにせLEDは相当に眩しいですから。また、こうすることでディスプレイの平面も浮くことなく保てています。

FastLEDライブラリーは容量を食わずに便利ですが、この場合はLED数768個x3バイト(3色の値)ぶんの配列を内部でこしらえるため、ArduinoはMega2560を使うことにします。

画像データはPCのシリアルから送る方法でもよいと思いますが、持ち運び用に、ここではマイクロSDカードから入力することにしました。

1つのファイルが画面1頁です。中身は3色のデータ#RRGGBBを768個収容したファイルで、ファイル名を順次変化させることで、自動的にページを順番に読ませることにしました。

そのArduinoスケッチは後ろにつけておきます。

簡単にファイルを作るために、画像を24x32ピクセルBMPにして、それをPCで読み込ませます。簡単なSmallBasicでテスト用にちょこっと作ったWindows用のプログラムですが、ご参考のため記事の最後に添付しておきます。

そして表示の一例が次です。

f:id:a-tomi:20210818174951g:plain

実際はとても綺麗なのですが、LEDの輝度が高過ぎてうまく撮れませんm(_ _ )m

活字も、「ドットフォント」を絵と同じように扱えば大丈夫。ここで使っているドットフォントはフリーのKHドットフォントのなかにある、小伝馬町16というフォントです。True Typeフォントがしっかり提供されていますので、絵として使うのにも適しています。色々便利に使わせていただいています。OLEDなどの表示も画像としてとり扱うと手間がかからないのでなかなかいい手段ではないかなと勝手に思います。もちろんコードで直接扱うのがベストではありますが。

 

次がArduino-Megaのスケッチです。

/********************************************************
   LED panel display for Arduino-Mega
      Read & show RGB data from "RGBtnnn.txt" files.
      Version 00  Aug.8, 2021 by Akira Tominaga
*********************************************************/
#include "FastLED.h"
#include "SPI.h"
#include "SD.h"
#define dPin 8                // data pin to LED tape
#define CS 53                 // SD MISO=50,MOSI=51,SCK=52
uint16_t X = 0, Y = 0, Pnl = 0; // column, row, and panel
#define maxX 24               // maximum X in total
#define maxY 32               // maximum Y
#define nPnls 3               // nnumber of panels (films) 
#define pnlX (maxX/nPnls)     // X length of each panel
#define NinPnl (pnlX*maxY)    // number of LEDs in a panel   
#define nLEDs (NinPnl*nPnls)  // number of total LEDs
CRGB myTp[nLEDs];             // construct myTp array
File mySD;                    // construct mySD
String fNbase = "RGBt";       // for file name RGBtnnn.txt
String fNext = ".txt";        // file name extention
uint16_t fNum = 0;            // file number = page (max999)
char fN[4];                   // file number in char
String fName = "";            // file name
#define fRlen 9               // file rec length 7char+CRLF
char SDin[fRlen + 1];         // SD-in area with CRLF + Null
uint8_t vRGB[3];              // temporally RGB work data

void setup() { // ***** Arsuino setup() *****
  Serial.begin(9600);
  delay(2000);                // enough time for LED pwr
  if (!SD.begin(CS)) {
    Serial.println(F("SD err."));
    while (true);
  }
  FastLED.addLeds<WS2812, dPin, GRB>(myTp, nLEDs);
  clrLED();
}
void loop() { // ***** Arduino loop() *****
  setFname();                 //next file name to open
  Serial.println(fName);
  clrLED();
  XY2LED();       // read RGB@(X,Y) and set to LED positions
  FastLED.show();             // show the page
  delay(1000);                // time to display a page
  mySD.close();               // close current page
  fNum++;                     // set next file(=page) number
}
/************************************************
    User defined functions
 ************************************************/
// ***** clear LED *** clrLED() *****
void clrLED(void) {
#define Black (0,0,0)
  for (int i = 0; i < nLEDs; i++) {
    myTp[i].setRGB Black;
  }
  FastLED.show();
}
// ***** set file name of next page *** setFname() *****
void setFname(void) {
  sprintf(fN, "%03d", fNum);
  fName = fNbase + String(fN) + fNext;
  mySD = SD.open(fName);      // open a page
  if (!mySD) {                // if file not found
    Serial.print(F("No "));
    Serial.println(fName);
    if (fNum > 0) {           // if no more page
      delay(1000);            // wait for a second
      fNum = 0;               // and return to page 0
      fName = fNbase + "000" + fNext; // restart from p.0
      mySD = SD.open(fName);  // and open page 0
    } else {                  // if page 0 file not found
      while (true) {}         // then stop
    }
  }
}
// ***** get RGB[](X,Y) val and set to LED pos. *** XY2LED() *****
void XY2LED(void) {
  uint16_t sLED;              // sequence # of LED from the top 
  for (Y = 0; Y < maxY; Y++) {
    for (X = 0; X < maxX; X++) {
      Pnl = X / pnlX;         // get panel number
      uint16_t nC = X % pnlX; // get X (column #) in that panel
      readRGB();              // read record for RGB values
      if (Y % 2 == 1) {       // for Ys 1,3,5,,,
        sLED=nC + Pnl * NinPnl + Y*pnlX;
      } else {                // for Ys 0, 2,4,,, reverse X sequence
        sLED=(pnlX - 1 - nC) + Pnl * NinPnl +  Y*pnlX;
      }
      myTp[sLED].setRGB(vRGB[0], vRGB[1], vRGB[2]);
    }
  }
}
// ***** read SD for RGB data *** readRGB() ***
void readRGB(void) {
  while (!mySD.available()) {}
  mySD.read(SDin, fRlen);     // read a record
  for (int i = 0; i < 3; i++) {  // for RGB data
    byte Vh = SDin[i * 2 + 1] & 0x0F; // if numeric, get value
    if (SDin[2] > 0x40) {     // if alfabet,
      Vh = SDin[i * 2 + 1] - 55; // set alphabetic value
    }
    byte Vl = SDin[i * 2 + 2] & 0x0F; // if numeric, get value
    if (SDin[2] > 0x40) {     // if alfabet,
      Vl = SDin[i * 2 + 2] - 55; // set alphabetic value
    }
    vRGB[i] = (Vh * 16 + Vl) / (3); // divide R|G|B w/ 3 
  }
}
// ***** end of program *****

 

読み込むファイルには次の形式の固定長レコードが、LEDの個数分並んでいます。

#RRGGBB\n

RR、GG、BBは赤、緑、青の強さで、0からFFで表します。しかし、そのままではLEDが明るすぎるため、Arduinoで読んだら各値を1/3に落としています。節電にも重要ですね。

ファイル1個が画面の1頁となり、Arduinoはファイル番号を増やしながら次々読み、次のファイルがなくなると最初に戻ります。

そのファイルをWindowsPCでBMP画像から自動生成する簡単なプログラムは次です。Small Basicでちょこっと作ったテスト用ですが。

myTitle="RGB text builder   Aug.8,2021 (c)Akira Tominaga"
TextWindow.Title=myTitle
TextWindow.BackgroundColor="Black"

' Get data path
myPath=File.GetSettingsFilePath()
myPath=Text.GetSubText(myPath,1,8)
myPath=myPath+"DatW\"

' Prepare picture
TextWindow.WriteLine("")
KeyIn:
TextWindow.Write("     Please type-in RGBt#. -> ")
keyinN=TextWindow.Read()
myPict=myPath+"RGBt"+keyinN+".bmp"
PsizeX=ImageList.GetWidthOfImage(myPict)
If PsizeX>5 Then
  Goto ImageOK
Else
  TextWindow.Write("*** No such bmp as ")
  TextWindow.WriteLine(myPict)
  Goto Keyin
EndIf
ImageOK:
PsizeY=ImageList.GetHeightOfImage(myPict)
TextWindow.Write("Xsize=")
TextWindow.WriteLine(PsizeX)
TextWindow.Write("Ysize=")
TextWindow.WriteLine(PsizeY)

'Setup output file
myFile=myPath+"RGBt"+KeyinN+".txt"
'lnum=1 'PsizeX,PsizeY (3chars left-zero)
Xs=Text.GetSubText(1000+PsizeX,2,3)
Ys=Text.GetSubText(1000+PsizeY,2,3)
header=Xs+","+Ys
'File.WriteLine(myFile,lnum,header)
lnum=0

'Graphics window
GraphicsWindow.BackgroundColor = "Black"
GraphicsWindow.Width=PsizeX*45
GraphicsWindow.Height=PsizeY*22
GraphicsWindow.Title=myTitle
inPic=ImageList.LoadImage(myPict)
GraphicsWindow.DrawImage(inPic,0,0)
For j= 0 to PsizeY-1
  For i=0 To PsizeX-1
    color=GraphicsWindow.GetPixel(i,j)
     TextWindow.WriteLine(Color)
     lnum=lnum+1
     File.WriteLine(myFile,lnum,Color)
     
    'Draw big image
    XXb=PsizeX+2
    YYb=PsizeY+2
    XX=i*20+XXb
    YY=j*20+YYb
    GraphicsWindow.BrushColor=Color
    GraphicsWindow.FillRectangle(XX,YY,20,20)

  EndFor
EndFor

lnum=lnum+1
eof="FileEnd"
File.WriteLine(myFile,lnum,eof)
TextWindow.WriteLine("**** txt file has been made. Next pls!")
Goto KeyIn

 

表示が粗くてもとにかく大きなディスプレイが要る際には、こうして作ると便利だと思います。

以上、簡単な記事でしたが皆様のなんらかのお役に立てば幸いです。

 

©2021 Akira Tominaga, All rights reserved.