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

[C] [ATmega32] - ATmega32 - obsługa timera/przepełnienie co 100ms/pomiar na ADC

sidiouss 10 Lis 2013 22:55 3186 19
REKLAMA
  • #1 12937813
    sidiouss
    Poziom 10  
    Witam wszystkich bardzo serdecznie.
    Mam problem z obsługą timera, nie wiem czy dobrze mam napisany kod, bo działa nie tak jakbym chciał. Mianowicie chciałbym generować przerwanie co 100ms i wykonywać pomiary na dwóch kanałach ADC i wyświetlać wyniki na ekranie terminala w PC.. Na początku udało mi się obsłużyć timer0 i wszystko działało prawidłowo, jednakże, gdy przeszedłem na timer1 i chciałem generować przerwanie przepełnieniem licznika dokładnie co 100ms, to przestało mi działać i przerwanie się nie generuje, co skutkuje zerowymi wartościami ADC wysyłanymi na terminal :oops: .
    Czy moglibyście popatrzeć na mój kod i spróbować wychwycić jakieś błędy?
    Z góry dziękuję :)

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #2 12938035
    zumek
    Poziom 39  
    sidiouss napisał:
    .Czy moglibyście popatrzeć na mój kod i spróbować wychwycić jakieś błędy?


    Włączyłeś niewłaściwe przerwanie.
    zamiast OCIE1A, masz TOIE1.
  • REKLAMA
  • #3 12938061
    slx
    Poziom 19  
    Piszesz o przerwaniu od przepełnienia i takie włączasz (TIMSK |= (1<<TOIE1)), ale go nigdzie nie obsługujesz. Ten komentarz
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    nie jest prawdziwy. Od przepełnienia jest: TIMER1_OVF_vect
    Poza tym w ten sposób
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    nigdy nie ustawisz danego bitu na zero.
  • REKLAMA
  • #4 12938089
    pawel_konin
    Poziom 20  
    sidiouss napisał:
    Witam wszystkich bardzo serdecznie.
    Mam problem z obsługą timera, nie wiem czy dobrze mam napisany kod, bo działa nie tak jakbym chciał. Mianowicie chciałbym generować przerwanie co 100ms i wykonywać pomiary na dwóch kanałach ADC i wyświetlać wyniki na ekranie terminala w PC.. Na początku udało mi się obsłużyć timer0 i wszystko działało prawidłowo, jednakże, gdy przeszedłem na timer1 i chciałem generować przerwanie przepełnieniem licznika dokładnie co 100ms, to przestało mi działać i przerwanie się nie generuje, co skutkuje zerowymi wartościami ADC wysyłanymi na terminal :oops: .
    Czy moglibyście popatrzeć na mój kod i spróbować wychwycić jakieś błędy?
    Z góry dziękuję :)

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


    Zdecyduj się czy przepełnienia od przepełnienia timera TOV1 czy tryb porównania compare match??
    Bo w tym masz problem gdyż nie pojawia ci się wektor przerwań od trybu porównania TCNT z OC1A.
  • #5 12938189
    sidiouss
    Poziom 10  
    Zmieniłem kod i zamiast:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    wstawiłem:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    .

    Znów działa mi i wyświetla wyniki ADC na terminalu :)

    Cały kod wygląda teraz tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wytłumaczcie mi tylko proszę, jak aktualnie jest generowane przerwanie?
    Rozumiem, że, gdy używa się isr(timerX_ovf_vect), to przerwanie jest generowane przy przepełnieniu licznika. A gdy używam ISR(TIMER1_COMPA_vect), to jak generowane jest przerwanie i czym się różni od overflow?
    Czy teraz mam poprawnie skonfigurowane i przerwanie jest generowane co 100ms? Jak można to sprawdzić w praktyce?

    I ostatnie pytanie - chciałbym wyniki ADC zbierać w paczki i wysyłać na terminal po uzbieraniu np po 10 wyników z każdego z kanałów, czyli co sekundę wyświetlać 10 pomiarów dla każdego z kanałów. Jak to zrobić, mam użyć jakiejś tablicy i czyścić ją po uzyskaniu pomiarów? I ma być ona generowana w przerwaniu timera czy już w programie głównym?

    Dziękuję serdecznie za wszystkie odpowiedzi :)
  • #6 12938370
    BlueDraco
    Specjalista - Mikrokontrolery
    To, kiedy jest generowane przerwanie i jakie, nie zależy od tego, jakie napiszesz procedury obsługi przerwań, a od tego, jakie przerwania włączysz w odpowiednim rejestrze. Do każdego włączonego przerwania musisz napisać procedurę jego obsługi. Jeśli włączasz TOIE - musisz mieć procedurę timerX_ovf_vect, jeśli włączasz OCIE1A - musisz mieć TIMER1_COMPA_vect.

    Wysyłanie wyników po 10 nie jest najlepszym pomysłem, bo komplikuje buforowanie transmisji. W takim przypadku potrzebujesz przerwania timera, najlepiej 20x na sekundę, żeby w każdym przerwaniu odbierać wynik poprzedniego pomiaru i inicjować następny oraz przerwania nadajnika UART do nadawania znaków. Wynik pomiaru wpisujesz w przerwaniu timer do bufora cyklicznego i odblokowujesz przerwanie UART. Obsługa przerwania UART wysyła kolejne znaki, a po wyczerpaniu bufora blokuje przerwanie. W pętli głównej umieszczasz jedną instrukcję - uśpienia procesora.
  • REKLAMA
  • #7 12938438
    pawel_konin
    Poziom 20  
    sidiouss napisał:
    Zmieniłem kod i zamiast:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    wstawiłem:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    .

    Znów działa mi i wyświetla wyniki ADC na terminalu :)

    Cały kod wygląda teraz tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wytłumaczcie mi tylko proszę, jak aktualnie jest generowane przerwanie?
    Rozumiem, że, gdy używa się isr(timerX_ovf_vect), to przerwanie jest generowane przy przepełnieniu licznika. A gdy używam ISR(TIMER1_COMPA_vect), to jak generowane jest przerwanie i czym się różni od overflow?
    Czy teraz mam poprawnie skonfigurowane i przerwanie jest generowane co 100ms? Jak można to sprawdzić w praktyce?

    I ostatnie pytanie - chciałbym wyniki ADC zbierać w paczki i wysyłać na terminal po uzbieraniu np po 10 wyników z każdego z kanałów, czyli co sekundę wyświetlać 10 pomiarów dla każdego z kanałów. Jak to zrobić, mam użyć jakiejś tablicy i czyścić ją po uzyskaniu pomiarów? I ma być ona generowana w przerwaniu timera czy już w programie głównym?

    Dziękuję serdecznie za wszystkie odpowiedzi :)



    Nadal masz jeszcze parę błędów np w przerwaniu ustawiasz flagę w main ja kasujesz a nigdzie nie sprawdzasz więc po co ona.
    sidiouss napisał:

    flag = 0;
    flag = 1;
    )


    i kolejny błąd najpoważniejszy nie masz warninga z tego powodu ??
    sidiouss napisał:

    #define F_CPU 11059200UL
    )


    kolejny błąd nie obliczasz napięcia tylko odczytujesz rejestr ADCW wiec po co ci VRef??
    sidiouss napisał:

    #define VREF 2,56
    )
  • #9 12939318
    sidiouss
    Poziom 10  
    Dziękuję serdecznie za wszystkie rady :)

    Co do
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    , to gdy tego nie wpisuję wyskakuje mi warning:
    # warning "F_CPU not defined for <util/delay.h>"
    , a gdy wpiszę, to wyskakuje:
    F_CPU redefined [enabled by default]
    ..
    Flaga, która została w kodzie służyła debuggingowi, gdy nie działało przerwanie - umieszczałem ją w obsłudze przerwania i następnie w pętli głównej - jeśli przerwanie nie zostało wygenerowane, to na terminalu wyskakiwał komunikat - "nie działa".

    Co do buforowania danych ADC, docelowo ma być to ramka wysyłana bezprzewodowo na 868Mhz poprzez układ RFM12B, a następnie wyświetlana w postaci wykresu na wyświetlaczu, a na razie chciałem taką ramkę zrobić i wysyłać poprzez uart, ale nie wiem czy może wyglądać ona tak samo..

    Schemat urządzenia ma wyglądać mniej więcej tak:

    Pomiar na ADC na dwóch kanałach co 100ms - buforowanie ramki co X pomiarów - wysyłanie ramki z danymi z ADC poprzez RFM12B - ponowne zapełnianie bufora - wysyłanie poprzez RFM12B i tak dalej..

    Jak to najlepiej zrobić?
  • #11 12939412
    sidiouss
    Poziom 10  
    @ dondu:
    Dzięki, teraz nie wyświetla mi żadnych warningów :)
  • #13 12939582
    sidiouss
    Poziom 10  
    Staram się żeby było ich jak najmniej, ale zawsze coś się krzaczyło :)
    Zaraz przejrzę, na bieżąco czytam książkę Pana Mirka, Pana Francuza, Twojego bloga, itp. w razie jakichkolwiek problemów :D

    A co zrobić z tym buforowaniem i wysyłaniem wyników ADC?
  • #15 12939608
    sidiouss
    Poziom 10  
    Hmm, tylko czy ten sam bufor mogę wysłać przez RFM12B czy muszę zrobić już coś innego?
  • #17 12941780
    pawel_konin
    Poziom 20  
    dondu napisał:

    Myślę że autor powinien mieć zmienne Volatile gdyż wykorzystuje zmienne w przerwaniu i pętli głównej ja bym dał Volatile ale czy słusznie może ktoś doświadczony odpowie ja się narazie uczę...:d
  • #18 12941827
    dondu
    Moderator na urlopie...
    pawel_konin napisał:
    dondu napisał:

    Myślę że autor powinien mieć zmienne Volatile gdyż wykorzystuje zmienne w przerwaniu i pętli głównej ja bym dał Volatile ale czy słusznie może ktoś doświadczony odpowie ja się narazie uczę...:d

    Nie rozumiem o co Ci chodzi. Przecież wskazałem mu, że nie ma volatile, a powinien mieć.
  • #19 12942214
    pawel_konin
    Poziom 20  
    dondu napisał:
    pawel_konin napisał:
    dondu napisał:

    Myślę że autor powinien mieć zmienne Volatile gdyż wykorzystuje zmienne w przerwaniu i pętli głównej ja bym dał Volatile ale czy słusznie może ktoś doświadczony odpowie ja się narazie uczę...:d

    Nie rozumiem o co Ci chodzi. Przecież wskazałem mu, że nie ma volatile, a powinien mieć.

    Chciałem tylko się upewnić by nie poradzić komuś źle. Czytam i dużo się uczę z waszych materiałów do atmegi(uczą profesjonalizmu) a nie żeby działało byle jak . I byłem przekonany na 99.99% nad słusznością volatile ale jak się komuś radzi lepiej nie radzić rzeczy na które jest się tylko 99.99% pewnym wiec wolałem się upewnić.
    Pozdrawiam
  • #20 12942228
    dondu
    Moderator na urlopie...
    OK.

    Należy także pamiętać o tym, że czasami volatile jest niepotrzebnie stosowane do zmiennych używanych tylko w przerwaniu. Takim przypadkiem jest definiowanie zmiennej globalnej z volatile w celu przechowywania wartości pomiędzy kolejnymi przerwaniami. Zamiast tego należy wykorzystać STATIC: http://mikrokontrolery.blogspot.com/2011/02/kurs-jezyka-c-zmienne-lokalne-statyczne.html
    i zdefiniować zmienną w funkcji przerwania.
REKLAMA