-1

this is my first time asking a question here, sorry in advance if this is a poor way to ask this question.

I'm at an intermediary point in coding a program, and at this stage I'd like my byte information which I'm inputting into my serial monitor to take the places of my array elements. I'm able to do so, but when I try to use a 5 digit input, I only get a 4 digit input in return.

It seems like my Serial.available() == 4 loop is preventing my Serial.available() == 5 loop from operating. Would there be a simple modification I could make to allow a 5 digit result from a 5 digit input, and a 4 digit result from a 4 digit input? I've tried many things and Chat GPT seems to think the current code should work, but it doesn't. Here's the code:

int fiveArray[5];
int fourArray[4];
const char* colors[] = {"black ", "brown ", "red ", "blue ", "yellow ", "orange ", "white ", "gold ", "green ", "purple "};

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

  Serial.print("Input a number value: ");
  Serial.println();
}

void loop() { 
  if (Serial.available() ==5 ) { 
    char tempArrayFive[6]; 
    Serial.readBytes(tempArrayFive, 6); 
    tempArrayFive[5] = '\0';

    for (int i = 0; i < 5; i++) {
      fiveArray[i] = tempArrayFive[i] - '0';
    }

    Serial.print("Color Value: ");
    for (int i = 0; i < 5; i++) {
      Serial.print(colors[fiveArray[i]]);
    }
    Serial.println();

  }
  if (Serial.available() == 4 ) {
    char tempArrayfour[5];
    Serial.readBytes(tempArrayfour, 5);
    tempArrayfour[4] = '\0';

    for (int i = 0; i < 4; i++) {
      fourArray[i] = tempArrayfour[i] - '0';
    }

    Serial.print("Color Value: ");
    for (int i = 0; i < 4; i++) {
      Serial.print(colors[fourArray[i]]);
    }
    Serial.println();
  }
}
4
  • "It seems like " - great observation, sending one byte (10bits with start and stop bits) using 9600baud per second takes around 1ms. On the other side Arduino on 16MHz during that time can handle 16000 instruction cycles - my guess is over 200 loops() between 4th and 5th character...
    – KIIV
    Oct 15, 2023 at 7:26
  • 2
    Can you please include a sample of what you are sending from the Serial Monitor and what line ending you have set there? Your current code doesn't make much sense to me. As KIIV wrote you have a race condition between the two if statements, but you also read 6 (and 5) bytes but you overwrite the last one with zero for string termination. You talk about byte data, but from your code it seems, that you are using ASCII encoded text (important difference when handling the data)
    – chrisl
    Oct 15, 2023 at 9:10
  • 1
    OT concerning ChatGPT: Never trust a chat bot, it has no idea about programming, it is just good at putting words together. Do not mix perfect grammar and wording with knowledge! Oct 15, 2023 at 10:28
  • "this is my first time asking a question here": Since you are supposedly a intelligent person, you want to take the tour and read "How to Ask" as well as other pages of the help center. Oct 16, 2023 at 6:08

2 Answers 2

2

Yes, if you send 5 bytes to the Arduino then they will arrive one at a time. When the 4th byte arrives then the if (Serial.available() == 4 ) statement is true and it runs that code. That code reads from the buffer which means that the part that checks for 5 bytes will never be able to run. There will always be 4 before there is 5.

A better idea would be to send your bytes with a start and end marker. The program on the Arduino will read bytes and collect them in an array until it sees the end marker. Then you can count how many bytes you have received if you want to take different actions depending on that number.

Here's a nice thread on handling Serial data: https://forum.arduino.cc/t/serial-input-basics-updated/382007

2

I have a post here which discusses handling incoming serial data. Also here on Stack Exchange.

For handling serial input like you are trying to do I suggest using an "end of line marker" like newline (which the Terminal Monitor in the IDE will do for you automatically).

Then it's just a case of seeing whatever-it-was you got before the newline. Example code:

/*
Example of processing incoming serial data without blocking.

Author:   Nick Gammon
Date:     13 November 2011. 
Modified: 31 August 2013.

Released for public use.
*/

// how much serial data we expect before a newline
const unsigned int MAX_INPUT = 50;

void setup ()
  {
  Serial.begin (115200);
  } // end of setup

// here to process incoming serial data after a terminator received
void process_data (const char * data)
  {
  // for now just display it
  // (but you could compare it to some value, convert to an integer, etc.)
  Serial.println (data);
  }  // end of process_data
  
void processIncomingByte (const byte inByte)
  {
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
    {

    case '\n':   // end of text
      input_line [input_pos] = 0;  // terminating null byte
      
      // terminator reached! process input_line here ...
      process_data (input_line);
      
      // reset buffer for next time
      input_pos = 0;  
      break;

    case '\r':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;

    }  // end of switch
   
  } // end of processIncomingByte  

void loop()
  {
  // if serial data available, process it
  while (Serial.available () > 0)
    processIncomingByte (Serial.read ());
    
  // do other stuff here like testing digital input (button presses) ...

  }  // end of loop

In your case, you would put code in the process_data function to turn the input text into a number and then do something with that number.

I'm surprised ChatGPT didn't point out my code <grin> but maybe you asked it a too-specific question.


I'd just point out that without a line-terminator character (like newline) then your code will be permanently out of step with incoming data if it starts in the wrong place. For example:

123456789

Depending on the speed at which that arrives, are we seeing 123 followed by 456? Or 12 followed by 34? Or 1234 followed by 5678? The end-of-line delimiter is really essential to avoid those ambiguities.

Or if the code happens to start running after you have sent the 1 but before the 2 it would think you sent 234 rather than 123 and then every other number would be out by one position.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.