Problems with Serial.print() and Serial.read

//THIS PROGRAM WILL GENERATE TWO RANDOM NUMBERS AND ADD THEM //THEN PRINTS THE RANDOM NUMBERS IN THE ADDITION EXPRESSION(A+B) //THEN WHEN THE USER WILL ENTER HIS CALCULATED ANSWER, THE //ARDUINO WILL FLASH AN LED(PIN 11) OR NO DEPENDING WHETHER THE ANSWER IS CORRECT OR NOT void setup() { pinMode(11,OUTPUT); Serial.begin(9600); randomSeed(analogRead(0));

}

void loop() { int rand1,rand2,ansArduino,ansUser; rand1=random(0,1000); rand2=random(0,1000); ansArduino=rand1+rand2;

if (Serial.available()){ Serial.print(rand1); //PROBLEM WITH Serial.print("+"); //THESE Serial.print(rand2); //FOUR ansUser=Serial.read(); //LINES if (ansArduino==ansUser) { digitalWrite(11,HIGH); delay(250); digitalWrite(11,LOW); delay(250); Serial.println("CORRECT"); } else { Serial.println("WRONG"); } }

} The program does not show the question first, it requests the answer before the question is displayed in the serial monitor...

Well, you put the part to show the question inside the block that is checking if Serial.available. Serial.available is going to return 0 until someone enters something in the serial monitor. At that point it is too late to show them the question.

Maybe move those prints up to the part before you ask for input.

I like it, You're expecting the user to enter their answer before you show them the question. Furthermore, you'll only accept the first character of their answer AND it's the character code of this key that you accept.

So on the off chance that the two random numbers are 6 and 8 and their answer starts with a '0' they'll get it right. This reduces the odds to about 1 in a million. You've not made things too easy for them have you?

Welcome to the Forum. As a new poster to this Forum, you owe it to yourself to read the posting guidelines by Nick Gammon which appear at the top of this Forum, especially the use of code tags and using Ctrl-T in the IDE to format your code in a standard manner. The guidelines will help us help you.

KenF: I like it, You're expecting the user to enter their answer before you show them the question. Furthermore, you'll only accept the first character of their answer AND it's the character code of this key that you accept.

So on the off chance that the two random numbers are 6 and 8 and their answer starts with a '0' they'll get it right. This reduces the odds to about 1 in a million. You've not made things too easy for them have you?

That is exactly what I don't want to do...I want the question expression (a+b) to be shown to the user so that the user can calculate and type in the answer. If the answer given by the user is the same as the answer calculated by the arduino, the led will blink and the serial monitor will show "CORRECT". If not then the the serial monitor will show "WRONG" and show the correct answer. This is a type of maths test. Maybe later I will add a time limit so the user has limited time...

Although I would like to know more about what you said about the acceptance of the character code of the first number...

arjmon:
That is exactly what I don’t want to do…I want the question expression (a+b) to be shown to the user so that the user can calculate and type in the answer. If the answer given by the user is the same as the answer calculated by the arduino, the led will blink and the serial monitor will show “CORRECT”. If not then the the serial monitor will show “WRONG” and show the correct answer. This is a type of maths test.
Maybe later I will add a time limit so the user has limited time…

Although I would like to know more about what you said about the acceptance of the character code of the first number…

Well, as stated before. Maybe you should then ask the question BEFORE you expect serial to be available for reading. Get that working and then we’ll look at the rest of this mess.

As you said Delta_G

//THIS PROGRAM WILL GENERATE TWO RANDOM NUMBERS AND ADD THEM //THEN PRINTS THE RANDOM NUMBERS IN THE ADDITION EXPRESSION(A+B) //THEN WHEN THE USER WILL ENTER HIS CALCULATED ANSWER, THE //ARDUINO WILL FLASH AN LED(PIN 11) OR NO DEPENDING WHETHER THE ANSWER IS CORRECT OR NOT void setup() { pinMode(11,OUTPUT); Serial.begin(9600); randomSeed(analogRead(0));

}

void loop() { int rand1,rand2,ansArduino,ansUser; rand1=random(0,1000); rand2=random(0,1000); ansArduino=rand1+rand2; Serial.print(rand1); Serial.print("+"); Serial.println(rand2); delay(10000);

if (Serial.available()){

ansUser=Serial.read(); if (ansArduino==ansUser) { digitalWrite(11,HIGH); delay(250); digitalWrite(11,LOW); delay(250); Serial.println("CORRECT"); } else { Serial.println("WRONG, CORRECT ANSWER IS "); Serial.println(ansArduino); } }

}

I have moved the question print lines before the Serial.begin(). This has solved a part that the question will now show before the answer is asked :) But as Kenf said, i think that the program is only accepting a part of what the user enters?

The user is entering a digit in the serial monitor. SO that digit gets sent to the Arduno as an ascii code. SO if the user enters a 2 then what comes over the Serial is 50. If you want to use that as the number two, then you have to convert it back to a real number.

You're also only taking in one character. But your random numbers get quite big. So the answer might be a multidigit number. Right now you are taking one read and moving on, so you will only get the first character the user enters.

Then would you please guide me through it? I don't know how to convert the user-entered number into an ascii value... also if you could help me with getting the program to accept the full multidigit answer...

arjmon: Then would you please guide me through it? I don't know how to convert the user-entered number into an ascii value... also if you could help me with getting the program to accept the full multidigit answer...

Maybe start here

Almost done with it! Thank you for the help... Though there is something that's still bugging me... Its that due to the delay function that even after the answer it types by the user, it waits for that stipulated amount of time? I want it to display the next question as soon as the user has entered the answer...

Then don't delay.

The simplest answer is this:

while(Serial.available() == 0);

That will do nothing until available returns that there are characters to read. You might want a quick few millisecond delay right after that to make sure all of the digits have arrived though and not just the first one.

You may find some useful stuff in serial input basics and in planning and implementing a program

…R

Here you go, fellow. I've added plenty comments, so that I hope you'll be able to get the dynamics of things. Let me know should you have further difficulties. I have NOT added the "blinking lights" code. That's pretty simple and you'll be able to handle it by yourself. Just remove the messages I wrote with your code and see if you can do it.

P.S.: As an exercise for you to better comprehend the workflow of the program, try splitting the code into functions.

String inData = ""; // String to hold input data.
int rand1 = 0, rand2 = 0, ansArduino = 0, ansUser = 0;

void setup () // This code runs only once.
{
    pinMode (0, INPUT); // Sets pin 0 as input.

    Serial.begin (9600); // Begins serial communication at 9600 bauds.
    while (!Serial) // While serial is not ready.
    {
    ; // Waiting for serial to be ready.
    }

    randomSeed (analogRead (0)); // Generates a random seed out of an analog reading of pin 0.
}

void loop () // This code keeps being executed infinitely.
{
    inData = ""; // Resets the input data string for each interaction.

    rand1 = random (0, 1000); // Generates a random number between 0 and 1000.
    rand2 = random (0, 1000); // Generates another random number between 0 and 1000.

    ansArduino = rand1 + rand2; // Assigns the sum of both random numbers.

    Serial.print (rand1); // Output the first random number to the Serial port.
    Serial.print (" + "); // Outputs " + " to the Serial port.
    Serial.print (rand2); // Outputs the second random number to the Serial port.
    Serial.println (": "); // Outputs ": " to the Serial port, followed by a new line.

    Serial.println ("Inform your answer and press ENTER."); // Outputs Inform your answer and press ENTER." to the Serial port.

    while (Serial.available () == 0) // While there is NO data comming from the Serial port.
    {
    ; // Waits for user input...
    }

    while (Serial.available () > 0) // While there's data comming from the Serial port...
    {
    int inChar = Serial.read (); // Reads each char...
    inData += (char) inChar; // Concatenates the char read into the string inData, with a typecast (char), for type conversion of the assignment.
    delay (10); // Give the Serial port some time to flush the last char and make the following one ready for reading...
    }
    ansUser = inData.toInt (); // Assigns the input data from inData, converted to Integer, to ansUser.
    Serial.print ("You entered "); // Outputs "You entered " to the Serial port.
    Serial.println (ansUser); // Outputs the contents of ansUser to the Serial port.
    if (ansArduino == ansUser) // Checks if value calculated by Arduino equals to the answer provided by the user.
    {
    // If the value calculated by Arduino MATCHES the user response...
    Serial.println ("Yay!"); // Outputs "Yay!" to the Serial port.
    }
    else
    {
    // If the value calculated by Arduino DOES NOT match the user response...
    Serial.print ("Dud torpedo, sir! Correct answer is "); // Outputs "Dud torpedo, sir! Correct answer is " to the Serial port.
    Serial.println (ansArduino); // Outputs the contents of ansArduino (the sum calculated by Arduino) to the Serial port, followed by a new line.
    }
    delay (5000); // Waits for 5 seconds before starting the next interaction...

    // Code inside loop ended... Starting it all over again...
}

Thanks fabianoantunes…

I am a newbie and though I understood most of the code, here is some thing i did not…

while (Serial.available () > 0) // While there’s data comming from the Serial port…
{
int inChar = Serial.read (); // Reads each char…
inData += (char) inChar; // Concatenates the char read into the string inData, with a typecast (char), for type conversion of the assignment.
delay (10); // Give the Serial port some time to flush the last char and make the following one ready for reading…
}
ansUser = inData.toInt (); // Assigns the input data from inData, converted to Integer, to ansUser.

What is happening and why are we doing this?
I tried using Serial.parseInt() and it worked wonderfully except that the program would wait for the delay() to pass. I want the the arduino to ask the next question immediately after the user enters the answer…

arjmon: delay (10); // Give the Serial port some time to flush the last char and make the following one ready for reading... } ansUser = inData.toInt (); // Assigns the input data from inData, converted to Integer, to ansUser.

What is happening and why are we doing this? I tried using Serial.parseInt() and it worked wonderfully except that the program would wait for the delay() to pass. I want the the arduino to ask the next question immediately after the user enters the answer...

There is no need to use delay()s while receiving serial data. It just wastes time that the Arduino could use for something useful.

I think you need to think clearly how to organize your program. The business of reading data and the business of when data is read should be separate. Look at the Thread planning and implementing a program. Separating your code into short functions makes the overall logic easier to see.

...R

Robin2: There is no need to use delay()s while receiving serial data. It just wastes time that the Arduino could use for something useful.

I'm sorry, but I must disagree, Robin2. That will depend on the control structure and instruction you use to read from the serial. For me, with Arduino Mega 2560 R3, with the following snippet...

...
int inputByte = 0;
...
while(Serial.available() > 0)
{
    inputByte = Serial.parseInt();
}
Serial.println(inputByte). // This prints 0
...

... the while loop restarts so fast that the last character read (carriage return) still counts as available in the serial port, thus the delay instruction. If you're performing a single read, the following snippet works fine.

...
int inputByte = 0;
...
if(Serial.available() > 0)
{
   inputByte = Serial.parseInt();
}
Serial.println(inputByte); // This prints correctly

Yes, I'm aware there are much cleaner and sophisticated ways of performing this task, but I don't think throwing those on a novice programmer's face would be convenient, from the didactic perspective.

[]'s

arjmon:
Thanks fabianoantunes…

I am a newbie and though I understood most of the code, here is some thing i did not…

while (Serial.available () > 0) // While there’s data comming from the Serial port…
{
int inChar = Serial.read (); // Reads each char…
inData += (char) inChar; // Concatenates the char read into the string inData, with a typecast (char), for type conversion of the assignment.
delay (10); // Give the Serial port some time to flush the last char and make the following one ready for reading…
}
ansUser = inData.toInt (); // Assigns the input data from inData, converted to Integer, to ansUser.

What is happening and why are we doing this?
I tried using Serial.parseInt() and it worked wonderfully except that the program would wait for the delay() to pass. I want the the arduino to ask the next question immediately after the user enters the answer…

arjmon, for you to use the same code with Serial.parseInt(), replace that while loop with this:

    if (Serial.available () > 0) // If there's data comming from the Serial port...
    {
	inChar = Serial.parseInt (); // Reads and Integer...
    }

You may want to refer to my previous message for further explanation on why I replaced the while for an if here.
For you to remove the delay in the end, just drop that last line which reads

    delay (5000); // Waits for 5 seconds before starting the next interaction...

BTW, this last one you could have solved on your own if you took the time to read the ALL the comments I spared you the time to write.

fabianoantunes: Yes, I'm aware there are much cleaner and sophisticated ways of performing this task, but I don't think throwing those on a novice programmer's face would be convenient, from the didactic perspective.

Allow me to disagree. I wrote the examples in serial input basics to be simple and reliable for novices. They do not use delay().

...R

Robin2: Allow me to disagree. I wrote the examples in serial input basics to be simple and reliable for novices. They do not use delay().

...R

Again, Robin2, allow me to disagree. I understand your perspective. I trully do. But from a real novice, such as in this case, with difficulties to understand and follow a procedural program, step by step, probably due to the repetition and conditional structures of the language, which is simply put like a "cake recipe", adding the complexity of following functions and understanding these functions return to the calling point in the stack is, yet, not simple. That's a great tutorial, and yes, that works very well, but for people with a little bit of previous knowledge on programming. As I've been seeing many people which are mostly technology enthusiasts, with no prior contact with development, thus my point of view, at least for this forum specifically. Of course, that's a case-by-case situation. []s