Arduino not is able to multiply numbers from 40 onwards by 1000 for example
void setup() {
Serial.begin(9600);
}
void loop() {
float a = 60 * 1000;
Serial.print(a);
}
the result is -5536 .-. ??? what ??
I need to convert seconds to milliseconds, but I do not know alternatives to multiplication by 1000
The problem is that you are
taking a (signed) int and setting it to 60
taking a (signed) int and setting it to 1000
multiplying them, obtaining a signed int. This generates an overflow, so the result is -5536
converting this number in a float; -5536 -> -5536.0
The solution? Since you want to deal with floats... Operate with floats!
float a = ((float)60) * 1000;
float a = 60.0 * 1000;
The two solutions are the same; the first converts (int)60 in a float, then multiplies it by (int)1000, which gives you (float)60000.
The second tells the compiler that 60.0 is a float.
In both cases a float multiplied by an int gives you a float, so... No overflow!
The problem is that Serial.print converts a to signed integer. Try this:
Serial.print((float)a);
or this:
#include "floatToString.h"
char buffer[25];
Serial.print(floatToString(buffer, a, 5));
Related
I write a code for Arduino Nano and I experience this weird behaviour:
#define GREAT (60 * 60000)
#define STRANGE (60 * 6000)
#define ZERO_X (60 * 1000)
void setup() {
Serial.begin(115200);
Serial.println(GREAT); // Prints 3600000, that's correct
Serial.println(STRANGE); // Prints 32320, thats wrong
long zerox = ZERO_X;
Serial.println(zerox); // Prints -5536, thats also wrong, obviously
}
void loop() {}
What is going on?
I use MSVS2019 Comunity with vMicro
You use integer literals to define your values, and as described in documentation type of literal depends on where it can fit. According to specs
On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value.
(emphasis is mine) Arduino Nano has CPU with 2 bytes int - 60, 6000 and 1000 fit in signed integer and such type is used. Though neither values of 60 * 6000 nor 60 * 1000 can fit in 2 bytes int so you get integer overflow with UB and unexpected values.
On another side 60000 does not fit into signed int of 2 bytes, so it gets type long with 4 bytes and 60000 * 60 fits there so you get expected result. To fix your problem you can just specify suffixes:
#define GREAT (60 * 60000L)
#define STRANGE (60 * 6000L)
#define ZERO_X (60 * 1000L)
and force them all to be type long. It is not necessary to do it for 60000, but it is better to have it for consistency.
For your code change:
long zerox = ZERO_X;
this line does not solve the issue as after macro substitution it is equal to:
long zerox = (60 * 1000);
and it does not help, as first calculations with type int are done on the right side of initialization, overflow happens and then int is promoted to long. To fix it you need to convert to long one of the arguments:
long zerox = 60 * static_cast<long>(1000);
or use suffix as suggested before.
Can someone please explain how the code below works to find the distance in bytes between two variable in memory?
#include<stdio.h>
int main()
{
int a = 5;
int b = 10;
int difn = (int)(&b) - (int)(&a);
if(difn < 0) difn *= -1;
printf("Difference in bytes: %d\n", difn);
return 0;
}
& operator return byte address in memory. Thus if you subtract two byte addresses you get byte difference between those addresses. Since this difference can be negative, you need to check if it is and if so multiply it by -1 (absolute value). Then you just print it out.
In my project I need to make some calculations with high-precision numbers. But I noticed that the answers are not correct. The code bellow shows what I mean.
void setup() {
Serial.begin(9600);
double l = 32.48750458;
double n = 32.48751068;
double im = l - n;
double im1 = im * 0.605;
double cs = 32.48751068 + im;
Serial.println(l, 8);
Serial.println(n, 8);
Serial.println(im1, 8);
Serial.println(cs, 8);
}
void loop() {
}
The output of this code on the serial monitor is:
32.48750305
32.48751068
-0.00000462
32.48750305
So how can I deal with this precision in Arduino?
On most Arduino the double data type doesn't exist. They all end up really being just regular float. The arduino just doesn't have the muscle to be playing with double precision numbers. The code generated wouldn't leave room for the rest of your program.
Floating point numbers just aren't that precise. They get about 6 or 7 digits of precision. Quite often it is better to use unsigned long and stick with fixed point math so you can get at least 9 digits and there aren't any approximations.
I do have a small Arduino programming that simply stops after first loop. I might overlook something...but I'm simply clueless about what is happening.
Here is the code
int led = 13;
//int led = 10;
unsigned long windtime = 1000 * 2; // 2 seconds
unsigned long pausetime = 1000 * 60; // 1 minute
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
Serial.print("Wind");
digitalWrite(led, HIGH);
delay(windtime);
Serial.print("Pause");
digitalWrite(led, LOW);
delay(pausetime);
}
I used Serial only as debug echo.
Any idea?
It seems that you need to explicitly set numeric literals to long (L) and they use them. Otherwise it does not work. If anyone can explain if there is any kind of automatic conversion it will be awesome but until then simply use:
unsigned long seconds = 1000L; // !!! SEE THE CAPITAL "L" USED!!!
unsigned long minutes = seconds * 60;
unsigned long hours = minutes * 60;
and then simply use delay(millisec) as usual:
delay(5 * minutes);
It worked for me.
in your line:
unsigned long pausetime = 1000 * 60; // 1 minute
the Arduino will look at 1000 (integer) and 60 (integer) and so will work out an answer that it will try to slot into... an integer! This means the biggest answer it can give to pausetime is 32,767. Anything bigger than this will wrap round, so 60,000 minus two lots of 32,768 comes out at -5536.
To see it in action add Serial.print(1000 * 60); to the setup and watch in your Tools>Serial Monitor:
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
Serial.begin(9600);
Serial.print(1000 * 60);
}
To force the Arduino to use your constants as unsigned longs add ul or UL to the end of the number.
It could be that the unsigned longs are getting over-written. As a debugging method try a hardcoding constant value like delay(6000) for six seconds. This will prove if your hardware is working.
Finally, not sure if the delay value should be unsigned long, I usually use int and not for 60,000 which is greater than what an int (2 bytes) on the Arduino can store. Remember, embedded systems really are smaller systems.
this example: http://arduino.cc/en/Tutorial/BlinkWithoutDelay implies that the value for delay must be an int.
Hope this helps.
instead of using
unsigned long windtime = 1000 * 2; // 2 seconds
unsigned long pausetime = 1000 * 60; // 1 minute
use
unsigned long windtime = 2000; // 2 seconds
unsigned long pausetime = 60000; // 1 minute
and done.
Which of the following two approches is more efficient on an ATmega328P?
unsigned int value;
unsigned char char_high, char_low;
char_high = value>>8;
value = value<<8;
char_low = value>>8;
OR
unsigned int value;
unsigned char char_high, char_low;
char_high = value>>8;
char_low = value & 0xff;
You really should measure. I won't answer your question (since you'd benefit more from measuring than I would), but I'll give you a third option:
struct {
union {
uint16_t big;
uint8_t small[2];
};
} nums;
(be aware of the difference between big endian and little endian here)
One option would be to measure it (as has already been said).
Or, compile both and see what the assembly language output looks like.
but actually, the 2nd code you have won't work - if you take value << 8 and assign it to a char, all you get is zero in the char. The subsequent >>8 will still leave you with zero.