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

[atmega16][bascom] Dziwne zachowanie programu z przerwaniem.

pier 15 Lut 2010 16:01 4439 35
  • #1 7698074
    pier
    Poziom 24  
    Witam
    Koledzy mam taki "program" który zapala i gasi diodę led w odstępach około 1sekundowych:
    
    Do
    Set Porta.3
    Wait 1
    Reset Porta.3
    Wait 1
    loop 
    end
    

    I taki programik działa jak należy ale dlaczego po dodaniu przerwania od timera0 które zmienia stan portu z określoną częstotliwością polecenie wait 1 trwa ponad minutę?
    Mam taki program:
    
    $crystal = 4000000
    Config Timer0 = Timer , Prescale = 1
    Enable Interrupts
    Enable Timer0
    Load Timer0 , 53
    
    On Timer0 Ir
    
    Do
    Set Porta.3
    Wait 1
    Reset Porta.3
    Wait 1
    loop
    
    Ir:
    Load Timer0 , 53
    Toggle Portd.5
    Return
    
    
    End
    
    
    


    Czy mam jakiegoś buga w programie?
  • Pomocny post
    #2 7698204
    landy13
    Poziom 31  
    Instrukcja WAIT
    Przeznaczenie:
    Przerywa działanie programu na określony czas.

    Składnia:
    WAIT il_sekund
    Opis:

    Instrukcja wstrzymuje działanie programu na podaną ilość sekund. Odmierzany czas jest wartością przybliżoną, więc nie należy stosować tej instrukcji do dokładnego odmierzania czasu. Używanie przerwań, może znacznie wydłużyć działanie instrukcji.



    (c) Zbigniew Gibek, 2002-2005 (c) MCS Electronics, 1999-2005
  • #3 7698220
    pier
    Poziom 24  
    Tak właśnie myślałem że używanie przerwań i poleceń wait nie jest dobrym rozwiązaniem. Dzięki za odpowiedź.
  • #5 7698450
    Konto nie istnieje
    Poziom 1  
  • #6 7699397
    janbernat
    Poziom 38  
    Aż sprawdziłem na ATMega8- bo nie mam 16.
    No i tak jest.
    
    $regfile "m8def.dat"
    $crystal = 4000000
    Config Timer0 = Timer , Prescale = 1
    Config Portb = Output
    Enable Interrupts
    Enable Timer0
    Load Timer0 , 53
    
    'On Timer0 Ir
    
    Do
    Set Portb.0
    'Portb.0 = 1
    Wait 1
    'sei
    Reset Portb.0
    'Portb.0 = 0
    Wait 1
    'sei
    loop
    
    '(
    Ir:
    'sei
    Load Timer0 , 53
    Toggle Portb.2
    Return
    ')
    
    End
    
    

    To w ciapkach ' to można sobie sprawdzić.
    Nie wiem, ale jakby w wait wyłączał sobie przerwania.
    Może ktoś wie.
  • #7 7699496
    Konto nie istnieje
    Poziom 1  
  • #8 7699524
    janbernat
    Poziom 38  
    Jakby Ci się chciało sprawdzić:
    Odremuj:
    'On Timer0 Ir
    I to:
    '(
    Ir:
    'sei
    Load Timer0 , 53
    Toggle Portb.2
    Return
    ')
    I wtedy jest PORTB.0 znieniany co kilka s.
  • #9 7699672
    mirekk36
    Poziom 42  
    pier napisał:
    Tak właśnie myślałem że używanie przerwań i poleceń wait nie jest dobrym rozwiązaniem. Dzięki za odpowiedź.


    To nie ma nic wspólnego. Po to są przerwania żeby w ten sposób z nich korzystać.

    Natomiast twój problem bierze się z całkowicie czegoś innego. Po prostu tak napisałeś przerwanie i tak często je wykonujesz, że u ciebie w tym konkretnym przypadku zajętość procesora na potrzeby przerwania to bardzo duży procent. Przez co nie dziwne , że nie tylko polecenia wait ale i wszystkie inne procedury będą ci działały jak muchy w smole. Trzeba w końcu nauczyć się:

    1. albo w celu generowania nośnej korzystać ze sprzętowego PWM'a
    2. albo w celu generowania nośnej korzystać z programowego togglowania jak ty to robisz ale wykorzystując tryb timera o nazwie CTC żeby ustawić sobie wartość OCRx na 53 i wtedy już w przewaniu unikniesz linijki:

    Load Timer0 , 53 


    i już kod przerwania będzie krótszy szczególnie że nie wiedzieć czemu stosujesz takie niskie częstotliwości taktowania procesora. Ja osobiście jeszcze nigdy gdy używałem wewn oscylatora nie pracowałem na procku, który byłby taktowany mniej niż 8MHz !!! Po co się bawić w 4MHz albo jak niektórzy 1MHz ? ;)

    a teraz kilka faktów i przeliczeń żebyś wiedział dlaczego tak się u ciebie dzieje i dlaczego byłoby już dużo lepiej gdybyś zrobił to choćby z Timerem w trybie CTC i taktowaniem 8MHz

    Po pierwsze taktujesz procka 4MHz czyli 1cykl=250ns - prawda? (jak dla mnie to kupa czasu - marnotraswo po prostu)

    Swoje przerwanie wywołujesz z częstotliwością 4MHz/53 czyli ok 75,5Khz czyli co ok 13,2us - prawda ? dosyć często

    więc policzmy ile cykli (rozkazów) może się wykonać pomiędzy przerwaniami , czyli 13,2us / 250ns = ok 52 cykle - czyli tylko ok 52 rozkazy asemblera. I te 52 cykle to w uproszczeniu 100% zajętości procesora.

    I teraz tak - gdyby przerwanie od Timera było wykonywane powiedzmy w 10 rozkazach (cyklach) czyli 2,5us to już dla programu głównego zostałoby o tyle mniej prawda?

    A teraz weź pod uwagę, że Bascomowe przerwanie nawet puste to DUUUUŻO DUUUŻO więcej niż 10 rozkazów asemblerowych. W związku z czym może ono u ciebie zabierać prawie 120% czasu (bo jeśli przerwanie ma ze 100 rozkazów cykli to będzie się wykonywało DŁUŻEJ niż te 13,2us!!!!) - przez co wydaje się, że program w pętli głównej się Ślimaczy pomimo to że nośna jest generowana OK ;) .... po prostu masakra amerykańską piłą tarczową na własne życzenie.

    -------------

    A teraz?

    A teraz dajesz sobie taktowanie 8MHz (co za problem przestawić fusebity i zmienić dyrektywę Crystal w Bascomie???) i co się będzie działo?

    1 dzielone przez 8MHz daje ci jeden cykl o długości 125ns (wiadomo cztery razy szybciej niż poprzednio)

    przerwanie ustawiasz nadal tak samo czyli co 13,2us (tylko inne wartości dajesz do OCR albo u siebie Load Timer, xx gdzie xx będzie teraz nie 53 a ok 106 (co za problem?)

    i teraz najważniejsze - ile rozkazów może się wykonać pomiędzy przerwaniami ? już ok 105 cykli. Więc jeśli np przerwanie wykonywać się będzie nawet 80cykli to już polecenie Wait 1 nie będzie się aż tak kosmicznie wydłużało.


    I dla porówniania dajesz tym razem kwarc 16MHz - czyli 1cykl = 62ns !!!! - więc sam widzisz co dalej się dzieje pozytywnego z twoim programem i obciążeniem procka przez takie szczególnie Bascomowe przerwanie, które ma okropnie długi tzw prolog i epilog.

    ------------------------------------

    Reasumując jeśli byś nawet przy 4MHz użył opcji NOSAVE dla przerwania Timera i napisałbyś w czystym asemblrze cykliczną zmianę stanu pinu wyjściowego co dałoby radę zrobić na prawdę w kilku instrukcjach to i na tych 4MHz twoje Wait 1 trwałoby jedną sekundę jak się należy. No ale tu trzeba by umieć w asemblerze programować

    Oczywiście to całe tłumaczenie moje - jest takie w przybliżeniu ale dobrze oddaje istotę twojego i nie tylko twojego problemu w takich programach.



    janbernat - Wait w Bascomie nie wyłącza żadnych przerwań - to byłoby niestety bez sensu. Myślę że te moje objaśnienia chociaż troszkę będą zrozumiałe.
  • #10 7700119
    landy13
    Poziom 31  
    mirekk36 napisał:
    Wait w Bascomie nie wyłącza żadnych przerwań - to byłoby niestety bez sensu.
    Oczywiście, że nie wyłącza (i może nie niestety, a na szczęście). To przerwania wydłużają Waita.
  • #11 7700978
    leon1313
    Poziom 15  
    Config Timer0 = Timer , Prescale = 1 

    Jeśli chcesz dokładnie odmierzać czas, to zapomnij o preskalerze 1
    Ciekawe, ile czasu trwa zrzucanie rejestrów na stos...
  • #12 7701056
    Konto nie istnieje
    Poziom 1  
  • #13 7702688
    janbernat
    Poziom 38  
    Ten load Timer mnie zmylił.
    Zawsze ustalam wartość początkową.
    Wyliczenia i sprawdzenie:
    Tak jak podał mirekk36- przerwanie co 13.2us
    Z tego co podał atom1477- odkładanie na stos 14us.
    Czyli praktycznie cały czas w przerwaniu.
    Ale układ gubi co drugie przerwanie i na wyjściu toggle stan zmienia się co 28.1us
    (teoretycznie powinien co 26.4us ale ostatecznie w tym przerwaniu też coś robi)
    W zasadzie program w pętli wcale nie powinien się wykonywać ale z tego co pamiętam przed wejściem do następnego przerwania procesor musi wykonać przynajmiej jeden cykl programu.
    To i tak szybko się wykonuje- tylko kilka minut.
  • #14 7703333
    pier
    Poziom 24  
    Według mnie najlepszym sposobem na generowanie przebiegu przez timer było by włączenie trybu CTC. Bo przecież do trybu CTC nie potrzeba nawet programu tylko polecenie konfiguracji timera. Ale jak widać w tym temacie próbowałem go bezskutecznie uruchomić. Może ma ktoś jakiś sprawdzony sposób na włączenie trybu CTC, albo jak za pomocą pwma wygenerować przebieg 36kHz?
  • #15 7704241
    zumek
    Poziom 39  
    pier napisał:
    ... próbowałem go bezskutecznie uruchomić.

    Nie wiem jaką masz wersję Bascoma, ale np. v1.11.9.8 ma błąd przy konfiguracji T0 w trybie CTC, dla ATMega16
    pier napisał:

    Może ma ktoś jakiś sprawdzony sposób na włączenie trybu CTC, albo jak za pomocą pwma wygenerować przebieg 36kHz?

    Sprawdzony sposób na wszystko, to ... czytanie dokumentacji, używanie helpa itp dyrdymałów :idea:
    A więc zaglądamy do dokumentacji Bascoma oraz ATMega16 i ""płodzimy" taki kod:
    
    $regfile = "m16def.dat"
    $crystal = 4000000
    
    Const Reload_t0 = Int(_xtal / 76000 - 1)
    Const T0_ctc_mode = 2 ^ Com00 Or 2 ^ Wgm01 Or 2 ^ Cs00
    Set Ddrb.pb3
    Ocr0 = Reload_t0
    Tccr0 = T0_ctc_mode
    
    Stop
    


    Albo uruchamiamy symulator i ...już wiemy, że kompilator się rypnął :D
    Korygujemy więc błąd "maszyny" ;)
    
    $regfile = "m16def.dat"
    $crystal = 4000000
    
    Const T0_reload = Int(_xtal / 76000 - 1)
    Ocr0 = T0_reload
    Config Timer0 = Timer , Prescale = 1 , Compare = Toggle , Clear Timer = 1
    Set Ddrb.pb3
    'Compiler     : BASCOM-AVR LIBRARY V 1.11.9.8
    'ustawia jako wyjście PB4, a powinien PB3
    Reset Ddrb.pb4
    Stop
    
  • #16 7724417
    pier
    Poziom 24  
    Próbowałem rozwiązania Zumka ale nadal nie działa.
    Może problem w tym że ja mam wersję bascoma 1.11.7.4.
    A jak wygenerować ten przebieg za pomocą pwm-a?
  • #17 7728985
    pier
    Poziom 24  
    Chyba wymyśliłem jak za pomocą pwm-a wygenerować ten przebieg.
    Muszę tylko zastosować zewnętrzny kwarc co najmniej 10MHz bo z wewnętrznego generatora 8MHz przy preskalerze ustawionym na 1 mogę wyciągnąć maksymalnie: 8000000/(256*1)=31250Hz, a to trochę za mało. Przy kwarcu 10MHz wyjdzie już 10000000/(256*1)= 39062Hz a to za dużo. Nie wiem tylko jak dalej to pociągnąć aby wyszło równe 36000Hz. Może ktoś podać wzór jak to się oblicza?
  • #18 7729005
    Konto nie istnieje
    Poziom 1  
  • #19 7729037
    pier
    Poziom 24  
    No właśnie tylko jak to zrobić i o ile?
  • #20 7729073
    Konto nie istnieje
    Poziom 1  
  • #21 7729179
    janbernat
    Poziom 38  
    ATMega16 ma tryb CTC- ale nie mam 16 aby sprawdzić.
    Strona 83 pdf.
    Nie jest to tryb PWM tylko CTC.
    Ustawić cierpliwie rejestry i zmierzyć.
  • #22 7729220
    Konto nie istnieje
    Poziom 1  
  • #23 7729232
    pier
    Poziom 24  
    Wiem że atmega16 ma tryb CTC który próbowałem bezskutecznie włączyć. Kolega Zumek napisał że bascom ma w tym miejscu błąd i nawet po zastosowaniu jego wskazówek nie mogłem tego trybu uruchomić a było by to najlepsze rozwiązanie.
    Męczę się już z tym przebiegiem strasznie i nic mi nie wychodzi.
    Może ktoś by mi napisał gotowca do bascoma jak skonfigurować timer1 dla atmega16 aby pracował on w trybie pwm z częstotliwością ok 36kHz dla wewnętrznego generatora 8MHz lub kwarcu 10MHz tak żebym to zrozumiał.
    Bo na włączenie trybu CTC nie mam już nadziei.


    A tak w ogóle to doszedłem do tego że należy skonfigurować timer1
    do pracy w trybie FAST PWM a później w pętli DO:LOOP wpisać pwm1a = 222 czy tak?
  • #24 7730301
    Konto nie istnieje
    Poziom 1  
  • #25 7730354
    pier
    Poziom 24  
    A mógłby kolega wyjaśnić co każda linijka znaczy i co ustawia? Tak abym mógł to zrozumieć i nie męczyć już nikogo.
    I nie potrzeba konfigurować już timera1?
  • #26 7730474
    Konto nie istnieje
    Poziom 1  
  • #27 7730743
    mirekk36
    Poziom 42  
    Widzisz pier - pomyśl w przyszłości nad językiem C (namawiam cię gorąco), tam zrobienie nośnej w oparciu o sprzętowy CTC to pikuś i zobacz jak jasno - sam chyba zrozumiesz tu o co chodzi

    tu masz CTC i wypełnienie 50%

    	// TIMER0	
    	TCCR0 |= (1<<WGM01);	// Tryb CTC (Mode 2)
    	TCCR0 |= (1<<COM00)	// Toggle OC0 on compare match
    	TCCR0 |= (1<<CS00);	// Prescaler = 1
    	OCR0=111;           // podział przez 111 (częstotliwość: ok 72.072kHz czyli ok 36kHz na wyjściu OC0


    Żeby dokładnie zrozumieć te powyższe ustawianie bitów zajrzyj do noty PDF procka do rozdziału:

    "8-bit Timer/Counter0 with PWM"


    i podrozdziału:

    Cytat:
    "8-bit Timer/Counter Register Description"


    gdzie masz ładnie po kolei opisane bity w rejestrze TCCR0

    Na podobnej zasadzie można je oczywiście poustawiać za pomocą asemblera w Bascomie jak to robił wyżej atom1477
  • #28 7730803
    pier
    Poziom 24  
    Wiem wiem że przydało by się przejść na C bo bascom jest dobry tylko do prostych rzeczy. Walczę z moim problemem bezskutecznie już za długo i nie mam już siły.
    Czyli kolega Atom1477 zrobił to za pomocą asemblera? Czy trzeba o tym informować kompilator?
  • #29 7730841
    Konto nie istnieje
    Poziom 1  
  • Pomocny post
    #30 7730898
    mirekk36
    Poziom 42  
    Nic nie trzeba informować kompilatora - Bascom ładnie przyjmuje wprost rozkazy asemblera ale w zasadzie atom1477 zrobił to nawet bez asemblera - sorki - po prostu "ręcznie" odwołał się do rejestrów i wpisał do nich odpowiednie wartości tzn poustawiał bity tak żeby coś tam działało

    w tym przypadku co ja ci podałem trza by to było mniej więcej zrobić tak:

    DDRB.3 = 1
    TCCR0 = &B00011001
    OCR0=111


    i już masz to samo co napisane w C - porównaj sobie te jedynki w tej wartości binarnej z rejestrem TCCR0 w nocie PDF i zobaczysz że ustawiłem dokładnie te co wyżej w kodzie napisanym w C. Tyle że taki zapis jest o wiele mniej czytelny sam przyznasz ;)

    Generalnie po takim kodzie powinieneś mieć już na wyjściu OC0 czyli PB3 ładną nośną. Inna kwestia że aby ją teraz wyłączać i włączać to nie wiem czy da radę tylko pisać w Bascomie Start Timer0 czy Stop Timer0 - na pewno za to zadziała zerowanie bitów CS2..0 żeby zatrzymywać nośną albo tylko zerowanie bitu COM00 i włączanie go.....
REKLAMA