21 septembre 2011

Experiments with the Arduino - Led Matrix

This one was way harder to implement, I wanted to simulate a led matrix with my Arduino.

The circuit


The circuit is not so difficult, basicaly you connect the anode of each row of leds to the same digital output of the Arduino and the cathode of each column of leds to the same digital output. Each led is then connected to a unique pair of digital output.


To turn a led on you just need to set the digital output for the correct row to HIGH and the output for the correct column to LOW.

This means that you can turn on several leds of the same row at the same time but you cannot turn on leds of different rows at the same time. Indeed if you set several rows to HIGH and several columns to LOW, all the intersecting pixels will be turned on, and this is not what we want.

A workaround for this problem is to use a technique named Row Scanning.

The idea is to turn on the leds of each row alternatively. If this is done fast enough, we will not perceive any flickering and we will have the feeling that all the pixels are on at the same time.



The code


The Row Scanning mechanism described above is not so difficult to implement. I decided to use a buffer to store the actual state of the pixels. The demo does not try to change the state of the digital outputs directly. Instead it changes the state of the pixels in the buffer. Then I added a refreshScreen routine that is responsible actually set the state of the digital outputs in a loop.

The problem is that the refreshScreen routine must be called periodically. This is not a problem if we don't have any delay statement in our code, because the delay statement will stop the screen refresh. Unfortunately to create a led matrix demo we definitely want to use some delay so that the user can actually see something on the led matrix.

The solution is to use an interrupt library (TimerOne) that allows to set a routine as callback for a periodic interrupt. So we set refreshScreen as the callback and we have no more problems.

#include "TimerOne.h"

const int XMIN = 2;
const int XMAX = 4;

const int YMIN = 8;
const int YMAX = 10;

int screen[3][3] = 
{
  { 0, 0, 0 },
  { 0, 0, 0 },
  { 0, 0, 0 }
};

int patterns1[][3][3] = {

  {
    { 1, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
  {
    { 0, 1, 0 },
    { 1, 0, 0 },
    { 0, 0, 0 }
  },
  {
    { 0, 0, 1 },
    { 0, 1, 0 },
    { 1, 0, 0 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 1 },
    { 0, 1, 0 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 1 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
};

int patterns2[][3][3] = {

  {
    { 0, 0, 0 },
    { 0, 1, 0 },
    { 0, 0, 0 }
  },
  {
    { 1, 1, 1 },
    { 1, 0, 1 },
    { 1, 1, 1 }
  },
  {
    { 0, 0, 0 },
    { 0, 1, 0 },
    { 0, 0, 0 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
};

int patterns3[][3][3] = {

  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
  {
    { 1, 1, 1 },
    { 1, 1, 1 },
    { 1, 1, 1 }
  },
};

int patterns4[][3][3] = {

  {
    { 1, 0, 0 },
    { 1, 0, 0 },
    { 1, 0, 0 }
  },
  {
    { 0, 1, 0 },
    { 0, 1, 0 },
    { 0, 1, 0 }
  },
  {
    { 0, 0, 1 },
    { 0, 0, 1 },
    { 0, 0, 1 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
};


// ----- MATRIX MANAGEMENT --------------------

void refreshScreen()
{
  for(int i = 0; i <= 3; i++) { // For each row
  
    digitalWrite(i + XMIN, HIGH);

    for(int j = 0; j <= 3; j++) { // For each column
    
      if (screen[i][j] == 1) {
        digitalWrite(j + YMIN, LOW);
      } else {
        digitalWrite(j + YMIN, HIGH);
      }
      
      digitalWrite(j + YMIN, HIGH);
    }
    
    digitalWrite(i + XMIN, LOW);
  }

}

void setPixel(int i, int j, int value = 1) {
  screen[i][j] = value;
}

void clearMatrix() {
  for(int i = 0; i < 3; i++) {
    for(int j = 0; j < 3; j++) {
      setPixel(i, j, 0);
    }
  }
}

void showPattern(int pattern[3][3]) {
  for(int i = 0; i < 3; i++) {
    for(int j = 0; j < 3; j++) {
      setPixel(i, j, pattern[i][j]);
    }
  }
}

// ----- DEMO FUNCTIONS -----------------------

void walkMatrixH(int wait, int repeat = 1) {
  for(int k = 0; k < repeat; k++) {
    for(int i = 0; i < 3; i++) {
      for(int j = 0; j < 3; j++) {
        clearMatrix();
        setPixel(i, j);
        delay(wait);
      }
    }
  }
}

void walkMatrixV(int wait, int repeat = 1) {
  for(int k = 0; k < repeat; k++) {
    for(int i = 0; i < 3; i++) {
      for(int j = 0; j < 3; j++) {
        clearMatrix();
        setPixel(j, i);
        delay(wait);
      }
    }
  }
}

void animatePattern(int wait, int patterns[][3][3], int steps, int repeat = 1) {

  for(int k = 0; k < repeat; k++) {
    for(int i = 0; i < steps; i++) {
      showPattern(patterns[i]);
      delay(wait);
    }
  }
}

// ----- MAIN PROGRAM -------------------------

void setup() {               
  
  for(int i = XMIN; i <= XMAX; i++) {
    pinMode(i, OUTPUT);
  }
  for(int i = YMIN; i <= YMAX; i++) {
    pinMode(i, OUTPUT);
  }
  clearMatrix();

  Timer1.initialize(10);
  Timer1.attachInterrupt(refreshScreen);
}

void loop() {
  
  // -------------------------------------------
  animatePattern(10, patterns3, 2, 3); // Flash

  walkMatrixH(10, 2);
  walkMatrixV(10, 2);
  
  // -------------------------------------------
  animatePattern(10, patterns3, 2, 3); // Flash
  animatePattern(10, patterns4, 4, 5);

  // -------------------------------------------
  animatePattern(10, patterns3, 2, 3); // Flash
  animatePattern(10, patterns1, 6, 5);

  // -------------------------------------------
  animatePattern(10, patterns3, 2, 3); // Flash
  animatePattern(10, patterns2, 4, 5);
}

Demo


18 septembre 2011

Experiments with the Arduino - Controlling 5 LEDs

The circuit


The code

void ledOn(int nr, int high = HIGH, int low = LOW) {

  for(int j = 1; j <= 5; j++) {
    if (nr == j) {
      digitalWrite(j, high);
    } else {
      digitalWrite(j, low);
    }
  }
}

void ledsOn(
  int wait,
  int l1 = LOW, 
  int l2 = LOW, 
  int l3 = LOW, 
  int l4 = LOW, 
  int l5 = LOW) {

  digitalWrite(1, l1);
  digitalWrite(2, l2);
  digitalWrite(3, l3);
  digitalWrite(4, l4);
  digitalWrite(5, l5);
  delay(wait);
}

void backAndForth(int nr, int wait, int high = HIGH, int low = LOW) {

  for(int t = 1; t <= nr; t++) {
    for(int i = 2; i <= 5; i++) {
      ledOn(i, high, low);
      delay(wait);          
    }
    for(int i = 4; i >= 1; i--) {
      ledOn(i, high, low);
      delay(wait);          
    }
  }
}

void fallingBrick(int wait, int high = HIGH, int low = LOW) {

  for(int i = 1; i <= 5; i++) {
    for(int j= 1; j <= 6 - i; j ++) {
      ledOn(j, high, low);
      for(int k = 7 - i; k <= 5; k++) {
        digitalWrite(k, high);
      }
      delay(wait);
    }
  }  
}

void boing(int nr, int wait) {
  
  for(int i = 1; i < nr; i++) {
    ledsOn(wait, 0, 0, 1, 0, 0);
    ledsOn(wait, 0, 1, 1, 1, 0);
    ledsOn(wait * 2, 1, 1, 1, 1, 1);
    ledsOn(wait, 0, 1, 1, 1, 0);
    ledsOn(wait, 0, 0, 1, 0, 0);
    ledsOn(wait * 2, 0, 0, 0, 0, 0);
  }
}

void wave(int nr, int wait) {
  
  for(int i = 1; i < nr; i++) {
    ledsOn(wait, 1, 0, 0, 0, 0);
    ledsOn(wait, 1, 1, 0, 0, 0);
    ledsOn(wait, 1, 1, 1, 0, 0);
    ledsOn(wait, 1, 1, 1, 1, 0);
    ledsOn(wait * 2, 1, 1, 1, 1, 1);
    ledsOn(wait, 1, 1, 1, 1, 0);
    ledsOn(wait, 1, 1, 1, 0, 0);
    ledsOn(wait, 1, 1, 0, 0, 0);
    ledsOn(wait * 2, 1, 0, 0, 0, 0);
  }
}

void setup() {                
  for(int i = 1; i <= 5; i++) {
    pinMode(i, OUTPUT);
  }
}

void loop() {
  
  int baf_wait = 50;
  int fb_wait = 100;

  wave(5, 50);
  delay(1000);
  backAndForth(5, 50);
  delay(1000);
  fallingBrick(100);
  delay(1000);
  backAndForth(5, 50, LOW, HIGH);
  delay(1000);
  fallingBrick(100, LOW, HIGH);
  delay(1000);
  boing(5, 50);
  delay(1000);
}

The result

Experiments with the Arduino

Lately I became the happy owner of an Arduino Sidekick Basic Kit.

I will post here some experiments with this lovely device.

What is the Arduino


Arduino is a tool for making computers that can sense and control more of the physical world than your desktop computer. It's an open-source physical computing platform based on a simple microcontroller board, and a development environment for writing software for the board.

Arduino can be used to develop interactive objects, taking inputs from a variety of switches or sensors, and controlling a variety of lights, motors, and other physical outputs. Arduino projects can be stand-alone, or they can be communicate with software running on your computer (e.g. Flash, Processing, MaxMSP.) The boards can be assembled by hand or purchased preassembled; the open-source IDE can be downloaded for free.

The Arduino programming language is an implementation of Wiring, a similar physical computing platform, which is based on the Processing multimedia programming environment.

Playing with a tricolor LED


The circuit



The code


void fade(int r1, int g1, int b1, int r2, int g2, int b2, int steps, int wait)
{
  float dr = (float)(r2 - r1) / steps;
  float dg = (float)(g2 - g1) / steps;
  float db = (float)(b2 - b1) / steps;
  
  float r = r1; float g = g1; float b = b1;
  
  for(int i = 0; i < steps; i++) {
    analogWrite(9, r);         
    analogWrite(10, g);         
    analogWrite(11, b);
    
    r = r + dr;
    g = g + dg;
    b = b + db;
    
    delay(wait); 
  }
}

void setup()  { 
} 
 
void loop()  {

 fade(255, 0, 0, 0, 255, 0, 100, 50);
 delay(1000);
 fade(0, 255, 0, 255, 0, 0, 100, 50);
 delay(1000);
}

The result




Conclusion


I'm an absolute beginner in electronics, but I already felt in love with this micro-controller board. Looking forward to experiment and understand some more :-)