I am trying to get the serial monitor to prompt me to input two settings - the PWM level and the Resonance level. I am being prompted to input the PWM level, but before I can input the Resonance level it is set to zero and then I am asked again for the PWM level.
I am using Serial.flush(); inbetween the commands to clear the serial input, but I still cannot input the Resonance level before it is set to zero.
Here is my code:
int PWMPin = 10; // Pin 10 connects to MOSFET gate on breadboard
int ResPin = 4; // Pin for the resonator stage
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); // Define baud rate for console to be 9600
pinMode(PWMPin, OUTPUT);
pinMode(ResPin, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("What PWM level do you want to test?"); // Testing only
while (Serial.available() == 0) {
// Wait for user input
}
int test_level_PWM = Serial.parseInt();
analogWrite(PWMPin, test_level_PWM);
Serial.print("PWM Level: ");
Serial.println(test_level_PWM);
Serial.flush();
Serial.println("What Resonance level do you want to test?");
while (Serial.available() == 0) {
// Wait for user input
}
int test_level = Serial.parseInt();
analogWrite(ResPin, test_level);
Serial.print("Resonance Level: ");
Serial.println(test_level);
delay(1000);
Here is the serial monitor output. I was able to input the PWM level but the Resonance level was set to zero immediately after and then I was asked to input the PWM level again.
Serial.flush() does not clear the input, it just ensures that whatever you printed is sent before continuing.
I would suggest to study Serial Input Basics to handle this. Serial.parseInt() and the likes have a builtin timeout and if you send \r or \n at the end of the text you might get surprising behavior as you see (because you still have data in the incoming buffer, your test while (Serial.available() == 0) does not wait and then you hit the 1s timeout)
if you want a very basic input mechanism for positive integers, not dealing with sign, not dealing with overflow and ignoring any character that is not a digit, this could get the job done
unsigned long getUserInputBlocking(const char * message) {
unsigned long result = 0;
bool receiving = true;
bool acquisitionStarted = false;
Serial.println(message);
do {
int r = Serial.peek();
if (r != -1) { // got something
if (isdigit(r)) {
acquisitionStarted = true;
Serial.read(); // remove the byte from the incoming stream
result = 10 * result + (r - '0'); // do the math, might overflow.
} else {
if (acquisitionStarted) {
receiving = false; // we are done
} else {
Serial.read(); // ignore that byte and remove it from the incoming stream
}
}
}
} while (receiving);
return result;
}
void setup() {
Serial.begin(115200);
Serial.println();
unsigned long x = getUserInputBlocking("What PWM level do you want to test?");
Serial.write('\t'); Serial.println(x);
unsigned long y = getUserInputBlocking("What Resonance level do you want to test?");
Serial.write('\t'); Serial.println(y);
}
void loop() {}
the serial monitor needs to be configured at 115200 bauds and needs to send something (CR, LF or both) when you input something
if you type xyz1234hello the parser will ignore xyz get 1234 and stop at the h and keep it in the incoming buffer.
May I a offer a suggestion. You are currently locking input and output of your application together. You ask a question and require the user to send an answer. I would recommend you divide this into two separate functions in your application. One prints out a how to use your application to the Serial Monitor and the other part just receives commands and sets variables accordingly. This will scale a lot better.
The first part is easy. You already know how to do that.
The second part will require a little bit different technique, but it is used in many application. You need to parse serial data that will contain information about the data and some numerical value. There are even standards for this e.g.,
Or you keep it very simple by using single letter commands ($P,20, $R,0). Then you only need to compare a single character and use switch-case for decoding.
You can use a special end character or return and new line ('\r', '\n') to tell your sketch when the message is complete.
Your problem sounds like a classic case of having the Line Ending in the Serial monitor set such that it leaves extra characters in the serial buffer after you have read the value that you want so that the next available() or read() finds them and does not allow entry of a second value
Arduino Software Solutions has a number of examples of reading from Serial each with their pros and cons.
I suggest you use one of the non-block examples and a small state machine to keep track of what to do with the next line of input you read.
i.e. is the loop() waiting for PWM level input OR Resonance level input.
and parse accordingly.
Also check out my Multi-tasking in Arduino tutorial so that you sketch is set up to run with non-blocking inputs.