Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Atmega8][bascom] timer2 CTC generuje przerwanie tylko raz

nanab 28 Oct 2018 02:04 654 10
  • #1
    nanab
    Level 27  
    Czy da się generować przerwania od timer2 przy każdym przepełnieniu w trybie CTC? Próbuję generować częstotliwość w zależności od ustawienia potencjometru, ale timer generuje przerwanie tylko raz, cały program poniżej:
    Code: vbnet
    Log in, to see the code

    Do OCR2 zostaje wpisana tylko pierwsza odczytana wartość zaraz po starcie programu, dalej już nie generuje przerwań. Po wrzuceniu " OCR2 = Dowpisania" do głównej pętli działa prawidłowo, zmienia częstotliwość. Po wyłączeniu CTC w configu ("Clear timer=0") wchodzi do przerwania, ale nie reaguje na wartość ocr2, mogę wpisać cokolwiek, a generowana częstotliwość się nie zmienia.
  • #2
    kamyczek
    Level 38  
    Zastanów się jaką częstotliwość będzie generował Licznik2 dla wartości zero ? Zastanów się też jak wpisać 10 bitową wartość przetwornika do 8 bitowego rejestru danych . Kolejne zagadnienie ,to jak się ma czas konwersji przetwornika adc do częstotliwości wystąpienia przerwań ? . Ten program przestanie się wykonywać gdy czas obsługi przerwania będzie dłuższy do częstotliwości jego wystąpień .
  • #3
    nanab
    Level 27  
    kamyczek wrote:
    Zastanów się jaką częstotliwość będzie generował Licznik2 dla wartości zero ?

    Równą częstotliwości jaką dostaje od prescalera. Tylko w jakim celu skoro taka sytuacja nigdy nie wystąpi? Wartość którą wyrzuca adc to 512+-320, potencjometr jest mechanicznie ograniczony.

    kamyczek wrote:
    Zastanów się też jak wpisać 10 bitową wartość przetwornika do 8 bitowego rejestru danych .

    Code: vbnet
    Log in, to see the code

    To jest końcówka obliczania średniej z dwóch pomiarów (/2) i skracanie wartości o 2 bity(/4) żeby weszła w 8b rejestr. Deklarując zmienną "dowpisania" jako bajt nic się nie zmienia.
    kamyczek wrote:
    Kolejne zagadnienie ,to jak się ma czas konwersji przetwornika adc do częstotliwości wystąpienia przerwań ?

    W czasie jednej pełnej pętli głównej licznik zwiększa się o 3, więc dla najwyższej możliwej częstotliwości pętla wykona się 16 razy zanim dojdzie do przerwania, nawet zostawiając w głównej pętli wysyłanie ocr2 przez uart, gdyby wywalić tę linijkę, pewnie trwałoby to jeszcze krócej.
    kamyczek wrote:
    Ten program przestanie się wykonywać gdy czas obsługi przerwania będzie dłuższy do częstotliwości jego wystąpień .

    Czas obsługi przerwania-nie mam pojęcia ile trwa, ale nic tam nie ma, odłożenie adresu na stos, wpisanie jednej wartości do jednego rejestru i powrót, kwestia pojedynczych us(nie liczyłem, zgaduję).
  • #4
    kamyczek
    Level 38  
    nanab wrote:
    Równą częstotliwości jaką dostaje od prescalera. Tylko w jakim celu skoro taka sytuacja nigdy nie wystąpi? Wartość którą wyrzuca adc to 512+-320, potencjometr jest mechanicznie ograniczony.


    Jak wpiszesz wartość 512+320 do 8 bitowego rejestru ?
  • #5
    nanab
    Level 27  
    kamyczek wrote:

    Jak wpiszesz wartość 512+320 do 8 bitowego rejestru ?

    nanab wrote:

    Kod: vbnet [rozwiń] [zaznacz wszystko]
    Dowpisania = Last / 8

    To jest końcówka obliczania średniej z dwóch pomiarów (/2) i skracanie wartości o 2 bity(/4) żeby weszła w 8b rejestr. Deklarując zmienną "dowpisania" jako bajt nic się nie zmienia.
  • #6
    emarcus
    Level 38  
    nanab wrote:
    . Deklarując zmienną "dowpisania" jako bajt nic się nie zmienia.

    W czasie jednej pełnej pętli głównej licznik zwiększa się o 3, więc dla najwyższej możliwej częstotliwości pętla wykona się 16 razy zanim dojdzie do przerwania, nawet zostawiając w głównej pętli wysyłanie ocr2 przez uart, gdyby wywalić tę linijkę, pewnie trwałoby to jeszcze krócej.



    Nie zmienia, bo masz błąd w innym miejscu.
    A w ogóle to powinieneś ten program przepisać od początku. Tak, (zbyt dużo błędów aby je pojedynczo korygować!), a przed tym, zaznajomić się z funkcjonalnością timerów, a w szczególności ich trybów pracy.....
    Zastanów się, co oznacza nazwa trybu CTC (?) – w ang. jest to ‘Clear Timer on Compare’ (pol. - wyzeruj zawartość licznika/timera, gdy jego zawartość jest równa wyznaczonej z góry i ustalonej, bądź to wyliczonej jakiejś wartości w zmiennej ‘Compare’). Zmienna ta jest umieszczona w rejestrze OCR2 (Compare2).
    Zatem (w tym trybie), zawartość licznika nigdy nie osiągnie jego maksymalnego stanu 255, momentu w którym może wystąpić interrupt OVF2 (w Bascom jest to nazwane ‘Timer2’) z tytułu przepełnienia tego licznika.
    Jeżeli chcesz wywołać przerwanie przy porównaniu zawartości TCNT2 z OCR2, to powinieneś skonfigurować przerwanie od ‘OC2’, albo w Bascom jest to ‘Compare2’, gdzie obie nazwy są akceptowane.
    Już na samym początku konfiguracja zmiennych nie jest poprawna...
    Zadeklarowanie zmiennej ‘integer’ do odczytu ADC nie jest poprawne.
    W Bascom zmienna integer może mieścić liczby zarówno ujemne jak i dodatnie: (-32768 do +32767).
    Twój odczyt ADC nigdy nie będzie ujemny, więc stosowne byłoby przyjąć ‘word’ (2 bajty).
    W Bascom, nie musisz nic kombinować z uśrednianiem zmiennej z dwóch pomiarów bo program już to robi za ciebie, chociaż tego w programie nie widać!
    Aby zabezpieczyć się od zerowych odczytów z potencjometru możesz wprowadzić ograniczenie (SW) softwarowe w programie warunkiem ‘If/then’ albo HW; dodając odpowiedni rezystor pomiędzy potencjometr i GND.
    Jeżeli chcesz mieć 8-bitowy odczyt z ADC (obcinając dwa dolne bity), możesz tego dokonać inna metodą:
    Ustawić bit (5) ADLAR w rejestrze ADMUX powodujący przesunięcie w lewo wyniku z konwersji ADC i odczytywać tylko górny bajt ADCH. Praktycznie podzielenie przez 4 całego odczytu ADC daje ten sam rezultat.
    U ciebie podwojony wynik /8.
    nanab wrote:

    Czas obsługi przerwania-nie mam pojęcia ile trwa, ale nic tam nie ma, odłożenie adresu na stos, wpisanie jednej wartości do jednego rejestru i powrót, kwestia pojedynczych us(nie liczyłem, zgaduję).

    W Bascom, jeżeli nie stosujesz ‘no save’ , potrzebujesz przyjąć minimum 64 cykle zegara na obsługę przerwania + to co jest tam do zrobienia; w twoim przypadku będzie to dodatkowe 5 cykli.
    Ponieważ masz prescaler ustawiony na 256 więc nie ma obawy na brak czasu pomiędzy przerwaniami.

    e marcus

    Marek Skalski: Poprawiłem pisownię. Nie trzeba krzyczeć. ;)
  • #7
    nanab
    Level 27  
    emarcus wrote:


    Nie zmienia, bo masz błąd w innym miejscu.

    Dokładnie to miałem na myśli-że błąd jest gdzieś indziej.
    emarcus wrote:
    Zastanów się, co oznacza nazwa trybu CTC (?) – w ang. jest to ‘Clear Timer on Compare’ (pol. - wyzeruj zawartość licznika/timera, gdy jego zawartość jest równa wyznaczonej z góry i ustalonej, bądź to wyliczonej jakiejś wartości w zmiennej ‘Compare’). Zmienna ta jest umieszczona w rejestrze OCR2 (Compare2).
    Zatem (w tym trybie), zawartość licznika nigdy nie osiągnie jego maksymalnego stanu 255, momentu w którym może wystąpić interrupt OVF2 (w Bascom jest to nazwane ‘Timer2’) z tytułu przepełnienia tego licznika.
    Jeżeli chcesz wywołać przerwanie przy porównaniu zawartości TCNT2 z OCR2, to powinieneś skonfigurować przerwanie od ‘OC2’, albo w Bascom jest to ‘Compare2’, gdzie obie nazwy są akceptowane.

    OC2 zamaist timer2, ok, sprawdzę jak będę w domu.
    emarcus wrote:
    Zadeklarowanie zmiennej ‘integer’ do odczytu ADC nie jest poprawne.
    W Bascom zmienna integer może mieścić liczby zarówno ujemne jak i dodatnie: (-32768 do +32767).

    W późniejszej wersji programu ta zmienna będzie mogła przyjmować ujemne wartości.
    emarcus wrote:

    W Bascom, nie musisz nic kombinować z uśrednianiem zmiennej z dwóch pomiarów bo program już to robi za ciebie, chociaż tego w programie nie widać!

    Tzn.? Za jednym poleceniem robi kilka pomiarów? Z tego co słyszałem(i doświadczyłem w sumie) jest wręcz przeciwnie, bascom nie potrafi poprawnie dokonać normalnego pomiaru, trzeba dla pewności robić po kilka razy "getadc" jedna po drugiej, bo przy pojedynczej może podać wartość z innego wejścia albo całkiem jakieś śmieci.
    emarcus wrote:
    Aby zabezpieczyć się od zerowych odczytów z potencjometru możesz wprowadzić ograniczenie (SW) softwarowe w programie warunkiem ‘If/then’ albo HW; dodając odpowiedni rezystor pomiędzy potencjometr i GND.

    To wiem, będzie w dalszej wersji programu.
    emarcus wrote:
    Jeżeli chcesz mieć 8-bitowy odczyt z ADC (obcinając dwa dolne bity), możesz tego dokonać inna metodą:
    Ustawić bit (5) ADLAR w rejestrze ADMUX powodujący przesunięcie w lewo wyniku z konwersji ADC i odczytywać tylko górny bajt ADCH. Praktycznie podzielenie przez 4 całego odczytu ADC daje ten sam rezultat.

    Bardziej intuicyjne i przejrzyste wydało mi się właśnie dzielenie w kodzie zamiast ustawianie w rejestrach.

    Dodano po 2 [godziny] 44 [minuty]:

    Sprawdziłem- ani z on OC2 tajmer ani z on compare2 tajmer nic się nie zmienia... A właściwie jedno się zmienia-teraz wcale nie wchodzi do przerwania, przy on timer2 tajmer chociaż ten jeden raz się udawało.
  • #8
    emarcus
    Level 38  
    nanab wrote:


    Bardziej intuicyjne i przejrzyste wydało mi się właśnie dzielenie w kodzie zamiast ustawianie w rejestrach.

    Tak, ale nie w tej formie co napisałeś w kodzie.
    Bascom nie wykonuje dwóch działań arytm. lub instrukcji w jednej lini.
    nanab wrote:

    Sprawdziłem- ani z on OC2 tajmer ani z on compare2 tajmer nic się nie zmienia... A właściwie jedno się zmienia-teraz wcale nie wchodzi do przerwania, przy on timer2 tajmer chociaż ten jeden raz się udawało.

    Wyglada że chcesz mi wmówic, że wprowadziłem cię w błąd. Tak nie jest.
    Ja też sprawdziłem z obydwoma kombinacjami (lub mieszane), i ta procedura pracuje tak jak oczekiwano.
    To wyjaw jeszcze sposób 'sprawdzania' :było to na aktualnym sprzęcie(?); czy w symulatorze?
    Wyjaw także swój kod: (ten skorygowany wg wskazówek i nie pracujący ) , a wtedy uzyskasz korektę błędów, które z pewnością nie uważnie popełniasz./

    e marcus
  • #9
    nanab
    Level 27  
    emarcus wrote:

    Bascom nie wykonuje dwóch działań arytm. lub instrukcji w jednej lini.

    Wiem to, wskaż w którym miejscu próbowałem coś takiego zrobić. Chodzi o last=last+getadc(1)? Instrukcja wykonuje się poprawnie.
    emarcus wrote:

    Wyglada że chcesz mi wmówic, że wprowadziłem cię w błąd.

    Nie, po prostu stwierdzam, że po wprowadzeniu zmian nadal nie działa tak jak bym chciał.
    emarcus wrote:
    To wyjaw jeszcze sposób 'sprawdzania' :było to na aktualnym sprzęcie(?); czy w symulatorze?

    Na sprzęcie, dla pewności na dwóch płytkach(korzystam z klona arduino nano z wstawionym atmega8a+7805 zamiast atmega328+ams1117), na obu identyczne zachowanie.

    emarcus wrote:
    Wyjaw także swój kod: (ten skorygowany wg wskazówek i nie pracujący ) , a wtedy uzyskasz korektę błędów, które z pewnością nie uważnie popełniasz./

    To kod z pierwszego postu, tylko konfiguracja przerwania jest:
    Code: vbnet
    Log in, to see the code

    lub
    Code: vbnet
    Log in, to see the code
  • #10
    emarcus
    Level 38  
    nanab wrote:


    To kod z pierwszego postu, tylko konfiguracja przerwania jest:
    Code: vbnet
    Log in, to see the code

    lub
    Code: vbnet
    Log in, to see the code


    No to jeszcze zmień zamiast:

    Code: vbnet
    Log in, to see the code

    na:

    Code: vbnet
    Log in, to see the code


    ‘Stop Timer2 – nie jest potrzebny bo później potrzebujesz go ponownie startowac.
    Nie zawsze jest to bez znaczenia, lecz często zależne od prescalera.
    Jeżeli prescaler = 1, to zatrzymany timer utrzymuje jego zawartośc dopóki nie zostanie wyzerowany. Przy ponownym uruchomieniu incrementuje dalej od tej już istniejącej wartości w jego liczniku do wartości wynikającej z jego konfiguracji.
    Przy innym prescalerze (256) jest sytuacja podobna, ponad to: „Start Timer2’ może przypadkowo trafic gdy prescaler ma wartośc inną niż zero, i moze byc wszędzie pomiędzy: 0 – 256. Z tego powodu pierwszy cykl może byc błędny jeżeli nie towarzyszy mu reset prescalera.
    Ważnośc tych szczegułów zależy od zastosowania timera. Dla zwykłego błyskania diodą, ‘bzykania buzzera’, nie ma to znaczenia.

    I na koniec o zgodności wielkości deklarowanych zmiennych:
    Ponieważ rejestr OCR2 jest tylko 8-bitowy to zmienna przewidziana do przypisania, winna byc tej sasmej ‘długości’.
    Code: vbnet
    Log in, to see the code

    Dalej, instrukcja: ‘Dowpisania = Last / 8’ - zajmuje 247 cykli zegarowych, gdy tymczasem może to byc zastąpione instrukcjami:
    Code: vbnet
    Log in, to see the code

    Co w efekcie zajmuje odpowiednio 34 i 38 cykli zegarowych. Czas tej ostatniej instrukcji obejmuje również konversję 2 bajtowej zmiennej ‘Last’ na zmienną 8-bitową. Zwykłe przypisanie wartości do zmiennej 'kosztuje' 2 do kilka cykli.

    e marcus
  • #11
    nanab
    Level 27  
    emarcus wrote:


    No to jeszcze zmień zamiast:


    Kod: vbnet [rozwiń] [zaznacz wszystko]

    Enable Interrupts
    Enable Timer2
    Stop Timer2

    na:


    Kod: vbnet [rozwiń] [zaznacz wszystko]
    Enable Interrupts
    Enable Oc2
    albo
    'Enable Compare2 'robi to samo co linia wyzej

    Trafna uwaga, o tym zapomniałem. I to rozwiązało problem :)
    emarcus wrote:

    ‘Stop Timer2 – nie jest potrzebny bo później potrzebujesz go ponownie startowac.

    To akurat tak samo jak deklaracja zmiennej "last" jako integer-na przyszłość. W finalnej wersji programu poniżej pewnej częstotliwości timer ma być zatrzymywany. Timer ma generować sygnał dla sterownika silnika krokowego, silnik ma być sterowany z potencjometru-w połowie ma być neutrum(timer zatrzymany), silnik stoi, w skrajnych położeniach silnik kręci z max prędkością w jedną lub w drugą stronę. Dlatego też ten integer, po odjęciu offsetu z odczytanej z potencjometru wartości może wyjść wartość ujemna, wtedy zmieniam stan na "dir" sterownika silnika, a liczbę mnożę razy (-1) dla zmiany znaku i dalej przetwarzam.

    emarcus wrote:
    Dalej, instrukcja: ‘Dowpisania = Last / 8’ - zajmuje 247 cykli zegarowych, gdy tymczasem może to byc zastąpione instrukcjami:

    Kod: vbnet [rozwiń] [zaznacz wszystko]
    Shift Last , Right , 3
    Dowpisania = Last

    Co w efekcie zajmuje odpowiednio 34 i 38 cykli zegarowych. Czas tej ostatniej instrukcji obejmuje również konversję 2 bajtowej zmiennej ‘Last’ na zmienną 8-bitową. Zwykłe przypisanie wartości do zmiennej 'kosztuje' 2 do kilka cykli.

    O tym nie miałem pojęcia, myślałem że to dokładnie to samo polecenie tylko pod innymi literkami, magia bascoma :)