SOLVED: Storing Serial Characters in an Array

I am experienced in programming and using Arduino. However, this is driving me up the wall, and I finally decided to give in and ask for help.

I have some code in my main loop that displays the boolean array imageArray to an 8x8 led matrix. (It displays this using the standard persistence of vision, row by row scanning method. Therefore, it is very important the main loop keeps looping with only very short interruption.) I have in initial image array defined like so:

boolean imageArray = { 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 };

This lights up the edges of the led matrix.
However, I want to be able to send 64 ASCII 1's and 0's over serial, and update the display to display that. So, I put a

if (Serial.available() > 0)
{

}

at the beginning of the program to check if any serial data has been sent.
(NOTE: assume there will always be exactly 64 characters that are either exactly ASCII 0 [or the value 48] or ASCII 1 [or the value 49].)

In that Serial.available part, I want to have some code to take the data sent over serial and store it in the array imageArray. This is the part I cannot figure out.

As an example of what I want I want:


The Arduino is displaying imageArray.
As soon as serial data is sent, it runs the Serial.available code
Let's say the data sent was:

1000000101000010001001000001100000011000001001000100001010000001

which is the image of an X.

Of course, I would have to subtract 48 from the Serial.read value to actually get 0 or 1.

I then want imageArray set to:

1,0,0,0,0,0,0,1,
0,1,0,0,0,0,1,0,
0,0,1,0,0,1,0,0,
0,0,0,1,1,0,0,0,
0,0,0,1,1,0,0,0,
0,0,1,0,0,1,0,0,
0,1,0,0,0,0,1,0,
1,0,0,0,0,0,0,1

Which is just the data sent (I've put some returns to make it more clear)

After that, the loop runs again, displaying the image.

Then it loops until more serial data is available and does the same thing.

Can someone please help me? I have tried around 5 different methods to do this and none of them worked. This should be simple, right? Just storing a serial string in an array. That's all.

Thanks,
Wyatt Jameson

It would help if you would post your code so we can see what isn't working.

What methods did you use ( code, not description ).

You just need to keep track of where you have filled up to, this method collects 1 char at a time.
Once you know the buffer is full, you can act on it.

bool arr[ 64 ];

void loop(){

  static bool *ref = arr;

  if( Serial.available() > 0 ){
    *ref++ = Serial.read();

    if( ref == ( ref + 64 ) ){
      ref = arr; //reset
      DoSomethingWithArray();
    }
  }
}

I think the serial code uses a 64 byte buffer, you could just wait till 64 bytes are waiting, then copy the whole lot. However there is a chance you'll loose data,... maybe.

Thanks for your reply.

pYro_65:
What methods did you use ( code, not description ).

sigh I admit, the whole ordeal is more complex than a simple 8x8 led matrix. I’m actually using a 4x4x4 led cube and 3 shift registers. That function works perfectly, I’m just trying to feed a boolean array to it that is sent over serial. For practical purposes, I figured just saying an 8x8 array would avoid distracting from the heart of the issue. Let’s assume it’s an 8x8 matrix. If you must know, the code would look something like this: (some of the nitty gritty stuff is just comments)

//Define the 8 col(#)Pin and the 8 row(#)Pin variables here
boolean imageArray = { 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 };

void setup()
{
    //set all the pins to outputs
    Serial.begin(9600);
}
void loop()
{
    if (Serial.available > 0)
    {
        //this is where I need the 64 serial characters stored in imageArray
    }
    display();
}

void display()
{
    //digitalWrite all pins to 0
    for (row = 1; row <= 8; row++)
    {
        //digitalWrite the correct row(#)Pin on
        //digitalWrite the col(#) pins according to imageArray[(row - 1) * 16] through imageArray[((row - 1) * 16) + 7]
        delay(5);
        //digitalWrite the col(#) pins off
        //digitalWrite the correct row(#)Pin off
    }
}

The display() uses multiplexing to basically turn on one row at a time on the matrix, because that’s how you have to use led matrices.

But back to the root of the problem. I need to be constantly running my loop. No matter what. I need the code to display on the led matrix constantly looping. That’s why the basic structure of the program needs to be

void loop()
{
    if (Serial.available > 0)
    {
        //store the serial data in the imageArray
    }
    display();
}

That way, it loops, and only if serial data has been sent does it do anything different.

The code:

bool arr[ 64 ];

void loop(){

  static bool *ref = arr;

  if( Serial.available() > 0 ){
    *ref++ = Serial.read();

    if( ref == ( ref + 64 ) ){
      ref = arr; //reset
      DoSomethingWithArray();
    }
  }
}

would only run the display function once, and only if serial was available.

Any other ideas?

Wyatt Jameson

would only run the display function once, and only if serial was available.

But do you want to display half finished data?
Sounds like you need a buffer which can store valid data which you can display every loop, while filling a secondary. Then switch the buffers when full.

My code wasn't meant to solve world hunger, but more give an idea of where to start.

I think the real problem is this:

int term;
void loop()
{
    term = 0;
    while (Serial.available() > 0)
    {
        imageArray[term] = Serial.read();
        term++;
    }
}

If 64 characters were sent through the serial port, shouldn't that little snippet set imageArray to them?

If 64 characters were sent through the serial port, shouldn’t that little snippet set imageArray to them?

No. The while loop will start when the first byte is available but there is no guarantee that there are any more bytes to be read. Try changing the Serial.available() test to check that there are 64 characters to read.

Okay! I tested some of my original code with serial data LESS THAN 64 chars, and guess what? It works perfectly.
Apparently, the serial buffer doesn’t like holding more than 63 bytes. I went here and found:

available()

Description

Get the number of bytes (characters) available for reading from the serial port. This is data that's already arrived and stored in the serial receive buffer ([u][b]which holds 64 bytes[/b][/u]). available() inherits from the Stream utility class.

So, I was having a buffer overflow or something. That’s fine, I’ll just find a way to separate the data I need to send into two sets of 32 chars or something. Like so: (I also learned about the serialEvent routine)

void serialEvent()
{
  for(int run = 0; run < 2; run++)
  {
    while (Serial.available() < 32) {}
    for (int i = 0; i < 32; i++)
    {
      imageArray[(run * 32) + i] = Serial.read() - 48;
    }
  }
}

There we go! Remember, I’m always going to get exactly 64 characters that are either 1 or 0. Therefore, this code is safe.

Thanks for all the help guys!

So, I was having a buffer overflow or something. That's fine, I'll just find a way to separate the data I need to send into two sets of 32 chars or something. Like so: (I also learned about the serialEvent routine)

If it was overflowing the buffer before you read even one byte then there must be quite a lot going on in your program because serial input is very slow compared to how fast Serial.read() can take each byte out of the buffer.

If you are going to the bother of sending and reading two 32 byte sequences then you may as well do it properly and put start and end bytes on the data and stop messing around counting incoming bytes. Just read when at least one byte is available, check that it is the start of message byte and carry on reading until you reach the end of message byte.

As to serialEvent, I could never see the point of it. Sure, it runs automatically at the end of the loop() function if serial data is available but you can do that yourself and anyway, the end of the loop() function may not be the most appropriate place to check for serial data.