Can't correctly write/print characters

I’m having a problem understanding how to correctly handling the character data type - I think.

Hardware: An UNO board with a wireless H-12 module transmitting the data through the hardware UART.
A second UNO board with another H-12 module receiving the data through a software serial port. It is then sent through the hardware UART to the serial monitor.

If I use this code:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

void setup()  
{
  pinMode (10,INPUT);
  pinMode (11,OUTPUT);
  
  
  Serial.begin(9600);
  


  Serial.println("Hardware UART working...");

    mySerial.begin(9600);
 
}

void loop() 
{
  if (mySerial.available())
    Serial.print(char(mySerial.read())); 
  
}

I get the data I would expect:

Here’s where I apparently don’t know what I’m doing. When I run this code:

 #include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX
 int i;
 int a;
 
 char data[10] ;
 
void setup() {
  
  pinMode (10,INPUT);  
  pinMode (11,OUTPUT);

  for (int i=0; i>10; i++) // Clear array
  {data[i] = (char)0;
  }
  
  Serial.begin(9600);
   
  Serial.println("Hardware UART working...");
  mySerial.begin(9600);
  }

void loop() {
  
   while (mySerial.available())  // Read serial input
   {
     data[i] = mySerial.read();
     
     if (i == 0) // First time through, select message depending on first char.
       {
     
     if (data[0] == ('A')) Serial.println ("Average: ");
		
     if (data[0] == ('D')) Serial.println ("Direction: ");
      
     if (data[0] == ('T')) Serial.println ("Temperature: ");
      
     if (data[0] == ('S')) Serial.println ("Speed: ");
        
     if (data[0] == ('G')) Serial.println ("Gust: ");

     if (data[0] == ('B')) Serial.println ("Battery Voltage: ");
     
     a=1;  // Assign 1 to variable 'a' so next loop runs.
     
       }
     
	i=i+1; // Increment array index.

       }
     if (a == 1)
      {
        for (int f=1; f<6; f++)
           {
             Serial.write (data[f]);
           }
      }

    
       a=0; // Assign 0 to variable so previous loop only runs once.
       i=0; // Starts array reading again at 0.
       
      
     
     }

I get this garbage:

The “data” looks like ASCII code, but I suspect there is more going on here than I realize.

I don’t mind digging for answers, but I’ve reached the of my research capabilities on this one.

Any thoughts or suggestions are appreciated.

Thanks,
Mike

You're not reading in the string before processing it.

Your while loop will drop through after the first character has arrived and the loop() will be called many, many times between each character arriving - however the call to Serial.write() will slow this down so that it only happens a few times.

I think you are trying to read in several characters and then process them once. You should probably be waiting for i to reach 6 or something like that, then trigger the if that prints out values. Reset i to 0 when you see a newline perhaps? You also need to avoid writing past the end of the data[] array.

Thanks Mark. I hadn't considered the time required to Serial.print. I've dealt with the hardware UART before, and it has a buffer that won't clear until it's written to again. I have no idea if the software serial works the same way.

I failed to mention this earlier, but there is a 10mS delay between the sets of data: D124, delay10ms, T24.3, delay, etc.

The max number of characters that will be transmitted are 6, so I reserved 10 in declaring the array. I'm sure there is some error handling code if an attempt is made to write more than 10. I'll deal with that later.

I'll make some changes and get back in a day or two.

Thanks...

You obviously have a line terminator for each line. Probably a newline (’\n’) or return (’\r’) or both. Read until you reach one of those (or until you run out of buffer space). If the first character is \n or \r you should skip it.

void loop() {

  if (mySerial.available() < 1)
    return;   // No character ready

  char input = mySerial.read();

  if (input == '\n' || input == '\r') {
    // Line terminator
    if (i == 0)
      return;

    // Buffer is ready to process
    if (data[0] == ('A')) Serial.println ("Average: ");
    if (data[0] == ('D')) Serial.println ("Direction: ");
    if (data[0] == ('T')) Serial.println ("Temperature: ");
    if (data[0] == ('S')) Serial.println ("Speed: ");
    if (data[0] == ('G')) Serial.println ("Gust: ");
    if (data[0] == ('B')) Serial.println ("Battery Voltage: ");
    for (int f = 1; f < i; f++) {
      Serial.write (data[f]);
    }
    i = 0;
    return;
  }

  if (i >= 10) {
    // Failure: too big for the buffer
    i = 0;
    return;
  }

  // Record the input character
  data[i++] = input;
}

A couple of things: First, rather than use a for loop to set the contents of data[], try:

   memset(data, 0, sizeof(data));

Second, what happens with this line:

  char input = mySerial.read();

if they type in a lowercase letter 'a'? Why not use:

  char input = toupper(mySerial.read());

which will convert all alpha characters to uppercase.

Third, this code is not too efficient:

     if (data[0] == ('A')) Serial.println ("Average: ");

     if (data[0] == ('D')) Serial.println ("Direction: ");
      
     if (data[0] == ('T')) Serial.println ("Temperature: ");
      
     if (data[0] == ('S')) Serial.println ("Speed: ");
        
     if (data[0] == ('G')) Serial.println ("Gust: ");

     if (data[0] == ('B')) Serial.println ("Battery Voltage: ");

The reason is because, if data[0] does in fact equal 'A', you still perform 5 more unnecessary if tests on data[0]. You could use what's called a cascading if-else block, which I find hard to read, or use a switch-case:

  switch (data[0]) {

     case 'A':
        Serial.println ("Average: ");
        break;


     case 'D':
        Serial.println ("Direction: ");
        break;

     case 'T':
        Serial.println ("Temperature: ");
        break;

     case 'S':
        Serial.println ("Speed: ");
        break;

     case 'G':
        Serial.println ("Gust: ");
        break;

     case 'B':
        Serial.println ("Battery Voltage: ");
        break;

     default:
        Serial.println("I shouldn't be here.");
        Serial.print("data[0] = ");
        Serial.println(data[0]);
        break;
  }

The default block is a catchall if there are no matches. Finally, use the Ctrl-T key in the IDE to format your code. It makes it easier for us to help you.

The examples in serial input basics are designed to collect all the incoming data without blocking the Arduino. After the data has been received you can parse it to figure out what to do with it.

...R

Thanks for your efforts in this guys. Very helpful - I can see what I was doing wrong. I hijacked your code messaged it into the rest of mine and it worked out of the box - thanks John.

 for (int i=0; i>10; i++) // Clear array
  {data[i] = (char)0;
  }

Was this for loop in your original code actually doing what the comment says or was it doing nothing ?

UKHeliBob: for (int i=0; i>10; i++) // Clear array  {data[i] = (char)0;  }

Was this for loop in your original code actually doing what the comment says or was it doing nothing ?

I'm not sure if it is/was or not. I read somewhere that is how they 'emptied' the array. I don't know if it correct or reasonable. It seems my weak point is not having a thorough understanding of the data types, and understanding what to do with them. In process of learning C...

It's not the data type that I was commenting on. Try this

void setup()
{
  Serial.begin(115200);
  for (int i = 0; i > 10; i++)
  {
    Serial.println(i);
  }
  Serial.println("Finished");
}

void loop()
{
}

What values of i do you see printed ? If, instead of printing we were storing a value to the array how many levels of the array would be stored to ?

Bob - I ran the program. The answers are: No numbers, just the string "Finished" is printed. How many levels of the array are used? None of them.

I assume the point is that the code in question does nothing of any value. Good lesson - thanks.

However, what if I have this in the array: "D12345" followed by '\n'. The data is then parsed and I do whatever I'm going to do with it - I'll be looking for the '\n' at the end so I can stop reading it. The next data set to be written to the array is: "S10" followed by '\n'. Does the array now contain: "S10 '\n' 45" followed by another '\n' ? Not that it really matters since I'm reading until the first '\n' anyway.

If I wanted to clear the array (for whatever reason), how would that be accomplished? What could be written so that there is nothing to print? Besides the space character...

Thanks again for your time in this.

Does the array now contain: "S10 '\n' 45" followed by another '\n'

Yes

Not that it really matters since I'm reading until the first '\n' anyway.

True

If I wanted to clear the array (for whatever reason), how would that be accomplished?

Use the for loop properly and write '\0' to each element.

Why did my short program never print the value of i ?

for (int i = 0; i > 10; i++)

This can be read as "set variable i to zero then, while the value of i is greater than ten, execute the code in the following code block and increment i"

Ok - I get it now. The expression i>10 was never true, so the for loop fell through. To do anything at all, the expression should have been i<10.
I routinely hang myself with things like that. Need to slow down.
Thanks for your time - greatly appreciated.