This site is archival. For maintained and responsive content, visit efuller.net.
© 2010 Elizabeth

Life Dress [Matrix]

The Life Dress has a maintained page at efuller.net/life-dress-f3.

After mocking up my circuitry in Illustrator, it is finally time to start breadboarding the circuit. After some initial wiring challenges with the multiplexters, I have successfully established control over one as a multiplexer and the other as a demultiplexer so that the two can work together to control an led matrix.

I am using the CD4051 to control the leds, one for columns of power and the other for rows connected to ground. Thus, while powering an entire row, I only turn on the one light that is also on the row connected to ground.

While only one led can be turned on at a time, by strobing each LED on in rapid succession, I can take advantage of persistance of visions to create the illusion of several LEDs being on at once.

Basic run through of matrix prototype, just turning each light on and then off.

First run with game of life. The code starts by running a glider but, with the walls of the matrix so small, the glider progresses into a series of shapes.

Code

The code used is a combination of code taken from the Arduino tutorial for the 4051 and my hacked together code written for the original Life Dress in my first semester at ITP.

/********************************************************************************
 *
 * Life Dress
 *
 *  Game of Life code and control code for the 4051 analog mutiplexer / demulti-
 *  plexer.  Based on game of life code by Daniel Shiffman and 4051 code by
 *  david c. and tomek n.* for k3 / malmö högskola
 *
 * by Elizabeth Fuller
 *
 *******************************************************************************/

// setting for order of pins to be called
int  bin [] = {11,0,1,10,101,111,110,100};

// set up control pins. these are the pins that turn on the different pins
int s1 = 4; // s1 control for ground
int s2 = 3; // s2 control for ground
int s3 = 2; // s3 control for ground
int s4 = 7; // s1 control for power
int s5 = 6; // s2 control for power
int s6 = 5; // s3 control for power

// game of life settings
const int COLS = 4;
const int ROWS = 4;
//game of life board
boolean old_board[COLS][ROWS];
boolean new_board[COLS][ROWS]; 

int refresh_rate = 10000; // rounds of stobe for each round

void setup(){
  // general pin settings
  pinMode(2, OUTPUT);    // s0
  pinMode(3, OUTPUT);    // s1
  pinMode(4, OUTPUT);    // s2

  pinMode(5, OUTPUT);    // s0
  pinMode(6, OUTPUT);    // s1
  pinMode(7, OUTPUT);    // s2

  // game of life setup code
  glider();

  Serial.begin(9600);
}

void loop () {
  //golTurnON();
  calculate();
  golTurnON();
  sendData();
}

/********************************************************************************
 * Control Code
 *  - ledON( x, y )
 ********************************************************************************/

void ledON(int x, int y) {
  int col = bin[x];
  int c0 = col & 0x01;
  int c1 = (col>>1) & 0x01;
  int c2 = (col>>2) & 0x01;

  digitalWrite(s1, c0);
  digitalWrite(s2, c1);
  digitalWrite(s3, c2);

  //Serial.println(bin[count]);
  int row = bin[y];
  int r0 = row & 0x01;
  int r1 = (row>>1) & 0x01;
  int r2 = (row>>2) & 0x01;

  digitalWrite(s4, r0);
  digitalWrite(s5, r1);
  digitalWrite(s6, r2);

}

/********************************************************************************
 * Game of Life Code
 *  - calculate()
 *  - initBoard()
 ********************************************************************************/

void golTurnON() {
  int ctr = 0;
  for(int t=0; t<=refresh_rate; t++) {
    for ( int i = 0; i < COLS; i++) {
      for ( int j = 0; j < ROWS; j++) {
        old_board[i][j] = new_board[i][j];
        if ((new_board[i][j] == 1)) {
          ledON(i+4,j+4);
        }
        ctr++;
      }
    }
  }
}

void calculate()
{

  int alive = 1;
  int dead = 0;
  //loop through every spot in our 2D array and check spots neighbors
  for (int x = 0; x < COLS;x++) {
    for (int y = 0; y < ROWS;y++) {
      int nb = 0;
      //Note the use of mod ("%") below to ensure that cells on the edges have "wrap-around" neighbors
      //above row
      if (old_board[(x+COLS-1) % COLS ][(y+ROWS-1) % ROWS ] == 1) { nb++; }
      if (old_board[ x                ][(y+ROWS-1) % ROWS ] == 1) { nb++; }
      if (old_board[(x+1)      % COLS ][(y+ROWS-1) % ROWS ] == 1) { nb++; }
      //middle row
      if (old_board[(x+COLS-1) % COLS ][ y                ] == 1) { nb++; }
      if (old_board[(x+1)      % COLS ][ y                ] == 1) { nb++; }
      //bottom row
      if (old_board[(x+COLS-1) % COLS ][(y+1)      % ROWS ] == 1) { nb++; }
      if (old_board[ x                ][(y+1)      % ROWS ] == 1) { nb++; }
      if (old_board[(x+1)      % COLS ][(y+1)      % ROWS ] == 1) { nb++; }
      //RULES OF "LIFE" HERE
      if      ((old_board[x][y] == 1) && (nb <  2)) { new_board[x][y] = 0; }      //loneliness
      else if ((old_board[x][y] == 1) && (nb >  3)) { new_board[x][y] = 0; }      //overpopulation
      else if ((old_board[x][y] == 0) && (nb == 3)) { new_board[x][y] = 1; }      //reproduction
      else                        { new_board[x][y] = old_board[x][y]; }  //stasis
    }
  }
}
void sendData()
{
  int ctr = 0;
  //RENDER game of life based on "new_board" values
  for ( int i = 0; i < COLS; i++) {
    for ( int j = 0; j < ROWS; j++) {
      // write old board like new board
      old_board[i][j] = new_board[i][j];
      // send board settings to Processing
      if ((new_board[i][j] == 1)) {
        // send living cell
        Serial.print(1, DEC);
        Serial.print(",");
      }
      else
      {
        // send empty cell
        Serial.print(0, DEC);
        Serial.print(",");
      }
      ctr++;
    }
  }
  Serial.print("\n");
}

/********************************************************************************
 * Initialization code for game of life
 ********************************************************************************/

//init board with random "alive" squares
void initBoard() {
  for (int i =0;i < COLS;i++) {
    for (int j =0;j < ROWS;j++) {
      if (int(random(2)) == 0) {
        old_board[i][j] = 1;
      }
      else {
        old_board[i][j] = 0;
      }
    }
  }
}

// fill baord with 0s
void emptyBoard() {
  for (int i =0;i < COLS;i++) {
    for (int j =0;j < ROWS;j++) {
      old_board[i][j] = 0;
    }
  }
}

void glider() {
  emptyBoard();
  old_board[0][3] = 1;
  old_board[1][3] = 1;
  old_board[2][3] = 1;
  old_board[0][2] = 1;
  old_board[1][1] = 1;
}

Related posts:

  1. Physical Computing Final: Life (week 1, Monday) Earlier in Life… I have already written code to run...
  2. Life Dress [Multiplexers v2] The Life Dress has a maintained page at efuller.net/life-dress-f3. Contents...
  3. Life Dress: LED Drivers and Lilypads The Life Dress has a maintained page at efuller.net/life-dress-f2. LED...
  4. Life Dress [multiplexers] The Life Dress has a maintained page at efuller.net/life-dress-f3. I...
  5. Life Dress [LED Choice] As I alluded to in my past post, I received...

2 Comments

  1. Neil M
    Posted March 31, 2010 at 6:02 am | #

    Make sure that when the grid is at its full size the LED’s won’t have too much of a delay between them, or else the dress will start to flicker.

    It looks like you’re looping through every tile every cycle. You may want to adjust the code so that it keeps track of the tile position and its neighbours instead of storing one large grid. If done right it can have a rather large speed up assuming the entire board isn’t lit up at once.

  2. Posted March 31, 2010 at 12:35 pm | #

    Excellent point, Neil!

    Yesterday I was just throwing code together to get something together. Now it’s optimization time!

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>