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

ATmega32, AVR Studio 4, ADC i TIMER2 próbkowanie.

lukashb 10 Lis 2011 14:42 3354 21
REKLAMA
  • #1 10123157
    lukashb
    Poziom 39  
    Witam! Od jakiegoś czasu bawię się AVR Studio 4 po przesiadce z BASCOMA. Jak narazie jest nieźle ;) ale mam mały problem. Mianowicie, chciałbym sobie przy pomocy ADC próbkować sygnał z częstotliwością X (dajmy na to 8kHz) i zapisać go do tablicy. O ile w BASCOMIE napisałem sobie taki programik (przerwanie Timer2 8kHz, w przerwaniu odczyt ADC do tablicy i inkrementacja wskaźnika która to zapisuje kolejne pozycje tablicy aż do osiągnięcia wartości Y (zadeklarowanej).
    Na ten czas mam uruchomione przerwanie od Timer2 i ono działa bardzo dobrze, w przerwaniu dajmy na to mogę migać diodą, a w pętli głównej wysyłam po RS232 dane. Czyli ta część działa. Problemem jest moim jak wkomponować obsługę ADC i odczyt w przerwaniu. Tu trzeba samemu czekać na zakończenie konwersji, samo się wystawia przerwanie, a nie bardzo wiem, czy to nie będzie problemem. Jak to dam radę odpalić to reszta pójdzie jak z płatka. Moje pytanie w tym momencie jest teoretyczne, bo nie miałem czasu popróbować uruchomić samego ADC. Może ktoś coś podobnego robił? i podpowie? nie koniecznie kodem, bo niechcę gotowca. Pozdrawiam ;)
  • REKLAMA
  • Pomocny post
    #2 10123208
    drzasiek
    Specjalista CNC
    ADC uruchom w trybie Free Run, bez zgłaszania przerwania po zakończonej konwersji.
    Przetwornik uruchom w miarę szybko, najlepiej blisko wielokrotności częstotliwości zgłaszania przerwania przez Timer.
    I wtedy w Przerwaniu od Timera przepisujesz wartość z rejestru ADC do jakiejś zmiennej/bufora.
  • Pomocny post
    #3 10123549
    tmf
    VIP Zasłużony dla elektroda
    Ja bym to jednak zrobił tak jak wynika z twojego opisu programu bascomowego. Czyli timer na 8kHz, w przerwaniu timera odczytujesz ADC i startujesz kolejną konwersję. ADC musi być tak ustawiony, aby skończyć konwersję przed kolejnym przerwaniem timera, co nie jest problemem. Dzięki temu masz gwarancję, że przy każdym przerwaniu timera (z wyjątkiem pierwszego) ADC będzie miał wartość z konwersji.
  • REKLAMA
  • Pomocny post
    #4 10123605
    INTOUCH
    Poziom 30  
    Przykład dla dwóch kanałów
    Przed wpisaniem tego kodu musisz odpowiednio ustawić Bity w rejestrach ADMUX i ADCSRA
    Jeśli chcesz mieć próbkowanie co określony czas to musisz odpowiednio ustawić rejestry zegara.
    Pisałem trochę z pamięci mogłem gdzieś zgubić klamrę przecinek lub średnik


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #5 10123624
    drzasiek
    Specjalista CNC
    tmf->No tak, ale to wymaga (dla tej częstotliwości próbkowania) 8000 tys razy w ciągu sekundy ustawienia bitu w rejestrze.

    Ale liniowość pomiaru za to będzie lepsza.
  • Pomocny post
    #6 10124477
    janbernat
    Poziom 38  
    A może wykorzystać Timer0 i ustawić odpowiednio rejestr SFIOR?
    Wtedy przerwanie od Timer0 compare wyzwala ADC.
    A pojawienie się flagi moźna sprawdzać w pętli głównej albo w przerwaniu od ADC.
  • REKLAMA
  • Pomocny post
    #7 10124835
    INTOUCH
    Poziom 30  
    Szanowny kolego.
    Pisząc jeden program zastanawiałem się nad wyzwalaniem ADC od timera przez ustawienie bitów w rejestrze SFIOR, ale zrezygnowałem z jednego powodu. Wszystkie 3 pomiary dla przebiegu sinusoidalnego (prąd 3 fazowy 50Hz) musiały być wykonane w praktycznie tym samym czasie.
    Niestety nie do zrealizowania ze względu na multipleksowanie. Chciałem przynajmniej doprowadzić do jak najkrótszej różnicy między czasem pomiaru 3 faz.

    Probem jaki niałem do rozwiązania to pomiar harmonicznych i TRUE-RMS. Metoda przesuwającego się okna. Za okna służyły 3 tablice 16 pomiarów z wiadomych powodów.
  • REKLAMA
  • Pomocny post
    #8 10125126
    janbernat
    Poziom 38  
    W multipleksowanym ADC nie da się zrobić pomiarów w tym samym czasie.
    W "praktycznie" tym samym czasie- da się.
  • #9 10126259
    lukashb
    Poziom 39  
    Witam! Popracowałem trochę, starałem się uruchomić pokolei każdy z bloków i tak. Okazuje się, że nie bardzo wiem, jak zmusić ADC do pomiarów wykonywanych z częstotliwością pracy Timera2. Ale do rzeczy. ADC odczytuje dobrze (po RS wysyłam dane) od 0 do 1023 regulując np. potencjometrem.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    To co powstało, to efekt czytania Internetu. Bardzo bym prosił o podpowiedź, jak i co zmienić by ADC próbkował częstotliwością pracy Timera2.
    Sądziłem, że wystarczy uruchamiać ADC poprzez ADEN w Timerze2 i ADSC czyli konwersja. Niestety, wyniki są taki same jak bym próbkował jak leci, tzn bez ograniczenia Timerem. Sygnał wygląda tak samo bezpośrednio jak i po przeróbkach. Podaję 1kHz sinus z przesunięciem poziomu (bo dolna połówka się by nie załapała), co przy 8kHz próbkowaniu powinno dać 8 punktów na 1 okres sygnału. U mnie czy z Timerem, czy bez, punktów jest 4. Dla 500Hz jest ich 6, czyli wychodzi, że sam ADC zbiera próbki z częstotliwością 4 kHz :| ? Ustawione jest inaczej przecież w preskalerze. Coś nie gra tak czy inaczej. Podrawiam
  • Pomocny post
    #10 10126367
    tmf
    VIP Zasłużony dla elektroda
    Po pierwsze uruchom timer w trybie CTC, nie będziesz musiał ciągle przeładowywać licznika. Po drugie jak raz uruchmoisz ADC to nie musisz tego robić ponownie, wystarczy uruchamiać konwersję. Po trzecie - po co preskaler ADC? On ma zakończyć konwersję w miarę szybko (w każdym razie przed kolejnym przerwaniem timera.
    I najważniejsze - w przerwaniu timera nie czekasz na koniec konwersji!!!
    Zaczynasz konwersję i wracasz, jej wynik odczytujesz w trakci ekolejnego przerwania.
  • #11 10126416
    lukashb
    Poziom 39  
    Tak też próbowałem - tzn. czekanie na konwersję poza timerem2 - wtedy się program na tym zawieszał. Narazie Timer pozostawię w spokoju - póki działa, a jak narazie działa on ;). W zasadzie czytam i czytam i nie widzę przykładów o Free Runing mode albo o Single Conversion. Jak narazie są przyklady typu "Help!" albo " ADC doesn't work" itp.

    ------------------
    Naprawdę, nie mam pomysłu dlaczego to nie działa i zawiesza sie na czekaniu na konwersję. Bez tego ADC działa ale "czyta" tak samo czy w przerwaniu czy bez przerwania od Timera. Podpowie ktoś może? W Bascomie było o tyle prosto, ze tam po prostu dawałem w przerwaniu Timera, GETADC(y) i tyle, samo sie robiło, tu problemów jak grzybów po deszczu.
  • Pomocny post
    #12 10126915
    tmf
    VIP Zasłużony dla elektroda
    Ale ty nigdzi emasz nie czekać na koniec konwersji, ani w przerwaniu (zgroza), ani poza nim. W przerwaniu zapisujesz do B wynik z ADC i startujesz kolejny pomiar. W kolejnym przerwnaiu znowu odczytujesz ADC i startujesz kolejny. Jeśli odstęp pomiędzy przerwaniami jest dłuższy niż czas konwersji to masz gwarancję, że ADC będzie gotowy i na nic czekać nie trzeba.
    Poza tym B koniecznie musi być volatile. Poza tym, przy takim odczycie w pętli głównej jest szansa, że pewne pomiary się zgubią. Poza tym utoa musi być wykonane atomowo, a najlepiej, ponieważ funkcja ta trwa długo, najpierw B przypisać zmiennej pomocniczej (atomowo), a dopiero potem ją konwertować.
  • Pomocny post
    #13 10126955
    INTOUCH
    Poziom 30  
    Jeżeli chciałeś zastosować moją metodę, to źle skonfigurowałeś przetwornik ADC.
    Niepotrzebnie włączyłeś auto wyzwalanie. Autowyzwlanie stosuje się tylko w trybie free running dla jednego kanału.
    Gdzie u mnie w kodzie programu było włączanie przetwornika co przerwanie od timera „ADCSRA |= (1 << ADEN)”; .
    Przetwornik włącza się tylko raz gdzieś w funkcji ADCinit().
    Przestudiuj dokładnie notę katalogową AVR32 tam jest w wszystko opisane. Tylko uważaj na przetłumaczoną na język polski jest tam mnóstwo błędów. Czasem trzeba się domyślać co tłumacz miał na myśli. Jeżeli źle ustawisz bity w rejestrach przewrotnika i timera to na pewno program nie będzie działał tak jak byś chciał.
    Na wszelki wypadek do testów wyłącz WATCHGOGa. Może powodować reset programu. Standardowo jest włączony.
  • Pomocny post
    #14 10127155
    janbernat
    Poziom 38  
    Można to zainicjalizować tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Tej funkcji używasz tylko raz- w main.
    Potem- tak jak napisał tmf.
  • #15 10130022
    lukashb
    Poziom 39  
    Witam! Z tego wszystkiego wgrałem program spod Bascoma, gdzie próbowanie wynosi 8kHz, ADC ustawiony na preskaler 8, Single Conv, rez. 16MHz. Dla potomnych, tak powinien wyglądać sygnał (i tak wygląda spróbkowany dzięki programowi z Bascoma). Sygnał 1kHz.
    ATmega32, AVR Studio 4, ADC i TIMER2 próbkowanie.
    Prawda, ze ładnie :)?
    Probkowany sygnał programem pisanym w AVRStudio wcale nie przypomina takiego czegoś pomimo tego samego układu badanego, takiego samego sygnału, ustawienia Timera2 na 8kHz i ADC na preskaler 8. W zasadzie zawsze na okres przypada tylko 4 punkty nie zależnie od ustawienia Timera. A powinno byc zgodnie ze wzorem 8000/fprobkowana. Cos tu nie gra, ale ja juz powoli odpuszczam. Może ktoś cos podpowie, co jest nie tak. Program poniżej. Zastosowałem sie do porad (tak uważam) i dalej nic.
    Kod: text
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #16 10130146
    tmf
    VIP Zasłużony dla elektroda
    Zastanów się nad swoją pętlą główną. Odczytujesz B (czyli ADC) tyle razy na sekundę ile razy wykona się ta pętla. A tempo jej wykonywania się determinuje szybkość wysyłania znaków przez UART. W efekcie twoje "samplowanie" jest zależne od prędkości UART. Piszę w cudzysłowiu bo prawdziwe samplowanie masz 8kHz, tyle, że samą zmienną B odczytujesz inną ilość razy. BTW, przy prędkości UART 19200 bps nie ma szans przesłać 8k sampli/s - więc to nawet teoretycznie nie ma prawa działać. To co musisz zrobić to zwiększyć prędkość UARTu tak aby wydalał z przesyłaniem oraz stworzyć jakąś flagę informującą, że B zostało uaktualnione.
  • #17 10130186
    lukashb
    Poziom 39  
    Czyli problem leży w tym, że UART nie nadąża wysyłać i stąd mój "przebieg" nie odpowiada wyglądem niczemu podobnemu, bo poprostu np. ADC odczytało do B szczyt sinusoidy, ale zanim ją wysłałem/odebrałem to już minął taki czas, że odczyt popadł gdzieś dalej - i to by tłumaczyło ten śmietnik na wyjściu. Faktycznie. To co oglądamy z Bascoma to jest najpierw wrzucone do tablicy (tam mam 40 elementów), flaga zakończenia uzupełniania tablicy i hop po kolei element po elemencie. Czyli jak bym tu dał tablicę, to powinno wyglądać to tak samo? konfig ADC rozumiem, że dobry jak i wywołanie w przerwaniu? (odczyt, start konwersji, powrót itp) Pozdrawiam!
  • Pomocny post
    #18 10130434
    janbernat
    Poziom 38  
    Teraz masz prescaler ADC ustawiony tak że zegar ADC ma 125kHz.
    Zegar ADC- a nie inne zegary.
    Zegar ADC ma mieć 50-200kHz.
    Jak Ci mniej zależy na dokładności niż na szybkości- można dać zegar ADC na 250kHz.
    A oprócz tego- możesz zrobić tablicę albo bufor dla UART-a.
  • #19 10132999
    lukashb
    Poziom 39  
    Witam! Wielkie piwo dla kol. TMF i JANBERNAT za naprowadzenie na tak błahą sprawę a jakże ważną. Oczywiście! Tablica dla próbek, zablokowanie timera, wystawienie flagi zapełnienia tablicy i dopiero odczyt UARTEM z dowolna prędkością. Rzecz jasna wszystko działa. Oto efekt:
    ATmega32, AVR Studio 4, ADC i TIMER2 próbkowanie.
    Dziwie sie samemu sobie, ze nie pomyślałem o tym od razu ze tak szybko lecą dane, ze UART nie wyrabia. Tematu nie zamykam, bo to dopiero początek projektu, a nie wiem czy nie będę miał jakiś pytań. Tym czasem pozdrawiam pomagających!

    PS. Dopiero teraz widać kolosalna różnice pomiędzy BASCOMEM a C. Temu pierwszemu zebranie 205 próbek do tablicy zajmowało ok. 50-100ms, C takie zadania załatwia w przerwie na kawę ;) i trwa to ok. 2-3ms może mniej, bo ustawiłem w przerwaniu zapalenie diody, i mrugniecie tak krotko trwa, ze prawie go niema ;).
  • #20 10133387
    zumek
    Poziom 39  
    lukashb napisał:
    ...
    PS. Dopiero teraz widać kolosalna różnice pomiędzy BASCOMEM a C. Temu pierwszemu zebranie 205 próbek do tablicy zajmowało ok. 50-100ms, C takie zadania załatwia w przerwie na kawę ;) i trwa to ok. 2-3ms może mniej, bo ustawiłem w przerwaniu zapalenie diody, i mrugniecie tak krotko trwa, ze prawie go niema ;).


    Tiaaa..., a gdyby napisać to w asemblerze, to pewnie zebranie 205 próbek z częstotliwością 8kHz, zajęłoby ze 100us ... .
    Następnym razem pomyśl, zanim znów coś palniesz :-P

    PS
    To w obronie sponiewieranego Bascom'a.
  • #21 10133552
    janbernat
    Poziom 38  
    Coś lukashb Ci się chyba poplątało.
    Przy takim ustawieniu Timera próbkę pobierasz co 7.936ms.
    Pobranie 205 próbek trwa 1.626s.
    Nieważne czy asm czy Bascom- tak ustawiłeś timer.
    A to że obsługa tego przerwania trwa w Bascomie 50-100ms to trochę trudno uwierzyć.
    Chyba że jakieś straszne obliczenia w tym przerwaniu robisz.
  • #22 10133882
    lukashb
    Poziom 39  
    Czy ja wiem, czy coś się poplątało. Korzystam tylko z AVR-CALC, i podpieram to pomiarem częstotliwości pracy przerwania (TOGGLE PORTx). Tak czy inaczej, preskaler 32 mam ustawiony, a wartość overflow ustawiona na 194 i otrzymuję 8kHz, to raz, a dwa, że przebieg pomierzony jest zgodny z założeniem fpróbkowana/fmierzona czyli tu będzie 8 punktów na okres przy jednym 1kHz sygnale. Napewno także operacja nie trwa 1,26 sekundy bo jak by tyle trwało to zamiast wykresu była by sieczka z przypadkowych punktów. Jak wcześniej kiedy UART nie wyrabiał i słał co złapał aktualnie ADC bez trzymania ram czasowych. Tak czy inaczej - dla mnie działa i spełnia wymagania, Można dalej przejść i pisać resztę. Co do Bascoma - może przesadziłem, ale tam potwornie długo trwa wszystko, to mi powie każdy kto się tym babrał. Niby dlaczego wszędzie gdzie się robi dokładn pomiary (okres, częstotliwość itp) to się przechodzi na C? na forum mnóstwo przykładów. Oscyloskopu by nie zrobił kol. drzasiek bodajże w Bascomie, bo zanim on by wyświetlił na LCD to połowa sygnału by poszła w kąt. Kończąc - kalkulator chyba nie kłamie, miernik częstotliwości tym bardziej, a wykres który jest efektem potwierdzenia prawdomówności dwóch poprzednich jest dopełnieniem tego, że działa poprawnie i niema prawa przerwanie być co 7ms.
REKLAMA