First program : boolean array

Hello all :slight_smile:
I just started with arduino and can make all the basic stuff work, even got it to interface a 32*64led matrix (multiplex/595 combo).
I am fairly good at programming, however I have not done much C/C++ before.

I am using a decimilla with usb power.

For the LED matrix, I would like to make a clock, so for starters I make an boolean array of 32*64 (32rows with 64leds).
And then loop trough it while printing it to serial, just to see that it works… and it does not :frowning:

I get all sort of wierd numbers back, instead of what I defined.

This is a sample of the output I get on serial connection

0:0 0
0:1 0
0:2 0
0:3 0
0:4 0
0:5 0
0:6 1
0:7 0
0:8 0
0:9 0
0:10 0
0:11 0
0:12 0
0:13 0
0:14 0
0:15 0
0:16 0
0:17 0
0:18 135
0:19 0
0:20 0
0:21 0
0:22 0
0:23 0
0:24 1
0:25 3
0:26 0
0:27 0
0:28 98
0:29 0
0:30 0
0:31 0
0:32 0
0:33 0
0:34 0
0:35 0
0:36 0
0:37 0
0:38 0
0:39 0
0:40 0
0:41 0
0:42 0
0:43 0
0:44 0
0:45 0
0:46 0
0:47 0
0:48 0
0:49 0
0:50 0
0:51 0
0:52 0
0:53 0
0:54 0
0:55 0
0:56 0
0:57 0
0:58 0
0:59 0
0:60 0
0:61 0
0:62 0
0:63 0
1:0 0
1:1 0
1:2 0
1:3 0
1:4 0
1:5 0
1:6 0
1:7 0
1:8 1
1:9 4
1:10 108
1:11 0
1:12 0
1:13 0
1:14 0
1:15 0
1:16 0
1:17 248
1:18 254

And this is the code, it should output row:col value, but value is a boolean and should only be 0 or 1, from the array I defined in the top.

#include <avr/pgmspace.h>

boolean rows[32][64] PROGMEM = {
{0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0},
{0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0},
{0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0}
-array cut for size limit same row repeats 32times-
}

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


  for (byte row = 0; row < 32; row++)
  {
      for (byte col = 0; col<64; col++)
      {
        Serial.print((int)row);        
        Serial.print(":");                
        Serial.print((int)col);                
        Serial.print(" ");
        Serial.println((int)rows[row][col]);

        delay(500);
      }
}
}

void loop() {}

Any advise is very welcome :-/

I don't know too much about the Arduino serial library, but my guess would be that serial.println() does not handle printing data from program space. It's probably just treating the program space pointer as a pointer in RAM and attempting to print from there.

  • Ben

Ben’s guess is correct, you need to read the data into ram using pgm_read_byte()

Also Boolean is stored as a byte so your array takes up 2k of program memory. You can see an example here of how to store and retrieve bit values from flash :
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1214715130#13

Thanks for your replies.
After moving it from PROGMEM it works (with a smaller array).

Is this something general, that functions wont work with items in PROGMEM ?

So I save the data I need in PROGMEM, and then read it out in chunks when needed, eg. 128bytes at a time, correct ?

It would be easyier if I could prepare the entire panel before shifting it out, but it will use up all of the memory alone (2colors=4possible values per led = 64324 = 1kb).

Yes, you do need to read data stored in PROGMEM in chunks of one to four byts at at time, atlhough you could write a function that copied large amounts in a loop.

But unless your code requires lots of data to be accessed at once to complete a calculation, its best to try and structure your code ot keep RAM usage low.

It's not clear from the example code you posted if there is any advantage in reading in 128 bytes at a time. Perhaps you could say more about what you want your sketch to do.

Ok first the code, its fairly long.

#include <avr/pgmspace.h>

/*
 * 0,1 = serial
 * 13  = led
 */

byte AddressA = 2;
byte AddressB = 3;
byte AddressC = 4;
byte AddressD = 5;

byte green1   = 6;
byte green2   = 7;
byte red1     = 8;
byte red2     = 9;

byte shift   = 10;
byte enable  = 11;
byte latch   = 12;

byte h1;
byte h2;
byte m1;
byte m2;
byte s1;
byte s2;

byte rowdata[64];  //I dont know how to call-by-reference yet, so declared here for all to use

//The numbers 16*8bits - will need to change this if each boolean takes 1 byte of the space
boolean number0[16][8] PROGMEM = {
{0, 1, 1, 1, 1, 1, 1, 0},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{0, 1, 1, 1, 1, 1, 1, 0}
};

boolean number1[16][8] PROGMEM = {
{0, 0, 0, 0, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1}
};

boolean number2[16][8] PROGMEM = {
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1}
};

boolean number3[16][8] PROGMEM = {
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1}
};

boolean number4[16][8] PROGMEM = {
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1}
};

boolean number5[16][8] PROGMEM = {
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1}
};

boolean number6[16][8] PROGMEM = {
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1}
};

boolean number7[16][8] PROGMEM = {
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1}
};

boolean number8[16][8] PROGMEM = {
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1}
};

boolean number9[16][8] PROGMEM  = {
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 1}
};
//the dots ":"
boolean number10[16][8] PROGMEM  = {
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
};

void setup()
{ 
//All this setup is not doing anything yet, since the display is not active with this code
  Serial.begin(9600);

  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);  

  digitalWrite(green1, HIGH);  
  digitalWrite(green2, HIGH);  
  digitalWrite(red1, HIGH);  
  digitalWrite(red2, HIGH);  

  digitalWrite(AddressA, LOW);  
  digitalWrite(AddressB, LOW);
  digitalWrite(AddressC, LOW);  
  digitalWrite(AddressD, LOW);  

  digitalWrite(shift, LOW);  
  digitalWrite(latch, LOW);

  //Control the brightness and current usage, about 150 is minimum for stable display
  analogWrite(enable, 175); 
}

void loop()
{
  //This will later be from a real clock, 24hr display.
  h1 = 1;
  h2 = 5;
  m1 = 3;
  m2 = 0;
  s1 = 1;
  s2 = 5;
   
  for (byte row = 0; row < 16; row++) //Add each row so we can shift out 1 complete row at a time
  {
    addData(row, h1);
    addData(row, h2);

    addData(row, 10);

    addData(row, m1);
    addData(row, m2);

    addData(row, 10);    

    addData(row, s1);
    addData(row, s2);
    
    shiftout();
  }

}

void addData(byte row, byte number)
{
  //retrive number from PROGMEM
  //add to datarow, 4bytes so that shiftout can be reused in other projects
}

void shiftout()  //not done yet, each byte controls 4leds (red/green/both/off = 2bits)
{
  for (byte i = 0; i<64; i++)
  {
    if ( rowdata[i] > 0 )
    {
      digitalWrite(red1, LOW); //LOW means led is on...
    } else {
      digitalWrite(red1, HIGH);
    }
    
    digitalWrite(shift, HIGH);  
    digitalWrite(shift, LOW);         
  }

  digitalWrite(latch, HIGH);  
  digitalWrite(latch, LOW);     
}

void selectRow(byte row)  //this works fine
{
  switch (row) {
  case 0:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, LOW);  

    break;
  case 1:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 2:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, LOW);  

    break;
  case 3:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 4:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, LOW);  

    break;
  case 5:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 6:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, LOW);  

    break;
  case 7:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 8:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, LOW);  

    break;
  case 9:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 10:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, LOW);  

    break;
  case 11:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 12:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, LOW);  

    break;
  case 13:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 14:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, LOW);  

    break;
  case 15:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, HIGH);  

    break;      
  }
}

So thats the code.
What I am missing is in addData.

I am trying to make a digital clock using the LED matrix of 16(32)rows with 64leds on each row.
When shifting out I set both r1/r2 for red, because I am shifting out row 1 and row 17 (2/18 3/19 etc) at a time.

So the 4 red1, red2, green1, green2 control color.
address controls row.
shift/latch controls 595.

Fire away with comments :slight_smile:

1 Like

you can reduce the memory to an eigth of current values by changing:

boolean number0[16][8] PROGMEM = {
{0, 1, 1, 1, 1, 1, 1, 0},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{0, 1, 1, 1, 1, 1, 1, 0}
};

to:
byte number0[16] PROGMEM= {
0B01111110,
0B10000001,
0B10000001,
… and so on…
};

You access the values by doing a binary ‚Äėand‚Äô as follows:
for( byte mask = 1; mask; mask <<=1)
if( mask & number0[0])
// do something if a but is set in each position of the first row of number 0

You may also want to make the numbers array two dimensional :
numbers[10][16] = { ?}

I hope that’s enough info to get you started.

Once you have things working, you could experiment doing your row shift with the long long type, this is 64 bits wide. I haven’t used it with the arduino compiler but its worth trying if you need to shift 64 bit arrays.

long long aLongLongRow; // a 64 bit value

aLongLongRow = 1 // initialise to 1

for( long long mask = 1; mask; mask <<=1)
if( mask & aLongLongRow)
// light an led or something if a bit is set

Then shift the row:
aLongLongRow <<=1;
aLongLongRow | = getBooleanValue(); // set the ms bit to some value

I have made some changes, but I am getting wrong data back on serial write again. Does the arduino handle converting to ASCII by it self ?

The changed code bits

byte numbers[11][16] PROGMEM = 
{
{//0
0B01111110,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B10000001,
0B01111110
}
,
{//1
.....

void addData(byte row, byte number, byte position)
{
  //retrive number from PROGMEM
  byte numrow = numbers[number][row]; //row is 0-7
  Serial.println((int)numrow);
  delay(1000);
    
  //add to datarow starting from position
}



and to test it

  addData(0, 0, 0);
  addData(1, 0, 0);
  addData(2, 0, 0);
  addData(3, 0, 0);
  addData(4, 0, 0);
  addData(5, 0, 0);
  addData(6, 0, 0);
  addData(7, 0, 0);

I would think it should output 126, 129, 129, 129, 129, 129, 129, 126 as that is the decimal values of the 8bytes that makes up number 0.

Instead I get 0, 0, 36,0, 0, 0, 1 ....

you need to use pgm_read_byte to get data back from progmem. This sketch illustrates how this can be done

#include <avr/pgmspace.h>

byte numbers[11][16] PROGMEM = 
{
  {//0
    0B01111110,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B01111110
  }
  // more initialisers go here....
};

byte getByte(byte number, byte row){
  return pgm_read_byte(&numbers[number][row]);
}

boolean getBit( byte number, byte row, byte position){
  byte b = getByte(number,row);
  //position is 0-7 with 0 the rightmost position
  return b & 1 << position;
}

void setup() {
  Serial.begin(19200);
}


void loop(){
  Serial.println("printing bytes...");
  for(int i = 0; i < 16; i++) {  
    byte b = getByte(0,i);
    Serial.println(b,DEC);  
  }  
  
  Serial.println("printing bits...");
  for(int i = 0; i < 16; i++){
    for(int j=0; j < 8; j++){ 
      if(getBit(0,i,j))
        Serial.print("1"); 
      else    
        Serial.print("0"); 
    }
    Serial.println();
  }    
  delay(1000);
}

the output looks like this:

printing bytes...
126
129
129
129
129
129
129
129
129
129
129
129
129
129
129
126

printing bits...
01111110
10000001
10000001
10000001
10000001
10000001
10000001
10000001
10000001
10000001
10000001
10000001
10000001
10000001
10000001
01111110

Thank you :)

I now have it working both on serial and the matrix.

Theres a hint of flicker, but I will leave that for another time.

I have to update 70times per second, so thats 850ms per update or just 50ms per row. As my code is now I am making 8calls to getbyte per row update, at 3ms that only leaves 24ms to the rest of the code.

Thanks again to everyone!

You should be able to speed things up considerably if you use direct port access instead of digitalWrite. Post your code if you want help with this to make it easier to make application specific suggestions. You may want to remove your array initialization code, it would be no bad thing moving it into a separate h file anyway.

A picture of the beast in action :slight_smile:


I am very new to arduino and this avr platform, so I didnt think about another way to set the pins.
Heres the code without the large array.

The selectRow should probaly be split into a file for itself also.

#include <avr/pgmspace.h>

/*
 * 0,1 = serial
 * 13  = led
 */

byte AddressA = 4;
byte AddressB = 3;
byte AddressC = 2;

byte AddressD = 5;

byte green1   = 6;
byte green2   = 7;
byte red1     = 8;
byte red2     = 9;

byte shift   = 10;
byte enable  = 11;
byte latch   = 12;

byte h1;
byte h2;
byte m1;
byte m2;
byte s1;
byte s2;

unsigned long startTime;

...

byte getByte(byte number, byte row){
 return pgm_read_byte(&numbers[number][row]);
}

boolean getBit( byte number, byte row, byte position){
  byte b = getByte(number,row);
  //position is 0-7 with 0 the rightmost position
  return b & 1 << position;
}

void setup()
{ 
//  Serial.begin(9600);
//  Serial.println();
//  Serial.println();
  
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);  

  digitalWrite(green1, HIGH);  
  digitalWrite(green2, HIGH);  
  digitalWrite(red1, HIGH);  
  digitalWrite(red2, HIGH);  

  digitalWrite(AddressA, LOW);  
  digitalWrite(AddressB, LOW);
  digitalWrite(AddressC, LOW);  
  digitalWrite(AddressD, LOW);  

  digitalWrite(shift, LOW);  
  digitalWrite(latch, LOW);

  //Control the brightness and current usage, about 150 is minimum for stable display
  //  analogWrite(enable, 200); 
  digitalWrite(enable, HIGH);  
  
  startTime = millis();
  
  //This will later be from a real clock, 24hr display.
  h1 = 2;
  h2 = 0;
  m1 = 1;
  m2 = 4;
  s1 = 0;
  s2 = 0;
}

void loop()
{
  if (millis() - startTime > 1000)
  {
//    Serial.print(h1,DEC);    
//    Serial.print(h2,DEC);    
//    Serial.print(":");        
//    Serial.print(m1,DEC);    
//    Serial.print(m2,DEC);    
//    Serial.print(":");        
//    Serial.print(s1,DEC);    
//    Serial.println(s2,DEC);        
    
    startTime = millis();
    
    s2++;

    if (s2 == 10)
    {
      s2=0;
          
      s1++;
      
      if (s1 == 6)
      {
        s1=0;
        
        m2++;
        
        if (m2 == 10)
        {
          m2=0;
          
          m1++;
          
          if (m1 == 6)
          {     
            m1=0;
            
            h2++;
            
            if (h1 == 2 || h2 == 4)
            {  
              h1=0;
              h2=0;
            }
            if (h2 == 6)
            {
                h1++;
                h2=0;
            }
          }     
        }
      }
    }
  }
  
  byte dot = 10;
  if (s2 == 1 || s2 == 3 || s2 == 5 || s2 == 7 || s2 == 9)
    dot = 11;
  
  
  for (byte row = 0; row < 16; row++)
  {
    addData(row, h1, 0);
    addData(row, h2, 1);
    addData(row, dot, 2);
    addData(row, m1, 3);
    addData(row, m2, 4);
    addData(row, dot, 5);    
    addData(row, s1, 6);
    addData(row, s2, 7);
    selectRow(row);
    
//    Serial.println(row,DEC);

    digitalWrite(latch, HIGH);  
    digitalWrite(latch, LOW);   
    
//    delay(1000);
  }
}
void addData(byte row, byte number, byte position)
{
  byte colmax = 7;   
  if (number == 10 || number == 11)
    colmax = 3;
  
  for(int col=colmax; col >= 0; col--){ 
    if(getBit(number,row,col))
    {
//      Serial.print("1"); 
      digitalWrite(red1, LOW); //LOW means led is on...      
      digitalWrite(green2, LOW); //LOW means led is on...            
    }
    else    
    {
//      Serial.print(" "); 
      digitalWrite(red1, HIGH);      
      digitalWrite(green2, HIGH);            
    }
    
    digitalWrite(shift, HIGH);  
    digitalWrite(shift, LOW); 
  }
  
//  if (position < 7)
//  {
    digitalWrite(red1, HIGH);        
    digitalWrite(green2, HIGH);          
    digitalWrite(shift, HIGH);  
    digitalWrite(shift, LOW); 
//  }
  
}

void selectRow(byte row)
{
  switch (row) {
  case 0:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, LOW);  

    break;
  case 1:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 2:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, LOW);  

    break;
  case 3:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 4:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, LOW);  

    break;
  case 5:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 6:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, LOW);  

    break;
  case 7:
    digitalWrite(AddressD, LOW);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 8:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, LOW);  

    break;
  case 9:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 10:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, LOW);  

    break;
  case 11:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, LOW);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 12:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, LOW);  

    break;
  case 13:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, LOW);  
    digitalWrite(AddressC, HIGH);  

    break;
  case 14:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, LOW);  

    break;
  case 15:
    digitalWrite(AddressD, HIGH);       

    digitalWrite(AddressA, HIGH);  
    digitalWrite(AddressB, HIGH);  
    digitalWrite(AddressC, HIGH);  

    break;      
  }
}

Here is a suggestion for replacing all your digital writes with direct port IO.
This is done with a macro and is around 40 times faster than digitalWrite on a pin that is known at compile time

First thing is to change your port addresses to constants as follows:

#define AddressA 4
#define AddressB 3
#define AddressC 2
#define AddressD 5
#define green1   6
#define green2   7
#define red1     8
#define red2     9
#define shift   10
#define enable  11
#define latch   12

then copy the following macro into your sketch just after the above defines

// this  macro sets a digital pin high or low, pin must be between 0 and 13 inclusive
// usage: fastWrite(2,HIGH); fastWrite(13,LOW);
#define fastWrite(_pin_, _state_) ( _pin_ < 8 ? (_state_ ?  PORTD |= 1 << _pin_ : PORTD &= ~(1 << _pin_ )) : (_state_ ?  PORTB |= 1 << (_pin_ -8) : PORTB &= ~(1 << (_pin_ -8)  )))

then find and replace all occurences of digitalWrite with fastWrite

for example
digitalWrite(AddressA, HIGH);
becomes
fastWrite(AddressA, HIGH);

there are lots of these so use the find/replace feature of the editor.
Make a backup of your sketch before you start just in case
Good luck, let me know you get on, the clock looks great!

very nice :slight_smile:

I cant see that its flickering anymore.
theres a bit of current leakage into leds close to the lit ones, but I think thats the boards fault, and at any distance its unnoticeable.

That macro is that a way to include assembly instructions ?

The macro is C code although the C compiler reduces it down to a single machine language instruction. At compile time it checks which port the pin is on, and sets a bit high or low using the following C code:

set a pin numbered from 0 to 7 high
PORTD |= 1 << pin

set the pin low
PORTD &= ~(1 << pin)

the other pins are set in similar fashion after converting the pin numbers to the correct port and bit

The macro is just a way of giving the source code a more familiar look than stuff that looks more like swearing than C source code: &= ~(1 << pn)

Hey that is pretty amazing! How did you build the massive LED array? Brian

Hey that is pretty amazing! How did you build the massive LED array? Brian

I didnt :)

I brought it from a ebay shop in china completed (115$ with postage from sure-electronics). Its build of out several 8x8 led matrixes (power one row and col at a time) Then several 595 and some multiplex chips to control the complete board.

more boards can be added with a ribbon cable, but at some point it will be too many to control without blinking.

im working on a nicer code with files, and ds1307 rtc. maybe serial control so it can display custom texts instead of clock.

thought about network too , but then its probaly better(and almost same price) to move it to an ethernet enabled board.

I’m working on a project where I need to store a whole bunch of static binary data into progmem and read it out piece by piece. The code example in reply#9 is very very similar to what I need. (Thanks!) I’ll repost it here so you don’t have to go back a page to read it.

#include <avr/pgmspace.h>

byte numbers[11][16] PROGMEM =
{
  {//0
    0B01111110,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B10000001,
    0B01111110
  }
  // more initialisers go here....
};

byte getByte(byte number, byte row){
  return pgm_read_byte(&numbers[number][row]);
}

boolean getBit( byte number, byte row, byte position){
  byte b = getByte(number,row);
  //position is 0-7 with 0 the rightmost position
  return b & 1 << position;
}

void setup() {
  Serial.begin(19200);
}


void loop(){
  Serial.println("printing bytes...");
  for(int i = 0; i < 16; i++) {  
    byte b = getByte(0,i);
    Serial.println(b,DEC);  
  }  
  
  Serial.println("printing bits...");
  for(int i = 0; i < 16; i++){
    for(int j=0; j < 8; j++){
      if(getBit(0,i,j))
        Serial.print("1");
      else    
        Serial.print("0");
    }
    Serial.println();
  }    
  delay(1000);
}

The only thing I can’t seem to figure out it is how this piece works.

return b & 1 << position;

The place it’s returning too, looks like it just takes a 0 or 1. First, how is it picking out a single bit from the byte? Second, what is getting returned? Could somebody explain this line of code in words?