Problem with scrolling 8x8 matrix + serial input

Hey all. First post, and hopefully one thats not too complicated. :stuck_out_tongue:

I've decided to try and write to code to get my single 8x8 matrix scrolling, and to display whatever I feed it via the serial monitor.
I'm progressing pretty well but I'm after getting stuck.
The Arduino is my first experience in programming in C, so my code is probably very inefficient and messy (I've only played with the arduino for 15-20 hours total since I got it). I'm just hoping by writing the code and not just copying a full program from someone else it'll help me get better at it.

My problem is that if I feed in 10 or so characters through serial, the output on the screen is missing one of the letters every so often. If I only feed in upto 4 letters it seems to get them all.

e.g. If I type"ACACACACACAC". The output will lose a random letter from that ending up with something like "ACACCACACAC".
I've only defined the letters A, C, H at the moment, I'll add the rest when I get it working.

At a guess, I think that the screenUpdate function that run's every 1/100th of a second to light the correct row of LED's, could be what's causing the problem. Maybe the program is skipping a letter if screenUpdate runs while its working?
If it is, I can't figure out how to get around it.

The alphabet font in there at the moment is someone elses, I'll make my own once the rest is done. The bitReverse function at the bottom is just to flip the bytes in the alphabet because it displayed upside down in my program.

The hardware is just 2 74HC595 shift registers and an 8x8 LED matrix.

Here's my code so far:

#include <TimerOne.h>
//initial serial buffer
char buffer[1];
//initial numchar
int numChar=0;
// Latch pin of shift registers
int latchPin = 8;
//Clock pin of shift registers
int clockPin = 12;
//Data pin of shift registers
int dataPin = 11;
//for bitReverse function
uint8_t mybitRev;
//--Setup counter for number of letters in buffer for passArray function (and any other function
//that needs it
uint8_t bufferCount=0;

  //alphabet (revered using bitReverse function)
uint8_t alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};


//Row incrementer
int rowInc = 0;

uint8_t led[200];
long counter1 = 0;
long counter2 = 0;

void setup() {
  
  for (int first=0; first<26; first++) {
    for (int second=0; second<5; second++) {
      bitReverse (alphabets[first][second]);
      alphabets[first][second] = mybitRev;
    }
  }
  
  Serial.begin(9600);
  Serial.flush();
  
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  


  Timer1.initialize(10000);
  Timer1.attachInterrupt(screenUpdate);
  }
  
  void loop() {
    if (Serial.available() > 0) {
      timeVal=10;
      for (int x=0; x<bufferCount ; x++) {
      buffer[x]='\0';
      }
      int index = 0;
      delay(100); //buffer fill time
      int numChar = Serial.available();
      char buffer [numChar];
      bufferCount = numChar;
      uint8_t led[bufferCount * 8];
      while (numChar--) {
        buffer[index++] = Serial.read();
      }
      passArray(buffer);
   timeVal=0;
 }
      
    delay(100);
      rowInc++;
      if (rowInc > bufferCount * 8) {
        rowInc = 0;
      }
      
    }
  
  
  void screenUpdate() {
    uint8_t row = B00000001;
    for (byte k = 0; k < 9; k++) {
      //open up the latch ready to receive data
      digitalWrite(latchPin, LOW);
      shiftIt(~row );
      shiftIt(led[k+rowInc] ); //LED Array
      
      
      digitalWrite(latchPin, HIGH);
      row = row << 1;
    }
  }
  
  void shiftIt(byte dataOut) {
    
    boolean pinState;
    
   digitalWrite(dataPin, LOW);
    
    for (int i=0; i<8; i++) {
      
      digitalWrite(clockPin, LOW);
      
      if (dataOut & (1<<i) ) {
        pinState = HIGH;
      }
      else {
        pinState = LOW;
      }
      
      digitalWrite(dataPin, pinState);
      
      digitalWrite(clockPin, HIGH);
      digitalWrite(dataPin, LOW);
    }
    
    digitalWrite(clockPin, LOW);
  }
  
  
  void passArray(char* data) {
    for (int bufferFeed=0; bufferFeed <= bufferCount; bufferFeed++) {

    if ((data[bufferFeed] == 'a') || (data[bufferFeed] == 'A')) {
    led[0+(bufferFeed * 8)] = alphabets[1][0];
    led[1+(bufferFeed * 8)] = alphabets[1][1];
    led[2+(bufferFeed * 8)] = alphabets[1][2];
    led[3+(bufferFeed * 8)] = alphabets[1][3];
    led[4+(bufferFeed * 8)] = alphabets[1][4];
    led[5+(bufferFeed * 8)] = 0;
    led[6+(bufferFeed * 8)] = 0;
    led[7+(bufferFeed * 8)] = 0;
  }
    if ((data[bufferFeed] == 'c') || (data[bufferFeed] == 'C')) {
    led[0+(bufferFeed * 8)] = alphabets[3][0];
    led[1+(bufferFeed * 8)] = alphabets[3][1];
    led[2+(bufferFeed * 8)] = alphabets[3][2];
    led[3+(bufferFeed * 8)] = alphabets[3][3];
    led[4+(bufferFeed * 8)] = alphabets[3][4];
    led[5+(bufferFeed * 8)] = 0;
    led[6+(bufferFeed * 8)] = 0;
    led[7+(bufferFeed * 8)] = 0;
  }
    if ((data[bufferFeed] == 'h') || (data[bufferFeed] == 'H')) {
    led[0+bufferFeed * 8] = alphabets[8][0];
    led[1+bufferFeed * 8] = alphabets[8][1];
    led[2+bufferFeed * 8] = alphabets[8][2];
    led[3+bufferFeed * 8] = alphabets[8][3];
    led[4+bufferFeed * 8] = alphabets[8][4];
    led[5+bufferFeed * 8] = 0;
    led[6+bufferFeed * 8] = 0;
    led[7+bufferFeed * 8] = 0;
  }
  

  
  }
  }
  
void bitReverse(uint8_t num) {
  uint8_t var = 0;    
  uint8_t i, x, y, p;
  uint8_t s = 8;

  for (i = 0; i < (s / 2); i++) {
    p = s - i - 1;
    x = num & (1 << p);
    x = x >> p;  
    y = num & (1 << i);
    y = y >> i;
  
    var = var | (x << i);       // apply x
    var = var | (y << p);       // apply y
  }
mybitRev = var;
}

Help out a newbie? :slight_smile:

Thanks.

You need to look at the scope and your handling of "buffer" - it is kind-of chaotic, particularly this bit:

     for (int x=0; x<bufferCount ; x++) {
      buffer[x]='\0';
      }

Hint: at this point, buffer is only one character big.

The hardware is just 2 74HC595 shift registers and an 8x8 LED matrix

And some current limiting resistors I hope.

Just some observations.
Why all the delays? You shouldn't need them.

Basically you are spending too long in the interrupt service routine, this is blocking the interrupts from the serial port. One thing you could try is to slow down the baud rate to try and prevent the data over run you are getting, but basically you are doing too much while inside the interrupts.

Thanks for the replies.

You need to look at the scope and your handling of "buffer" - it is kind-of chaotic, particularly this bit:
Code:
for (int x=0; x<bufferCount ; x++) {
buffer[x]='\0';
}

Hint: at this point, buffer is only one character big.

When I look at the code it looks like at that point (I assume you mean the first time it runs), bufferCount should be equal to 0 so that for loop shouldn't do anything. On subsequent runs the values should match up so it should fill the buffer correctly with null characters.
(If I'm wrong, let me know, because like I said I'm very new to C and any pointers I can get would be great.)

Maybe I should just write the program from scratch, because as I found things didn't work as I expected I changed parts of the code a lot of times. It ended up getting kind of messy and out of hand (as you noticed :P)

And some current limiting resistors I hope.

Just some observations.
Why all the delays? You shouldn't need them.

Yes, I have current limiting resistors in the circuit too. (I'm just a newbie at C. Electronics, I have no problems with :slight_smile: )

I'm not sure which delays you mean.

This 1 is to give the buffer a chance to fill before I do anything from it (I picked that habit up from a project in the Arduino starter kit I got). I'm not sure if it's necessary, but I did it just in case.

delay(100); //buffer fill time

This 1 I'm using to control the speed that the text is scrolling at:

delay(100);
      rowInc++;

Basically you are spending too long in the interrupt service routine, this is blocking the interrupts from the serial port. One thing you could try is to slow down the baud rate to try and prevent the data over run you are getting, but basically you are doing too much while inside the interrupts.

Could you explain in a bit more detail what's going wrong there?
I'd really like to know what I've done wrong so I can learn from it, and I don't fully understand what you mean.

Thanks.

I've changed the code a bit, and added in some Serial.print commands, to try and help me debug the code. I've also added a lot of comments to make it easier for someone else to see what I'm trying to do.

This is the code:

#include <TimerOne.h>
//buffer for serial data
char buffer[128];

//initial numchar
int numChar=0;

// Latch pin of shift register
int latchPin = 8;

//Clock pin of shift register
int clockPin = 12;

//Data pin of shift register
int dataPin = 11;

//bit for bitReverse function
uint8_t mybitRev;

//--Setup counter for number of letters in buffer for passArray function
uint8_t bufferCount=0;

  //alphabet font
uint8_t alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};


//Row incrementer to move through led[] array 1 at a time (to make it scroll)
int rowInc = 0;

//Led array to store a byte for each row to be displayed
uint8_t led[128 * 8];



void setup() {
  
  for (int first=0; first<26; first++) {      //Flips the bytes in the font
    for (int second=0; second<5; second++) {
      bitReverse (alphabets[first][second]);
      alphabets[first][second] = mybitRev;
    }
  }
  
  //serial setup
  Serial.begin(4800);
  Serial.flush();
  
  //set pins to output
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  


  Timer1.initialize(10000);             //Timer for interrupt service routine
  Timer1.attachInterrupt(screenUpdate);
  }
  
  void loop() {
    if (Serial.available() > 0) {
      delay(100); //buffer fill time
      
      Timer1.detachInterrupt();   //Disable interrupt service routine temporarily if serial data present
      
      for (int x=0; x<128 ; x++) {
      buffer[x]='\0';             //Fill buffer with NULL characters
      }
      
      for (int clrLed=0; clrLed<128*8; clrLed++) {  //Resets all values in led[] to 0. (blank on screen)
        led[clrLed] = 0;
      }
      
      int index = 0;
      int numChar = Serial.available(); //Set numChar as value of Serial.available
      Serial.print(numChar);            //For Debug -- Prints value of Serial.available ()
      Serial.println();
      
      bufferCount = numChar;            //Set buffercount to value of Serial.available
      while (numChar--) {                 //Transfers contents of real serial buffer into buffer[]
        buffer[index++] = Serial.read();
      }
         for (int prnt=0; prnt<=bufferCount; prnt++) { //Debug - Prints contents of buffer[] BEFORE passArray
      Serial.print(buffer[prnt]);
      }
      passArray(buffer);
      Serial.println();
      for (int prnt=0; prnt<=bufferCount; prnt++) {    //Debug - Prints contents of buffer AFTER passArray
      Serial.print(buffer[prnt]);
      }
   Serial.flush();
   Timer1.attachInterrupt(screenUpdate);
 }
 
      
    delay(100);
      rowInc++;                       //This scrolls the text and
      if (rowInc > bufferCount * 8) { //resets to the start when it
        rowInc = 0;                   //displays the last byte
        delay(100);
 }
      
}
  
  
  void screenUpdate() {        //For multiplexing - next line every 1/100th of a second and
    uint8_t row = B00000001;   //using the values in led[]
    for (byte k = 0; k < 9; k++) {
      digitalWrite(latchPin, LOW);
      shiftIt(~row );
      shiftIt(led[k+rowInc] ); //LED Array
      
      digitalWrite(latchPin, HIGH);
      row = row << 1;
    }
  }
  
  void shiftIt(byte dataOut) { //shift data out to shift registers
    
    boolean pinState;
    
    digitalWrite(dataPin, LOW);
    for (int i=0; i<8; i++) {

      digitalWrite(clockPin, LOW);
      
      if (dataOut & (1<<i) ) {
        pinState = HIGH;
      }
      else {
        pinState = LOW;
      }
      
      digitalWrite(dataPin, pinState);
      
      digitalWrite(clockPin, HIGH);
      digitalWrite(dataPin, LOW);
    }
    
    digitalWrite(clockPin, LOW);
  }
  
  
  //passArray checks through the serial buffer 1 letter at a time and passes the binary values out to
  //the correct positions in the led[] array, ready to be shifted out
  void passArray(char* data) {
    for (int bufferFeed=0; bufferFeed <= bufferCount; bufferFeed++) {
  if ((data[bufferFeed] == 'h') || (data[bufferFeed] == 'H')) {
    led[0+bufferFeed * 8] = alphabets[8][0];
    led[1+bufferFeed * 8] = alphabets[8][1];
    led[2+bufferFeed * 8] = alphabets[8][2];
    led[3+bufferFeed * 8] = alphabets[8][3];
    led[4+bufferFeed * 8] = alphabets[8][4];
    led[5+bufferFeed * 8] = 0;
    led[6+bufferFeed * 8] = 0;
    led[7+bufferFeed * 8] = 0;
  }
  
  if ((data[bufferFeed] == 'a') || (data[bufferFeed] == 'A')) {
    led[0+(bufferFeed * 8)] = alphabets[1][0];
    led[1+(bufferFeed * 8)] = alphabets[1][1];
    led[2+(bufferFeed * 8)] = alphabets[1][2];
    led[3+(bufferFeed * 8)] = alphabets[1][3];
    led[4+(bufferFeed * 8)] = alphabets[1][4];
    led[5+(bufferFeed * 8)] = 0;
    led[6+(bufferFeed * 8)] = 0;
    led[7+(bufferFeed * 8)] = 0;
  }
  
    if ((data[bufferFeed] == 'c') || (data[bufferFeed] == 'C')) {
    led[0+(bufferFeed * 8)] = alphabets[3][0];
    led[1+(bufferFeed * 8)] = alphabets[3][1];
    led[2+(bufferFeed * 8)] = alphabets[3][2];
    led[3+(bufferFeed * 8)] = alphabets[3][3];
    led[4+(bufferFeed * 8)] = alphabets[3][4];
    led[5+(bufferFeed * 8)] = 0;
    led[6+(bufferFeed * 8)] = 0;
    led[7+(bufferFeed * 8)] = 0;
  }
  

  
  }
}
  
void bitReverse(uint8_t num) {   // Flips each byte in the in the font, so that it is the right
  uint8_t var = 0;               // way up on the screen
  uint8_t i, x, y, p;
  uint8_t s = 8;    // number of bits in 'num'. (This case a 8-bit byte)

  for (i = 0; i < (s / 2); i++) {
    // extract bit on the left, from MSB
    p = s - i - 1;
    x = num & (1 << p);
    x = x >> p;  
    // extract bit on the right, from LSB
    y = num & (1 << i);
    y = y >> i;
  
    var = var | (x << i);       // apply x
    var = var | (y << p);       // apply y
  }
mybitRev = var;
}

I've given it a set buffer size of 128 for the moment to make it easier to follow.
I also set it to detach my interrupt service routine "screenUpdate" while the functions that are using the serial data are running.
Neither of those solved the problem.

If enter 12 letters in the serial monitor, the Serial.print(numChar) command here shows me that sometimes the value of Serial.available is equal to 12, but randomly it is equal to 9, 10 or 11.

  void loop() {
    if (Serial.available() > 0) {
      delay(100); //buffer fill time
      
      Timer1.detachInterrupt();   //Disable interrupt service routine temporarily if serial data present
      
      for (int x=0; x<128 ; x++) {
      buffer[x]='\0';             //Fill buffer with NULL characters
      }
      
      for (int clrLed=0; clrLed<128*8; clrLed++) {  //Resets all values in led[] to 0. (blank on screen)
        led[clrLed] = 0;
      }
      
      int index = 0;
      int numChar = Serial.available(); //Set numChar as value of Serial.available
      Serial.print(numChar);            //For Debug -- Prints value of Serial.available ()
      Serial.println();

The other 2 Serial print command's always match eachother, so I don't think anything is going wrong there.

The 1 thing that does seem to work is setting the serial baud rate to 4800bps instead of 9600bps (Thanks for that Mike).

Can anyone shed some light as to what's going wrong?
Or why setting the baud rate to 4800bps fixes it?

Thanks.