Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATTiny45] - Timer nie uruchamia się

piotr92 27 Maj 2010 23:34 1921 18
  • #1 27 Maj 2010 23:34
    piotr92
    Poziom 10  

    Witam
    To mój jeden z pierwszych programów. Procesor ma zmieniać co 1minute stan 2 portów na przeciwny lub ręcznie przyciskiem przez użytkownika. Niestety Timer nie załącza się a porty raz zmieniają sie tak jak mają a raz nie. Proszę o pomoc. Procesor to ATTiny45.

    Code:
    $regfile = "attiny45.dat"
    
    $crystal = 4000000

    Config Pinb.0 = Output                                      'wyjście
    Config Pinb.1 = Output                                      'wyjście
    Config Pinb.2 = Input                                       'przycisk

    Portb.0 = 1
    Portb.1 = 0
    Portb.2 = 1

    Dim Js As Byte

    Config Timer0 = Timer . Prescale = 1024

    Start Timer0
    Do
    Debounce Pinb.2 , 0 , Pr
    Pr:
    Toggle Portb.1
    Toggle Portb.0
    Loop

    Zegar:
       Incr Js
       If Js = 2 Then
       Js = 0
       Toggle Portb.0
       Toggle Portb.1
       End If
    Return
    End

    Dziękuję i pozdrawiam

    0 18
  • #2 27 Maj 2010 23:40
    mirekk36
    Poziom 42  

    A globalne włączenie przerwań

    Enable Interrupts

    zjdała amba ? ;)

    Dodano po 2 [minuty]:

    ooo jej a poza tym co to za pętla Do .. Loop w której środku znajduje się procedura PR:

    poza tym co to za podprogram oderwany od rzeczywistości ZEGAR:

    0
  • #3 27 Maj 2010 23:45
    piotr92
    Poziom 10  

    To bez pętli ma być?

    0
  • #4 27 Maj 2010 23:47
    mirekk36
    Poziom 42  

    Wymieniłem ci 3 błędy i to poważne a ty pytasz czy bez pętli ma być? Nawet nie wiem co na takie pytanie opdowiedzieć.

    0
  • #5 27 Maj 2010 23:50
    piotr92
    Poziom 10  

    Pętle to już wiem mniej więcej jak zrobić tylko jak powiązać ten ZEGAR?

    0
  • #6 28 Maj 2010 00:01
    mirekk36
    Poziom 42  

    Twoja procedura Zegar: wygląda mi na zagubioną w kosmosie procedurę może obsługi jakiegoś przerwania Timera ? ;) może timera0

    No tylko żeby ona toglowała piny raz na minutę to trzeba odpowiednio jeszcze preskaler i w ogóle dzielnik podobierac oraz podciągnąć jeszcze podział tą zmienną Js

    0
  • #7 28 Maj 2010 19:14
    piotr92
    Poziom 10  

    Code:
    $regfile = "attiny45.dat"
    
    $crystal = 4000000

    Config Pinb.0 = Output                                      'wyjście
    Config Pinb.1 = Output                                      'wyjście
    Config Pinb.2 = Input                                       'przycisk
            Portb.0 = 1
            Portb.1 = 0
            Portb.2 = 1

    Dim Js As Byte
    Config Timer0 = Timer . Prescale = 1024
    Enable Interrupts
    Enable Timer0
    Start Timer0
    on ovf0 zegar
    'Gosub Zegar

    Do
     If Pinb.2 = 0 Then
     Toggle Portb.0
     Toggle Portb.1
     End If

    Loop



    Zegar:
       Incr Js
       If Js = 255 Then
       Js = 0
       Toggle Portb.0
       Toggle Portb.1
       End If
    Return
    End


    Poprawiłem i powiązałem ten zegar tylko Js zmienia się do 1 a Timer0 nadal nie chodzi.

    0
  • #8 28 Maj 2010 19:43
    Logan
    Poziom 30  

    Zobacz w HELPie On Interrupt

    0
  • #9 28 Maj 2010 20:16
    piotr92
    Poziom 10  

    Nadal Timer0 w symulacji pokazuje 0. Jak obliczyć Js i prescale aby zmieniał co minutę przy kwarcu 4MHz? Może z Bascom'em jest coś nie tak?
    Pozdrawiam

    -1
  • #10 28 Maj 2010 20:38
    mirekk36
    Poziom 42  

    piotr92 napisał:
    Może z Bascom'em jest coś nie tak?


    Niestety dokąd będziesz zadawał takie pytania , dotąd nie nauczysz się programować. Jak ci coś nie wychodzi, to szukaj błędu u siebie, w swojej niewiedzy a nie w kompilatorach, środowiskach, procesorach itd

    0
  • #11 28 Maj 2010 20:51
    piotr92
    Poziom 10  

    Racja. Tylko nie mogę znaleźć tego błędu i proszę o pomoc.

    -1
  • #12 28 Maj 2010 21:12
    micha3
    Poziom 12  

    To ja Ci może podpowiem:
    nie masz zdefiniowanej procedury która ma być wykonywana podczas przerwania od Timer0. Najprawdopodobniej jest to 'Zegar' ale Bascom o tym nie wie.

    0
  • #13 28 Maj 2010 21:24
    piotr92
    Poziom 10  

    To co to jest GOSUB?

    -1
  • #14 28 Maj 2010 21:42
    landy13
    Poziom 29  

    Tłumaczą Ci ludzie już drugi dzień. Zwłaszcza kolega Logan. Czy tak trudno przeczytać w Helpie:

    Cytat:
    Instrukcja ON INTERRUPT


    Przeznaczenie:

    Wykonuje skok do podprogramu gdy wystąpiło określone przerwanie.


    Składnia:

    ON źródło_przerwania nazwa_podprogramu [ NOSAVE ]



    gdzie:

    źródło_przerwania symboliczna nazwa źródła przerwania,
    nazwa_podprogramu etykieta określająca gdzie znajduje się podprogram obsługi przerwania.


    Opis:

    Gdy wystąpi określone przerwanie – określone symbolicznie po słowie ON – instrukcja skacze do podanego podprogramu.

    Język BASCOM BASIC rozpoznaje następujące źródła przerwania (po przecinku podano nazwy w konwencji stosowanej przy opisie procesorów AVR):



    INT0 przerwanie zewnętrzne końcówka INT0
    INT1 przerwanie zewnętrzne końcówka INT1
    INT2 przerwanie zewnętrzne końcówka INT2 (tylko niektóre kontrolery)
    INT3 przerwanie zewnętrzne końcówka INT3 (tylko niektóre kontrolery)
    INT4 przerwanie zewnętrzne końcówka INT4 (tylko niektóre kontrolery)
    INT5 przerwanie zewnętrzne końcówka INT5 (tylko niektóre kontrolery)
    TIMER0, OVF0 przerwanie przepełnienia licznika TIMER0
    TIMER1, OVF1 przerwanie przepełnienia licznika TIMER1
    TIMER2, OVF2 przerwanie przepełnienia licznika TIMER2 (tylko niektóre kontrolery)
    ADC, ADCC przerwanie przetwornika A/D (tylko niektóre kontrolery)
    EEPROM, ERDY przerwanie - gotowość wbudowanej pamięci EEPROM
    CAPTURE1, ICP1 przerwanie rejestru przechwycenia licznika TIMER1
    COMPARE1A, OC1A przerwanie pierwszego rejestru porównania licznika TIMER1
    COMPARE1B, OC1B przerwanie drugiego rejestru porównania licznika TIMER1
    COMPARE1 przerwanie rejestru porównania licznika TIMER1
    OC2 przerwanie rejestru porównania licznika TIMER2 (tylko niektóre kontrolery)
    SPI przerwanie interfejsu SPI
    URXC przerwanie układu sprzętowego UART – odebranie znaku
    UTXC przerwanie układu sprzętowego UART – wysłanie znaku
    UDRE przerwanie układu sprzętowego UART – bufor pusty
    ACI przerwanie wewnętrznego komparatora


    Ilość i źródła przerwań są ściśle związane z budową użytego procesora AVR. Nazwy możliwych przerwań można znaleźć w pliku rejestrów wybranego procesora. Na przykład w pliku 2313def.dat podano, że istnieje źródło przerwania nazwane COMPARE1 (patrz na końcu pliku).

    Procedura obsługi musi się kończyć instrukcją RETURN, co spowoduje, że na końcu procedury zostanie umieszczona instrukcja maszynowa RETI.
    Instrukcja RETURN może występować w kilku miejscach podprogramu. W przypadku podprogramów obsługi przerwań tylko pierwsza instrukcja RETURN zostanie przetłumaczona na sekwencję powrotu z przerwania (tj. odtworzenie stanu rejestrów i wykonanie RETI). Przy czym nie może ona występować w połączeniu z instrukcja warunkową. Wszystkie dalsze instrukcje RETURN zostaną skompilowane do zwykłego RET.







    Określenie parametru NOSAVE spowoduje, że zawartość rejestrów nie będzie zapamiętana przed wejściem do procedury przerwania i odtworzona na jej końcu. Dlatego też, gdy podano NOSAVE należy zapewnić by zawartość rejestrów została zapamiętana i otworzona. Służą do tego instrukcje PUSHALL i POPALL.
    Gdy parametr NOSAVE nie występuje, zawartość wszystkich rejestrów zostanie automatycznie zapamiętana i odtworzona. Dotyczy to tylko rejestrów użytkowych R31-R16, R11-R10 i rejestru SREG.


    Jeśli w procedurze obsługi przerwania wykonywane są operacje na liczbach typu Single (nie zalecane!), należy zapamiętać a potem odtworzyć zawartość rejestrów R12-R15. Na przykład:


    Moja_ISR:
    Push R12 'zapamiętaj rejestry na stosie
    Push R13
    Push R14
    Push R15
    Single = single + 1 'używamy operacji zmiennoprzecinkowej
    Pop R15 'odtwarzamy zawartość rejestrów
    Pop R14
    Pop R13
    Pop R12
    Return



    Zrozumieć przerwania

    By przybliżyć idee działania przerwań, można sobie wyobrazić następującą sytuację: W dość dużym domu z ogrodem jest zatrudniona osoba zajmująca się pracą w ogrodzie jak i w roli kamerdynera. Kamerdyner gdy nie ma co robić strzyże żywopłot lub pracuje w ogrodzie. Gdy ktokolwiek zadzwoni do drzwi frontowych obowiązkiem kamerdynera jest zostawienie nożyc w ogrodzie, zrzucenie ubrania roboczego i przystąpienie do obowiązków przyjmowania gości.
    Gdy wszystkie grzeczności zostaną już zakończone, kamerdyner znów wraca do miejsca w którym przerwał pracę ogrodnika i zostawił nożyce.

    W powyższym przykładzie (przytoczonym przez tłumacza) źródłem przerwania jest dzwonek u drzwi, a procedurą obsługi są wszystkie działania kamerdynera począwszy od usłyszenia sygnału dzwonka, a skończywszy na powrocie do pracy ogrodnika.

    W przełożeniu na język BASCOM BASIC, wygenerowanie sygnału przerwania spowoduje wstrzymanie działania programu głównego, gdyż procesor przechodzi do wykonywania procedury obsługi przerwania. Po zakończeniu procedury procesor wraca do miejsca w którym zatrzymał program główny. Można na przykład stworzyć pustą pętlę DO..LOOP, która będzie przerywana, gdy na określonej końcówce pojawi się stan niski.



    Najlepszym przykładem wykorzystania przerwań jest program zegara. Można zaprogramować któryś z liczników, by co 10ms generował przerwanie. Procedura jego obsługi będzie zliczać te impulsy. Naliczenie 100 impulsów oznacza, że upłynęła właśnie jedna sekunda i trzeba licznik sekund zwiększyć. Gdy przepełni się licznik sekund (>59), zwiększany będzie licznik minut, itd.
    Program główny będzie się zajmował tylko obsługą klawiatury i wyświetlacza, nie zważając na to co robi procedura przerwania.


    Używanie przerwań w języku BASCOM BASIC.

    By używać przerwań we własnych programach należy obowiązkowo włączyć globalny system przerwań instrukcją ENABLE INTERRUPTS, oraz włączyć odpowiednie źródło przerwania. Na przykład:



    Enable Timer0


    spowoduje, że będą generowane przerwania przepełnienia licznika TIMER0. Instrukcją DISABLE można wyłączyć system przerwań jak i poszczególne ich źródła.


    Gdy procesor stwierdzi, że wystąpiło przerwanie, skacze pod ustalony adres, umieszczony na początku pamięci FlashROM. Adresy te i powiązane z nimi źródła przerwań są zdefiniowane przez projektantów z firmy Atmel. Przeglądając plik .DAT można dowiedzieć się, o które adresy dokładnie chodzi.
    Normalnie pod tymi adresami kompilator BASCOM BASIC umieszcza instrukcje RETI, więc po wygenerowaniu przerwania, nic się nie dzieje i procesor natychmiast wraca do programu głównego.


    Gdy jednak w programie umieszczona będzie instrukcja ON INTERRUPT, wtedy pod odpowiednim adresem procedury obsługi przerwania zostanie umieszczony skok do podprogramu, którego adres określa podana etykieta.
    Przed wykonaniem jednak zawartego pod podaną etykietą kodu, zostanie zapamiętana zawartość rejestru SREG i rejestrów użytkowych. Zostaną one później przed wykonaniem właściwej instrukcji RETURN odtworzone. Chodzi o to, by po powrocie z przerwania stan procesora był dokładnie taki sam jak tuż przed wystąpieniem przerwania. Inaczej mogłoby dojść do zakłóceń w działaniu programu głównego. Zakończyło by się to pewnie – w żargonie programistów - “pójściem w maliny” programu.



    Gdy procesor jest w trakcie wykonywania procedury przerwania, następne przerwanie nie będzie przyjęte, gdyż procesor (nie kompilator!) zeruję flagę globalnego zezwolenia na przerwania. Tak samo flaga bieżącego przerwania (tego, którego procedura obsługi jest wykonywana) zostaje automatycznie wyzerowana. Po zakończeniu przerwania flaga globalnego zezwolenia jest na powrót ustawiana i procesor może przyjąć następne przerwanie.

    W procesorach AVR nie jest zatem możliwe swobodne ustawienie priorytetu źródeł przerwań. Standardowo priorytet jest ustawiany według adresów programów obsługi. Dlatego przerwania o niższym adresie stoją wyżej w hierarchii (mają wyższy priorytet)!



    Wskazówki dotyczące obsługi przerwań

    · Gdy wykorzystano przerwania w celu generacji impulsów, np. co 10ms, należy się upewnić czy procedura obsługi będzie w stanie zakończyć się w czasie krótszym niż 10ms. Inaczej można doprowadzić do zapętlenia się przerwań!



    · Polecane jest utworzenie flagi (widocznej w programie głównym), która byłaby ustawiana w trakcie działania podprogramu przerwania i zerowana przed wyjściem z procedury. Pozwala to na podanie parametru NOSAVE, co w rezultacie spowoduje mniejsze rozrastanie się stosu oraz zredukuje użytą pamięć programu. Należy jednak zadbać by zapamiętać i odtworzyć zawartość rejestrów R24 i SREG.



    Zobacz także: ENABLE , DISABLE





    Przykład:



    Enable Interrupts

    Enable Int0 'włączenie przerwania

    On Int0 Label2 Nosave 'nastąpi skok do Label2 gdy wystąpi przerwanie

    Do 'nieskończona pętla

    Loop



    End





    Label2:

    Dim a As Byte

    If a > 1 Then

    Return 'zastąpione będzie przez RET, gdyż

    'jest powiązanie z instrukcja IF

    End if



    Return 'zostanie przetłumaczone na RETI, gdyż

    'jest to pierwsza instrukcja RETURN



    Return 'zostanie przetłumaczone na RET, gdyż

    'jest to następna instrukcja RETURN





    (c) Zbigniew Gibek, 2002-2005 (c) MCS Electronics, 1999-2005

    Jeśli trudno to porzuć programowanie - są łatwiejsze profesje.

    0
  • #15 29 Maj 2010 00:34
    piotr92
    Poziom 10  

    OK te pętle zrobiłem. Tylko jak zrobić żeby to przerwanie było co 1 minutę?
    Teraz on liczy do 256 i zmienia stan. Podłącze kwarc 4MHz.
    Pozdrawiam

    0
  • Pomocny post
    #16 31 Maj 2010 20:08
    jacekk232
    Poziom 16  

    Witam.

    Możesz zrobić tak:

    Code:
    Config Timer0 = Timer , Prescale = 64
    
    Timer0=6
    Enable Interrupts
    Enable Timer0
    Start Timer0
    On Timer0 zegar

    Przy takim ustawieniu przerwanie będzie wywoływane dokładnie co 4ms.
    Zmienną Js zdeklaruj jako Word.
    A w podprogramie Zegar zrób tak:
    Code:
    Zegar:
    
       Timer0 = 6
       Incr Js
       If Js = 15000 Then
           Js = 0
           Toggle Portb.0
           Toggle Portb.1
       End If
    Return

    Zmienna Js będzie zwiększana o jeden co 4ms. Łatwo policzyć, że wartość 15000 osiągnie dokładnie po 60 sekundach. Tak więc PB0 i PB1 będą zmieniać swe stany na przeciwne co minutę.

    Pozdrawiam Jacek

    0
  • #17 02 Cze 2010 23:36
    piotr92
    Poziom 10  

    Dziękuje bardzo za pomoc. Ostatnio nie miałem dostępu do internetu i napisałem coś takiego:

    Code:
    $regfile = "attiny45.dat"
    
    $crystal = 4000000

    Config Pinb.0 = Output                                      'wyjście
    Config Pinb.1 = Output                                      'wyjście
    Config Pinb.2 = Input                                       'przycisk
            Portb.0 = 1
            Portb.1 = 0
            Portb.2 = 1

    Config Timer0 = Timer , Prescale = 1024
    Enable Interrupts
    Enable Timer0
    Start Timer0
    Dim Js As Integer

    Do
       Incr Js
       If Js = 1000 Then
       Js = 0
       Toggle Portb.0
       Toggle Portb.1
       End If
       Debounce Pinb.2 , 0 , Pr , Sub
    Loop

    Pr:
    Toggle Portb.0
    Toggle Portb.1
    Return
    End

    Proszę mi z ciekawości powiedzieć czy mój program jest dobry.
    Pozdrawiam

    0
  • #18 03 Cze 2010 06:56
    Logan
    Poziom 30  

    A gdzie masz On Timer0 o którym wszyscy Ci mówimy?!

    0
  • Pomocny post
    #19 03 Cze 2010 16:26
    jacekk232
    Poziom 16  

    Jeśli chcesz robić odliczanie w pętli głównej to zrób tak:

    Code:
    $regfile = "attiny45.dat"
    
    $crystal = 4000000

    Config Pinb.0 = Output                                      'wyjście
    Config Pinb.1 = Output                                      'wyjście
    Config Pinb.2 = Input                                       'przycisk
            Portb.0 = 1
            Portb.1 = 0
            Portb.2 = 1

    Config Timer0 = Timer , Prescale = 1024
    Enable Interrupts
    Enable Timer0
    Start Timer0
    On Timer0 Zegar

    Dim Flaga As Bit
    Dim Js As Integer

    Do
    If Flaga = 1 Then
       Flaga = 0
       Incr Js
       If Js = 1000 Then
          Js = 0
          Toggle Portb.0
          Toggle Portb.1
       End If
    End If
    Debounce Pinb.2 , 0 , Pr , Sub
    Loop
    End

    Zegar:                     
    Flaga = 1                     'zmienna Flaga ustawiana co około 65ms
    Return

    Pr:
    Toggle Portb.0
    Toggle Portb.1
    Return

    0