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

Jak powiązać licznik i ADC w ATmega16 do generowania sygnału o zmiennej częstotliwości?

Aroni525 07 Sty 2016 19:16 1329 10
  • #1 15311079
    Aroni525
    Poziom 9  
    Witam.
    Zwracam się z prośbą o pomoc w znalezieniu błędu. Siedzę 6h i próbuję ogarnąć od podstaw liczniki i ADC. Moim celem jest wygenerowanie sygnału o zmiennej częstotliwości.
    Jak piszę coś na sam ADC to działa, na licznik też działa, a jak próbuję połączyć to za nic;/

    Problemem jest chyba przepisywanie rejestru ADC do OCR1A którego używam do CTC licznika 1 w głównej pętli. Nie wiem jak to prawidłowo zrobić.
    A, program pisany pod mega16, taktowanie 1MHz jakby
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod



    Są momenty, gdzie jakby coś działało przez moment i reaguje odpowiednio na kręcenie potencjometrem, ale z reguły to głupoty pokazuje...
  • #2 15311661
    dondu
    Moderator na urlopie...
    1. ADC_init() powinieneś wywołać tylko raz na początku programu.
    2. Startowanie pomiaru i czekanie na koniec konwersji w pętli głównej.
    3. Gdybyś jeszcze podał co to za mikrokontroler ....
    4. ... o schemacie już tylko wspomnę.
  • #3 15311835
    Aroni525
    Poziom 9  
    Procek napisałem wyżej, że to ATmega16, choć można to było przeoczyć;]

    Schemat to część z całości, ale i tak tylko tyle mam podpięte:
    Jak powiązać licznik i ADC w ATmega16 do generowania sygnału o zmiennej częstotliwości?

    Na razie chodzi mi tylko o to, żeby na pinie podpisanym CTC wygenerować sygnał o którym pisałem.

    dondu napisał:
    1. ADC_init() powinieneś wywołać tylko raz na początku programu.
    2. Startowanie pomiaru i czekanie na koniec konwersji w pętli głównej.


    Pierwotnie zrobiłem dokładnie jak napisałeś, ale wtedy sam przetwornik mi nie chciał działać... Nie sprawdziłem tego dokładnie, bo od razu kombinowałem i szukałem czegokolwiek co zadziała, a to zadziałało. Spróbuję jeszcze zmienić jak piszesz.
    Ale samo przepisanie rejestrów powinno działać? Bo dokładnie w tym miejscu pojawia się problem, każdy kod osobno działa, a jak tylko wstawię tą linię kodu to klapa.
  • Pomocny post
    #4 15312086
    Eagle
    Poziom 24  
    Skąd wnioski, że źle działa ? Tz. opisz dla konkretnego stanu : oczekuję .... mam ....

    Albo zastub'uj funkcję od ADC niech zwraca jakąś przewidywalną wartości i ją wpisz do OCR1A.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Jeśli podejrzewasz problem przy przepisywaniu, może musisz buforować.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #5 15312206
    Aroni525
    Poziom 9  
    Operuję na niskich częstotliwościach tj. ~~1-1000Hz. Żeby cokolwiek obserwować, to mam podpiętą diodę LED pod to wyjście. Powinienem widzieć mruganie z zakresu powiedzmy 1-30Hz a potem ciągłe świecenie. Dokładny test wykonam potem w laboratorium na uczelni, bo sam nie mam oscyloskopu, ale muszę widzieć, że to przynajmniej ma szanse działać przez obserwacje, o których napisałem wyżej. A co się dzieje - czasem mruga cały czas, czasem gaśnie, czasem znowu ciągle świeci, wszystko oczywiście niezależnie od potencjometru. Wygląda to jakbym dostawał jakieś śmieci w rejestrze.

    Dzięki za odpowiedzi i chęć pomocy! Na razie muszę coś innego zrobić, ale za parę godzin spróbuję zastosować rady, w razie czego znowu zapytam ;]
  • #6 15312261
    slx
    Poziom 19  
    Aroni525 napisał:
    Operuję na niskich częstotliwościach tj. ~~1-1000Hz.

    No właśnie. A odczyt ADC i zapis OCR1A "mielisz" w pętli, tak szybko jak się da.
    Zegar ADC: 1MHz/8= 125kHz / 25(cykli zegara na konwersję) .
    Czyli pomiar i zapis do OCR1A co około 5kHz. Timer głupieje.
    Dopisz w pętli chociaż jakiś _delay_ms(100);

    A jeszcze lepiej przepisywać nową wartość w przerwaniu:

    ISR(TIMER1_COMPA_vect)
    {
    OCR1A=ADC;
    }
  • #7 15312483
    dondu
    Moderator na urlopie...
    slx napisał:
    Zegar ADC: 1MHz/8= 125kHz / 25(cykli zegara na konwersję) .
    Czyli pomiar i zapis do OCR1A co około 5kHz.

    25 cykli trwa pierwsza konwersja, kolejne już tylko 13 cykli stąd: 1MHz / 8 / 13 ≈ 9615Hz
    czyli pomiar i zapis do OCR1A następują z częstotliwością 9,6kHz.

    Ale wniosek końcowy oczywiście prawidłowy:

    slx napisał:
    Timer głupieje.

    gdyż pracuje on z częstotliwością zaledwie: 1MHz / 1024 ≈ 976Hz
  • #8 15318505
    Aroni525
    Poziom 9  
    Dzięki za pomoc panowie. Napisałem od nowa program na innym timerze i ruszyło, wyskalowałem sobie to jak chciałem i git. Potem dodałem drugi potencjometr na inne wejście i zdefiniowałem drugi timer - tym razem chcę pwm o wypełnieniu z zakresu 6-27%. Generalnie mi się to udało mniej więcej obliczyć i zaimplementować. Ale pojawił się problem z pomiarem i zmianą kanałów. Początkowo mi się w ogóle nie chciały zmieniać i wszystko szło z jednego potencjometru, wyniki były ok.
    Wreszcie udało się zmieniać kanały, ale teraz pojawiły się problemy i zakłócenia. Niby oba timery są sterowane przez osobne potencjometry, ale jeden pomiar wpływa mocno na drugi... Do tego stopnia, że jak jeden chcę ustawić np częstotliwość timera2 na maksa, to automatycznie wypełnienie timera1 wskakuje na maksa i nie reaguje na zmiany swojego potencjometru. Coś znowu mi nie gra, ile ja na to szukanie błędów czasu poświęcam to aż mnie przytłacza... Ogólnie jak testuję osobno albo na jednym kanale to jest cacy, jak na osobnych to za dużo zakłóceń. Próbowałem przepinać na inne piny, ale nic to nie dało.
    Zerknąłby ktoś na kod i może ktoś coś zauważy? Innej osobie czasem łatwiej wyłapać błędy czy w ogóle zły sposób programowania, a ja dopiero od paru dni na dobrą sprawę się tym zajmuję więc jestem otwarty na krytykę i wskazówki.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #10 15323433
    Aroni525
    Poziom 9  
    Jak nie działało tak nie działa ;( Dzisiaj byłem u mojego opiekuna projektu, dał mi parę wskazówek co można poprawić i czego spróbować, ale nie znalazłem jednoznacznego błędu w moim algorytmie.
    Dodałem obsługę i wyświetlanie wyników na LCD i podpinałem się dla pewności pod oscyloskop. Używając jednego kanału, obojętnie którego wszystko jest ok, idealnie wyskalowane, czyli tak jak pisałem wcześniej... do czasu aż nie próbuję uruchomić 2 kanałów na raz. Wtedy pojawiają się zakłócenia, widać czasem przeskoki, jakby jeden timer łapał pomiar przeznaczony dla drugiego i na odwrót (to widać na wyświetlaczu).

    Już przerzucam te funkcje, staram się je odseparować żeby zachować atomowość kodu i żeby do każdego rejestru przepisać to, co mu się należy, ale ciągle coś jest nie tak. Jutro spróbuję napisać na nowo kod używając innych algorytmów, może przerwań i dodatkowego timera, bo przy tym to już chyba wszystko przemieliłem;/
    Pewnie i tak omijam coś istotnego i podstawowego w kodowaniu albo rozumowaniu, ale jak powiedziałem, dopiero zacząłem.

    A wrzucę kod (w sumie niewiele się zmieniło), może ktoś przeczyta i coś zauważy, zawsze przyda się uwaga co jest nie tak i co powinno być inaczej.

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



    Jeszcze zapytam: jest jakaś bardziej oszczędna funkcja konwersji liczby na typ znaków? itoa powiększa wagę programu o 500b chyba, i tak nieźle w porównaniu do sprintf, gdzie było to chyba 1700b ;o Ale pytam z ciekawości.
  • Pomocny post
    #11 15323717
    grko
    Poziom 33  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Te bufory są za małe na przechowanie warości zwracanych przez itoa. Nie wziąłeś pod uwagę null termination stringa. Twój program jeżeli działa to przypadkiem;)

    Jeżeli chcesz to możesz wząć jakąś uproszczoną wersję itoa. Np przerobić coś istniejącego z internetu.

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


    Takie coś zajmuje tyle:
    Kod: Bash
    Zaloguj się, aby zobaczyć kod
REKLAMA