Hi, This subject has been bought up before and then closed after 6 months. Looking up the replies it seems there was no satisfactory answer to it.
I try to input numbers like 15.25, 15.5, 15.75 into the serial monitor. The decimal points are ignored. Actually the numbers represent times in my project. 3:15pm, 3:30pm, 3:45pm.
But anyway that is beside the point here. Is there a fix for this in Arduino?
Unless I can fix it I can only enter hours and not minutes in my project.
You certainly can enter decimal points (ie full stops) into the Serial monitor. The problem may be how you interpret them.
Please post a full sketch that illustrates your problem, using code tags when you do
Then why don't you enter "3:15pm" and solve that in code ?
Can you show what you have ? Can you show a minimal sketch that ignores the decimal points.
Should your code allow every possible line ending from the Serial Monitor (CarriageReturn, LineFeed, timeout).
What about this? Have you tried this?
enlighten us... which topics, which replies? what's your code?
here is an example that seems to work OK
click to see the code
/* ============================================
code is placed under the MIT license
Copyright (c) 2024 J-M-L
For the Arduino Forum : https://forum.arduino.cc/u/j-m-l
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/
const byte maxLengthMessage = 64;
char message[maxLengthMessage + 1]; // + 1 for the null character at the end of the string
bool messageReceived() {
enum t_state : byte {DONE, IN_PROGRESS};
static t_state state = IN_PROGRESS;
static byte index = 0;
bool messageReady = false;
int r = Serial.read();
if (r != -1) { // -1 means nothing to read
switch (state) {
case DONE:
message[0] = '\0';
state = IN_PROGRESS;
__attribute__ ((fallthrough)); // fall through on purpose
case IN_PROGRESS:
if (r == '\n') { // end of reception
message[index] = '\0';
index = 0;
state = DONE;
messageReady = true;
} else {
if (index < maxLengthMessage) {
message[index++] = r;
}
}
break;
}
}
return messageReady;
}
void analyzeMessage() {
Serial.print(F("Analyzing \""));
Serial.print(message);
Serial.println(F("\""));
if (strlen(message) != 0) {
char * startPtr = message, * endPtr;
do {
double value = strtod(startPtr, &endPtr); // https://cplusplus.com/reference/cstdlib/strtod/
if (endPtr == startPtr) {
Serial.println(F("error: could not parse decimal numbers."));
break;
} else {
Serial.println(value, 3); // print with 3 digits after the decimal point
if (*endPtr == '\0') break;
else startPtr = endPtr+1; // skip the separator
}
} while (*startPtr);
}
}
void setup() {
Serial.begin(115200); Serial.println();
Serial.println(F("enter numbers separated by space"));
}
void loop() {
if (messageReceived()) {
analyzeMessage();
}
}
Numbers can be separated by any one character (non digit) separator or multiple spaces. Line needs to end with a new line '\n'
as end marker so if you try in the IDE with your arduino, make sure you set the Serial monitor's line ending to LF or CRLF
Thanks odometer. That fixes it. Pretty well hidden on the reference in Arduino. Not on the main page. You only have 'serial' on the main page. Have to press serial to bring up Serial.parseFloat(). I only found 'int' when I was looking for a way to enter into the serial monitor. It was in some ones programming.
Found the fix. See my reply to Odometer.
I just googled "Serial parse float" or maybe it was "Arduino Serial parse float", and that's how I found the function Serial.parseFloat()
.
Serial.parseFloat()
is tricky as
-
If it times out you get a value that is not documented and you don't know if that was because of a timeout or because you actually entered that value. You also get a number if the user did not enter any valid number.
You have to look into the source code to see that the returned value is 0 if there is a timeout (but this could change in future implementations as it's not documented)
it's 0 as well if you typed "Hello" instead of 123.456
you can play a bit with the lookahead and ignore parameters but you still won't be able to catch errors.
- It's blocking. Nothing else in your code gets executed whilst you are waiting for the data to come. If you need to tend to other things (blinking a led, monitoring a button, ...) then it's stalled until you get that number.
Dealing with data entry in an asynchronous way makes your code more dynamic and handling the buffer with a better parsing function (cf my wokwi and the use of strtod() ) will let you handle edge cases and errors better.
This is a really interesting, yet fundamental problem faced over decades.
Async Serial comms are the simplest form of transferring complex data.
I don’t think I’ve ever seen a well written library that handles all likely situations.
Command line parsers are the perfect example, but they seem to be proprietary to each application.
I’ve written my own, reusable parser, but it’s probably too complex for many here, and there are things I’d still like to refine.
Funny tho, the most fundamental thing in almost any project is the last thing addressed,
The major challenges are :
- Single key ‘hot keys’
- Case insensitive when required
- Multi parameters per line
- Multi line commands
- Numeric extraction of all types - int, float, string etc
- Keyword & token detection
- and so on…
All live, without blocking the foreground code !
unless you define a strong protocol for what you want to transfer it's hard to be fully encompassing with the challenges you listed.
You should also add the challenge of sending binary data sets, endianness and types size, and integrity verification.
In the general case of serialising complex data sets, there are things out there worth looking at like Protocol Buffers
I'd consider entering the times using the 24 hour clock, as integers:
1515, 1530, etc.
This is another example of how simple, yet complex input parsing can become.
It the program i’s expecting a time or date in a particular ffield, it should try to make best sense of it in any likely format. HHMM, HH:mm, hhmm and so on, with or without am/pm identifiers, colons, spaces or periods as field separators.
IF it can’t make sense of any field, it should stop the parser and tell the user there was an error detected in th input !
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.