Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Solved] Odczyt wartości Timera1 błędne wyniki

m72 11 Mar 2020 03:48 858 29
  • #1
    m72
    Level 12  
    Celem jest zrobienie funkcji zliczającej czas między przerwaniami generowanymi przez zewnętrzny generator (docelowo będzie to obrotomierz). Generator jest precyzyjny, AD9850. Na wejście zapodaje prostokąt o różnym od 50% stopniu wypełnienia ale to właśnie nie powinno mieć znaczenia. Wyjaśniam.

    W poniższym kodzie korzystam z funkcji micros która mierzy czas od włączenia kontrolera, robię różnice i wyświetlam przez Seriala.

    Code: c
    Log in, to see the code


    Wyniki są błędne w pewnym znaczeniu bo np przy 10Hz dostaje...
    Code:

    Roznica: 45276
    Roznica: 55032
    Roznica: 45276
    Roznica: 55036
    Roznica: 45276
    Roznica: 55032
    Roznica: 45280
    Roznica: 55028
    Roznica: 45276
    Roznica: 55032





    Wynikiem są naprzemiennie lecące 2 bardzo zbliżone wartości. Tak się dzieje niezależnie od zapodanej częstotliwości.
    Zauważyć należy że jeśli weźmiemy parę dwu kolejnych liczb to wynik się zgadza. W tym przypadku dla 10Hz 45276+55032=100308 czyli jest OK.

    Mój wniosek jest taki że przerwanie się wykonuje zarówno na opadającym o rosnącym zboczu a jako że stopień wypełnienia nie jest 50% to wynikiem są właśnie takie pary liczb odzwierciedlające poszczególne połówki okresu a nie cały okres (raczej poprawnie zmierzone).

    Pierwotnie nie korzystałem z funkcji micros tylko na piechotę odczytywałem stan timera1 i go zerowałem i wyniki były takie same (w taktach licznika oczywiście a nie mikrosekundach) .
    Code: c
    Log in, to see the code


    Pytanie, czy wg fachowców faktycznie problem jest z wywołaniem przerwania na obydwu zboczach zamiast jednego ?
    Jeśli tak to gdzie tkwi błąd.
  • #3
    n6210
    Level 29  
    W tym pierwszym kodzie gdzie jest nadawana wartośc (również początkowa) zmiennej roznica_old ? nie widze jakoś, a używasz jej do porównania i do roznica=roznica_old; może miało być odwrotnie? roznica_old = roznica;
  • #4
    m72
    Level 12  
    n6210 wrote:
    W tym pierwszym kodzie gdzie jest nadawana wartośc (również początkowa) zmiennej roznica_old ? nie widze jakoś, a używasz jej do porównania i do roznica=roznica_old; może miało być odwrotnie? roznica_old = roznica;


    No tak, racja, poprawione ale to nic nie zmieniło.
    Jestem pewien że problem jest wyzwalaniu przerwania na obydwu zboczach. To nawet na oko widać że odczyt idzie 2x na sekundę zamiast 1x.
  • #5
    onehour
    Level 11  
    Pomijając serial i nadawanie wartości początkowych zmiennym to zdaje się, że Twoim zamierzeniem było aby instrukcja warunkowa była spełniona zawsze zakończeniu obsługi przerwania. W obecnym programie warunek jest spełniony jeśli aktualna różnica (roznica) ma inną wartość niż poprzednia (roznica_old), czy tak się dzieje po zakończeniu każdego przerwania. Co w sytuacji kiedy następujące po sobie wartości są identyczne...?
  • #6
    m72
    Level 12  
    onehour wrote:
    Pomijając serial i nadawanie wartości początkowych zmiennym to zdaje się, że Twoim zamierzeniem było aby instrukcja warunkowa była spełniona zawsze zakończeniu obsługi przerwania. W obecnym programie warunek jest spełniony jeśli aktualna różnica (roznica) ma inną wartość niż poprzednia (roznica_old), czy tak się dzieje po zakończeniu każdego przerwania. Co w sytuacji kiedy następujące po sobie wartości są identyczne...?


    Nie, wyświetlenie wyników ma się pojawić tylko wtedy gdy wartość obrotów się zmieni. Jak jest taka sama jak poprzenia to się ma dziać NIC :) bo i po co ma się coś dziać.
  • #7
    n6210
    Level 29  
    m72 wrote:
    To nawet na oko widać że odczyt idzie 2x na sekundę zamiast 1x.
    To pytanie jaką zapodałeś czestotliwość? 1Hz? Wcześniej pisałeś o 10Hz. Dodatkowo wyniku nie buforujesz w żaden sposób, a jest to int - czyli wartość tej zmiennej (jej bajtów składowych) może ulec zmianie w przerwaniu podczas trwania funkcji pirintf. Ba ustawiając że jest ona volatile nawet chcesz sobie taki proces najwyraźniej zagwarantować. Nie do końca to rozumiem. To jak procedura obsługi przerwania reaguje na zbocza to jeszcze inny temat osobiście nie miałem z tym problemu ale jak się obawiasz, ze działa to źle zrób na początku funkcji test stanu linii np dla zbocza opadającego:
    if (checkPin == LOW) wtedy wykonujesz twoje pomiary.
  • #9
    m72
    Level 12  
    Problemem jest wyzwalanie przerwania na obydwu zboczach i nie ma co filozofować.
    Nagrałem filmik na którym to widać jak byk i tu trzeba szukać problemu.
    Dla najprostszego skeczu który tylko zmienia stan na wyjściu problem jest ten sam.
    Code: c
    Log in, to see the code



  • #11
    m72
    Level 12  
    n6210 wrote:
    Napisałem ci jak upewnić się, ze liczysz tylko wtedy gdy potrzebujesz, ale to z jakiegoś powodu ignorujesz wiec... powodzenia


    Czy ty w ogóle przeczytałeś post powyżej ?
  • #12
    khoam
    Level 41  
    m72 wrote:
    Dla najprostszego skeczu który tylko zmienia stan na wyjściu problem jest ten sam.

    Spróbuj może tego "skeczu":
    Code: c
    Log in, to see the code
  • #14
    khoam
    Level 41  
    ekrzychoooo wrote:
    Wrzuciłem to do pro-mini i program z postu #9 i postu #12 dają ten sam efekt.

    W tym wypadku tak, ponieważ zmienna state jest typu atomowego - przykład wrzuciłem bardziej pod potrzeby kodu z postu pierwszego.
  • #15
    ekrzychoooo
    Level 17  
    khoam wrote:
    Wrzuciłem to do pro-mini i program z postu #9 i postu #12 dają ten sam efekt.

    W tym wypadku tak, ponieważ zmienna state jest typu atomowego - przykład wrzuciłem bardziej pod potrzeby kodu z postu pierwszego.

    Chodziło mi o to że u mnie jest inaczej niż na filmie z #9
  • #16
    m72
    Level 12  
    Dobra, Panowie działa, jak ktoś mówił że problem jest z generatorem to miał racje.
    Dałem kondensator między generator a nano i działa.
    Mimo tego plan jest do bani bo powyżej około 20Hz chyba zaczynają na siebie włazić funckje print i przerwanie - zaczynają się duże wahania odczytów. Dla wolniejszych częstotliwości jest super.

    Pewnie trzeba będzie jedno nano poświęcić tylko na odczyt tajmera i jakoś przez SPI wysyłać do drugiego.l
  • #17
    ekrzychoooo
    Level 17  
    m72 wrote:
    Pewnie trzeba będzie jedno nano poświęcić tylko na odczyt tajmera i jakoś przez SPI wysyłać do drugiego.l
    dlatego wymyślono tryb capture aby nie robić takiej ekwilibrystyki.
    Nie podałeś jaka częstotliwość Cię interesuje
  • #18
    khoam
    Level 41  
    m72 wrote:
    Mimo tego plan jest do bani bo powyżej około 20Hz chyba zaczynają na siebie włazić funckje print i przerwanie

    Przy użyciu ATOMIC_BLOCK(ATOMIC_RESTORESTATE też? Jeżeli tak, to pokaż proszę kod.

    m72 wrote:
    Pewnie trzeba będzie jedno nano poświęcić tylko na odczyt tajmera i jakoś przez SPI wysyłać do drugiego.l

    Nie sądzę.
  • #19
    m72
    Level 12  
    A co to takiego to capture ?
    A częstotliwości to takie jak powiedzmy w bardzoszybko obrotowych silnikach powiedzmy 12000obr/min czyli do 200Hz
    Od biedy można zastosować jakiś filtr typu średnia ciągniona ale wolałbym żeby to był pomiar dokładny a nie uśredniany

    Dodano po 4 [minuty]:

    khoam wrote:
    m72 wrote:
    Mimo tego plan jest do bani bo powyżej około 20Hz chyba zaczynają na siebie włazić funckje print i przerwanie

    Przy użyciu ATOMIC_BLOCK(ATOMIC_RESTORESTATE też? Jeżeli tak, to pokaż proszę kod.

    m72 wrote:
    Pewnie trzeba będzie jedno nano poświęcić tylko na odczyt tajmera i jakoś przez SPI wysyłać do drugiego.l

    Nie sądzę.



    Code: c
    Log in, to see the code
  • #20
    n6210
    Level 29  
    m72 wrote:
    Czy ty w ogóle przeczytałeś post powyżej ?
    tak i jak juz wiesz nic sensownego tam nie bylo... :)
    khoam podał ci sposób zabezpieczania kodu z wykorzystaniem ATOMIC_BLOCK(ATOMIC_RESTORESTATE){} i nie ma tego u ciebie w kodzie powyżej... czytałeś jego posty? :cunning:
  • #21
    khoam
    Level 41  
    Kod poniżej. Zmieniłem parametr w Serial.begin() na 115200 - trzeba przestawić monitor portu szeregowego.
    Code: c
    Log in, to see the code
  • #22
    m72
    Level 12  
    Nie ma poprawy, wyniki są takie.
    Przy 10Hz rozrzut wyników jest na poziomie 20-30us czyli bomba

    Code:


    Roznica: 100328
    Roznica: 100296
    Roznica: 100336
    Roznica: 100312
    Roznica: 100292
    Roznica: 100328
    Roznica: 100312
    Roznica: 100308
    Roznica: 100312
    Roznica: 100308
    Roznica: 100312



    to już przy 100Hz jest raczej mina poślizgowa, prawie 1000us

    Code:



    Roznica: 5492
    Roznica: 4524
    Roznica: 5496
    Roznica: 4520
    Roznica: 5496
    Roznica: 4524
    Roznica: 5488
    Roznica: 4528
    Roznica: 5492
    Roznica: 4524
    Roznica: 5492



    Chyba nie ma co drążyć tematu póki nie zrobię porządku od strony elektrycznej bo widzę że znów wyniki idą stabilnie ale co drugi :) Może puszczę to przez jakiś przerzutnik szmita alboco żeby sygnał wyczyścić
  • #23
    khoam
    Level 41  
    m72 wrote:
    bo widzę że znów wyniki idą stabilnie ale co drugi :) Może puszczę to przez jakiś przerzutnik szmita alboco żeby sygnał wyczyścić

    Na wejściu w atmedze jest już przerzutnik schmitta. Raczej masz problem z zakłóceniami.

    m72 wrote:
    Przy 10Hz rozrzut wyników jest na poziomie 20-30us czyli bomba

    Dokładniej z użyciem micros() to raczej nie będzie. Ta funkcja też korzysta z przerwań, więc może dawać nieco rozbieżne wyniki od rzeczywistych - przy blokowaniu przerwań wstrzymywane jest odliczanie dla micros().
  • #24
    m72
    Level 12  
    khoam wrote:

    Dokładniej z użyciem micros() to raczej nie będzie.


    Napisałem bomba w sensie że super.
    EDIT:


    Problem rozwiązany, pobawiłem się z kondensatorami, na wejściu i jest rewelacja.

    Code:
    Roznica: 5008
    
    Roznica: 5004
    Roznica: 5012
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004
    Roznica: 5012
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004


    To są wyniki dla 200Hz. Czego chcieć więcej :)

    Kolega Elvis na forum arduino pomierzył generator AD9850 i się okazało że on strasznie syfi na zboczu. To był problem.


    OBRAZEK
  • #25
    JacekCz
    Level 39  
    n6210 wrote:
    Ba ustawiając że jest ona volatile nawet chcesz sobie taki proces najwyraźniej zagwarantować.


    Dla przypomnienia: volatile:
    GWARANTUJE: odczyt sensownej liczby, tj wszystkie bajty z tej samej chwili czasowej, i jest to jedyna gwarancja
    NIE GWARANTUJE operacji inkrementowania, lub odczyt-zmiana-zapis. Tu by ewentualnie tzreba mówić o synchronizacji, wyłączaniu przerwań itd...
  • #26
    khoam
    Level 41  
    JacekCz wrote:
    Dla przypomnienia: volatile:
    GWARANTUJE: odczyt sensownej liczby, tj wszystkie bajty z tej samej chwili czasowej, i jest to jedyna gwarancja

    Niezupełnie. Kwalifikator volatile instruuje kompilator, że zmienna ma być przechowywana tylko w pamięci (a nie np. w rejestrach MCU), przez cały czas jej życia w programie. Operacje na zmiennych volatile nie są operacjami atomowymi.

    https://en.cppreference.com/w/c/language/volatile
  • #27
    ekrzychoooo
    Level 17  
    JacekCz wrote:
    Dla przypomnienia: volatile:
    GWARANTUJE: odczyt sensownej liczby, tj wszystkie bajty z tej samej chwili czasowej, i jest to jedyna gwarancja
    NIE GWARANTUJE operacji inkrementowania, lub odczyt-zmiana-zapis. Tu by ewentualnie tzreba mówić o synchronizacji, wyłączaniu przerwań itd...

    A nie jest tak że volatile mówi kompilatorowi nie optymalizuj mnie(wszystkie operacje na zmiennej dokonuj na pamięci która została przydzielona dla zmiennej)?
    Volatile właśnie chyba nie zapewnia operacji atomowej o czym ju8ż tu inni pisali.
  • #28
    n6210
    Level 29  
    Nie rozumiem o co dyskusja. @JacekCz wyrwał zdanie z kontekstu gdzie właśnie mówiłem, że kolega wręcz chciał sobie zapewnić brak atomowości operacji przez działanie na zmiennej w RAM (co napisał też @khoam), a to w tym wypadku działanie błędne. Czemu napisałem zapewnić? Bo gdyby optymalizacja zrobiła lokalną kopię tej zmiennej w rejestrach to może zaistaniała by szansa, że przerwanie by nie modyfikowało wartości użytych do konwersji. Co więcej @khoam podał gotowy kod więc starczyło go użyć... co ostatecznie się stało.
    Jak widać starczy dokładnie poczytać i nie ma o co się spierać bo wszystko było już jasne przed dyskusją :)
  • #29
    LChucki
    Level 31  
    m72 wrote:

    Napisałem bomba w sensie że super.
    EDIT:
    Problem rozwiązany, pobawiłem się z kondensatorami, na wejściu i jest rewelacja.
    Code:
    Roznica: 5008
    
    Roznica: 5004
    Roznica: 5012
    Roznica: 5008
    Roznica: 5004
    Roznica: 5008
    Roznica: 5004

    To są wyniki dla 200Hz. Czego chcieć więcej :)

    Jak dla mnie to wynik nie super ale tylko akceptowalny. Widać, że przerwania powodują błędne odczyty bo wartość nominalna, jak się można domyślać 5004 skacze do nawet 5012. Daje to błąd niby tylko około 0,16% ale to aż 1600ppm! Najgorszy kwarc to 50ppm ale dokładność a nie stabilności, bo stabilność krótkoterminowa to kilka ppm. Problem by nie istniał gdyby użyć trybu ICP timera o czym już wcześniej było napisane. Nie tylko odczyt byłby stabilny ale i kod byłby krótszy.

    Dodano po 7 [minuty]:

    m72 wrote:
    Przy 10Hz rozrzut wyników jest na poziomie 20-30us czyli bomba

    Na 90% przerwanie od uart daje te 30us odchyłki albo nałożenie przerwania UART na przerwanie timera. Samo przerwanie od timera0 to pewnie 10-15us.
  • #30
    m72
    Level 12  
    Problem nieaktualny zamykam temat