Serial Graphic LCD 84x48 SGD-A

Hey all, I'm trying to interface my Arduino with the Serial Graphic LCD 84x48 SGD-A from Sparkfun.

The following is a snippet of code including some of the functions that I'm using to communicate with the display:

void setup() {
  beginSerial(9600);
  
  print("Let's test this.");
  delay(1000);
  sleep();
  delay(1000);
  wake();
  delay(1000);
  printf("That worked nicely!");
}

void loop() {
}

void print(char string[]) {
  Serial.print('S', BYTE);
  Serial.print(sizeof(string));
  Serial.print(string);
}

void ping() {
  Serial.print('X', BYTE);
}

void wake() {
  char result = 'Z';
  do {
    ping();
    //delay(100);
    if(Serial.available() > 0) {
      result = Serial.read();
    }
  } while(result != 'X');
}

void sleep() {
  Serial.print('Z', BYTE);
}

The problem is that once I print() none of my other functions will work. Instead they print their "control characters" to the LCD display. It's as if I'm "stuck" in "string" mode. To be thorough, I also tried looping through a null terminated string and sending the BYTES individually, (and replacing sizeof()) but no matter what I do, I'm stuck in text mode after writing to the display. Any suggestions?

Thanks,
Tim

I wanted to be thorough, and troubleshoot this at the lowest possible level, so I used this code snippet:

void setup() {
  beginSerial(9600);
  
  // this part works
  Serial.print('P', BYTE);  // move cursor
  Serial.print(20);         // x=20
  Serial.print(20);         // y=20
  
  // this part works
  Serial.print('S', BYTE);  // begin string
  Serial.print(4);          // length of string
  Serial.print('T', BYTE);  
  Serial.print('E', BYTE);
  Serial.print('S', BYTE);
  Serial.print('T', BYTE);
  
  // this part is displayed onscreen instead of moving the cursor
  Serial.print('P', BYTE);  // move cursor
  Serial.print(40);         // x=40
  Serial.print(40);         // y=40
  
  // this part works
  Serial.print('S', BYTE);  // begin string
  Serial.print(4);          // length of string
  Serial.print('T', BYTE);  
  Serial.print('E', BYTE);
  Serial.print('S', BYTE);
  Serial.print('T', BYTE);
}

The end result looks something like, " TESTP4040S4TEST" on the LCD display. As you can see, the first "move cursor" operation worked fine, but once I issue any text commands, the LCD never recovers.

Any help would be greatly appreciated.

Read the documentation for Serial.print.

You don't want Serial.print(4), you want Serial.print(4,BYTE). You're printing the ascii value of 4, and the LCD thinks your string is very long.

I wish that were true. I've actually tried:

Serial.print(4,BYTE);
Serial.print('4', BYTE);
Serial.print(4, DEC);
Serial.print('4', DEC);
Serial.print(4);

etc. Sending BYTE is actually worse because it won't even send the entire string, ie.
Serial.print('S', BYTE);
Serial.print(7, BYTE);
Serial.print("Testing");

may only display "Te" to the screen.

That looks correct, it should be working. Are there any other commands before the S command? Strip your program down to nothing, just the S command. Try substituting other values for 7 (even though 7 is the correct value). Are you monitoring serial communications in the Arduino IDE? Maybe you could get it written to a file and do a hex dump? I've barely used the Serial object before, but I'm pretty certain you're using it correctly in the last bit of code you posted.

[EDIT] I was totally unaware that we had access to the entire standard C library from arduino. That is awesome. The code now works perfectly. I added a strcat to append a null terminator to printed text. This is to prevent buffer overflows.

void print(char string[]) {
  strcat(string, "\0");
  Serial.print('S', BYTE);
  Serial.print(strlen(string), BYTE);
  Serial.print(string);
}

[/EDIT]

I got it working. When I was passing char[] to the print() function it was being passed as a pointer, so sizeof() returned 1, apparently causing all sorts of chaos. I tried to find an elegant solution, but a friend of mine who is comfortable with C suggested that I use null-terminated strings, or pass the length as a parameter, so I created an overloaded function like so:

void print(char string[], int length) {
  Serial.print('S', BYTE);
  Serial.print(length, BYTE);
  Serial.print(string);
}

void print(char string[]) {
  Serial.print('S', BYTE);
  Serial.print(strlen(string), BYTE);
  Serial.print(string);
}

int strlen(char str[]) {
  int i;
  for(i=0; i<=255; i++) {
    if(str[i]=='\0') {
      return(i);
    }
  }
}

It can be used as either print("Junk", 4); or print("Junk\0");

If anyone has a better solution, please let me know. Otherwise, it works.

Thanks for your help Horace.
Tim

String literals are nul-terminated anyway. In fact, strcat(str,"\0") should be a no-op. You'd be adding a nul byte to a memory location that already contains a nul byte, and you're calling strcat with a zero-length string which does nothing. C string functions have no way to differentiate an empty string literal "" from a string literal with a nul as its first byte "\0more string here".

Your code now is exactly the same as your code before. You shouldn't even need "Junk\0", since the string literal "Junk" already has a nul byte at the end.

It does function as a noop, but a useful one. It prevents buffer overflows like:

char a[3] = {65, 67, 64};
print(a);

so it allows me to print strings that may not have been input as string literals.

Thanks again for the help Horace.
Tim

Actually, it doesn't. The strcat function doesn't know how long the string is, it'll seek from the beginning of the string until it finds a nul byte. And replacing a nul byte with a nul byte, well.. doesn't do much, does it? It's best to either use string literals (which are nul-terminated) or nul terminate your strings as they are input.