displaying double variable problem (Arduino) - arduino

so I have a problem with displaying a double variable in OLED & IR remote calculator, like this (using u8g2):
displayTextOnRight(String(100000, 0)); //ex. of an void and a number
It displays: " "
But when I set to ex. 99999 it displays: "99999"
The same is with
displayTextOnRight(String(1000.00, 2));
It also displays nothing. (100.00 displays 100.00)
I tried values below zero and it crashes. When I try 6 it's empty whatever I type on my remote.
Please help.

You're wrong. This would not work neither as you obviously expect
void setup() {
Serial.begin(9600);
Serial.print("Test: ");Serial.println(String(99999,0));
}
The function String handles integers differently than floats:
for floats you specify the number of decimal digits ( 2 as default )
for int you specify the radix ( DEC as default )

Related

Arduino: while (Serial.available()==0) gives input

I am trying to input GPS coordinate into the serial monitor to use in my drone project
However, whenever I try to input GPS coordinate, it automatically writes one of the GPS coordinates without my input. For example, GPS latitude is shown as 0.00, but the program waits for GPS Longitude info.
For a detailed situation please look at the picture attached.
int GPSNumCor;
void setup() {
// put your setup code here, to run once:
Serial.begin (115200);
Serial.print("What is the number of your GPS Coordinate? ");
while (Serial.available() == 0);
GPSNumCor = Serial.parseInt();
Serial.println(GPSNumCor);
delay (200);
float GPSLat[GPSNumCor], GPSLon[GPSNumCor];
for (int i = 0; i < GPSNumCor; i++)
{
if (i == 0)
{
Serial.println("What is your 1st GPS Coordinate");
}
if (i == 1)
{
Serial.println("What is your 2nd GPS Coordinate");
}
if (i == 2)
{
Serial.println("What is your 3rd GPS Coordinate");
}
if (i > 2)
{
Serial.print("What is your ");
Serial.print(i + 1);
Serial.println(" th GPS Coordinate");
}
delay(200);
Serial.print ("Latitude: ");
while (Serial.available() == 0);
GPSLat[i] = Serial.parseFloat();
Serial.println(GPSLat[i]);
Serial.print("Longitude: ");
while (Serial.available() == 0);
GPSLon[i] = Serial.parseFloat();
Serial.println(GPSLon[i]);
}
}
It has to wait for all input until I make an input to the program, but it does not wait.
I know while (Serial.available()==0) is a way to go, but I do not know why it would not work.
First, there's no reason to use while (Serial.available() == 0);. The parseFloat function you are about to use waits for data to be available and, if it didn't, merely checking for zero wouldn't be sufficient anyway because that would stop waiting as soon as a single character was available.
So here's why that while loop is a bad idea:
If you really do need to wait for the input before calling parseFloat, this won't do it. It only waits until at least one character is received and the coordinates may be more than one character.
The parseFloat function doesn't return until it has read an entire float anyway. So it already waits for you.
But that's not your problem. Think about the input stream, say it's "11.0<newline>22.0newline44.0". Where is the code to read the spaces between those numbers? When parseFloat tries to read a space, it returns a zero, as the documentation says. That's why you're getting zeroes -- you don't have any code to do anything with the separators between the floats.
Think about how parseFloat must work when it reads "12.34newline". First it reads the 1 and has no idea whether that's the whole number of not, so it keeps checking. Then it reads the "2.34" and still has no idea it has the whole number. Not until it sees the newline does it know that 12.34 is the correct float to return. But it does not consume the newline. Why? Because that might mean something.
With the code you showed, your next call to parseFloat will then try to read the newline and see that this is not a valid character to be part of a floating point number. So, as the documentation says, it will return zero.
Look closely at parseFloat's documentation to find out how to correctly match the delimiters in your serial stream. The parseFloat function has the ability to behave differently, consuming and ignoring delimeters rather than returning zero.
I don't know how it work, I just add Serial.read() in every time I want to read.
If u don't want to add Serial.read(), u can also use old version like 1.6.0, it still work fine but it don't work when u make like C# Serial app.
Just add Serial.read(), it work fine every place.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
while(Serial.available()==0){}
int r=Serial.parseInt();
Serial.println(r);
Serial.read(); // it work fine
while(Serial.available()==0){}
int g=Serial.parseInt();
Serial.println(g);
Serial.read();
}
In the Serial Monitor window, in the drop-down menu on the bottom-right, change from "Newline" to "No line ending" and that will solve the problem (by preventing the Serial Monitor from automatically entering zero value(s)).
Both the parseInt() and parseFloat() have a hard time reading other data types (this also includes white spaces such as new lines) than the ones specified, and as a result they automatically return zero.
Reference: This page on Programming electronics offers valuable, detailed explanations (look for a paragraph with bold text):
https://www.programmingelectronics.com/parseint/

Need help on understanding Writefile

I would like your assistance to understand a bit of code that would hugely help me in my project. Without going into too much details, here is what is causing me so much problems :
bool Serial::WriteData(char *buffer, unsigned int nbChar)
{
DWORD bytesSend;
//Try to write the buffer on the Serial port
if(!WriteFile(this->hSerial, (void *)buffer, nbChar, &bytesSend, 0))
{
//In case it don't work get comm error and return false
ClearCommError(this->hSerial, &this->errors, &this->status);
return false;
}
else
return true;
}
I use this function to send a variable to my Arduino Uno over Serial port like this :
snprintf(Data, sizeof(Data) - 1, "%3.1f", (int)(pf->speedKmh)*1.0);
SP->WriteData(Data, sizeof(Data) - 1); printf("\nData\n");
Some helpful info :
speedkmh is a float
char Data[8] = "";
So my question is : I would like to know exactly what is being sent to the Arduino. At the moment I don't really know if it is sending an array, bits one at a time, if it sends a float etc... Could you help me understand this?
Thanks!
The following line:
snprintf(Data, sizeof(Data) - 1, "%3.1f", (int)(pf->speedKmh)*1.0);
converts your floating point number to a string (an array of characters). Then
SP->WriteData(Data, sizeof(Data) - 1); printf("\nData\n");
sends these characters, one at a time, over the serial port.
BTW, it is not very clear why you convert your float to an integer, then back to a float (by multiplying it by 1.0), then to a string. As I see it, this would have the result of truncating the fractional part of the float, then appending a misleading ".0" to the string (from the ".1f" part of the control string). That is, both 1.0 and 1.4 will be converted to "1.0".

Arduino sketch with Serial.available() passes twice

When I test Serial.available() or Serial.available() > 0 in my loop() function, it appears to return true twice each time I enter serial data. The second time, it sets the throttle value in my code to 0. Here is the code:
#include <Servo.h>
Servo rc_rotor;
int throttle = 0; // servo position indicates throttle position.
String s_throttle_set = "Throttle set to: ";
String s_throttle_read = "Reading throttle value: ";
String s_action_error = "No action known for input value: ";
void setup()
{
rc_rotor.attach(9);
Serial.begin(9600);
while(! Serial);
Serial.println("Throttle value: 0 through 255, or 999 to read current value.");
}
void loop()
{
rc_rotor.write(throttle);
delay(20);
if (Serial.available())
{
int temp_throttle = Serial.parseInt();
if (temp_throttle >= 0 && temp_throttle <= 180)
{
throttle = temp_throttle;
Serial.println(s_throttle_set + throttle);
}
else if (temp_throttle == 999)
{
Serial.println(s_throttle_read + throttle);
}
else
{
Serial.println(s_action_error + temp_throttle);
}
}
}
Please note this code is not my final masterpiece. Much of it is from publicly available examples. Anyway, the statement if (Serial.available()) succeeds twice. By that I mean, it is true when I type in a value such as 125, and a moment later it will be 'true' again when I have typed in nothing additional. I only expect one value to go through this way. The result is that my throttle is being set to the value I enter, and then almost immediately re-set to 0. Why would something like this happen?
It turns out there is no mysterious problem with the hardware or the code, as I first suspected there was. Actually, the solution is simply to select "no line ending" in the Arduino Serial Monitor's dropdown option (by default, I guess mine was set to "New Line"). Without the additional character being inserted by the Serial Monitor, everything behaves as expected.
One thing I did not expect is how the Arduino software interprets the newline. I debugged by printing the ascii values that were making it through my if-statement. First of all, the Serial Monitor sent the number I typed in, followed moments later by ascii 10, which is the line feed character. Fine, no problem. But then Serial.parseInt() chewed on that line feed for a moment (there was a slight but noticeable delay), then fed the numeral 0 to my function. It took me a little while to figure out why. Here is an explanation from the Serial part of the Arduino Language Reference:
parseInt()
Description
Looks for the next valid integer in the incoming serial stream.
parseInt() inherits from the Stream utility class.
In particular:
Initial characters that are not digits or a minus sign, are skipped;
Parsing stops when no characters have been read for a configurable
time-out value, or a non-digit is read;
If no valid digits were read
when the time-out (see Serial.setTimeout()) occurs, 0 is returned;
So Serial.available() is true after the line feed character enters the buffer, but there is no "valid digit" according to Serial.parseInt(). Understandably... we are looking at an empty buffer that finally times out. Therefore Serial.parseInt() returns 0 and the code that follows proceeds with that value.
The code in the question assumed that the only input would be integers coming over the serial connection, which is actually a pretty fragile assumption. If you need to use Serial.parseInt in a situation where empty buffers (null), line feeds or other unexpected characters might come through, it should just be a matter of filtering the input better than I did in the example code.

scanning a float, getting seemingly random values

I was given an assignment to create a procedure that scans a float, called getfloat.
for some reason, I am getting random values. If I enter "1" it prints 49.Why does this happen? And also, when i input values, I can't see them on the screen? when I use scanf for example i see what i hit, on the little black screen. but now the screen is just blank, and when i click enter it shows a bad output:
Example - input: -1. Output: 499.00000
Here is my code:
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <ctype.h>
void getfloat(float* num);
void main()
{
float num=0;
printf("Enter the float\n");
getfloat(&num);
printf("\nThe number is %lf\n",num);
getch();
}
void getfloat(float* num)
{
float c,sign=1,exponent=10;
c=getch();
if((!isdigit(c))&&(c!='+')&&(c!='-')) //if it doesnt start with a number a + or a -, its not a valid input
{
printf("Not a number\n");
return;
}
if(c=='-') //if it starts with a minus, make sign negative one, later multiply our number by sign
sign=-1;
for(*num=0;isdigit(c);c=getch())
*num=(*num*10)+c; //scan the whole part of the number
if(c!='.') //if after scanning whole part, c isnt a dot, we finished
return;
do //if it is a dot, scan fraction part
{
c=getch();
if(isdigit(c))
{
*num+=c/exponent;
exponent*=10;
}
}while(isdigit(c));
*num*=sign;
}
There are a number of issues.
1) Your posted code does not match your example "input: -1. Output: 499.00000", I get 0 due the lack of a getch() after finding a '-'. See #6.
1) 'c' is a character. When you enter '1', c took on a code for the letter 1, which in your case being ASCII coding, is 49. To convert a digit from its ASCII value to a number value, subtract 48 (the ASCII code for the letter '0', often done as c - '0'
*num=(*num*10)+c;
*num+=c/exponent;
becomes
*num = (*num*10) + (c-'0');
*num += (c-'0')/exponent;
2) Although you declare c as a float, recommend you declare it as an int. int is the return type from getch().
3) Function getch() is "used to get a character from console but does not echo to the screen". That is why you do not see them. Consider getchar() instead.
4) [Edit: delete Avoid =-. Thank-you #Daniel Fischer]
5) Your exponential calculation needs rework. Note: your exponent could receive a sign character.
6) When you test if(c=='-'), you do not then fetch another c. You also might want to test for else if(c=='+') and consume that c.
Good luck in your C journey.
49 is the Ascii code for the number 1. So when (0'<=c && c <='9') you need to subtract '0' to get the number itself.
A small hint: 49 is the ASCII for the character 1. You are using getch(), which gives you the return value char.

Arduino: Want to make something only print once

I was writing a script for the ardunio so that it would print how far away something was, and I was trying to make it so that if it was equal to the default length (when the script first started) it would not work, and if the distance between the two numbers is greater than 3 inches to print again. Not sure why it isn't working. At first I tried to make it so that it would not print, also, if it was the same as the last printed length, so if anyone could figure that out instead, that would be amazing. Also, sorry if I sound stressed, I've been working on this probably super-simple script for at least 3 hours now.
#include <Ping.h>
Ping ping = Ping(13,0,0);
int defaultlength = 0;
int length = 0;
int afterlength = 0;
void setup(){
Serial.begin(9600);
ping.fire();
defaultlength = ping.inches();
}
void loop(){
ping.fire();
length = ping.inches();
delay(100);
afterlength = length - defaultlength;
sqrt(afterlength^2);
if (afterlength >= 3) {
Serial.print(afterlength);
ping.fire();
Serial.print("Inches: ");
Serial.print(ping.inches());
Serial.print(" | Centimeters: ");
Serial.print(ping.centimeters());
Serial.print(" | Light: ");
if (analogRead(A0) >= 1000) {
Serial.print("ON");
Serial.println();
}
else {
Serial.print("OFF");
Serial.println();
}
}
delay(1000);
}
Also, It is not printing anything at all ever. I'm not sure if its not going through the loop or what.
Your line sqrt(afterlength^2); doesn't do anything useful. Did you mean to take the absolute value by writing
afterlength = sqrt(afterlength*afterlength);
The ^ operator is the bitwise XOR -- not at all what you were trying to do.
Does that make it better?
As for your other question:
"At first I tried to make it so that it would not print, also, if it was the same as the last printed length, so if anyone could figure that out instead, that would be amazing." - here is what you can do:
1) define another variable in the head of the script - call it lastlength and initialize it to defaultlength (right after you did your first ping in setup())
2) in the loop, change the if statement to
if ((afterlength >= 3) && (abs(length - lastlength) > 0.1)) {
3) finally, at the end of your if{} statement, add:
lastlength = length;
The reason to put that in the if{} block is to make sure that you only update it if things have changed sufficiently - otherwise, you keep the same "don't tell me again until it's different than the number you told me before" value. Of course, the > 0.1 value can be replaced with whatever tolerance you want. Note also use of abs() - a bit more compact than the square root of the square.

Resources