0
votes

I am having a problem with the serial monitor on Arduino Uno.

Basically I want to write some commands on the Serial Monitor, read the string and according to the string do something.

The problem is the following: supposing I type the command 'read 4' in the Serial Monitor, sometimes the string is read correctly, sometimes it is read like: 'ead 4', missing the first character. I even put a delay between two readings from the Serial Monitor. Does anyone have an explanation?

For completeness I post my code (basically it reads/writes from/to the EEPROM: for example 'read 5' will read the 5 block of EEPROM, 'write 4 5' will write the value 5 to the 4th block of memory).

#define MAX_STRING_LENGTH 14
#include <ctype.h>
#include <EEPROM.h>


//The function initializes the string to spaces
void initString(char* mystr, char strLength);

//The function returns true if it is a read operation, false otherwise
boolean isReadEEPROM(char *myStr, char strLength);

//The function returns true if it is a write operation, false otherwise
boolean isWriteEEPROM(char *myStr, char strLength);

//The function returns the EEPROM address from the string
unsigned int findAddress(char *myStr, char strLength);

char findValue(char *myStr, char strLength);

//Check the address range
boolean isAddressOk(unsigned int address);



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);


}

void loop() {

  char pos = 0; 
  bool newDataFound = false;
  char serialStr[MAX_STRING_LENGTH];
  unsigned int address = 0;
  char val = 0;
  while(Serial.available()){
    val = Serial.read();

  }
  val = 0;
  initString(&serialStr[0], (char) MAX_STRING_LENGTH);
  while(Serial.available() && pos < MAX_STRING_LENGTH){
    serialStr[pos] = Serial.read();
    pos ++;
    newDataFound = true;
    delay(200);
  }
  if (newDataFound){
    Serial.print("New Command found: ");
    Serial.println(serialStr);
    address = 0;
    address = findAddress(&serialStr[0], MAX_STRING_LENGTH);

    if (isReadEEPROM(&serialStr[0], MAX_STRING_LENGTH) && isAddressOk(address)){
      Serial.println("Reading from EEPROM");
      Serial.print("Address is ");
      Serial.println(address);
      val = EEPROM.read(address);
      Serial.print("Value is: ");
      Serial.println( (uint8_t) val );
      Serial.println(" ");

    }
    else if (isWriteEEPROM(&serialStr[0], MAX_STRING_LENGTH) && isAddressOk(address)){
      Serial.println("Writing to EEPROM");
      Serial.print("Address is ");
      Serial.println(address);
      Serial.println(" ");

      val = findValue(&serialStr[0], MAX_STRING_LENGTH);
      EEPROM.write(address, val);

    }
    else{
      if (!isAddressOk(address)){
        Serial.write(address);
        Serial.println("Address out of range");
        Serial.println("");
      }
      Serial.println("Not recognized operation\n");
    }

   delay(2000);
    }
}

void initString(char* mystr, char strLength){
  for(char ii=0; ii<strLength; ii++){
    (*mystr) = ' ';
    mystr++;
  } 
}

//The function returns true if it is a read operation, false otherwise
boolean isReadEEPROM(char *myStr, char strLength){
  //The string should contain first the 'read' operation
  char expected[] = "read";

  int ii =0;

  while (ii<4){
    if ( *(myStr + ii) !=  expected[ii]){
      return false;
      Serial.println("Not a Read Operation\n");
    }
    ii++;
  }
  return true;
  Serial.println("Read Operation");
}

//The function returns true if it is a write operation, false otherwise
boolean isWriteEEPROM(char *myStr, char strLength){
  //The string should contain first the 'read' operation
  char expected[] = "write";
  int ii =0;

  while (ii<5){
    if ( *(myStr + ii) !=  expected[ii]){
      return false;
    }
    ii++;
  }
  return true;
}

//The function returns the EEPROM address from the string
unsigned int findAddress(char *myStr, char strLength){
    unsigned int address;
    char tmpStr[strLength];
    char strAddress[] = "    ";
    int ii = 0;
  while(ii< strLength){
   tmpStr[ii] = *(myStr+ii);
   ii++;
  }
  Serial.print("The address found is: ");
  Serial.println(strAddress);
  ii= 0;

  if (isReadEEPROM(myStr, strLength)){
      while (ii<=4){
          if (isdigit(*(myStr + 5 + ii))){
            strAddress[ii] = *(myStr + 5 + ii);
          }
          else{
            break;
          }
          ii++;
      }
      address = atoi(strAddress);
  }

else if(isWriteEEPROM(myStr, strLength)){
        while (ii<=4){
          if (isdigit(*(myStr + 6 + ii))){
            strAddress[ii] = *(myStr + 6 + ii);
          }
          else{
            break;
          }
          ii++;
        }
        address = atoi(strAddress);
}

else{
  address = 0;
  //Serial.println("Address not available in function 'findAddress'");
}
 return address;
}

//The function returns the value to be written to the EEPROM from the string
char findValue(char *myStr, char strLength){
  char val;
  char tmpStr[strLength];
  char strVal[] = "   ";
  int ii, idx = 0;
  while(ii< strLength){
   tmpStr[ii] = *(myStr+ii);
   ii++;
  }
  ii= 0;
 // first found the first digits corresponding to the address
  while (ii<=4){
      if (isdigit(*(myStr + 6 + ii))){
        ;//strAddress[ii] = *(myStr + 6 + ii);
      }
      else{
        ii++;
        break;
      }
      ii++;
  }
  // now find the value
  while (ii<=4+3){
      Serial.println(*(myStr + 6 + ii));

      if (isdigit(*(myStr + 6 + ii))){
        strVal[idx] = *(myStr + 6 + ii);
      }
      else{
        break;
      }
      ii++;
      idx++;
  }          
 Serial.print("original string: ");
 Serial.println(tmpStr);
 Serial.print("Value found: ");
 Serial.println(strVal);
 val = (char)atoi(strVal);
 return val;
}

boolean isAddressOk(unsigned int address){
  if (address < 1024 && address >= 0){
    return true;
  }
  else{
    return false;
  }
}
1

1 Answers

2
votes

This snippet:

char val=0;
while(Serial.available()){
  val = Serial.read();
}
val = 0;

Is just consuming any characters that may be left in the input buffer. You could also do:

while (Serial.avaialble())
  Serial.read();

The next while loop does not wait for the entire command. Sometimes, it gets the 'r', and then doesn't get the 'ead...' in time. They will be there the next time loop executes, so it looks like the 'r' is missing. It was just consumed in the previous loop.

Things sent over the USB (from the Serial Monitor window) can have odd delays in them.

To gather up a complete line, you should save characters until a '\n' is received:

for (;;) {
  if (Serial.available()) {
    char c = Serial.read();
    if (c == '\n')
      break;
    if (pos < MAX_LINE_LENGTH) {
      serialStr[pos] = c;
      pos ++;
    }
    newDataFound = true;
  }
}

The delay call is totally unnecessary, because the for loop waits until a '\n' character is received (be sure that in the Serial Monitor pull down menu either 'New Line' or 'both NL & CR' is selected). Then you know you've read all the characters in the line.