Slightly confused over Serial.read - can someone help me understand?
Simple code snippet.
while (Serial.available()==0){ // Loop forever waiting for serial port input
}
//Key has been pressed
for (int i=0; i<=10; i++){
int s=Serial.available();
int r=Serial.read();
Serial.println(i);
Serial.println (s);
Serial.println(r);
}
I type in 'a' and press the send button in serial console.
This results in the following:
Why the gap between the 'a' that I entered and the '/n' ?
Is this just some internal delay in moving data around or am I missing something?
I would have expected
0 1 97
1 1 10
2 0 -1
3 0 -1
etc....
Do I simply need a delay between serial.reads in order to read both the 97 and the /n or do I need a specific number of reads (5) to capture both 97 and /n?
You should wait until the required/expected number of characters is available. Reading the input buffer is so much faster than the transmission over the line.
In other words, you check if there is/are one or more characters available and next you read 10 regardless. The -1 indicates that there was no characcter available at the time of reading.
You are missing that serial is super slow compared to what the processor can do. In between one byte and the next the processor can make a cup of tea and relax with it's favourite novel for a while before checking to see if there's another byte. Any well written code for handing serial input will only see at most 1 or a very small number of bytes, mostly it will not see any, each time it checks, you have to write code to assemble those individual bytes in to whatever it was you were trying to get.
The tutorial @sterretje linked to is very good, I suggest you read it.
while (Serial.available()==0){ // Loop forver waiting for serial port input
}
//Key has been pressed
for (int i=0; i<=10; i++){
int s=Serial.available();
int r=Serial.read();
Serial.println(i);
Serial.println (s);
Serial.println(r);
Serial.println();
delay(100);
}
The code moves on as soon as the 'a' is received and loops like crazy while the /n is being received.
It's a single character that I need from the user - but of course the user may put in a string of characters....
The best approach is to look for the /n before stepping on.
That way, the user can input any number of characters, but the code will not step on until it reads the /n character, at which point any future reads of Serial.available should read 0 and serial.read should read -1
I don't know if this is the right time to mention this but don't get too hooked on using delay(), it will fix small problems like this now, but as soon as you want your code to do more than one thing at a time you will need a more advanced strategy for writing code. Delay stops anything else from happening and is much debated on here.
Here is a slightly different example sketch from my tutorial Arduino Software Solutions
change the
if (readStringUntil(input, terminatingChar, 20)) to
if (readStringUntil(input, terminatingChar, 10)) if you want to only read 10 chars
// readStringUntilLimited.ino
// Reads chars into a String until newline '\n'
// https://www.forward.com.au/pfod/ArduinoProgramming/SoftwareSolutions/index.html
// Pros: Simple. Non-Blocking, more Robust against unexpectedly long input lines
// Cons: Does not return short lines until the until_c char is found. i.e. no timeout
String input;
void setup() {
Serial.begin(9600);
for (int i = 10; i > 0; i--) {
Serial.print(' '); Serial.print(i);
delay(500);
}
Serial.println();
Serial.println(F("readStringUntilLimited.ino"));
input.reserve(20); // expected line size, see Taming Arduino Strings
// https://www.forward.com.au/pfod/ArduinoProgramming/ArduinoStrings/index.html
}
// read Serial until until_c char found or limit char read, returns true when found/limited else false
// non-blocking, until_c is returned as last char in String, updates input String with chars read
bool readStringUntil(String& input, char until_c, size_t char_limit) {
while (Serial.available()) {
char c = Serial.read();
input += c;
if (c == until_c) {
return true;
}
if (input.length() >= char_limit) {
return true;
}
}
return false;
}
char terminatingChar = '\n';
void loop() {
if (readStringUntil(input, terminatingChar, 20)) { // read until find newline or have read 20 chars
if (input.lastIndexOf(terminatingChar) >= 0) { // could also use check if (input[input.length()-1] == terminatingChar) {
Serial.print(F(" got a line of input '")); Serial.print(input); Serial.println("'");
} else {
Serial.print(F(" reached limit without newline '")); Serial.print(input); Serial.println("'");
}
input = ""; // clear after processing for next line
}
}
Here is a simple way to flush any old input on start up (also in the tutorial)