8x8 LED Matrix animation using Arduino (and Processing sketch) [電子工作]

8x8 LED Matrixでアニメーションを編集するプロジェクトの紹介です。
MATRIX_ARDUINO.jpeg

1. 前書き

8X8 のLED Matrixは、Arduinoのプロジェクトでよく使用される機器です。
Arduinodoでは標準のMatrixライブラリを使うことで、簡単にLED Matrixを制御することが出来ます。
このライブラリは、MAXIM社のMAX7219シリアルLEDドライバの使用を前提にしていますが、このICを使わないライブラリを公開している方もいらっしゃいます。(参照:Arduinoで遊ぼう - Direct8x8ライブラリ
今回はMAX7219を使って、8x8 LED Matrixを制御します。

2. プロジェクトの概要

上記の通り、8x8 LEDの利用自体は簡単に実現できますが、いつも同じアニメーションでは面白くありません。
そこでPCで自由にパターンをエディットして、Arduinoに送信する設計としました。
プロジェクトのイメージは下図の通りです。(あくまでイメージなので、回路図の参考にはしないでください)
MatrixMaker.jpeg
  1. Processingで作成したUIで8x8のアニメーションのパターンを編集します。
  2. 編集中のパターンはボタン一発で、USB/Serial接続されたArduinoに転送されます。
  3. Arduinoでは転送されたデータをEEPROMに書き込みます。
  4. EEPROMからデータを読み込み直し、アニメーションを表示します。


使用環境
・Windows XP SP2
・Processing 1.0.3
・Arduino 0015

Arduino
・Arduino Duemilanove (ATMega168バージョン)


3. PC側の実装(Processing)

OnDevelopment.PNG
ProcessingにはGUI部品が存在しないので、Exampleを参考にして「Buttonクラス」を作成し、それを継承することで、各ボタン機能をインプリしています。
最初は1フレーム分しか画面に表示されていませんが、次フレームに移動する時に、最後のフレームなら自動的にフレームを追加するようにしています。
画面上ではフレームの追加・削除、パターンのコピー・ペースト、PC上でのアニメーションの開始・停止等が実施できます。
作成したパターンはPCに保存することが出来ます。今のバージョンではファイル名は固定なので、複数のパターンを保存したい場合は、PC上でファイルをリネームするなどの対応が必要になります。
Sendボタンを押すとSerialインターフェース経由でArduinoにパターンを送信します。
データは先頭1バイトが総フレーム数が、2バイト目以降が各フレームのデータになります。
フレームのデータは8x8の一列を1バイトで送信しているので、1フレームしかないアニメーションの場合(動かないのでアニメーションとは呼べないかもしれませんが)1+8で合計9バイトを送信します。
例)
【図】パターンと各バイトとの関係
○○○○○○○○ --> 00000000 -->0x00
○○○○○○○○ --> 00000000 -->0x00
○○●○○●○○ --> 00100100 -->0x24
○○○○○○○○ --> 00000000 -->0x00
○○○○○○○○ --> 00000000 -->0x00
○●○○○○●○ --> 01000010 -->0x42
○○●●●●○○ --> 00111100 -->0x3c
○○○○○○○○ --> 00000000 -->0x00

尚、ProcessingではByte型は符号付きなので、128以上の数字はprintすると負数(128 → -128、129→-127)で表示されます。
なお、SerialポートはProcessingからはポート一覧のX番目という指定になるので、環境によって166行目当たりを見直す必要があります。
ボタンアイコンはLGPLで公開されている、Crystal Projectのものを利用しています。

【Processingコード】
import processing.serial.*;

// FOR SIZE
int SIZEX=500;
int SIZEY=300;


// FOR LED MATRIX
int TOPX = 30;
int TOPY = 30;
int LENX=30*8;
int LENY=30*8;
int WIDTHX=30;
int WIDTHY=30;

int BACKGROUND=51;
int OFFCOLOR=100;
int MAXFRAME=64;
int MINFRAME=0;


// FOR PREV/NEXT BUTTON

int FRAME_BUTTON_X=3;
int FRAME_BUTTON_Y=96;
int FRAME_BUTTON_W=19;
int FRAME_BUTTON_H=100;

// FOR ACTION BUTTON
int BUTTON_START_X= 310;
int BUTTON_START_Y= 40;
int BUTTON_ROW_HEIGHT= 60;
int BUTTON_WIDTH=24;
int BUTTON_HEIGHT=36;
int BUTTON_SPACE = 10;

String DATA_FILE = &"savedat.csv&";

int pX, pY;
color c1,c2;
PFont label;

LedMatrix[] led;
LedMatrix c_led;
LedMatrix buf_led;

PrevButton btn_prev;
NextButton btn_next;

RunButton   btn_run;
StopButton  btn_stop;
ClearButton btn_clear;
EraseButton btn_erase;
SendButton  btn_send;
CopyButton  btn_copy;
PasteButton btn_paste;
SaveButton  btn_save;
LoadButton  btn_load;
InsertButton btn_insert;


boolean c_sw = false;
boolean run_sw = false;


int p_frame=0;    // Current frame Number
int max_frame=0;  // Max frame Numnber

PImage mask;


Serial port;


// ==========================================
//   Setup ( )
// ==========================================
void setup(){
  int i,j;

  background(BACKGROUND);
  size(SIZEX,SIZEY);


  // image files from 
  // http://www.everaldo.com/crystal/
  PImage img_run=loadImage(&"player_play.png&");
  PImage img_stop=loadImage(&"agt_pause-queue.png&");
  PImage img_clear=loadImage(&"editclear.png&");
  PImage img_erase=loadImage(&"edit_remove.png&");
  PImage img_send=loadImage(&"exec.png&");
  PImage img_copy=loadImage(&"editcopy.png&");
  PImage img_paste=loadImage(&"editpaste.png&");
  PImage img_save=loadImage(&"filesave.png&");
  PImage img_load=loadImage(&"fileopen.png&");
  PImage img_insert=loadImage(&"edit_add.png&");

  // 24x24 png 
  mask = loadImage(&"blank.png&");
  
  // draw LED Matrix
  stroke(255);
  fill(0);
  rect(TOPX,TOPY,LENX,LENY);
  stroke(195);
  for (i=1 ; i < 8 ; i++){
    line(TOPX,TOPY+WIDTHY*i,TOPX+WIDTHX*8,TOPY+WIDTHY*i);
    line(TOPX+WIDTHX*i,TOPY,TOPX+WIDTHX*i,TOPY+WIDTHY*8);
  }

  // create instance of LED pattern data
  led= new LedMatrix[MAXFRAME];
  led[0] = new LedMatrix();
  c_led = led[0];
  buf_led = new LedMatrix();

  label = createFont(&"Arial&",14);

  // Set Prev/Next Frame Buttons
  c1 = color(20,20,20);
  btn_prev = new PrevButton (FRAME_BUTTON_X, FRAME_BUTTON_Y, FRAME_BUTTON_W, FRAME_BUTTON_H, &"<<&");
  btn_next = new NextButton (FRAME_BUTTON_X+TOPX+LENX, FRAME_BUTTON_Y, FRAME_BUTTON_W, FRAME_BUTTON_H, &">>&");

  // create & display Action Buttons

  i = BUTTON_START_X;
  j = BUTTON_START_Y;  

  btn_run    = new RunButton   (i , j , BUTTON_WIDTH, BUTTON_HEIGHT , img_run, &"Run&");

  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_stop   = new StopButton  (i , j , BUTTON_WIDTH, BUTTON_HEIGHT, img_stop, &"Pause&");

  i += BUTTON_WIDTH + BUTTON_SPACE; 

  i = BUTTON_START_X;
  j = BUTTON_START_Y + BUTTON_ROW_HEIGHT;  


  btn_copy   = new CopyButton  (i , j , BUTTON_WIDTH, BUTTON_HEIGHT , img_copy, &"Copy&");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_paste   = new PasteButton(i , j , BUTTON_WIDTH, BUTTON_HEIGHT, img_paste, &"Paste&");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_clear  = new ClearButton (i , j , BUTTON_WIDTH, BUTTON_HEIGHT, img_clear, &"Clear&");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_insert  = new InsertButton (i , j , BUTTON_WIDTH, BUTTON_HEIGHT, img_insert, &"Add&");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_erase  = new EraseButton (i , j , BUTTON_WIDTH, BUTTON_HEIGHT, img_erase, &"Del&");

  i = BUTTON_START_X;
  j = BUTTON_START_Y + BUTTON_ROW_HEIGHT + BUTTON_ROW_HEIGHT;  

  btn_load   = new LoadButton  (i , j , BUTTON_WIDTH, BUTTON_HEIGHT, img_load, &"Load&");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_save   = new SaveButton  (i , j , BUTTON_WIDTH, BUTTON_HEIGHT, img_save, &"Save&");
  i += BUTTON_WIDTH + BUTTON_SPACE; 

  i = BUTTON_START_X;
  j = BUTTON_START_Y + BUTTON_ROW_HEIGHT + BUTTON_ROW_HEIGHT + BUTTON_ROW_HEIGHT;  

  btn_send   = new SendButton  (i , j , BUTTON_WIDTH, BUTTON_HEIGHT, img_send, &"Upload&");
  i += BUTTON_WIDTH + BUTTON_SPACE; 

  println(Serial.list());
  // Assuming that 3rd serial port is connected to Arduino
  port = new Serial(this, Serial.list()[2], 9600); 


}

// ==========================================
//   draw  ( )
// ==========================================
void draw(){
  int dsp_p_frame, dsp_max_frame;
  if (run_sw) {
    frameRate(5);
    p_frame ++ ;
    if ( p_frame > max_frame) { 
      p_frame =0;
    }
    // println (&"in run mode, p_frame is &" + p_frame);
    c_led = led[p_frame];
  } 
  else {
    frameRate(60);
  }
  noStroke();
  fill(BACKGROUND);
  rect(0,0,250,23);
  fill(255);
  smooth();

  dsp_p_frame = p_frame +1 ;
  dsp_max_frame = max_frame +1 ;

  textFont(label);

  text (&"Flame = &" + dsp_p_frame + &"/&" + dsp_max_frame ,160,10);
  drawAll();


}
// ==========================================
//   mousePressed  ( )
// ==========================================
void mousePressed(){
  if (!run_sw) {
    if (mouseX > TOPX  && mouseX < TOPX+LENX && mouseY > TOPY && mouseY < TOPY + LENY){
      pX =floor (map( mouseX-TOPX,0,LENX,0,8));
      pY= floor (map( mouseY-TOPY,0,LENY,0,8));
      // debug
      // println(&" Mouse : &" + mouseX + &" &" + mouseY + &" Mapped :&" + pX + &" &" +pY);

      // invert off/on
      c_led.setStats(pX, pY, !c_led.getStats(pX, pY));

      if ( c_led.getStats(pX, pY) )  // is ture
      {
        switch_led(pX, pY, true);
      } 
      else {
        switch_led(pX, pY, false);
      }
    } 
    else if ( btn_prev.pressed() ) {
      btn_prev.setButton(100);
      if ( !c_sw) {
        btn_prev.doAction();
      }
    } 
    else if ( btn_next.pressed() ) {
      btn_next.setButton(100);      
      if ( !c_sw) {
        btn_next.doAction();
      }
    } 
    else if ( btn_run.pressed() ) {
      btn_run.setButton(100);
      if ( !c_sw) {
        btn_run.doAction();
      }
    } 
    else if ( btn_clear.pressed() ) {
      btn_clear.setButton(100);
      if ( !c_sw) {
        btn_clear.doAction();
      }
    } 
    else if ( btn_erase.pressed() ) {
      btn_erase.setButton(100);
      if ( !c_sw) {
        btn_erase.doAction();
      }
    } 
    else if ( btn_send.pressed() ) {
      btn_send.setButton(100);
      if ( !c_sw) {
        btn_send.doAction();
      }
    } 
    else if ( btn_copy.pressed() ) {
      btn_copy.setButton(100);
      if ( !c_sw) {
        btn_copy.doAction();
      }
    } 
    else if ( btn_paste.pressed() ) {
      btn_paste.setButton(100);
      if ( !c_sw) {
        btn_paste.doAction();
      }
    } 
    else if ( btn_save.pressed() ) {
      btn_save.setButton(100);
      if ( !c_sw) {
        btn_save.doAction();
      }
    } 
    else if ( btn_insert.pressed() ) {
      btn_insert.setButton(100);
      if ( !c_sw) {
        btn_insert.doAction();
      }
    } 
    else if ( btn_load.pressed() ) {
      btn_load.setButton(100);
      if ( !c_sw) {
        btn_load.doAction();
      }
    }
    // to make it sure that doAction() never called in next loop. (When mouse being pressed). 
    c_sw = true ;
  } 
  else { // if animation is running, only stop button is available.
    if ( btn_stop.pressed() ) {
      btn_stop.setButton(100);
      btn_stop.doAction();
    }
  }

}

// ==========================================
//   mouseReleased  ( )
// ==========================================
void mouseReleased(){
  btn_prev.setButton(0);
  btn_next.setButton(0);
  btn_run.setButton(0);
  btn_stop.setButton(0);
  btn_clear.setButton(0);
  btn_erase.setButton(0);
  btn_send.setButton(0);
  btn_copy.setButton(0);
  btn_paste.setButton(0);
  btn_insert.setButton(0);
  btn_save.setButton(0);
  btn_load.setButton(0);
  c_sw = false ;
}

// ==========================================
//   functions
// ==========================================

//  drawAll
void drawAll() {
  int i,j;
  for (i=0; i<8 ;i++){
    for (j=0; j<8; j++){
      switch_led(i, j, c_led.getStats(i,j));
    }
  }
}

//  switch_led
void switch_led(int pX, int pY, boolean on){
  noStroke();
  if (on) {
    fill(255,0,0);
  } 
  else {
    fill(OFFCOLOR);
  }
  ellipse(TOPX + WIDTHX*pX + WIDTHX/2, TOPY + WIDTHY * pY +WIDTHY/2, 20,20);
}




// ------------------------------------------------------
//  L e d M a t r ix
// ------------------------------------------------------
class LedMatrix {
  boolean[][] stats = new boolean[8][8];

  // Constructor
  LedMatrix(){
    init();
  }
  // init 
  void init(){
    int i,j;
    for (i=0 ; i < 8 ; i++){
      for (j=0 ; j < 8 ; j++){
        stats[i][j]=false;
      }
    }
  }

  // getStats()
  boolean getStats(int x, int y){
    return stats[x][y];
  }
  // setStats()
  void setStats(int x, int y, boolean val){
    stats[x][y] = val;
  }

  // on()  for future use
  void on(int x, int y){
    stats[x][y] = true;
  }

  // off() for future use
  void off(int x, int y){
    stats[x][y] = false;
  }

  // getString() for DEBUG
  String getStrings(){
    int x,y;
    String buf = &"&";

    for (y=0 ; y<8 ; y++){
      String r=&"&";
      for (x=0 ; x < 8 ; x++){
        r = r + ( getStats(x,y) ? &"1&" : &"0&" );
      }
      buf = buf + unbinary(r) + &",&";
    }
    return buf;
  }

  // getDump()
  Byte[] getDump(){
    int x,y;
    String r;
    Byte[] b= new Byte[8];

    for (y=0 ; y<8 ; y++){
      r=&"&";
      for (x=0 ; x < 8 ; x++){
        r = r + ( getStats(x,y) ? &"1&" : &"0&" );
      }
      // println(r); // DEBUG
      b[y]= byte(unbinary(r));
    }
    return b;
  }
}


// ------------------------------------------------------
//  B u t t o n
// ------------------------------------------------------
class Button  {
  int _x,_y,_w,_h;

  Button (int x, int y, int width, int height) {
    _x = x;
    _y = y;
    _w = width;
    _h = height;
  }

  boolean pressed () {
    if (mouseX > _x && mouseX < _x + _w && mouseY > _y && mouseY < _y + _h ){
      return true;
    } 
    else {
      return false;
    }
  }
}
// ------------------------------------------------------
//  F r a m e B u t t o n
// ------------------------------------------------------

class FrameButton extends Button {
  String _msg;
  color _c;

  FrameButton (int x, int y, int width, int height,String msg ) {
    super(x, y, width, height);
    _msg = msg;
    setButton(0);

  }

  void setButton (int c) {
    stroke(255);
    fill(c);
    rect(_x,_y,_w,_h);   
    fill(255);
    textAlign(CENTER,CENTER);
    textFont(label);
    text (_msg, _x + _w/2, _y + _h/2);

  }

  void doAction(int x){
    int p; 
    p = p_frame + x;

    if ( p < MINFRAME ) {
      p = MINFRAME;
    }
    if (p > MAXFRAME) {
      p = MAXFRAME;
    }

    if ( led[p] == null ) {
      led[p] = new LedMatrix();
    }
    p_frame = p ;
    if (p_frame > max_frame) { 
      max_frame = p_frame; 
    } 
    c_led = led[p];

    fill(255);
    text (&"Flame:&" + p_frame + &" &",125,10);
  }

}

// ------------------------------------------------------
//  N e x t B u t t o n
// ------------------------------------------------------

class NextButton extends FrameButton {

  NextButton (int x, int y, int width, int height,String msg ) {
    super (x, y, width, height, msg );
  }

  void doAction() {
    super.doAction(1);
  }
}

// ------------------------------------------------------
//  P r e v B u t t o n
// ------------------------------------------------------

class PrevButton extends FrameButton {
  PrevButton (int x, int y, int width, int height,String msg ) {
    super (x, y, width, height, msg );
  }
  void doAction() {
    super.doAction(-1);
  }
}

// ------------------------------------------------------
//  C o n t r o l B u t t o n
// ------------------------------------------------------
class ControlButton extends Button {

  PImage _img;
  String _msg;
  PFont label_button;


  ControlButton (int x, int y, int width, int height, PImage img,String msg) {
    /*
      _x = x;
     _y = y;
     _w = width;
     _h = height;
     */
    super(x, y, width, height);
    _img = img;
    _msg = msg;

    label_button = createFont(&"Arial&",10);

    //noStroke();
    stroke(28);
    fill(BACKGROUND);

    rect(x -4 , y -4 , 32,50);
    stroke(128);
    line(x - 4, y -4 + 50, x -4 + 32,  y -4 + 50);
    line(x - 4 + 32 , y -4 + 50, x -4 +32 ,  y -4 );
   
    fill(255);
    textFont(label_button);
    text(_msg, _x+13, _y+32);


    setButton(0);

  }
  void setButton (int c) {
    int diff=0;

    image(mask,_x,_y);

    if ( c > 0 ) { // button pressed
      diff = 2;
    } 
    else {
    }
    // fill(BACKGROUND);
    // rect(_x-2, _y-1, 28,30);

    // println(_img);
    image(_img, _x + diff, _y + diff);
  }


}

// ------------------------------------------------------
//  R u n B u t t o n
// ------------------------------------------------------
class RunButton extends ControlButton {
  RunButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    if (max_frame > 0 ) {
      run_sw = true;
      p_frame = 0;
      c_led = led[0];
    }
  }
}

// ------------------------------------------------------
//  S t o p B u t t o n
// ------------------------------------------------------
class StopButton extends ControlButton {
  StopButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    run_sw = false ;
  }
}

// ------------------------------------------------------
//  C l e a r B u t t o n
// ------------------------------------------------------
class ClearButton extends ControlButton {
  ClearButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    c_led.init();
  }
}

// ------------------------------------------------------
//  E r a s e B u t t o n
// ------------------------------------------------------
class EraseButton extends ControlButton {
  EraseButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int i;

    // can not erase last frame
    if ( max_frame == 0 ) {
      return;
    }

    led[p_frame] = null;
    if (p_frame == max_frame){
      p_frame--;
    } 
    else {
      for ( i=p_frame;  i<max_frame; i++) {
        led[i]=led[i+1];
      }
      led[max_frame]=null;
    }
    max_frame--;
    c_led=led[p_frame];


  }
}
// ------------------------------------------------------
//  I n s e r t B u t t o n
// ------------------------------------------------------
class InsertButton extends ControlButton {
  InsertButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int p;

    // no more frame
    if ( max_frame == MAXFRAME ) {
      return;
    }

    for ( p = max_frame ; p >= p_frame ; p--) {
      led[p+1] = led[p];
    }
    led[p_frame] = new LedMatrix();
    max_frame++;
    c_led = led[p_frame];



    // 1,2,*3*,4,5,6     6 to 7, 5 to 6 , 4 to 5, 3 to 4 , 3 new)


  }
}

// ------------------------------------------------------
//  C o p y B u t t o n
// ------------------------------------------------------
class CopyButton extends ControlButton {
  CopyButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int i,j;
    for (i=0 ; i < 8 ; i++){
      for (j=0 ; j < 8 ; j++){
        buf_led.setStats(i,j,c_led.getStats(i,j));
      }
    }
  }
}

// ------------------------------------------------------
//  P a s t e B u t t o n
// ------------------------------------------------------
class PasteButton extends ControlButton {
  PasteButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int i,j;
    for (i=0 ; i < 8 ; i++){
      for (j=0 ; j < 8 ; j++){
        c_led.setStats(i,j,buf_led.getStats(i,j));
      }
    }

  }
}

// ------------------------------------------------------
//  S a v e B u t t o n
// ------------------------------------------------------
class SaveButton extends ControlButton {
  SaveButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int p;
    String s;
    String [] buf={
    };

    for (p = 0 ; p <= max_frame ; p++){
      s = p + &",&" + max_frame + &",&" + led[p].getStrings();
      buf = append (buf,s);
    }
    saveStrings(&"data/&"+ DATA_FILE,buf);

  }
}

// ------------------------------------------------------
//  L o a d B u t t o n
// ------------------------------------------------------
class LoadButton extends ControlButton {
  LoadButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    String lines[] = loadStrings(DATA_FILE);

    led = null ; 
    led = new LedMatrix[MAXFRAME];

    for (int i = 0 ; i <lines.length ; i++) {
      String p[] = splitTokens(lines[i], &",&");
      led[i] = new LedMatrix();
      // println (&"i=&" + i );          // DEBUG
      // println (lines[i]);           // DEBUG
      for (int j=2 ; j <=9 ; j++){
        int pj = int(p[j]);   // ex. 0-255
        // println (&"  j =&" + j );     // DEBUG
        // println (&"  pj =&" + pj );   // DEBUG
        for (int k=0 ; k < 8 ; k++){
          if ( ( pj >>(7-k) & 1 ) == 1) {
            led[i].on(k,j-2);
          }
        }
      }
    }

    max_frame=lines.length-1;
    p_frame=0;
    c_led = led[p_frame];
  }
}

// ------------------------------------------------------
//  S e n d B u t t o n
// ------------------------------------------------------
class SendButton extends ControlButton {
  SendButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int p;
    Byte[] b = new Byte[8];

    port.write(max_frame);    

    for (p = 0 ; p <=   max_frame ; p++){
      b = led[p].getDump();
      for (int i=0 ; i< 8 ; i++){
        port.write(b[i]);
      }
    }
  }
}






4. Arduino側の実装

Matrixライブラリで8x8 LED Matrixをコントロールします(SPI制御)。また Analog PINに可変抵抗を接続して、アニメーションの速度をコントロール出来るようにしています。
setup()ではEEPROMからアニメーションのフレームを呼び出して内部に展開しています。
またSerialのデータを受信した場合は、データの読み込み&EEPROMへの書き出し&内部への展開、を行います。
EEPROMを使うことで、一旦受信したアニメーションパターンは、一旦電源OFFしても保存されます。ただしそのため、保存出来るパターン数には限界があります。
ATMega168の場合はSRAM 1K、EEPROM 512 Byteなので、今の実装では最大48フレームとし、それ以上の長さのデータを受信しても読み飛ばすようにしています。

また回路については下記ページをほぼそのまま使用しています。異なるのはANALOG PIN2 に可変抵抗を接続していることだけです。(もちろん5VとGNDも)
・建築発明工作ゼミ2008:Arduino マトリクスLED2/MAX7219


【Arduinoコード】
#include <EEPROM.h>
#include <Matrix.h>

#define MAX_FRAME 48
#define MAX_BUFF 8*MAX_FRAME+1


// MATRIX DRIVER
// by elekid

Matrix myMatrix = Matrix(4, 2, 3);
int InputPin = 2;

// 8x8 = 64  ;  8x16=128 ; 8x32 = 256 
byte data_buff[MAX_BUFF];  // 8byte * 48frames= 384 byte

int max_frame;
int p_matrix=0;
int waits=0;



void setup()
{
  int i;


  Serial.begin(9600);

  // INIT FOR TEST DEBUG USE ONLY
  // EEPROM.write(7,0);

  max_frame = EEPROM.read(7);
  if (max_frame == 0 || max_frame==255) {

    max_frame = 1 ;
    data_buff[0] = max_frame;
    for ( i=1 ; i < MAX_BUFF ; i++){
      data_buff[i]=0;
    }
    data_buff[4] = 24;
    data_buff[5] = 24;
    data_buff[11] = 4+8+16+32;
    data_buff[12] = 4+32;
    data_buff[13] = 4+32;
    data_buff[14] = 4+8+16+32;
  } 
  else {

    if (max_frame > MAX_FRAME) {
      max_frame = MAX_FRAME;
    }

    for ( i=0 ; i < (max_frame+1)*8 ; i++){
      data_buff[i+1]=EEPROM.read(i+8);
    }
  }


}

void loop()
{
  int val;
  int msglen;
  int i,j; 
  byte b;

  // control delay secion
  val = analogRead(InputPin);
  val = map (val,0,1024,100,10000);

  if ( waits > val ){
    waits=0;


    myMatrix.clear(); // clear display
    for (j = 0 ; j < 8 ; j++){
      b = data_buff[p_matrix * 8 + j + 1];
      for (i =0 ; i < 8 ; i++){
        if ( ( b>>(7-i) ) & 0x01 ) {
          //if ( ( b >> i ) & 0x01 ) {
          myMatrix.write(i, j, HIGH);
        }
      }
    }
    p_matrix++;
    if ( p_matrix > max_frame ) { 
      p_matrix=0;
    }
  }
  waits++ ;

  msglen=0;
  // check new data from PC
  if ( Serial.available()  >  0 ) {


    b = Serial.read();
    data_buff[0]=b;
    msglen = ((int)b + 1) * 8;


    for ( i =0 ; i < msglen ; i++){
      while ( Serial.available() < 1 ){
        // NOP

      }
      b=Serial.read();
      if ( i <= MAX_BUFF) {
        data_buff[i+1] = b;
      }
    }
  }

  if (msglen > 0) { 
    p_matrix = -1;


    if (max_frame <= MAX_FRAME) {
      max_frame=data_buff[0];
    } 
    else {
      max_frame=MAX_FRAME;
      data_buff[0] = MAX_FRAME;
    }

    for ( i = 0 ; i < msglen ; i ++){
      EEPROM.write(i+7,data_buff[i]);
    }
    Serial.flush();

  } //  if msglen > 0 
} // loop()


5. 感想とTODO
ArduinoのSerialで長い文字を送受信するのは意外とプログラミングが面倒で手間取りました。今は9600bpsで問題なく動作していますが、速度を上げると取りこぼしが発生するかもしれません。
ArduinoとProcessingはIDEは似ていますが、言語的には別物と考えおいたほうが良いと思います。実際同時にプログラミングしていると混乱します。(Arduinoで継承が使えないとか、Processingでdefine文が使えない等々...)
今後は、先日Make Tokyo Meeting 03で購入したXBeeでワイヤレス化にチャレンジしてみたいと考えています。スクロールアニメーション版も作っておきたい。

【デモ動画】

nice!(0)  コメント(1)  トラックバック(0) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 1

千田 雅彦

はじめまして 千田と申します。
私は 60歳のものづくり大好き人間です youtubeで見た8*8*8のLED CUBEが作りたくてarduinoを購入 先ずは8*8matrix(max7219)で勉強のつもりで(ボケ防止) アニメーションメーカーを作りたくて あなたのページに遭遇 始めてのprocessingはスケッチをcopy-して貼り付けてもエラーばかしで 
そこで調べてみたのですがアイコンボタンのページがない!?!
文字列を扱う&”****.***&”行でエラー どうしたらよいよいのか 教えてほしいのですが・・・
arduinoはUNO 10 0022 prrcessingは1.5.1 OSは7です。
なにとぞよろしくお願いいたします。 まったくの初心者です。
by 千田 雅彦 (2012-12-21 09:23) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

eJackino mini 制作メモSX-150ふたたび ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。