logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[AtMega32][C] - Timer1 liczy dobrze tylko dla jednej wartości - dlaczego?

Nowax 14 Paź 2013 03:15 1263 5
REKLAMA
  • #1 12841324
    Nowax
    Poziom 10  
    Witam!
    Nie znalazłem odpowiedzi na forum, a już mnie zaczął męczyć ten timer1. Chciałem, żeby po prostu odliczał mi czas. Do funkcji przekazuje mu wartość odpowiadającą ilości milisekund (tu w ogóle jakieś cuda się dzieją - wartość "ms" po wyliczeniu OCR1A przyjmuje jakieś kosmiczne wartości [sprawdzane jtagicem], stąd też zrobiłem przypisanie do zmiennej automatycznej). Program działa tylko dla wartości "1000". Już zupełnie nie ogarniam co jest nie tak - robię niby wszystko tak jak napisane zostało w datasheetcie, a mimo wszystko program nie bangla :( Poniżej istotny wycinek kodu: (btw. na początku próbowałem robić bez zmiennej "until"... ale oczywiście nie działało; pozostałości w komentarzu)
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Czy byłby ktoś w stanie wskazać błąd albo przynajmniej kierunek rozumowania?

    edit1: dodam jeszcze, że bawiłem się zmianą ustawień wewnątrz atmegi, bo podłączałem zewnętrzny kwarc 14,7456 MHz. Aktualnie ustawioną mam opcję:
    Ext Crystal/Resonator High Freq.; Start-up time : 16K CK + 64ms
  • REKLAMA
  • #2 12841339
    Steryd3
    Poziom 33  
    Mam wrażenie, że problem leży w tej linijce kodu:

    Nowax napisał:
    OCR1A=(short int)(14400*(local_ms/1000));


    Chodzi o problem z typem zmiennych -zaznaczyłeś, że operacje mają być przeprowadzane na typie short int który to typ jest typem całkowitym i wyniki operacji pośrednich też będą całkowite. Pewnie i twoje funkcja będzie działać dobrze i dla opóźnień 2000, 3000, 4000,... -dla całej reszty będzie działać błędnie. Zamiast wpisywać typ short int w nawiasie wpisz folat lub obliczenia wykonaj na innej zmiennej typu float a później przepisz ją do OCR1A ograniczając zakres wartości za pomocą warunków "if".
  • REKLAMA
  • #3 12841417
    BlueDraco
    Specjalista - Mikrokontrolery
    Wszystko, tylko nie float, a w tym przypadku również nie int, tylko unsigned int.

    Spróbuj tak, o ile local_ms nie przekracza 227:

    OCR1A = 144 * local_ms / 10;

    Jeśli nie przekracza 455:

    OCR1A = 72 * local_ms / 5;

    Jeśli przekracza:

    OCR1A = 72 * (unsigned long)local_ms / 5;
  • REKLAMA
  • #4 12844928
    Nowax
    Poziom 10  
    Float faktycznie nie wchodzi w rachubę zwłaszcza przy 8-bitowym procesorze - podchodziłoby to pod znęcanie nad MCU :P

    Co do propozycji to poskutkowały, aczkolwiek użyłem takiej instrukcji:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    zakładając, że błąd rzędu 3% jest dopuszczalny. :)

    Nie rozumiem natomiast propozycji kolegi BlueDraco:
    BlueDraco napisał:

    Spróbuj tak, o ile local_ms nie przekracza 227:
    OCR1A = 144 * local_ms / 10;
    Jeśli nie przekracza 455:
    OCR1A = 72 * local_ms / 5;
    Jeśli przekracza:
    OCR1A = 72 * (unsigned long)local_ms / 5;

    Przecież chyba z wyliczeń nie ma różnicy jaki jest zakres local_ms (czy może się mylę?)? Więc wystarczy w takim wypadku jedno przypisanie, tak? Poza tym to dlaczego rzutowanie do unsigned longa? Potrzebuje typu tylko dwubajtowego (bo OCR1A ma dwa bajty), a z tego co wiem to long ma w zależności od urządzenia 4 lub 8 bajtów? Jest tu jakiś trik, którego nie znam a warto z niego korzystać?
  • REKLAMA
  • #5 12845164
    tmf
    VIP Zasłużony dla elektroda
    Poczytaj o domyślnej promocji typów w C. Problem leży w tym, że o ile nie wskażesz inaczej, wszelkie operacje prowadzone są na literałach tak, jakby miały typ int. Pomnóż teraz podane wartości i zastanów się dlaczego nie mogą być większe. Z kolei promocja do UL daje ci to, że pośrednie wyniki obliczeń mogą być 32-bitowe, co upraszcza wiele rzeczy.
  • Pomocny post
    #6 12845180
    BlueDraco
    Specjalista - Mikrokontrolery
    Pomyśl, jaki jest zakres każdego z wyrażeń:
    14400 * local_ms
    144 * local_ms
    72 * local_ms

    oraz które z nich przy jakiej wartości local_ms przekroczy wartość 32767.
REKLAMA