Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Przerwania i PWM, ATmega8A - Brak reakcji na wektory przerwań

Bartosz36 22 Mar 2015 00:43 2109 49
  • #1 22 Mar 2015 00:43
    Bartosz36
    Poziom 12  

    Witam,
    Jako początkujący zmierzyłem się z zagadnieniem przerwań i PWM próbując sterować serwomechanizmami podpiętymi do PB1, PB2. Sterowanie ma odbywać się za pomocą potencjometrów, jak w jednym z przykladów Arduino.
    Początkowo problem rozwiązałem nie wykorzystując przerwań, a jedynie zapisując wartość odczytaną z ADC do tablicy, która następnie wysyłała je do serwomechanizmów. Efekt był taki, iż owszem - działało, jednak serwomechanizmy trzęsły się niczym w ataku padaczki a ich ruch i sterowanie nimi było bardzo... niepłynne.
    Następnym krokiem było wykorzystanie przerwań. Tu pojawił się problem stricte dotyczący tematu.

    Jakikolwiek wektor nie zostałby przekazany silniki nie reagują na zmianę wartości ADC. Moje podejrzenia są takie, iż zwyczajnie przerwanie nie następuje. Poniżej wrzucam listing, zerknijcie i powiedzcie o czym zapomniałem, lub jakie błędy popełniłem. Jakbym coś niejasno napisał, to pytać :)

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Z góry dzięki :)
    Pozdrawiam

    0 29
  • Pomocny post
    #2 22 Mar 2015 07:44
    Zaquadnik
    Poziom 27  

    Z tego co widzę, nie włączyłeś przerwania od ADC. Nie widzę ustawienia bitu ADIE w rejestrze ADCSRA.

    1
  • #3 22 Mar 2015 12:37
    Bartosz36
    Poziom 12  

    Rzeczywiście, zapomniałem o tym. Dzięki wielkie :)
    A co z drganiami serwomechanizmów? Po ustawieniu potencjometru na danej pozycji orczyk skokowo obraca się w to położenie, ale nie jest w stanie dopasować się do zadanego kąta, więc wykonuje "szarpnięcia" oscylując wokół danego kąta.
    Jak pozbyć się tego efektu? Czy wartość przekazywana do OCR1B/A jest prawidłowa?

    0
  • #4 22 Mar 2015 15:14
    Zaquadnik
    Poziom 27  

    Wartość z ADC nie będzie tak stała, jak Ci się wydaje. Aby ograniczyć drgania serwa możesz użyć jednej z dwóch metod.
    1. Możesz ograniczyć wynik z ADC do 8-miu najstarszych bitów.
    2. Możesz dodać uśrednianie wyniku z ADC, zwykła średnia krocząca (moving average) za x próbek (x dowolne całkowite =]). Im dłuższa średnia, tym mniej wynik z ADC będzie oscylował.
    3. Możesz połączyć obie metody.

    0
  • #5 22 Mar 2015 15:44
    Bartosz36
    Poziom 12  

    Dzięki za odpowiedź Zaquadnik :D
    Do ośmiu najstarszych, czyli jeśli dobrze rozumiem wyrównać wynik do lewej ustawiając bit ADLAR rejestru ADMUX, czy też po prostu odczytywać wynik jedynie z rejestru ADCH bez uprzedniego wyrównywania?
    Po drugie w jaki sposób mogłoby to ograniczyć drgania? Bo rozumiem, że wynik odczytany jedynie z najstarszych bitów plus średnia sprawi, że wynik pozbawiony będzie niewielkich mało znaczących wartości: zamiast 123,46 będzie 120?
    Wyprowadźcie mnie z błędu jakby co :P

    0
  • #6 22 Mar 2015 15:55
    Zaquadnik
    Poziom 27  

    Cytat:

    Do ośmiu najstarszych, czyli jeśli dobrze rozumiem wyrównać wynik do lewej ustawiając bit ADLAR rejestru ADMUX, czy też po prostu odczytywać wynik jedynie z rejestru ADCH bez uprzedniego wyrównywania?


    Tak, dokładnie tak.

    Cytat:

    Po drugie w jaki sposób mogłoby to ograniczyć drgania?


    Te dwa najmłodsze bity są najbardziej "zaszumione". One najbardziej oscylują przy pomiarze, wydawałoby się, stałego napięcia. Ich obcięcie sprawi, że dana z ADC będznie nieco mniej "pływać".

    Cytat:

    Bo rozumiem, że wynik odczytany jedynie z najstarszych bitów plus średnia sprawi, że wynik pozbawiony będzie niewielkich mało znaczących wartości: zamiast 123,46 będzie 120?


    Wynik będzie oczywiście mniej dokładny. Jeśli zależy Ci na większej ilości bitów zastosuj nadpróbkowanie. W celu zwiększenia rozdzielczości o 1 bit musisz czterokrotnie zwiększyć częstotliwość próbkowania. Aby uzyskać wynik, uśredniasz za tyle próbek, ile wynosi "ktrotność" nadpróbkowania. Mam nadzieję, że wyjaśniłem to jasno, jeśli nie to zerknij na artykuł o nadpróbkowaniu.

    0
  • #7 22 Mar 2015 16:21
    BlueDraco
    Specjalista - Mikrokontrolery

    Kol. Zaquadnika radziłbym nie słuchać, bo dziwne i nieprawdziwe rzeczy wypisuje.

    Pierwszy problem, to mało sensowne użycie ADC. Odczytuj go i startuj go w przerwaniu timera i nie używaj przerwania ADC (które zresztą jest w Twoim kodzie całkowicie błędne).

    Odczyty ADC należy filtrować (przeszukaj forum - pokazałem taki przykład z miesiąc temu) - jest to łatwiejsze i szybsze, niż uśrednianie. Nie ma sensu obcinanie ostatnich bitów, bo te nieobcięte będą "latały" równie dobrze, jak obcięte. Dodatkowo można też "filtrować" sterowania serw, np. poprzez inkrememtację lub dekrementację wartości wypełnienia zamiast ustawiania go na wartość wynikającą bezpośrednio z odczytu ADC.

    0
  • #8 22 Mar 2015 16:25
    Bartosz36
    Poziom 12  

    BlueDraco Na czym polega błąd w przerwaniu z wektorem ADC?

    0
  • #9 22 Mar 2015 17:19
    Zaquadnik
    Poziom 27  

    Tym razem z kol. BlueDraco się nie zgodzę. To, że jego rozwiązanie jest być może lepsze nie znaczy, że piszę źle. U kolegi Bartosza brakowało rzeczywiście ustawienia bitu włączającego przerwanie w ADC.

    Niemniej jednak, w moich programach najczęściej ADC wyzwalam timerem. Próbowałem używać trybu free run i działało to cokolwiek dziwnie.

    Kolega Blue Draco prawdopodobnie chciał zasugerować właśnie takie rozwiązanie. Ustawiasz timer tak, aby generował przerwanie co określony czas, w nim inicjujesz konwersję ADC, a w przerwaniu od ADC daną z rejestru ADC przepisujesz do bufora, z którego później korzystasz w głównej pętli. Dodatkowo możesz zrobić programową flagę, którą ustawisz w przerwaniu od ADC, aby poinformować główną pętlę, że dane od ADC są już dostępne. Jeśli próbkujesz kilka kanałów, robisz kilka flag, każda informuje, że dana z danego kanału jest dostępna. W pętli głównej robisz warunek sprawdzający daną flagę. W nim ją czyścisz i obrabiasz daną z ADC. To tak z grubsza.

    0
  • #10 22 Mar 2015 17:41
    Bartosz36
    Poziom 12  

    To jeszcze dwa pytania:
    Jeśli ADC wyzwalam timerem, to jak ustawić czas, po jakim nastąpi przerwanie? Po drugie, jeśli w ISR(Timer0_vect) ma następować konwersja, to po co drugie przerwanie z wektorem ADC_vect w którym następuje filtracja?
    Wybaczcie, że nie wszystko rozumiem, ale jestem jeszcze początkujący :P

    0
  • Pomocny post
    #11 22 Mar 2015 17:43
    BlueDraco
    Specjalista - Mikrokontrolery

    Free run plus przerwania - to gotowy kłopot. W kodzie Autora jest znacznie poważniejszy błąd - gotowość ADC jest testowana w pętli, a niedziałające przerwanie ADC nie odczytuje danych z ADC.

    Natomiast sugestia, jakoby ignorowanie bitów ADC poprawiało stabilność jest całkowicie błędna. To tak, jak byś sugerował, że w celu poprawienia wahania odczytów pomiędzy 99 i 100 (wahania o 1 %) należy gubić cyfrę jednostek i mieć w zamian wahanie pomiędzy 9 i 10 (o 10%).

    A pomysł, żeby w przerwaniu ADC tylko czytać dane i ustawiać znacznik gotowości, jest z gatunku "przykład jak robić nie należy". Równie dobrze można w pętli sprawdzać znacznik sprzętowy znacznik gotowości ADC.

    0
  • #12 22 Mar 2015 18:01
    Zaquadnik
    Poziom 27  

    Cytat:

    Jeśli ADC wyzwalam timerem, to jak ustawić czas, po jakim nastąpi przerwanie?


    W sekcji Analog to Digital Converter dokumentacji od ATmegi jest opisane ile cykli trwa konwersja ADC. Przerwanie od timera ustawiasz tak, aby jego okres był krótszy od czasu trwania konwersji. W praktyce, czas ten powinien być dużo dłuższy.

    Cytat:

    Po drugie, jeśli w ISR(Timer0_vect) ma następować konwersja, to po co drugie przerwanie z wektorem ADC_vect w którym następuje filtracja?


    Ja tego używałem w następujący sposób. Przerwanie od Timera ustawia wymagany kanał i inicjuje konwersję. W przerwaniu od ADC mamy już gotowy wynik konwersji. Ów wynik wpisywałem sobie do zmiennej globalnej (z modyfikatorem volatile) i, poprzez flagę, informowałem pętlę główną o dostępności danych. Z tym, że u mnie próbkowałem równolegle 5 kanałów ADC z dwiema różnymi częstotliwościami.

    0
  • #13 22 Mar 2015 20:02
    BlueDraco
    Specjalista - Mikrokontrolery

    Co więcej, wynik konwersji ADC jest gotowy zwykle przed wyjściem z przerwania timera lub tuż po nim, ale żeby go odczytać, musimy poczekać na wyjście z przerwania timera i wejście w przerwanie ADC, co zajmuje min. 20 cykl procesora. Realnie będziemy potrzebować tego wyniku dopiero przy następnym przerwaniu timera (bo przecież następną konwersję zainicjuje timer), ale za to mamy satysfakcję, że odczytaliśmy go wcześniej, marnując kilkadziesiąt cykli procesora.

    ;)

    Przerwanie ADC na ogół sensu nie ma, a tu mamy ewidentnie do czynienia z przypadkiem "na ogół".

    0
  • #14 22 Mar 2015 20:27
    Bartosz36
    Poziom 12  

    Czyli wykorzystywać tylko przerwanie TIMER0_OVF_vect? Próbowałem to zrobić, ale serwa zwyczajnie nie reagują, nie ruszają się - czyli wracam do problemu będącego de facto tematem tego tematu...
    Reasumując:
    Wykorzystuję jakiekolwiek przerwania? (jakie?)
    Jak realizuję pozbycie się "drgań" serwomechanizmów? (próbowałem zarówno sposobem BlueDraco, jak i Zaquadnik. Sposób podany przez BlueDraco działał naprawdę nieźle, ale pogubiłem się w przerwaniach :( )
    Po trzecie, czy wartość pobrana z przetwornika musi być jeszcze jakoś konwertowana, zanim wrzucę ją w OCR1A/B (dzielenie, mnożenie itp) czy też mogę wrzucać surową wartość?

    Wybaczcie taką ilość pytań, ale staram się dobrze zrozumieć temat, zanim ruszę z czymś do przodu.

    Dzięki i pozdrawiam ;)

    0
  • #15 22 Mar 2015 21:02
    BlueDraco
    Specjalista - Mikrokontrolery

    Użyj jednego przerwania od timera generującego przebieg PWM dla serw. Cały kod powinien mieścić się w przerwaniu timera - w pętli głównej tylko usypiaj procesor.

    Jeżeli po preskalerze będziesz miał zegar timera 1 MHz, to możesz użyć wartości ADC do sterowania serwem po dodaniu do niej 500. Ustaw okres na 20000, wtedy zakres ADC 0..1023 będzie odpowiadał szerokości impulsu 500..1523 us, czyli w sam raz dla serwa. Tyle, że odczyt ADC trzeba filtrować, a sterowanie "przez dodanie 500" da w wyniku drgania serwa.

    Ja bym to zrobił tak

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #16 22 Mar 2015 21:11
    tmf
    Moderator Mikrokontrolery Projektowanie

    Wrzuć poprawiony kod to zapewne powiemy ci dlaczego serwa nie reagują. Przerwanie masz wykorzystać jedno - ovf timera. Na początku przerwania odczytujesz ADC (który zawiera wynik konwersji, która zakończyła się wcześniej), po czym startujesz kolejną konwersję ADC i kończysz przerwanie. Wyniki uśredniasz tak jak pisze kol. BlueDraco. Czy wartość pobrana z przetwornika musi być jakoś obrobiona to zależy. Zapewne tak, bo serwo oczekuje impulsu w określonym przedziale, np. 1,25 do 1,75 ms - a więc wartości z ADC musisz przetworzyć tak, aby generować impuls w tym przedziale.

    Dodano po 4 [minuty]:

    BlueDraco napisał:

    Ja bym to zrobił tak

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Tylko jeśli to będzie w ISR timera, a impuls sterujący powtarzamy co 20 ms, to serwa będą się ruszać raczej powoli - na sekundę przechodzimy tylko 50 jednostek, w efekcie pełny zakres ruchu serwa może trwać kilka sekund.

    0
  • #17 22 Mar 2015 22:12
    Bartosz36
    Poziom 12  

    Dzięki za zainteresowanie panowie ;)

    Wrzucam poprawiony kod, serwomechanizmy nie reagują. Póki co zdecydowałem się w ciemno wykorzystać wartość zaproponowaną przez BlueDraco. Jeśli chodzi o prędkość serwomechanizmów, to nie jest to problem mniejsza prędkość, to w moim projekcie większa dokładność, po drugie prędkość zawsze będzie można zwiększyć. Ale oczywiście to dobra uwaga i dziękuję za nią :)

    Listing:

    Kod: C
    Zaloguj się, aby zobaczyć kod


    Chciałbym dodatkowo zapytać, co w przypadku użycia pętli while() oczekującej na zakończenie konwersji, czy jej użycie jest konieczne w przypadku pojedynczej konwersji, lub w przypadku braku przerwania wektorem ADC_vect?

    Pozdrawiam :)

    0
  • #18 22 Mar 2015 23:10
    BlueDraco
    Specjalista - Mikrokontrolery

    Problem z Twoją pętlą while() polega na tym, że ona NIE czeka na zakończenie konwersji, tylko w kółko obrabia wynik poprzedniej konwersji, bardzo intensywnie go filtrując, co ma efekt taki sam, jak brak jakiegokolwiek filtrowania. ;)

    0
  • #19 22 Mar 2015 23:34
    Bartosz36
    Poziom 12  

    Wyrzuciłem wszystko poza pętlę while()

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Ale bez zmian. Dodałem także:
    TIMSK |= _BV(TOIE0);
    w funkcji inicjalizującej timer. Co jest nie tak z moim przerwaniem? Kończą mi się pomysły... :(

    0
  • #20 23 Mar 2015 08:49
    tmf
    Moderator Mikrokontrolery Projektowanie

    Mam propozycję - odpal twój kod w symulatorze i sobie prześledź krok po pkroku co on robi i jak są ustawione poszczególne peryferia. A BTW, ten kod odczytu ADC i uśredniania to przenieś do funkcji obsługi przerwania ovf. Po co masz go w pętli głównej?

    0
  • #21 23 Mar 2015 12:46
    Bartosz36
    Poziom 12  

    Zanim odpalę symulację, muszę powalczyć z AtmelStudio... nie wiedzieć czemu wyskakuje mi błąd:

    Kod: c_loadrunner
    Zaloguj się, aby zobaczyć kod

    Jak już się coś sypie, to się wszystko sypie :(
    Spróbuję coś wykombinować. Jak odpalę symulację, dam znać.
    Kod odczytu i uśredniania przeniosłem do przerwania, ale nic to nie zmieniło.
    Pragnę zapytać, czy użyłem odpowiedniego timera: TIMER0_OVF_vect, jeśli definiuję ICR1 = 20000? Czy ta wartość jest poprawna?
    Po drugie, czy czegoś w moim kodzie brakuje, że przerwanie nie następuje?

    0
  • #22 23 Mar 2015 13:34
    szczywronek
    Poziom 27  

    Bartosz36 napisał:
    Czy ta wartość jest poprawna?
    Niet ;) Masz mały bałagan z numerami liczników:

    - Przerwanie od licznika 2: ISR(TIMER2_OVF_vect)
    - Inicjalizacja licznika 1: TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
    - Włączenie przerwania od licznika 0: TIMSK |= _BV(TOIE0);

    [znaczniki syntax pominąłem z premedytacją - w syntax'ach nie działa BBcode]

    0
  • #23 23 Mar 2015 21:57
    Bartosz36
    Poziom 12  

    Dzięki Szczywronek ;)
    Poprawiłem błędy, ustawiając wszędzie Timer jako 1. Przerwanie normalnie następuje, ale praca serwomechanizmów polega na wykonywaniu stałych ruchów od skrajnego prawo, do skrajnego lewo. Dzieje się tak dlatego, że wartość w tabeli dla każdego serwomechanizmu jest równy zero.
    Po podmianie kodu na:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    serwomechanizmy zgodnie ustawiły się w pozycji zerowej.
    Dlaczego zatem żadna wartość nie zostaje wpisana do tablicy? Czy może sam pomiar nie następuje?

    0
  • #24 24 Mar 2015 01:08
    Damian_Max
    Poziom 14  

    Witam, poniżej moje uwagi / sugestie / pytania.
    - W tym przypadku rozwiązanie z jednym przerwaniem, jest jak najbardziej ok.
    - Nie powinno się czekać w przerwaniu (mam na myśli to: 'while(ADCSRA & _BV(ADSC))').
    - Co ile jest wykonywane przerwanie (chodzi mi o wartość w ms)?
    - Czy są gdzieś ograniczenia OCR1x (coś jak: OCR1A = MAX(POZYCJA_PRAWA,MIN(OCR1A,POZYCJA_LEWA)) )?
    - Dodanie regulatora P rozwiąże problem drgania serwa.
    - Ile trwa przejście serwa od max lewej do max prawej strony (też w ms)?
    - Z czego zasilane jest serwo i ATMega?; czy to jest to samo źródło?
    - Czy są dodane niezbędne elementy filtrujące takie jak kondensatory; ile i gdzie?
    - Fajnie byłoby zobaczyć schemat - głównie chodzi o zasilanie i tor pomiarowy.

    0
  • #26 24 Mar 2015 13:21
    Bartosz36
    Poziom 12  

    Witam,
    1. Oczekiwanie w przerwaniu wyraźnie nie wpływa na przebieg przerwania (w moim przypadku. Ale ogólnie wiem, że oczekiwać w przerwaniu nie należy :) )
    2. Nie bardzo wiem, jak zdefiniować czas określony na przerwanie, próbowałem bitem TCNT, ale bez rezultatów - tutaj proszę o szybkie wytłumaczenie definiowania okresu przerwań ;)
    3. Ograniczeń nie stosowałem, nie wydawały mi się konieczne. Dodatkowo patrząc na linijkę napisaną przez Ciebie nie bardzo rozumiem gdzie miałaby ona działać i w jaki sposób wpływać na pracę serwomechanizmów.
    4. Źródło zasilania początkowo było to samo - niestety prosto z programatora. Potem zostało zmienione na oddzielne, biorąc pod uwagę szpilki, ale nie poprawiło to ani ich pracy, ani wykonywania się samego programu
    5. Kondensatory jak najbardziej. 100nF sprzęgające zasilanie VCC i AVCC z masą, dodatkowo dławik przy wejściu AVCC.
    6. Schemat wrzucę wieczorem (uczelnia)
    Wrzucam poniżej listing kodu po poprawkach:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Pozdrawiam :)

    0
  • Pomocny post
    #27 24 Mar 2015 15:45
    BlueDraco
    Specjalista - Mikrokontrolery

    I cały czas masz podstawowe błędy w obsłudze ADC. Zapuść pojedynczy pomiar ADC pod koniec obsługi przerwania timera, odczytaj jego wynik w następnym przerwaniu i zapuść następny pomiar - na nic nie musisz czekać, ani sprawdzać bitu gotowości.

    0
  • #28 24 Mar 2015 18:14
    Damian_Max
    Poziom 14  

    szczywronek:
    Tu mój błąd, nie doczytałem, ze potencjometry są elementami nastawczymi, wiec całe moje zdanie niema sensu.

    Bartosz36 :
    Ad 1. Zgadzam się z Tobą, prawie napewno masz rację; chyba, że przerwanie trwa 12 sekund a wywoływane jest co 10 sekund.
    Ad 2.
    Niema tu żadnych haczyków, chodzi mi o czas - co który wywoływane jest przerwanie (najlepiej podany w milisekundach), albo np: 4 razy na sekundę. (Niemam tu na myśli czasu trwania funkcji przerwania.)
    Ad 3.
    Zauważyłem że piszesz coś takiego: OCR1B--;, bez kontroli czy wartość OCR1B nie zjedzie poniżej zera, co spowoduje że wartość będzie wynosiła 65535.
    Nie wnikałem w cały Twój kod, więc coś takiego może wogóle niemieć miejsca.
    W Twoim przypadku wartość licznika ma sens tylko w przedziale od 15 do 75 (wnioskuję na podstawie Twoich define-ów), reszta wartości jest błędna. A jak pisałem, nie znalazłem miejsca które by to pilnowało.
    Ad 4, 5, 6.
    Brzmi okej, mając schemat będzie łatwo znaleźć błędy związane z zasilaniem.
    W internecie jest sporo artykułów jak zasilać i jak nie zasilać układu: ATMega + silnik / serwomechanizm.

    Możesz dla testu skompilować z taką funkcją main:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Dodatkowo niepokojąco wygląda ta linia (głównie ta ostatnia pięćsetka):
    Code:
    TablicaSerwomechanizmow[i] = WartoscADC + 500;


    BlueDraco
    Także bym tak zrobił.


    EDIT:
    Polecam dopisanie w nagłówku pliku konfiguracji fusebit-ów.

    0
  • #29 24 Mar 2015 18:33
    Bartosz36
    Poziom 12  

    Odpowiadając na post BlueDraco zamieszczam kod z poprawkami:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Mam nadzieję, że tym razem ma on nieco więcej sensu, w razie czego proszę o kolejne uwagi (każda jest dla mnie cenna :D )

    Kolego DamianMax Podobny kod kompilowałem już dwa razy (jednak tylko raz z przerwaniem) efekt był oczywisty - silniki pracują jak należy dla wartości poza przerwaniem. Potem cisza.
    Co do wartości wykraczającej poza zakres zgadzam się w stu procentach. Jest to poważny problem jeśli nie znamy dokładnego przelicznika wartości ADC i tej zmierzonej z potencjometrów na wartość akceptowaną przez serwomechanizmy. Stąd właśnie losowa wartość 500 która, de facto, zmieniana była wieeele razy na inne. Bez rezultatu. Obecnym problemem jest jednak jedynie to, że wartość w tabelce wynosi zawsze zero, nawet po wprowadzeniu ostatnich poprawek.

    Proszę o sprawdzenie mojego toku rozumowania. Schemat niedługo się pojawi ;)

    0
  • #30 24 Mar 2015 18:37
    Damian_Max
    Poziom 14  

    Jeżeli do liczby całkowitej dodatniej mniejszej od 65035 dodasz 500 to zawsze będzie ona większa od 75.


    EDIT:
    W funkcji SterujSerwomechanizmami nie musisz inkrementować i dekrementować liczników, wystarczy coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod



    EDIT2:
    Z tego:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    wynika, że nie jest obsłużony wypadek gdy OCR1A jest równy TablicaSerwomechanizmow[0]. Czyli zawsze będzie oscylować.


    EDIT3:
    Korzystasz ze zmiennej SredniaADC, której nigdy nie inicjujesz, więc jej początkowa wartość jest z przedziału 0 - 65k.
    Po drugie proponował bym ją usunąć ze zmiennych globalnych i zadeklarować wewnątrz funkcji PobierajWartosci, jako zmienną statyczną.
    Po trzecie należy dodać drugą dla drugiego serwa, lub przerobić ją na tablicę.
    Zaś zmienna WartoscADC powinna być zmienną lokalną a nie globalną.

    0