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

program w AVR błędnie zlicza impulsy z wejścia T1

mototest 25 Kwi 2008 13:24 3107 20
  • #1 5075394
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    WItam kolegów

    jest taki problem

    podaję na wejśie T1 atmega8 przy kwarcu 16Mhz impulsy o okresie 11us co daje około 90kHz i procek zlicza jak należy bo porównuję z oscyloskopem, ale problem rozpoczyna się gdy włączę INT0 na którym też są te same impulsy ,gdzie sprawdzany jest kierunek obrotu enkodera , wtedy licznik zlicza głupoty w zasadzie około dwa razy więcej niz powinien, dlaczego tak sie dzieje ? wydaje mi sie że licznik powinien działać poza programem i przerwaniami, ale skąd w ogóle bierze się dwa razy więcej impulsów ??

    test robię w bascomie

    config timer1 = counter , edge = falling
    Config Int0 = Falling


    Bogdan
  • #2 5075600
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    Witam,

    zapamiętaj sobie na zawsze, wtedy łatwiej ci będzie żyć ale także zadawać prawidłowe pytania na forum oraz o wiele łatwiej będzie ci samemu radzi sobie z podobnymi sytuacjami...

    .... nigdy nie zrzucaj winy przy tak podstawowych operacjach jeśli chodzi o dowolne procki czy układy logiczne na właśnie te układy lub firmy, które je wyprodukowały. Czyżbyś był pierwszym człowiekiem na kuli ziemskiej, który odkrył tę wadę i chcesz ją zgłosić do firmy ATMEL???? chyba nie? prawda? .... więc po pierwsze zmień ten bezsensowny tytuł tematu , który założyłeś

    zawsze w takich przypadkach szukaj winy u siebie, w swoim postępowaniu tym bardziej, że jesteś początkujący co widać ale to nie grzech. Grzechem jest tylko odkrywanie takich teorii wszechczasów po iluś tam latach obecności na rynku danego układu - a to właśnie tobie tylko się przydarzyło, jakby inni nie wykorzystwali tego licznika T1. To tytułem wstępu

    .... druga sprawa to jak zadajesz pytanie i pytasz to bądź łaskaw podać swój kod - a nie taki lakoniczny opis i jak rozumiem pewność już 100% towa, że ty wszystko dobrze zrobiłeś a procek się wykrzacza (sorry ale to bzdurne podejście)

    tego typu pytania często kończą z zerową ilością odpowiedzi albo zjechaniem za to, że w ogóle programujesz tylko w Bascomie....

    .... licząc więc, że się poprawisz i to szybko na tym forum, podpowiem chociaż nie lubię udzielać odpowiedzi na zasadzie wróżbity - a ty takiego raczej szukasz przy tak dziwnie opisanym problemie...

    ..... moim zdaniem aczkolwiek mogę się mylić, nie rozumiesz jeszcze przerwań i jak one działają, stąd twoje problemy (chyba że dokładniej opiszesz problem , pokażesz kod to wtedy dojdzie się do innych wniosków)

    otóż wyzwalasz licznik impulsem i jednocześnie przerwanie INT0. Jak piszesz impulsy mają czas ok 11uS - czyli b. krótko - tak więc generują ci się teoretycznie 2 przerwania w prawie jednym czasie - ale zawsze jedno zostanie wyzwolone wcześniej a drugie później. Co więcej gdy najpierw zostanie wyzwolone przerwanie od T1 to zaraz po nim albo w tym czasie (w zależności od tego jak ustawiasz zewzolenia na przerwania już po ich wystąpieniu - ale togo nie wiemy - bo ni pokazałeś swojego kodu) to .... w czasie gdy będzie wykonywał się kod INT0, a będzie trwał np dłużej niż 11us to chyba zrozumiałe, że stracisz co najmniej zliczenie jednego impulsu z T1

    naprawdę przemyśl to wszystko i swoje podejście i poraw się w zadawaniu pytań na na forum, a jak coś jeszcze to spokojnie dopytaj na pewno wszyscy chętnie pomogą

    pozdrawiam
  • #3 5075679
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    OK pytanie poprawiam :) nie miałem na myśli żle działającego procesora tylko mój program oczywiście.
    jesli w bascomie to będzie działać to nie będę kombinował dalej

    zmostkowałem wejścia INT0 i T1 bo to jest ten sam impuls z wyjścia A enkodera, enkoder chodzi dobrze, ale obroty są liczone źle, dobrze są liczone jeśli obraca sie bardzo powoli.
    Przerwania INT0 nie mogę wyłączyć ani na chwilę ,bo ciągle musi zliczać impulsy enkodera.

    oto kod:

    $crystal = 16000000 
    $regfile = "m8def.dat"
    Config Lcd = 16 * 2
    config timer1 = counter , edge = falling                   
    Config Int0 = Falling
    On Int0 Getencoder
    
    cha alias pind.2 'wejscia enkodera
    chb alias pind.1
    
    dim x as integer , b as byte , kat as single , obroty as word , obr as word
    dim obr_tmp as single
    
    config pind.2 = input
    config pind.1 = input
    config pind.3 = input
    config portc.5 = output
    
    enable interrupts
    enable int0
    enable timer1
    
    do
    counter1 = 0
       'pomiar ilości impulsów od T1
    waitms 100
    obroty=counter1 / 8
    home
    lcd obroty ; "  "
    loop
    
    'INT0
    getencoder:
    If Chb = 0 Then decr x Else incr x
    return



    próbowałem tez nie używać T1 i zmienna obroty była zwiększana bezpośrednio w INT0 ale skutek też był marny, sprawiało to wrażenie jakby procek się nie wyrabiał w czasie

    wtedy pętla wyglądała tak :

    do
    obroty=0     'obroty zwiększane w INT0
    waitms 100
    obroty = obroty / 8
    lcd obroty
    loop


    Proszę umieszczać listingi programów w znacznikach "Code". [c_p]
  • #4 5075759
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    po pierwsze - to coś dziwnie chyba jak dla ATmega8 zdefiniowałeś wejście T1, u ciebie to linijka chyba:

    cha alias pind.2 'wejscia enkodera 


    przecież to jest pin -nóżka do obsługi INT0, a T1 jest na Portd.5

    chyba że czegoś nie rozumiem jeszcze w twoim układzie albo nie wiem

    poza tym w przerwaniu masz:

    If Chb = 0 Then decr x Else incr x 


    no przecież po wejściu w przerwanie skoro jest wyzwalane zboczem opadającym to twoje Chb będzie zawsze w stanie 0 więc u ciebie zawsze będzie zachodził tylko warunek spełniający decr x

    zresztą nigdzie to nie jest potem używane, ale może poprostu nie pokazałeś całego kodu

    tylko co w zasadzie zlicza twój counter1 skoro wisi w powietrzu a na dodatek mówisz, że działa dobrze gdy są wolne obroty

    Dodano po 4 [minuty]:

    skoro więc napisałeś :

    Cytat:
    "zmostkowałem wejścia INT0 i T1"


    to które fizycznie nóżki w tym procku zmostkowałeś - bo coś znowu czuję, że tu jakiś bład już duży się czai poza troszkę pokręconym kodem
  • #5 5075779
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    mam jeszcze wrażenie że coś za wolno chodzi to przerwanie albo cały procesor, bo podłączyłem oscyloskop do procesora i w przerwaniu zmieniam PORTC.5 na przeciwny nic więcej nie robiąc w programie
    i na załączonym oscylogramie widać ,że zmiana stanu na porcie c.5 jest dopiero po 5us od załączenia przerwania , czy to jest normalne ?

    Na oscylogramie niebieski wykres to impuls z enkodera wyzwalający INT0 a zielony to odpowieź portu C.5

    getencoder:
    portc.5 = not portc.5
    return

    _____________________________________________________________

    wejścia T1 nie definiowałem

    1) "Cha" i "chb" to piny enkodera z tego "cha" jest na INT0
    T1 poprostu zwarłem drutem z INT0 czyli z "cha" pinD.5 i D.2

    2) "chb" nie jest 0 bo jest podciągnięte do 5V (to działa dobrze)
    na razie nie liczę tej zmiennej "X" bo tamto nie działa, ale impulsy enkodera liczy dobrze jak sprawdzałem ,czyli dodaje w prawo odejmuje w lewo.

    3) counter1 zwiększa sie w tych 100ms w pętli , od impulsów enkodera (czyli je zlicza przez 100ms)

    4) kod jest cały ,czasem dokładam wyświetlanie "x" jak potrzebuję.

    Moderowany przez crazy_phisic:

    Istnieje funkcja "Zmień" i proszę z niej korzystać. Posty scaliłem.

    Załączniki:
    • wykres.zip (98.94 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #7 5075946
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    wszystkie piny z enkodera są podciągnięte a D5 jest również na enkoderze. Załączam schemat podłączeń
    Załączniki:
    • schemat.zip (38.95 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #8 5076371
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    mototest napisał:
    mam jeszcze wrażenie że coś za wolno chodzi to przerwanie albo cały procesor,


    a ustawiłeś prawidłowo fusebity w procku żeby działał z zewnętrznym kwarcem 16MHz który podłączyłeś ????????????

    wyjmij kwarc - i jeśli zobaczysz, że procek nadal działa to będziesz wiedział, że nie przeprogramowałeś fusebitów i procek taktowany jest wewn oscylatorem o częstotliwości 1MHz ... eeeeeh
  • #9 5076477
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    mototest napisał:
    ...i na załączonym oscylogramie widać ,że zmiana stanu na porcie c.5 jest dopiero po 5us od załączenia przerwania , czy to jest normalne ?

    Jak najbardziej normalne :|
    W kodzie jaki podałeś , od momentu wystąpienia zbocza opadającego na INT0 , do zmiany stanu na PORTC.5 , procek musi wykonać "pracę", która zajmuje mu około 60 cykli zegara.

    Piotrek
  • #10 5076507
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    oczywiście że fusebity są OK, z tym nie mam problemu.

    W takim razie mam wrażenie że AVRy są za wolne do tego zadania, co myslicie ? mój enkoder ma 5000 impulsów na obrót i może kręcić do 6000 obrotów/min ja będę potrzebował jakieś 3000 obrotów/min. co jak się nie mylę daje impuls co 4us, więc chyba zostaje jakiś ARM...
  • #11 5076562
    PietrekDer
    Poziom 13  
    Posty: 134
    Pomógł: 1
    Ocena: 5
    No tak, zapewne procek dalej korzysta z wewnętrznego generatora RC, dlatego wydaje Ci się że wolno chodzi. Po drugie, widzę, że licznik T1 "pokazuje" wynik z częstotliwością 10 pomiarów na sekundę, co 100ms go zerujesz. Do tego celu użyłbym jakiegoś licznika T0 lub T2, by dokładniej odmierzyć te 100ms, tak to wyniki mogą odbiegać od rzeczywistości, ale w jakim stopniu to nie wiem. Proponuję zrobić sobie z tego małe "doświadczenie" pt. "odchylenia w pomiarach z zastosowaniem Bascomowego <<waitms>> a sprzętowego licznika".
  • #12 5076577
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    ja nie potrzebuję dokładnie obliczać tych obrotów więc 100ms mi wystarcza, tutaj wyłącznie chodzi o sprawę nieprawidłowego zliczania impulsów przez T1 gdy chodzi INT0 , nad innymi sprawami nie ma się co zastanawiać bo działaja dobrze. Jak już pisałem FUSE bity są OK
  • #13 5076599
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    mototest napisał:
    ... tutaj wyłącznie chodzi o sprawę nieprawidłowego zliczania impulsów przez T1 gdy chodzi INT0...

    To raczej przerwanie źle zlicza impulsy , a nie T1.Procedurę przerwania napisz w assemblerze , a M8 się wyrobi :D

    Piotrek
  • #14 5076643
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    w C dałbym rady , ale asembler odpada, nie trybię go :)
  • #15 5076659
    PietrekDer
    Poziom 13  
    Posty: 134
    Pomógł: 1
    Ocena: 5
    Mam rozumieć, że układ zliczał prawidłowo, jeśli nie wykorzystywałeś INT0.
    Jeśli tak, to ja mam taką teorię:
    enkoder podaję impulsy o częstotliwości 250kHz (impuls co 4us), w czasie 100ms, takich impulsów może przyjść 25000. Z racji że opóźnienie jest programowe, każde wywołanie przerwania INT0, powoduje "wyskok" z procedury waitms (załóżmy że to jest taki mały wewnętrzny "podprogramik"). Bascom jest nieoptymalny, za każdym takim wywołaniem, odkłada na stos WSZYSTKIE rejestry robocze. Czyli tak: ilkadziesiąt instrukcji PUSH, później instrukcja skoku oraz kilka instrukcji w obsłudze przerwania INT0, i później instrukcje POP, załóżmy że w sumie tych instrukcji za jednym przerwaniem będzie 50. Przy zegarze 16MHz, jedna instrukcja trwa 62,5ns. Ten czas pomnóż przez 50 instrukcji = 3.125us. Czyli na oko, tyle czasu jest dodawane do późnienia waitms100 za KAŻDYM wywołaniem przerwania, pomnóż to jeszcze przez 25000, = 78.125ms. Czyli, ta duża ilość przerwań od INT0, powoduje, że do tych 100ms dodawane jest jeszcze ok 80ms na obsługę przerwań (oczywiście są to dane bardzo zbliżone, nie wiem dokładnie ile instrukcji mu zajmuje obsłużenie tego INT0, na oko wyszło ok 50). Dlatego proponuję Ci wykorzystanie sprzętowego licznika do odmierzania tych 100ms.
  • #16 5076678
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    tak ,jeśli wyłączę INT0 to sam licznik T1 liczy dobrze , jutro spróbuję, może coś pomoże
  • #17 5076746
    PietrekDer
    Poziom 13  
    Posty: 134
    Pomógł: 1
    Ocena: 5
    W takim razie wydaje mi się, że problem polega na tym o czym wspomniałem wyżej. Zapomniałem tylko o instrukcjach POP, czyli na oko będzie to chyba coś koło 70 instrukcji, czyli jakieś dodatkowe 109.375ms.
  • #18 5076965
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    w pierwszej swojej odpowiedzi na twoje pytanie jeszcze bez pokazania kodu tak na czuja podpowiadałem ci już, że właśnie problem może leżeć w tym, że procedura obsługi przerwania INT0 może się wykonywać zbyt długo i przez to następują takie rzeczy. Teraz można być tego prawie pewnym gdy się widzi kod i zna twoje zależności czasowe jeśli chodzi o ten enkoder itp.

    masz rację, wyłącz na chwilę to liczenie w INT0 i jak będzie dobrze to masz potwierdzenie na żywo tego o czym tutaj mówię ja i poprzednicy.

    pozdr

    Dodano po 3 [minuty]:

    a tak z czystej ciekawości zapytam bo sam jeszcze nie bawiłem się enkoderem - a widzę , że w Bascomie jest gotowe polecenie Encoder do obsługi tegoż - próbowałeś się nim posłużyć ????
  • #19 5077905
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    to polecenie encoder z bascoma nadaje się wyłącznie do enkodera takiego jak w radiach samochodowych itp. przy powolnym kręceniu, przy takim szybkim enkoderze nie reaguje prawie wcale, a w kazdym razie liczy głupoty... :) ,więc mozna go sobie podarować.



    sprawdziłem odmierzanie czasu 100ms na timerze i jest zdecydowana poprawa ,ale i tak od 1000obr/min przerwanie nie wyrabia w czasie, wyrabia się jak dołożę nosave w konfiguracji INT0 (widzę to na oscyloskopie) ale nie wiem jak się to nosave obsługuje bo LCD przestaje pokazywać wyniki.
  • #20 5079744
    elektrofil
    Poziom 18  
    Posty: 505
    Pomógł: 32
    Ocena: 46
    no save zastosowane w bascomie powoduje nieodkładanie niczego na stos. wtedy to na Tobie ciąży odpowiedzialność umieszczenia na stosie rejestru stanu oraz używanych przez Ciebie rejestrów Rxx oraz przed wyskokiem z podprogramu przerwania zdjęcia ze stosu poprzedniego stanu użytych rejestrów i rejestru stanu.

    jeżeli masz możliwość wyciągnięcia skądkolwiek sygnału informującego o kierunku tych obrotów ( najlepiej przez transoptor ) to odpada problem określania kierunku za pomocą enkodera i wtedy Twój program spokojnie wyrobi.

    jeżeli nie masz takiej możliwości odezwij się do mnie na gg wtedy napiszę Tobie wstawki asemblerowe.
  • #21 5084042
    mototest
    Poziom 19  
    Posty: 440
    Ocena: 4
    to jednak bascom jest powolny, bo zrobiłem to samo w C ale na procku ADUC842 też 16Mhz i tam jest tylko 1us opóźnienia od pojawienia się impulsu na INT0 do reakcji tego przerwania na inne czynności, wiec jedyną mozliwością są wstawki assemblerowe

Podsumowanie tematu

✨ Problem dotyczy błędnego zliczania impulsów na wejściu T1 mikrokontrolera Atmega8 taktowanego kwarcem 16 MHz przy częstotliwości impulsów około 90 kHz (okres 11 µs). Licznik T1 działa poprawnie, gdy jest używany samodzielnie, jednak po włączeniu przerwania INT0, które jest wyzwalane tymi samymi impulsami enkodera (podłączonymi równolegle do T1 i INT0), licznik zlicza około dwukrotnie więcej impulsów niż powinien. Problem wynika z przeciążenia procesora obsługą przerwań INT0, które przy wysokiej częstotliwości impulsów (do 250 kHz przy 3000 obr/min i 5000 impulsów na obrót) generują zbyt dużą liczbę wywołań procedury przerwania. Bascom generuje nieoptymalny kod przerwania, co powoduje znaczne opóźnienia i błędne zliczanie impulsów. Próby optymalizacji obejmują użycie opcji "nosave" w Bascom, co zmniejsza czas obsługi przerwania, ale wymaga ręcznego zarządzania rejestrami i powoduje problemy z wyświetlaniem na LCD. Sugerowano napisanie procedury przerwania w asemblerze dla lepszej wydajności, co jednak jest trudne dla autora. Alternatywnie rozważano użycie innego mikrokontrolera (np. ADUC842), który lepiej radzi sobie z szybkim przerwaniami. Dodatkowo zwrócono uwagę na prawidłowe podłączenie pinów (T1 to PD5, a INT0 to PD2) oraz konieczność podciągania linii sygnałowych. Fusebity zostały poprawnie ustawione na zewnętrzny kwarc 16 MHz. Wskazano, że licznik T1 działa niezależnie od przerwań, więc problem leży w obsłudze przerwania INT0 i przeciążeniu procesora. Propozycje rozwiązań to optymalizacja kodu przerwania, użycie asemblera lub zastosowanie sprzętowego układu do określania kierunku obrotów enkodera.
Wygenerowane przez model językowy.
REKLAMA