Coding doubt in serial monitor

When I type for Eg: Read 201 on the serial monitor I need to store this content in a variable and obtain the portion Read in another variable.
Can anyone point out the mistake in my code

// C++ code #include char instr[10], mainpart[10]; int addr, data=0, i, j, n; void setup() { Serial.begin(9600); Serial.print("The formats used are: \n Read 201 \n Write 21 93\n"); for (addr=0; addr<255; addr++,data++) { EEPROM.write(addr, data); }

}

void loop()
{
while(Serial.available())
{
i = 0;
instr[i] = Serial.read();
Serial.print(instr[i]);
i++;
}
for( i=0,j=0; instr[i] != ' '; i++,j++ )
{
mainpart[j] = instr[i];
}
Serial.print(mainpart);
}

serial.print(mainpart) does not print anything

You keep resetting i to 0.
Try

i = 0;
while(Serial.available())
{
instr[i] = Serial.read();
Serial.print(instr[i]);
i++;
}

could you edit your post so that we can copy the code. I've just tried to copy your code to the Arduino IDE and got an error when I tried to compile it.

When copying code, copy it to the forum by first typing CTRL+E on a new line then paste your code

Hi, @anujajacob
To add code please click this link;

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

// C++ code
#include<EEPROM.h>
char instr[10], mainpart[10];
int addr, data = 0, i, j, n;
void setup()
{
  Serial.begin(9600);
  Serial.print("The formats used are: \n Read 201 \n Write 21 93\n");
  for (addr = 0; addr < 255; addr++, data++)
  {
    EEPROM.write(addr, data);
  }

}

void loop()
{
  while (Serial.available())
  {
    i = 0;
    instr[i] = Serial.read();
    Serial.print(instr[i]);
    i++;
  }
  for ( i = 0, j = 0; instr[i] != ' '; i++, j++ )
  {
    mainpart[j] = instr[i];
  }
  Serial.print(mainpart);
}

this is more difficult than your code suggests.

the posted code

  • is missing setup()
  • the variables: i, j, instr[] and mainpart [] are not defined
  • as pointed out, i is being reset to zero before each read
  • the attempt to print mainpart each iteration of loop() prevent various processing
  • i is not reset to 0 when acceptable input (a complete line) is received
  • it's not clear when a complete line of input is received and conditionally process/print it

consider (set serial monitor the newline terminations)

char mainpart [80];
char instr    [80];
int i = 0;

void loop ()
{
    char c = 0;

    while (Serial.available ())
    {
        instr[i] = c = Serial.read ();
        Serial.print (instr[i]);
        i++;
    }

    if ('\n' == c)  {
        for (int j=0; instr[j] != ' '; j++ )
        {
            mainpart[j] = instr[j];
        }

        Serial.println (mainpart);
        i = 0;
        c = 0;
    }
}

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

The formats used are:
Read 201
Write 21 93

now gets printed infinite number of times

what do these mean?

This simply means the general format to be used while we enter data in serial monitor. Eg: read addr
write addr data
If you enter read addr, i need to read data from the location addr of EEPROM
If you enter write addr data, i need to write data to the location specified by addr of EEPROM

I modified my code as shown, but now the problem is when I type "Read 21" in the serial monitor, the serial monitor displays


// C++ code
#include<EEPROM.h>
char instr[10], mainpart[10], c;
int addr, data = 0, i, j, n;
void setup()
{
  Serial.begin(9600);
  Serial.print("The formats used are: \n Read 201 \n Write 21 93\n");
}

void loop()
{
  i = 0;
  while (Serial.available())
  {
    instr[i] = c = Serial.read();
    Serial.print(instr[i]);
    i++;
  }
  if ( c == '\n' )
  {
    for ( i = 0, j = 0; instr[i] != ' '; i++, j++ )
    {
      mainpart[j] = instr[i];
    }
  }

  Serial.print(mainpart);
}

there are easier ways to read a complete line and tokenize the input

(this doesn't verify proper number of arguments)


char s [80];
int  adr;
int  val;

// -----------------------------------------------------------------------------
int
read (
    int adr )
{
    sprintf (s, "read: %d", adr);
    Serial.println (s);

    return 0;
}

// -----------------------------------------------------------------------------
void
write (
    int adr,
    int val )
{
    sprintf (s, "write: %d %d", adr, val);
    Serial.println (s);
}

// -----------------------------------------------------------------------------
void
loop (void)
{
    if (Serial.available ())  {
        Serial.readBytesUntil ('\n', s, sizeof(s));

        if (sscanf (s, "Write %d %d", &adr, &val))
            write (adr, val);
        else if (sscanf (s, "Read %d", &adr))
            read (adr);

        memset (s, 0, sizeof(s));
    }
}

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

Sir, you have defined two functions read and write one has return type "int" and the other "void". Why?

sprintf function is used to store the string variable s with read: adr, if function read is invoked. Am I correct?

Serial.println prints the content stored in the string variable s and moves the cursor to the next line. Isn't?

Can you explain this?

I didn't understand this one too?

Why is my code wrong?


Why is my serial monitor showing like this when I type Read 21

it was supposed to show Read 21 followed by Read

@anujajacob
1. When one intends to write program using C++, he is required to know syntax and semantics rules of the C++ Language.

2. Similalry if someone wants to parse string coming from the Serial Monitor, he is required to know which function (s) he is going use and what kind of "formattng" is to be used for the string being sent from Serial Monitor.

3. In the sketch given below in Step-4, I am going to use strtoul() function to parse the string coming from Serial Monitor. Accordingly, I will use the following formatting for the incoming string. The Newline (in C, it is written as '\n') option for the "Line ending tab" of the Serial Monitor (Fig-2) must be selcetd for the sketch to work.

Write, wAddr, wData; Read, rAddr;
//wAddr = Write address, wData = Write Data, rAddr = Read address

I have choosen write function first so that next read function can easliy check if data has been written correctly.

4. The sketch

// C++ code
#include<EEPROM.h>
char myArray[50];
char *temPtr;

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

void loop()
{
  byte n = Serial.available();
  if (n != 0)
  {
    byte m = Serial.readBytesUntil('\n', myArray, 50); //receive all charcaters until Newline('\n') is detected
    myArray[m] = '\0';
    //Write, 21, 93; Read, 21;   (Write, wAddr, wData; Read, rAddr;)
    int noData = strtoul(myArray, &temPtr, 10); //noData1 = 0
    int wAddr = strtoul(temPtr + 6, &temPtr, 10); //wAddr = 21
    byte wData = strtoul(temPtr + 1, &temPtr, 10); //wData = 93
    int rAddr = strtoul(temPtr + 7, &temPtr, 10); //wData = 21
    //---------------------------------------------------------
    Serial.print(wAddr);Serial.print(' ');Serial.print(wData);Serial.print(' ');Serial.println(rAddr);
    //-----------------------------------
    Serial.print("Writing "); Serial.print(wData, DEC);Serial.print(' ');
    Serial.print("at EEPROM location("); Serial.print(wAddr, DEC); Serial.println(").");
    EEPROM.write(wAddr, wData);
   //--------------------------
   Serial.print("Data reading from EEPROM location("); Serial.print(rAddr, DEC); Serial.print(')');
   byte x = EEPROM.read(rAddr);
   Serial.print(" is: "); Serial.println(x, DEC); 
   Serial.println();
  }
}

5. The OutputBox of the Serial Monitor

Smaz
Figure-1:

6. Layout of Arduino Serial Monitor


Figure-2:

7. Working Principle of strtoul() Function:
The function parses (reads a character from a character type array and checks if it is a decimal or hexadecimal digit) a string (array of characters) and stops at the non-digit character. The ASCII codes of the digits which have been parsed so far are converted into a numerical number and are saved in a variable. For example:

char myArray = “1234, 56, 78”;
char *temPtr;r
unsigned int x1 = strtoul(myArray, &temPtr, 10); // x1 = 0x04D2
Serial.println(x1, DEC); //shows: 1234

The arg3 (= 10) says that the function looks for decimal digits in the array. The parsing stops at the first comma (,); there remains the sub-array/sub-string (, 56, 78) which will be parsed next time to extract 56. Now, we need a pointer variable (*temPtr) to point the beginning of the sub-array. The arg2 (= &temPtr) passes to the pointer variable the address of the character at which parsing had stopped and thus offers a way to the strtoul() function to locate the beginning of the sub-array.

If you are not averse to using String:

// C++ code
#include <EEPROM.h>

void setup()
{
  Serial.begin(9600);
  Serial.print("The formats used are: \n Read 201 \n Write 21 93\n");
  for (unsigned addr = 0; addr < 255; addr++)
  {
    EEPROM.write(addr, addr);
  }
}

void loop()
{
  String command;

  do
  {
    command = Serial.readStringUntil(' ');
  }
  while (command == "");


  if (command == "Read")
  {
    int address = Serial.parseInt();
    Serial.print("Address ");
    Serial.print(address);
    Serial.print(" contains ");
    Serial.println(EEPROM[address]);
  }
  else if (command == "Write")
  {
    int address = Serial.parseInt();
    int value = Serial.parseInt();
    EEPROM[address] = value;
    Serial.print("Address ");
    Serial.print(address);
    Serial.print(" set to ");
    Serial.println(value);
  }
  else
  {
    Serial.print("Unrecognized command: \"");
    Serial.print(command);
    Serial.println("\"");
  }

  // Clear the input buffer
  delay(1000);
  while (Serial.available())
    Serial.read();
}

This is the output for "Read 201", "Write 201 93", "Read 201".

The formats used are: 
 Read 201 
 Write 21 93
Address 201 contains 201
Address 201 set to 93
Address 201 contains 93

i believe there were several issue:

  • Serial.print (mainpart) ; executes each iteration of loop. it prints what is in mainpart and maybe more, which may not be initialized. if initialized to ".", "."s flood the screen
  • i moved Serial.print (mainpart) ; inside the if (c == condition so that it only prints after a complete line is received.
  • i modified the print to be println, adding a newline
  • i added code to terminate mainpart with a NULL, \0, terminating a string. without it, it appears to continue to print chars including the `"The formats used are: \n Read 201 \n Write 21 93\n" string which must follow mainpart in memory
  • the above still resulting in mainpart being printed each iteration of loop. i added code to set both c and i to 0
// C++ code
// #include<EEPROM.h>
char instr[10];
char mainpart[10] = ".";
char c;
int addr, data = 0, i, j, n;
void setup()
{
    Serial.begin(9600);
    Serial.print("The formats used are: \n Read 201 \n Write 21 93\n");
    i = 0;
}
void loop()
{
    while (Serial.available())
    {
        instr[i] = c = Serial.read();
        Serial.print(instr[i]);
        i++;
    }
    if ( c == '\n' )
    {
        for ( i = 0, j = 0; instr[i] != ' '; i++, j++ )
        {
            mainpart[j] = instr[i];
        }
        mainpart [j] = 0;
        Serial.println (mainpart);
        c = i = 0;
    }
}

a read function typically returns a value. a write function doesn't need to return anything, void describes it as a function that does not return anything and would result in an error if a value were expected (e.g. int a = write ():wink:

you need to use google. sprinf() formats strings

println prints a string along with a newline character which ends the line and starts the next line at column 0

sscanf
extracts values, strings from a formatted line of input and returns a non-zero value if the format string matches (e.g. "Read) in the string argument. in this case in replaces strncmp() and aoti()

Sir, why is the while loop condition defined in this way?

Suppose we have typed in "Read 21"
So we need to store "Read" in mainpart, right?
According to the conditions of the loop, when i=0, j=0, mainpart[0] = R
i=1, j=1, mainpart[1] = e
i=2, j=2, mainpart[2] = a
i=3, j=3, mainpart[3] = d
i=4, j=4 the conditon of the loop is false, so loop is terminated, and mainpart[4] = 0 is stored.
Can you elaborate your fourth bulletin point?
How does terminating the string mainpart with "0" prevent the content "The formats used are: \n Read 201 \n Write 21 93\n" from being printed on the serial monitor repetitively?

Sir, I made the following changes to my code, as you suggested

// C++ code
#include<EEPROM.h>
char instr[10], mainpart[10], c;
int addr, data = 0, i, j, n;
void setup()
{
  Serial.begin(9600);
  Serial.print("The formats used are: \n Read 201 \n Write 21 93\n");
  for ( addr = 0; addr < 255; addr++, data++)
  {
    EEPROM.write(addr, data);
  }
}

void loop()
{
  while (Serial.available())
  {
    instr[i] = c = Serial.read();
    Serial.print(instr[i]);
    i++;
  }
  if ( c == '\n' )
  {
    for ( i = 0, j = 0; instr[i] != ' '; i++, j++ )
    {
      mainpart[j] = instr[i];
    }
    mainpart[j] = 0;
    Serial.println(mainpart);
    c = i = 0;
  }
  if (mainpart == "Read")
  {
    Serial.println(EEPROM.read(addr), DEC);
  }
  else if (mainpart == "Write")
  {
    EEPROM.write(addr, data);
    Serial.println("Specified location is updated");
  }

}