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

ADC- błędy poczas pomiaru na kilku kanałach

INTOUCH 21 Maj 2011 15:32 2416 24
  • #1 9529847
    INTOUCH
    Poziom 30  
    Witam.
    Pomiar dla pojedynczego kanału, który bym nie wybrał jest zawsze poprawny.
    Problem pojawia się gdy występuje multipleksowanie (zmiana kanału).
    Podejrzewam, że może być problem z przesłuchem od kanałów.

    Poniżej przedstawiam dwa kody: Proszę o pomoc bardziej doświadczonych forumowiczów o rozwiązanie problemu.

    Pomiar z wykorzystaniem pojedynczego kanału:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod



    Pomiar z wykorzystaniem kilku kanałów
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #2 9529893
    tadzik85
    Poziom 38  
    Tryb free running nie jest najlepszy przy pomiarze wielu kanałów. Zastosuj tryb single. lub pobieraj 2 pomiar z danego kanału.
  • #3 9529966
    INTOUCH
    Poziom 30  
    Czy tryb single mogę zrobić na przerwaniu.
    Nie uśmiecha mi się pisanie funkcji ponieważ kod wykonywany w pętli głównej programu może być długi.
  • #4 9529977
    tadzik85
    Poziom 38  
    oczywiście, że może po odczytanie ADC zmienia kanału ponownie startujesz ADC. i to wszystko. W twoim przypadku jest błąd bo kanał zmieniasz podczas konwersji. Stąd błędy.

    A zmiana jest prosta wyłącz free running dodaj na końcu przerwania uruchomienie przetwornika.
  • #5 9529984
    tmf
    VIP Zasłużony dla elektroda
    Błąd wynika z tego, że zmiana MUX będzie obowiązywać dopiero przy kolejnym pomiarze ADC. W momencie kiedy jesteś w procedurze obsługi przerwania pomiar już trwa. Stąd też odczytywany wynik dotyczy poprzedniego kanału, a nie tego, który aktualnie znajduje się w rejestrze MUX.
  • #6 9530242
    McMonster
    Poziom 32  
    I jeszcze zamiast starych nazw przerwań zaczynających się od "SIG_" powinno się używać tych kończących się na "_vect".
  • #7 9530413
    INTOUCH
    Poziom 30  
    Czyli krótko mówiąc muszę ustawić ADATE w stan zero i na końcu obsługi przerwania do ADSC wpisać 1.
    Potrzebuję tylko 2 kanałów w których pomiar będzie wykonywany z częstotliwością 1100Hz.
    Czy mogę do przerwania wrzucić opóźnienie?
  • #8 9530426
    tadzik85
    Poziom 38  
    nie! a jeśli chcesz próbkować określoną F proponuję pobierać 2 pomiar z próbkowania z 2xf. do wyzwalania można wykorzystać timer.
  • #9 9530435
    krru
    Poziom 33  
    Żadnych opóźnień lepiej nie umieszczaj w obsłudze przerwania. Podłącz przerwania z timera 1100 razy na sekundę, tam startuj przetwornik na jednym kanale, w pierwszym przerwaniu od ADC odczytaj wartosc i wystartuj przetwarzanie na drugim kanale, w kolejnym przerwaniu odczytaj wynik i już nie ruszaj ADC. Niech czeka na przerwanie z zegara. Będziesz potrzebował prościutki automat stanowy pamiętający, w której fazie przetwarzania jesteś, by wiedzieć co zrobić w przerwaniu od ADC. Być może da się wykorzystać do tego odczyt rejestru MUX, ale lepiej na zmiennej. Przy okazji możesz sprawdzić czy wyrabia się przetwornik (jak za szybko dostaniesz przerwanie od timera).
  • #10 9530570
    INTOUCH
    Poziom 30  
    Nadal nie działa.
    Czyta mi mi tylko z kanału 1;

    Auto wyzwalanie wyłączone.
    CLR_BIT(ADCSRA, ADATE);//AUTOWYZWALANIE WYŁĄCZONE

    ISR(ADC_vect)
    {
    pomiar[kanal]=ADC;
    ADMUX =(ADMUX & 0b11000000) + kanal;
    ++kanal;

    if(kanal > 7)
    {
    kanal = 0;
    }
    SET_BIT(ADCSRA, ADSC);
    }
  • #11 9530631
    tadzik85
    Poziom 38  
    pokaż cały kod.
  • #12 9530705
    INTOUCH
    Poziom 30  
    Wszystkie Timery będą wykorzystane do innych celów dlatego nice chcę wykorzysta któregokolwiek timera do przetwarzania ADC




    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #13 9530726
    GSM
    Poziom 25  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Nawiasem mówiąc, inkrementując zmienną 'kanal' PO ustawieniu multipleksera przy następnej konwersji do tablicy 'pomiar' do pozycji n'tej zapisze się wynik z n+1'tego kanału.
    I ja to bym zrobił raczej jakoś tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Poza tym, możesz powiedzieć na jakim mikrokontrolerze pracujesz?

    Pozdrawiam,
    GSM
  • #14 9530869
    INTOUCH
    Poziom 30  
    Mikrokontroler to ATMEGA32.

    Nie bardzo rozumiem jak to ma działać?
    Ile kanałów obsłuży poniższy kod?
    pomiary[kanal++] = ADC;
    ADMUX = 0b11000000 | (kanal & 0b00000111);
  • #15 9531064
    GSM
    Poziom 25  
    Tyle samo ile kolegi wersja - 8;
    Czego dokładnie nie rozumiesz?
    Po zakończonym pomiarze wartości napięcia na kanale N,
    zapisana zostanie wartość z przetwornika do N'tej komórki tablicy 'pomiary',
    zmienna 'kanal' zostanie zwiększona o 1,
    do rejestru ADMUX zostanie wpisany stały nastaw źródła referencyjnego 2,56V (0b11000000) zsumowany z 3 ostatnimi bitami zmiennej 'kanal' (kanal & 0b00000111).
    Gdy zmienna kanał będzie miała wartosc 7 (0b111) i zwiększymy ja o 1 otrzymamy 8 (0b1000), porzucają wszystko poza 3 najmłodszymi bitami otrzymamy liczbę 0 (0b000). Gdy 9 (0b1001) to 3 ostatnie bity będą miały wartość 1, i tak w kółko.
    Oszczędzamy sobie tym samym skoku warunkowego.

    Pozdrawiam,
    GSM
  • #16 9532879
    INTOUCH
    Poziom 30  
    Według DTR dla(0b1000) (ustawienie najmłodszych bitów) uruchamiany jest pomiar dla kanałów różnicowych. Po co miałbym przechodzić z pomiaru z pojedynczych kanałów na różnicowe?
  • #17 9532914
    tadzik85
    Poziom 38  
    Przecież kanał nigdy nie przekroczy wartości 7. Maskowane są bity od 3 w gore. czyli z 7 przeskoczysz na 0.
  • #18 9533116
    INTOUCH
    Poziom 30  
    Można jaśniej z tym maskowaniem?
    Jak dla mnie taka realizacja może zmienić stan trzech najstarszych bitów i wtedy pomiar nie będzie działa tak jak powinien.
  • #19 9533154
    tadzik85
    Poziom 38  
    gdy po kanal++ kanal wyniesie 8 czyli 0001000 maskowane jest 5 starszych bitów czyli w wyniku uzyskujesz 0

    więc w czym problem?
  • #20 9533493
    INTOUCH
    Poziom 30  
    Chodzi mi o wynik.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod



    ADMUX = 0b11000000 | (kanal & 0b00000111) dla kanału =0 ADMUX = 0b11000111

    ADMUX = 0b11000000 | (kanal & 0b00000111) dla kanału =1 ADMUX = 0b11001000
    dla wartości 0b11001000 wchodzi na pomiar różnicowy.

    Gdy ADMUX będzie miał wartość 0b11100000 włączy się bit ADLAR.

    Według mnie to tak działa. No chyba że się mylę.
  • #21 9533518
    tadzik85
    Poziom 38  
    mylisz się zapis jest poprawny i obsługa 8 kanałów różnicówka nigdy się nie włączy po kanale 7 wybrany zostanie 0 nie różnicowy.

    Ale jak nie rozumiesz zrób sobie to inaczej.

    prościej ci to zapiszę.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #22 9533568
    INTOUCH
    Poziom 30  
    Opisz mi słowami czemu się nie włączy a nie kodem.
  • #23 9533603
    tadzik85
    Poziom 38  
    bo operacja & 0b00000111 zeruje bity od 3 do najstarszego więc niemożliwe jest by bit 3 się ustawił a co za tym idzie włączył pomiar różnicowy.
  • #24 9533621
    INTOUCH
    Poziom 30  
    Wygląda na to że jeden z forumowiczów wprowadził mnie w błąd poniższą treścią
    Cytat:
    Gdy zmienna kanał będzie miała wartosc 7 (0b111) i zwiększymy ja o 1 otrzymamy 8 (0b1000), porzucają wszystko poza 3 najmłodszymi bitami otrzymamy liczbę 0 (0b000). Gdy 9 (0b1001) to 3 ostatnie bity będą miały wartość 1, i tak w kółko.
    Oszczędzamy sobie tym samym skoku warunkowego.


    dla wartości kanal=1;

    kanal &= 0b00000111; będzie 0b00000001, a nie 0b1000 ostatnie bity z wartości 0b00001000.
  • #25 9533696
    tadzik85
    Poziom 38  
    Pisał dobrze ale ty masz problem ze zrozumieniem tego myślisz dziesiętni nie binarnie. a binarne myślenie wielokrotnie ułatwia życie. np w tym przypadku.


    Choć jego przykład z 9 jest nie na miejscu bo nigdy nie wystąpi bo nie wystąpi również 8 ale dobrze pokazuje zasadę działania.
REKLAMA