Go Down

Topic: 8x8 Matrix and Loops (Read 964 times) previous topic - next topic

dr0wned

I'm working on a project where part of it uses an 8X8 led matrix. I'm using one I bought from Adafruit.

The pattern is on a video here (I had to use a piece of paper so the leds didn't cause distortion in the image): http://youtu.be/FGIAMo4Cw_c


I was wondering if anyone could give me any ideas on how I could shorten the code.  Right now it uses many For loops but I imagine there must be a way to do it in a very short amount of code.  This is just one pattern of many and I hope to use whatever advice I get and apply it towards them all.

Here's my code so far (separated out so it's just this matrix):

Code: [Select]

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

void setup() {
  Serial.begin(9600);
  Serial.println("8x8 Test");
  matrix.setBrightness(0);
  matrix.setRotation(1);
  matrix.begin(0x70);  // pass in the address
}

void loop() {
  matrix.clear();
 
  for (int x=0; x<=7; x++) {
    matrix.drawPixel(0,x, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=1; x<=7; x++) {
    matrix.drawPixel(x,7, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=6; x>=0; x--) {
    matrix.drawPixel(7,x, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=6; x>=1; x--) {
    matrix.drawPixel(x,0, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
//
  for (int x=1; x<=6; x++) {
    matrix.drawPixel(1,x, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=2; x<=5; x++) {
    matrix.drawPixel(x,6, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=6; x>=1; x--) {
    matrix.drawPixel(6,x, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=5; x>=2; x--) {
    matrix.drawPixel(x,1, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }   
  //
  for (int x=2; x<=5; x++) {
    matrix.drawPixel(2,x, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=3; x<=4; x++) {
    matrix.drawPixel(x,5, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=5; x>=2; x--) {
    matrix.drawPixel(5,x, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
  for (int x=4; x>=3; x--) {
    matrix.drawPixel(x,2, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }     
    matrix.drawPixel(3,3, LED_ON);
    matrix.writeDisplay();
    delay(100);
    matrix.drawPixel(3,4, LED_ON);
    matrix.writeDisplay();
    delay(100);
    matrix.drawPixel(4,4, LED_ON);
    matrix.writeDisplay();
    delay(100);
    matrix.drawPixel(4,3, LED_ON);
    matrix.writeDisplay();
  delay(500);

}


Any advice would be appreciated.

tobyb121

You could try putting the loops into a function that draws a single square, then call that function for each of the corners in turn
Code: [Select]

void drawSquare(int top, int left,int width){
    int x;
    for(x=top; x<=(top+width); x++){
        matrix.drawPixel(left, x, LED_ON);
        ...
    }
    for(x=left+1; x<=(left+width); x++){
        matrix.drawPixel(x, top+width, LED_ON);
        ...
    }
    etc...
}

UKHeliBob

The first thing that I would do is to use meaningful variable names for the matrix coordinates.  Using x for both rows and columns makes seeing the wood for the trees, at least for me.  Changing the variable names will not answer your question of course, but may help you spot a pattern in how they vary which could lead to shortening the code.

As a first step, how about a function to turn on leds in a row and another in a column.
Something like this (NOTE - UNTESTED !)

Code: [Select]
void colLeds(int col, int startRow, int endRow, int increment)
{
  for (int row=startRow; row<=endRow; row+=increment)
  {
    matrix.drawPixel(col,row, LED_ON);
    matrix.writeDisplay();
    delay(100);
  }
}


Then call it like this
Code: [Select]
colLeds(0,0,7,1);


If I have got it right (fingers crossed) this will light each LED in the left column from top to bottom.

You could have a single function to turn on LEDS in a row or column by feeding it more parameters.

Using functions like this would not reduce the number of for loops executed, of course, but could potentially reduce the number of them in your sketch to 2 or even 1

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

lloyddean

There is always the table driven method.

To conserve just a little space the table entries consist of paired 4 bit XY pairs that are pulled apart into separate X, Y parameters.

Code: [Select]

#include <Wire.h>

#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

#define ENTRIES(ARRAY)  (sizeof(ARRAY) / sizeof(ARRAY[0]))

uint8_t pattern[] =
{
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
   , 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77
   , 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70
   , 0x60, 0x50, 0x40, 0x30, 0x20, 0x10
   , 0x11, 0x12, 0x13, 0x14, 0x15, 0x16
   , 0x26, 0x36, 0x46, 0x56, 0x66
   , 0x65, 0x64, 0x63, 0x62, 0x61
   , 0x51, 0x41, 0x31, 0x21
   , 0x22, 0x23, 0x24, 0x25
   , 0x35, 0x45, 0x55
   , 0x54, 0x53, 0x52
   , 0x42, 0x32
   , 0x33, 0x34
   , 0x44
   , 0x43
};

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

void loop()
{
   matrix.clear();
   
   for (int i = 0; i < ENTRIES(pattern); i++ )
   {
       int x = pattern[i] >> 4;
       int y = pattern[i]  & 7;
   
       matrix.drawPixel(x, y, LED_ON);
       matrix.writeDisplay();
       delay(100);
   }

   delay(400);
}

void setup()
{
   Serial.begin(9600);

   Serial.println("8x8 Test");

   matrix.setBrightness(0);
   matrix.setRotation(1);
   matrix.begin(0x70);  // pass in the address
}


dr0wned

#4
Jan 17, 2013, 09:50 am Last Edit: Jan 17, 2013, 10:27 am by dr0wned Reason: 1
Thank you for your responses. They're all of value to me because they are distinctly different, so I know I will find uses for them.

tobyb121:  That solution sounds good and is something I'll use. Maybe not for this one in particular, but it gave me ideas on something else.  I hadn't thought of it that way so I'll save that info in my "cheat sheet" for the future.

UKHeliBob: Thanks for the advice on the variables. To be honest, I threw this together kind of quickly to extract it from my larger project.  I was kind of lazy and just copy+pasted the same thing and edited what was needed. It makes sense to give them different names for both me and anyone else who reads it.  Your solution with that function does clean it up.  I'm also saving your example to use as needed.

lloyddean:  Your idea intrigues me the most.  I uploaded it straight to my arduino and the results matched what my longer example did but in so much less space. As you can probably tell, I'm a novice at programming (at least anything beyond VBA/VBScript and some old Delphi/pascal stuff.)  Where can I learn more about this method?  I've figured out that 0x00/0x01 etc refers to the individual LEDs and I could easily adapt that for future use, but I'd love to understand it. Especially the lines "int x = pattern >> 4;"  and "int y = pattern  & 7;" -- Is there a phrase I could search to learn more about how >> and & work?  I assume it is to extract the data from the 3rd & 4th characters/digits from that part of the array, but I'm not sure how it referring to them.  Also, did you manually come up with that pattern by imagining the matrix and the LED locations, or was there a  particular method you used?   [Edit: just found the >> refers to bitshifting, so I've been reading about it and messing with examples.  Is there anywhere you could point me that could explain why "pattern >> 4"  turns the value in the pattern of 0x43 to "4"? I know if I print that part of the pattern to serial it shows up as 67 but after shifting it then it shows 4. I do realize 0x43 is hex for 67, but I'm not sure how it changes to 4.  I'm not just fishing for the answer--  While I'd like the answer, I'd love to know what to search for so I can learn more about it.]

Thanks :)

lloyddean

We're using the C++ programming language.

I encoded the x, y values into BCD pairs with the left hand 4 bits as 'x' and the right most 4 bits as 'y'.  This works since 4-bits has the range 0 - 15 for 16 unique values which is less than needed for your 8 x 8 LED matrix.

Binary representation of the hex value 0x43 is a concatenation of '0100' (decimal 4) as the hi 4 bits of a single byte and '0011' (or decimal 3) as the lo 4-bits of the byte.  This gives you '01000011' as the encoded byte.

To extract the 'X' value you'll need to shift the byte 4 bits to the right. This throws the lo 4 bits into the but buck leaving '0100'.  Next to extract the 'Y' we need the lo 4 bits which can be extracted with a simple bit-wise 'AND' (which in C/C++ is performed with the '&' operator) leaving use with '0011'.

We now have decode the BCD encoded x and y value form the encoded value 0x43.

All sequences members are encoded values stored in a lookup table.  The lookup table here is simply a C/C++ array of precomputed values.

Does this make sense?

dr0wned

That actually helps a lot. I had to do some searching but was able to wrap my mind around how it all works. 

My only other question is in the line: int y = pattern  & 7;

In this case, was 7 chosen because we know that the first four bits would be zero and that would make sure that once we use 'AND' the first 4 bits would predictably be 0, in essence making it as if only 4 bits mattered?

Thanks again for all your help.

lloyddean

#7
Jan 18, 2013, 05:58 pm Last Edit: Jan 19, 2013, 02:40 am by lloyddean Reason: 1
You have an 8 x 8 matrix meaning x, or y, needs a minimum of 8 (0 - 7) unique values to identify any individual LED.

The encoding is 4 bits X and 4 bits Y

X can be had with -

Code: [Select]

0x43 = 01000011
>> 1   --------    1 falls away
0x21   00100001
>> 1   --------    1 falls away
0x10   00010000
>> 1   --------    0 falls away
0x08   00001000
>> 1   --------    0 falls away
0x04   00000100    X


and X can be had with

Code: [Select]

0x43 = 01000011
0x07 = 00000111
  &   --------
0x03   00000011    Y


By rights we should perform an AND with 0x0F (0 - 15) but we don't need the additional range so I simply used 0x07 (for 0 - 7).

EDIT: And as to why I encoded the 2 values into a single byte?  The answer is probably obvious - to occupy half a much memory space!


And I keep forgetting to answer your question as to HOW the table was generated.

I used a generalized algorithms for an M x N version of the curve but could've used your program as the basis of a very quick and dirty C++ console program thusly -

Code: [Select]

/* Set 'current' directory:
*
*      cd ~/Desktop/Spiral/
*
* Compile with:
*
*      clang++ -stdlib=libc++ -std=c++11 main.cpp
*
* Run with:
*
*      ./a.out
*/

#include <iostream>

int main()
{
   using std::cout;
   using std::endl;
   using std::uppercase;
   
   for ( int x = 0; x <= 7; x++ ) { cout << "0x" << uppercase << 0 << x << ", "; }
   for ( int x = 1; x <= 7; x++ ) { cout << "0x" << uppercase << x << 7 << ", "; }
   for ( int x = 6; x >= 0; x-- ) { cout << "0x" << uppercase << 7 << x << ", "; }
   for ( int x = 6; x >= 1; x-- ) { cout << "0x" << uppercase << x << 0 << ", "; }
   for ( int x = 1; x <= 6; x++ ) { cout << "0x" << uppercase << 1 << x << ", "; }
   for ( int x = 2; x <= 5; x++ ) { cout << "0x" << uppercase << x << 6 << ", "; }
   for ( int x = 6; x >= 1; x-- ) { cout << "0x" << uppercase << 6 << x << ", "; }
   for ( int x = 5; x >= 2; x-- ) { cout << "0x" << uppercase << x << 1 << ", "; }    
   for ( int x = 2; x <= 5; x++ ) { cout << "0x" << uppercase << 2 << x << ", "; }
   for ( int x = 3; x <= 4; x++ ) { cout << "0x" << uppercase << x << 5 << ", "; }
   for ( int x = 5; x >= 2; x-- ) { cout << "0x" << uppercase << 5 << x << ", "; }
   for ( int x = 4; x >= 3; x-- ) { cout << "0x" << uppercase << x << 2 << ", "; }

   cout << "0x" << uppercase << 3 << 3 << ", ";
   cout << "0x" << uppercase << 3 << 4 << ", ";
   cout << "0x" << uppercase << 4 << 4 << ", ";
   cout << "0x" << uppercase << 4 << 3;

   cout << endl;
       
   return 0;
}


lloyddean

Made you look!

Actually I added to the above message ...

Go Up