Go Down

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

#### dr0wned

##### Jan 14, 2013, 07:56 am
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>

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);

}

#### tobyb121

#1
##### Jan 14, 2013, 09:11 am
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

#2
##### Jan 14, 2013, 09:26 am
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

#3
##### Jan 14, 2013, 07:22 pm
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>

#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
};

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 amLast 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.

Thanks

#### lloyddean

#5
##### Jan 17, 2013, 06:23 pm
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

#6
##### Jan 18, 2013, 09:24 am
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 pmLast 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

#8
##### Jan 19, 2013, 11:52 pm

Actually I added to the above message ...

Go Up

Please enter a valid email to subscribe