3

I was following the official tutorial and confused by the source code.

Arduino Official built-in example: RowColumnScanning

// when the row is HIGH and the col is LOW,
// the LED where they meet turns on:
digitalWrite(col[thisCol], thisPixel);
// turn the pixel off:
if (thisPixel == LOW) {
  digitalWrite(col[thisCol], HIGH);
}

Here is my understanding:

  1. If thisPixel is LOW, the pin col[thisCol] would be HIGH.
  2. If thisPixel is HIGH, the pin col[thisCol] would still be HIGH.

Question

Because it col[thisCol] is always HIGH regardless of thisPixel, does it make sense to have an extra if statement?

In case the URL is dead

enter image description here

/*
  Row-Column Scanning an 8x8 LED matrix with X-Y input

  This example controls an 8x8 LED matrix using two analog inputs.

  This example works for the Lumex LDM-24488NI Matrix. See
  https://sigma.octopart.com/140413/datasheet/Lumex-LDM-24488NI.pdf
  for the pin connections.

  For other LED cathode column matrixes, you should only need to change the pin
  numbers in the row[] and column[] arrays.

  rows are the anodes
  cols are the cathodes
  ---------

  Pin numbers:
  Matrix:
  - digital pins 2 through 13,
  - analog pins 2 through 5 used as digital 16 through 19
  Potentiometers:
  - center pins are attached to analog pins 0 and 1, respectively
  - side pins attached to +5V and ground, respectively

  created 27 May 2009
  modified 30 Aug 2011
  by Tom Igoe

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/RowColumnScanning
*/

// 2-dimensional array of row pin numbers:
const int row[8] = {
  2, 7, 19, 5, 13, 18, 12, 16
};

// 2-dimensional array of column pin numbers:
const int col[8] = {
  6, 11, 10, 3, 17, 4, 8, 9
};

// 2-dimensional array of pixels:
int pixels[8][8];

// cursor position:
int x = 5;
int y = 5;

void setup() {
  // initialize the I/O pins as outputs iterate over the pins:
  for (int thisPin = 0; thisPin < 8; thisPin++) {
    // initialize the output pins:
    pinMode(col[thisPin], OUTPUT);
    pinMode(row[thisPin], OUTPUT);
    // take the col pins (i.e. the cathodes) high to ensure that the LEDS are off:
    digitalWrite(col[thisPin], HIGH);
  }

  // initialize the pixel matrix:
  for (int x = 0; x < 8; x++) {
    for (int y = 0; y < 8; y++) {
      pixels[x][y] = HIGH;
    }
  }
}

void loop() {
  // read input:
  readSensors();

  // draw the screen:
  refreshScreen();
}

void readSensors() {
  // turn off the last position:
  pixels[x][y] = HIGH;
  // read the sensors for X and Y values:
  x = 7 - map(analogRead(A0), 0, 1023, 0, 7);
  y = map(analogRead(A1), 0, 1023, 0, 7);
  // set the new pixel position low so that the LED will turn on in the next
  // screen refresh:
  pixels[x][y] = LOW;

}

void refreshScreen() {
  // iterate over the rows (anodes):
  for (int thisRow = 0; thisRow < 8; thisRow++) {
    // take the row pin (anode) high:
    digitalWrite(row[thisRow], HIGH);
    // iterate over the cols (cathodes):
    for (int thisCol = 0; thisCol < 8; thisCol++) {
      // get the state of the current pixel;
      int thisPixel = pixels[thisRow][thisCol];
      // when the row is HIGH and the col is LOW,
      // the LED where they meet turns on:
      digitalWrite(col[thisCol], thisPixel);
      // turn the pixel off:
      if (thisPixel == LOW) {
        digitalWrite(col[thisCol], HIGH);
      }
    }
    // take the row pin low to turn off the whole row:
    digitalWrite(row[thisRow], LOW);
  }
}
3
  • It prevents ghosting when the next row is brought high ... also reduces the overall current because only one LED is lit at any one time
    – jsotola
    Feb 19 at 17:29
  • Would you mind to copy the complete sketch into your question, please? External resources tend to vanish... and we like to help future readers understand the issue completely. Feb 19 at 17:32
  • 1
    @thebusybee Thanks for the reminder. I have updated the question. Feb 20 at 8:43

2 Answers 2

3

You are right, the if does not make sense. Not all tutorials are correct, and even if, they are often not very good.

The reason for the second digitalWrite() is to switch the pixel off after it was potentially on. If it stays on when the row is changed, you could see ghosting.

However, I would switch all pixel of a row, delay a bit, and then in a second loop, switch them all off again, before I process the next row.

1

I'm going to split this answer into two parts, the first about matrix displays in general, and the latter considering this particular dubious example.

The fundamental idea of a matrix display is that the LEDs don't need to be on continuously. If they are illuminated sufficiently often and for a sufficient proportion of the time, then the human eye will average things out.

Exactly what "sufficiently often", and a "sufficient proportion" of the time are can be hard to pin down. The former depends on the particular person viewing, but I would aim for at least 100Hz. The latter depends mostly on how bright your LEDs are when turned on (more on that later).

This is useful because it saves you a lot of IO lines, if you wanted individual control of 256 LEDs you would need 256 IO lines. By using a row/column matrix you only need 16. Of course with a row/colum matrix, it isn't possible to illuminate all combinations of LEDs at the same time, but that doesn't actually matter because as long as you illuminate each active LED sufficiently often the human eye won't notice the difference.

It's good practice to turn off the LEDs that you have turned on for one row before moving on to the next row. Otherwise you can get "ghosting" where an unintended LED illuminates. How much of a problem ghosting is in practice depends heavily on the specifics of your matrix drive code.


Several things however set this example apart from a "Normal" matrix drive implementation.

  • This example only lights a single LED at a time. Most matrix drive implementations light a whole row (or column) at a time. That means the LEDs are illuminated a much greater proportion of the time, it does have downsides though, it means your row drivers have to have enough current drive capacity to drive a whole row at once.
  • This example has no series resistors! the current through the LEDs is limited only by the internal resistance of the LEDs and the IO pin drivers in the AVR. This likely results at the LEDs and the GPIO pins operating significantly above their nominal max current!
  • There is nothing to control the timing in the code, and the LED on time is very short. Depending on how well the compiler optimizes the code, it may only be a few clock cycles.

Some of these factors cancel each other out, the drive current is likely very high, but it's only applied very briefly and only to one LED at a time. So the overall result is likely that nothing gets fried and the display has a usable brightness.

But nevertheless, I think it's the sort of example that gets Arduino a bad name. It presumably works (or it wouldn't have been posted), but it's driving components out of specification, and the brightness of the display is totally at the mercy of poorly specified internal resistances and code execution speed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.