hello, I'm testing an arduino nano with PWM output 500-10 hz
arduino have incorrect behavior, a mathematical action in line 62 (int duty = (frq*10)/inp;), why when the <19 hz frequency variable "duty" is reached in a negative value?
Because you have not said otherwise I am going to assume that you are using an Arduino board that uses an AVR processor. If that is not the case, then please tell us which board you are using
Firstly, you are using int variables in your sketch. These are 16 bit signed variables and their value can, therefore, be negative
Secondly, in your calculation, do any of the results ever exceed the maximum value that a signed 16 bit integer can hold ?
the issue is not there. the input is really within the 0 - 1023 range and the output range is well within the int representable range. The maths within the function is done with longs, so will handle some level of overflow.
The map function performs its calculation using long, and returns a long, which is then stored in an int. The numbers being used will not cause a problem with that. The error the OP is seeing is caused by int overflow in their equation.
Not sure what you mean, the maths in the map() function are performed as long, and parameters are promoted from int to long which is lossless.
in general yes, assigning a long (the result of the map() call) to an int could be a problem, but not here.
the value submitted into map is the result of an analogRead() so between 0 and 1023 and the map does map that full range map(pot0, 0, 1023, 6249, 118); into something ([118, 6249]) that fits on an int. So the conversion of long to int when you assign the result of the call to map will not create any issue. (same for the other [19, 100] is within range of an int).
the issue is later on, when OP does freq * 10, that's when the overflow happens.
yes, In the example you give the long returned value is beyond the bounds of an int. (that's what I meant with "in general yes, assigning a long (the result of the map() call) to an int could be a problem,".
But here you are 100% sure this is not the case as the input to the map function is always within the two provided x_min x_max, you are sure that the output will be within y_min y_max. As those 4 values are compatible with an int, there is no issue assigning the result back to an int.
int frq1 = mapp(); //<-------- doesnt match return type
Serial.println(frq1); // <== OK 6249
the calll to the function is NOT the issue.
later in int duty1 = (frq1*10)/19; the variable frq1 is an int, so the math is conducted int int, and frq1*10 overflows. writing int duty1 = (frq1*10l)/19; would solve it because 10l is a long, so the whole thing would be promoted to long calculation
but when you do int duty2 = (frq2*10)/19; , frq2 is a long, so the maths are conducted in long format and frq2*10 does not overflow.
long mapp()
{
return 6249;
}
void setup() {
Serial.begin(9600);
int frq1 = mapp(); //<-------- doesnt match return type
long frq2 = mapp(); //<-------- matches return type
int duty1 = (frq1*10)/19;
int duty2 = (frq2*10)/19;
Serial.println(duty1);
Serial.println(duty2);
}
void loop() {
// put your main code here, to run repeatedly:
}
Still a bad example. If you print frq1 and frq2 you will see the correct number. It is the multiplication by 10 that is overflowing the int, and that will occur regardless of whether you call the map (or in this case the mapp) function.
< edit > If you cast frq1 to long in the equation then the answer will be correct, the problem is directly caused by the compiler defaulting to int math since both frq1 and 10 are int. You can completely eliminate the function call to mapp, and just directly initialize frq1 and frq2 to 6249, and the results will still be incorrect for duty1.
You are implying that the error is caused by storing the long as int, which implies the call to the map function is part of the problem. That in itself is completely irrelevent to the actual problem.
Again a bit misleading, implying that the map function has something to do with the actual problem. It is fine in this case to store the return value as an int, as long as it is cast to long in the equation (or the 10 is explicitly declared to be long by using 10L).
No... if you don't declare it long, the math frq1*10 is conducted as an int. That's why it overflows. This has nothing to do with map and its returned value;
proof point: you can Keep it as an int, but use frq1*10l and you'll see all is fine... (because the compiler sees 10l as a long, so promotes frq1 to long before doing the math using long arithmetic)
This is what I've been trying to tell, in my own way. If OP matched the return of the map type it would have been long and without knowing everything would have been fine...If only one would follow the return type...
OK, not sure why you brought map() into the mix and in your examples.
it has nothing to do with map as demonstrated by frq1*10l working completely fine, even if frq1 is an int and not a long.
OK... that was confusing at least for me as map() is not the issue. it's perfectly OK to store the result of the map() call into an int. The language has precise rules on how this will be dealt with if you overflow (and there was no possible overflow from map in the current code)
In this case yes (well no, as we discussed, but yes), but what if the map range was different? As the rule of thumb matching return type shouldnt land you in trouble, like in this case, even though it is not map related directly