Arduino Polska Forum
Problem z zerowaniem licznika - Wersja do druku

+- Arduino Polska Forum (https://forum.arduinopolska.pl)
+-- Dział: Korzystanie z Arduino (https://forum.arduinopolska.pl/dzial-korzystanie-z-arduino)
+--- Dział: Piaskownica (https://forum.arduinopolska.pl/dzial-piaskownica)
+--- Wątek: Problem z zerowaniem licznika (/watek-problem-z-zerowaniem-licznika)



Problem z zerowaniem licznika - kataklysm - 10-09-2019

Mam problem z bardzo prostą funkcją mianowicie kiedy kręcę enkoderem na wyświetlaczu co obrót dodawałem 1 a kiedy osiągnął pewną wartość to się zerwał, mniej więcej tak:

int suma = 0;

suma = suma + 1;
if (suma == 30){
suma = 0;
}

I to działało ale potrzebowałem miec większą rozdzielczość tego licznika więc użyłem float:

float suma = 0;

suma = suma + 0.10;
if (suma == 30.00){
suma = 0.00;
}


Niestety ten zapis nie działa licznik w ogóle się nie zeruje a w drugą stronę zaczyna pokazywać liczby ujemne. 

Proszę o pomoc.


RE: Problem z zerowaniem licznika - Robson Kerman - 10-09-2019

Może suma nie osiąga wartości 30?
Może osiąga, ale w tym czasie program jest gdzie indziej?
Ciężko stwierdzić nie mając schematu i kodu.

Na pewno zadziała: if(suma>30)


RE: Problem z zerowaniem licznika - semi - 10-09-2019

(10-09-2019, 08:29)Robson Kerman napisał(a): Może suma nie osiąga wartości 30?
Dla liczb zmiennoprzecinkowych == często nie mają zastosowania.

kataklysm napisał(a):potrzebowałem miec większą rozdzielczość tego licznika więc użyłem float:
W ten sposób nie zwiększysz rozdzielczości enkodera tylko sposób reprezentacji. W programach należy unikać liczb zmiennoprzecinkowych, zwłaszcza w powolnych AVR bez FPU. Jeśli dane chcesz reprezentować z rozdzielczością 0,01 użyj liczb stałoprzecinkowych. Jeśli chcesz zwiększyć rozdzielczość enkodera używaj obu zboczy sygnału z enkodera (rozdzielczość x 2) albo obu zboczy obu sygnałów (A i B) wtedy rozdzielczość zwiększysz 4 krotnie. Nie z każdym enkoderem to się uda, niektóre zatrzymują się tylko w takich pozycjach, że rozdzielczość można zwiększyć tylko 2 krotnie. Jeśli potrzeba jeszcze większa precyzja użyj innego enkodera, który daje więcej impulsów na obrót.
Porównanie trzeba realizować w procedurze przerwania od enkodera, w przeciwnym wypadku nie zawsze będzie wykonane poprawnie.


RE: Problem z zerowaniem licznika - Agregacik - 10-09-2019

Sprawdziłem to na takim przykładzie i stwierdziłem, że program nie działa tak jak pisał autor.



float suma = 0;
float a = 30;
float b = 0.5; //podstawiając za b = 0.5 program działa poprawnie dla b = 0.2 już nie

void setup()
{
Serial.begin (9600);
}

void loop() {


suma = suma + b;
Serial.println ( suma );
if (suma == a) // gdy tu zmieni się warunek na >= to działa poprawnie przy b = 0.1
{
Serial.println ( "suma = 30" );
suma = 0;
}
delay (100);
}

Dlaczego warunek == nie działa poprawnie dla float.

Sprawdziłem
Liczba 0.1 w systemie dwójkowym przyjmuje wartość przybliżoną a wielokrotna suma tej liczby, nie może być nigdy dokładnie 30 i stąd warunek (suma ==30) nigdy nie będzie spełniony. Trzeba dać warunek (suma >=30) lub (suma > 30).


RE: Problem z zerowaniem licznika - kataklysm - 11-09-2019

(10-09-2019, 11:57)Agregacik napisał(a): Sprawdziłem to na takim przykładzie i stwierdziłem, że program nie działa tak jak pisał autor.



float suma = 0;
float a = 30;
float b = 0.5; //podstawiając za b = 0.5 program działa poprawnie dla b = 0.2 już nie

void setup()
{
Serial.begin (9600);
}

void loop() {


suma = suma + b;
Serial.println ( suma );
if (suma == a) // gdy tu zmieni się warunek na >= to działa poprawnie przy b = 0.1
{
Serial.println ( "suma = 30" );
suma = 0;
}
delay (100);
}

Dlaczego warunek == nie działa poprawnie dla float.

Sprawdziłem
Liczba 0.1 w systemie dwójkowym przyjmuje wartość przybliżoną a wielokrotna suma tej liczby, nie może być nigdy dokładnie 30 i stąd warunek (suma ==30) nigdy nie będzie spełniony. Trzeba dać warunek (suma >=30) lub (suma > 30).


Zgadza się, ale < > działa więc sobie poradziłem. Dzięki wszystkim


RE: Problem z zerowaniem licznika - kaczakat - 11-09-2019

I dlatego wszędzie piszą, by unikać float'ów. W kodzie programu możesz mieć wartości 0-300 z typem np. int czy uint16_t, zastosowanie jest dużo szersze niż float, a gdy potrzeba pokazywać z przecinkiem użyć własną funkcją na kilka linijek.
Na liczby ujemne sam musisz napisać obsługę, że jak mniejsze od 0 to =0, dla typów bez znaku przekręci Ci licznik na koniec zakresu typu, np. 255 dla typu uint8_t.