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

[Atmega8][ADC] - Przetwornik ADC z przerwaniem nie działa

Thomas1988 19 Cze 2014 15:25 2583 10
REKLAMA
  • #1 13721604
    Thomas1988
    Poziom 16  
    Witam

    Mam problem z przerwaniem od przetwornika ADC w Atmega8. Napisałem następujący kod:

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


    Ogólnie program ma liczyć różnicę wartości pomiędzy dwoma kanałami przetwornika ADC. Jednak zatrzymałem się na samym przełączaniu kanałów. Konkretnie gdy wartość na kanale adc1 będzie większa niż 300 mają się zapalić diody. Nic się jednak takiego nie dzieje. Może któryś z kolegów podpowiedzieć jak zrobić to przerwanie od przetwornika ADC w trybie FreeRun ? Co mam tutaj źle ?[/code]
  • REKLAMA
  • #2 13721669
    BlueDraco
    Specjalista - Mikrokontrolery
    Nie robić - nie ma to sensu, bo czas obsługi przerwania będzie większy od czasu przetwarzania, a pożytku z tego żadnego. Zaprogramuj przerwanie od timera, w każdym przerwaniu timera czytaj poprzedni wynik z ADC, interpretuj go, a na koniec - wyzwalaj nową konwersję.
  • REKLAMA
  • #3 13721680
    dondu
    Moderator na urlopie...
    Po pierwsze w trybie Free running:

    Cytat:
    In Free Running mode, a new conversion will be started immediately after the conversion completes, while ADSC remains high.

    czyli zanim zdążysz zmienić kanał.

    Powinieneś więc ustawić tryb pojedynczej konwersji, wystartować pierwszy pomiar a następnie w funkcji przerwania zmieniać kanał i startować kolejną konwersję. Oczywiście zależy to także od preskalera - Ty masz zaledwie 16. Możesz więc zrobić tak jak radzi BlueDraco.

    Po drugie, skoro już użyłeś switch() to po co robisz dodatkowe warunki if()?
    W poszczególnych case wykonuj wszystkie operacje.

    Po trzecie po co zerujesz ADMUX skoro w następnej linijce ustawiasz właściwą wartość?

    Po czwarte czy tutaj nie powinno być adc zamiast adc1?:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #4 13721795
    Thomas1988
    Poziom 16  
    ADMUX muszę wyzerować żeby wprowadzić nową wartość, inaczej trzeba by chyba negować przypisane już bity.
  • REKLAMA
  • #5 13721911
    dondu
    Moderator na urlopie...
    Thomas1988 napisał:
    ADMUX muszę wyzerować żeby wprowadzić nową wartość, inaczej trzeba by chyba negować przypisane już bity.

    Zastanów się jeszcze raz:

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

    jakiego operatora używasz do załadowania wartości ADMUX.
  • #6 13721935
    tmf
    VIP Zasłużony dla elektroda
    Ja tylko dodam, że jeśli autor chce obliczać różnicę między dwoma kanałami to można to zrobić całkowicie sprzętowo korzystając z trybu różnicowego przetwornika ADC.
  • #7 13724203
    Thomas1988
    Poziom 16  
    dondu

    Przerobiłem kod według twoich porad. Teraz mam przerwanie od Timera0.

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


    Kod przerobiłem tak, żeby gdy wartość ADC na kanale PC4 przekroczy 300 zapali się jedna dioda. Natomiast gdy przekroczy 300 na kanale PC5 zapali się druga dioda. Jakoś dziwnie mi to działa po steruję jednocześnie obiema diodami za pomocą jednego kanału. Nie wiem o co chodzi, gdzieś pewnie wkradł się prosty błąd i nie mogę go wyszukać.
  • Pomocny post
    #8 13724221
    dondu
    Moderator na urlopie...
    Oj pomieszałeś :)

    Dwie możliwości:

    Pierwsza wersja (opisałem wyżej):
    1. wyłącz Free Running
    2. zostaw przerwanie ADC,
    3. przed pętlą główną w main() wywołaj pierwszą konwersję,
    4. w przerwaniu ADC wykonuj to, co aktualnie wykonujesz w przerwaniu + wystartuj kolejną konwersję.

    Druga wersja zaproponowana przez BlueDraco:
    1. wyłącz Free Running
    2. zostaw przerwanie ADC,
    3. ustaw timer na przerwania co X czasu,
    4. w przerwaniu timera startuj pojedynczą konwersję,
    5. w przerwaniu ADC wykonuj to, co aktualnie wykonujesz w przerwaniu.

    W tej wersji punkt 4 możesz zastąpić badaniem w pętli głównej flagi przerwania timera i zamiast funkcji przerwania tam (w pętli głównej) startować kolejną konwersję. Podobnie można zrobić z przerwaniem ADC. Na razie zrób jednak za pomocą funkcji przerwań.
  • #9 13724238
    Thomas1988
    Poziom 16  
    Ok rozumiem. Tylko powiedz mi dlaczego na stronie mikrokontrolery.blogspot.com
    bardzo podobny kod działa, a u mnie jakoś nie za bardzo ?
  • Pomocny post
    #10 13724267
    dondu
    Moderator na urlopie...
    Thomas1988 napisał:
    Tylko powiedz mi dlaczego na stronie mikrokontrolery.blogspot.com bardzo podobny kod działa, a u mnie jakoś nie za bardzo ?

    Trzeba by przeanalizować kody Drzaśka i porównać do Twoich, żeby odpowiedzieć na to pytanie.
    Prawdopodobnie w Drzaśkowym kodzie nie ma zmiany kanałów.
    Zmiana kanałów rządzi się konkretnymi wymaganiami dot. procedury pomiaru.
  • #11 13724401
    Thomas1988
    Poziom 16  
    dondu

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


    Przerobiłem kod według twoich wskazówek i jest to samo. jednym kanałem steruję obiema diodami. Wynika z tego, że sam ADC działa ok. Coś chyba jest w tym switchu albo w instrukcjach if.

    Dodałem else if zamiast drugiego if teraz działa tak że jednym kanałem steruję obiema diodami, a drugim jedną diodą.

    Znalazłem problem :D Tkwił on w instrukcjach if :D
REKLAMA