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.

Zegarek na LCD i atmega8 ,brak precyzji...i Timer'ów.

jacynka84 11 Lis 2006 23:57 5092 38
  • #1 11 Lis 2006 23:57
    jacynka84
    Poziom 26  

    Cześć.
    Zrobiłem prosty zegarek na LCD i atmega8 ,
    kwarc wewnętrzny 8Mhz
    No i problem ,kod jest dość prymitywny :

    Code:
     Config Lcdpin = Pin , Db4 = Portb.2 , Db5 = Portb.3 , Db6 = Portb.4 , Db7 = Portb.5 , E = Portb.1 , Rs = Portb.0
    
    Config Lcd = 16 * 2

    Dim Sekunda As Byte
    Dim Minuta As Byte
    Dim Godzina As Byte

    Do

    Waitms 1000
    Incr Sekunda

    If Sekunda = 59 Then
    Sekunda = 0
    Incr Minuta
    End If

    If Minuta = 59 Then
    Minuta = 0
    Incr Godzina
    End If

    If Godzina = 24 Then
    Godzina = 0
    End If

    If Sekunda = 20 And Minuta = 1 Then                         'budzik,zał np. Led                   
    Reset Portx.x
    End If

    Cls
    Cursor Off
    Locate 1 , 2
    Lcd "" ; Godzina
    Locate 1 , 4
    Lcd ":" ; Minuta
    Locate 1 , 7
    Lcd ":" ; Sekunda

    Loop Until Godzina = 24

    Proste ,nie?
    Tylko jako że nie umiem jeszcze Timer'ów obsługiwać ,nie wiem jak odmierzyć
    "prawdziwą" sekundę - na razie te funkcję pełni 'Waitms 1000'
    Ale jest precyzyjna jak tasak przy operacji neurochirurgicznej...
    Ma ktoś pomysł aby wytrzasnąć sekundę?
    Czy może wewn. kwarc nie będzie precyzyjny ??
    Wie ktoś może jak najprościej się określa cyfry w wyświetlaczu Led'owym?
    Np na PortB0-10 (7Pinów sterujących + 4 do tranzystorów).

    0 29
  • #3 12 Lis 2006 00:32
    Kubbaz
    Poziom 26  

    mogę pomóc, ale w C, w BASCOMie sobie już sam pokminisz, bo algorytm działania jest wszędzie taki sam :)
    na początek wpychamy zewnętrzny kwarc 11.059200 MHZ + 2 kondensatory x 22pF,
    w nagłówkach należy dodać:

    Code:
    #include <avr/interrupt.h> 

    przed int main'em należy dodać:
    Code:

    #define HI PORTC=0xFF;
    SIGNAL (SIG_OVERFLOW0)   // funkcja obsługi Timer'a0 radzę jej nie nadwyrężać, aby nie opóźniać 1 sekundy ;)
    {
       if(prescaler++==674)   // jeśli licznik Timer'a0 się przepełni, to wykonuje pętlę (co 1 sekundę) 
                      {
                             HI = ~HI
                       }
    }


    w int main piszemy:
    Code:
    int main ()         // program główny
    
    {   
       TCCR0=0x03;      // prescaler 64
       TCNT0=0x00;      // wartośc początkowa zliczania Timer'a0 = 0
       TIMSK=0x01;      // włączony Overflow Timer'a0
            sei();         // włączenie przerwań
            for (;;)      // pętla główna programu pusta (tylko na razie)
       {
            }   
            return (0);
    }


    Trochę teorii: Skąd sięwzięła magiczna liczba "(prescaler++==674)" ??

    F_CPU = 11059200 Hz
    Prescaler = 64 (ustawiamy ręcznie rejestr TCCR0 - zaobacz do datasheet'u)
    MAX_VAL = 256 (bo 8-mio bitowy TIMER0)

    więc:

    TOV ck = (F_CPU/Prescaler)/MAX_VAL = 675 (ilość wewnętrznych przerwań na sekunde)

    czyli wynika że w ciągu jednej sekundy timer zrobi 675 wewnętrznych przerwań.

    Dodano po 2 [minuty]:

    oo ..widzę, że kolga wyżej mnie uprzedził i w to w odpowiednim języku.... :)

    0
  • #4 12 Lis 2006 00:47
    jacynka84
    Poziom 26  

    Ciekawe, czytałem już te tematy. czy bez tego kwarca 32khz sie nie obejdzie?
    Jednak nie łapię tych timerów.
    nie rozumiem w ogóle kolejności ich działań i ustawień.
    jak i co obliczyć dla 8Mhz?

    0
  • #5 12 Lis 2006 01:02
    teedd
    Poziom 18  

    Obejdzie się bez kwarca zegarkowego.
    Zajrzyj do Samples w katalogu Bascom-AVR i przećwicz przykłady z timerami. Sam dojdziesz do tego, jak to zrobić.
    Powodzenia - teedd

    0
  • #6 12 Lis 2006 01:04
    Kubbaz
    Poziom 26  

    jacynka84 napisał:
    Ciekawe, czytałem już te tematy. czy bez tego kwarca 32khz sie nie obejdzie?
    Jednak nie łapię tych timerów.

    Generalnie timer służy jako licznik przerwań :), wewnętrznych albo zewnętrznych na pinie TO, zewnętrzne przerwania widziane są z portu TO, a wewnętrzne przerwania generuje prescaler - wewnętrzny przerywacz "sterowany" kwarcem zewnętrznym lub oscylatorem wewnętrznym :).
    jacynka84 napisał:
    nie rozumiem w ogóle kolejności ich działań i ustawień.

    wartrości ustawiane są za pomocą odpowiednich rejestrów uC:
    TCCR0=0x03; // prescaler 64 - ustawiana jest wartość prescalera
    TCNT0=0x00; // ustawiana jest wartośc początkowa zliczania Timer'a0 = 0 - TIMER zlicza z prescalera od zera do wartości wyznaczonej w pętli funkcji SIGNAL (SIG_OVERFLOW0)
    TIMSK=0x01; // włączony Overflow Timer'a0

    Chyba proste, nie ??;)
    jacynka84 napisał:
    jak i co obliczyć dla 8Mhz?

    bardzo prosto :) - jak wyżej:

    F_CPU = 8000000 Hz
    Prescaler = 64 (ustawiamy ręcznie rejestr TCCR0 - zobbacz do datasheet'u)
    MAX_VAL = 256 (bo 8-mio bitowy TIMER0)

    więc obliczamy ilośc wewnętrznych przerwań w ciągu jedej sekundy:

    TOV ck = (8000000/64)/256 = 488,28125 - ilość wewnętrznych przerwań przypadających na 1 sekundę

    ....dobra ide spać, koniec pałowania się z uC-mi na dzisiaj :).

    Dobranoc. Pozdrawiam, Kuba.

    0
  • #7 12 Lis 2006 09:41
    jacynka84
    Poziom 26  

    Nie mam pojęcia jak zrobić prescaler na tym rejestrze TCCR0 w Bascom.
    Ale czy tałem że im większy ten prescale tym mniejsza dokładność ,może lepiej zostać przy tym co jest ?

    0
  • #8 12 Lis 2006 10:09
    M. S.
    Poziom 34  

    Przeanalizuj sobie to. Dorób ustawianie zegara i gotowe.

    Code:
    $regfile = "m8def.dat"
    
    $crystal = 4194304
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portd.5 , Db6 = Portb.7 , Db7 = Portb.6 , E = Portd.7 , Rs = Portb.0
    Config Timer1 = Timer , Prescale = 64       'konfiguracja timer1

    Dim Sekunda As Byte
    Dim Minuta As Byte
    Dim Godzina As Byte
    Dim Sekunda1 As Byte

    Enable Interrupts             'zezwolenie na przerwania
    Enable Timer1
    On Timer1 Timer1_int          'przerwanie timer1
    Cursor Off                    'zeruj zminną
    Start Timer1
    Cls

    Do

    If Sekunda => 60 Then
       Sekunda = Sekunda - 60
       Incr Minuta
    End If

    If Minuta => 60 Then
       Minuta = Minuta - 60
       Incr Godzina
    End If

    If Godzina => 24 Then Godzina = Godzina - 24

    Locate 1 , 4
    Lcd "GODZ. " ;
    If Godzina < 10 Then Lcd " " ; Godzina ; ":" ; Else Lcd Godzina ; ":";
    If Minuta < 10 Then Lcd "0" ; Minuta ; ":" ; Else Lcd Minuta ; ":";
    If Sekunda < 10 Then Lcd "0" ; Sekunda ; "     " ; Else Lcd Sekunda ; "  "

    Loop

    End

    Timer1_int:
       Incr Sekunda
    Return


    To z moich zbiorów, nie wiem czy to wersja ostateczna więc spojrzyj na to krytycznym okiem.
    Znajdziesz tu konfigurację timera i obsługę przerwań.

    0
  • #9 12 Lis 2006 10:55
    jacynka84
    Poziom 26  

    Ten działa:

    Code:

    $regfile = "m8def.dat"
    $crystal = 4000000

    Config Lcdpin = Pin , Db4 = Portb.2 , Db5 = Portb.3 , Db6 = Portb.4 , Db7 = Portb.5 , E = Portb.1 , Rs = Portb.0
    Config Lcd = 16 * 2

    Config Timer1 = Timer , Prescale = 64

    Dim Godz As Byte
    Dim Mint As Byte
    Dim Sek As Byte

    Enable Interrupts
    Enable Timer1
    On Timer1 Timer1_int
    Cursor Off
    Start Timer1

    Do

     If Sek = 60 Then
     Sek = 0
     Incr Mint
     End If

      If Mint = 60 Then
      Mint = 0
      Incr Godz
      End If

    Cls
    Cursor Off

    Locate 1 , 1
    Lcd "" ; Sek
    Locate 1 , 4
    Lcd "" ; Mint
    Locate 1 , 7
    Lcd "" ; Godz
    Loop Until Godz = 24

    Timer1_int:
       Incr Sek
    Return

    Ale ze względu na częstotliwość odświerzania ,LCD nie nadąża i nie widać godzin...
    jak nie urok to sr*czka ,wewn. oscylator 4Mhz.
    Kupię ten kwarc 32.768Khz i wtedy sie zobaczy, podłącza sie go do XTAL czy do TOSC??

    0
  • #10 12 Lis 2006 21:14
    M. S.
    Poziom 34  

    Oj szefie

    Code:
    Cls
    
    Cursor Off

    wyrzuć przed pętlę DO - LOOP
    Poza tym gdzie program pójdzie po 24 godzinach?
    Code:
    Loop Until Godz = 24 

    No i z kwarcem 4MHz będzie się trochę spaźniał. Zastosuj kwarc 2²²Hz.

    0
  • #11 13 Lis 2006 08:29
    jacynka84
    Poziom 26  

    Znaczy np 8mhz,czy lepiej 11.059mhz?

    0
  • #13 13 Lis 2006 16:28
    jacynka84
    Poziom 26  

    A...dlaczego akurat 2^22?
    Ps mam ten zegarkowy oraz 11.059.

    0
  • #14 13 Lis 2006 16:53
    M. S.
    Poziom 34  

    Bo tym kwarcem nie odmierzysz 1s. w taki prosty sposób. Bęziesz musiał ładować wartość początkową do timera. Z kawrcem 2²²Hz wartość początkową trzeba by ustawić na 0 czyli tyle na ile timer wskakuje po przepełnieniu. Jednym słowem z tym kwarcem timer samoczynnie generuje przerwania co sekundę. Jak nie wierzysz to sobie policz. Kwarc ten był stosowany w niektórych zegarach - to taki zagarowy2.

    0
  • #15 13 Lis 2006 18:07
    zumek
    Poziom 39  

    M. S. napisał:
    Bo tym kwarcem nie odmierzysz 1s. w taki prosty sposób. Bęziesz musiał ładować wartość początkową do timera. Z kawrcem 2²²Hz wartość początkową trzeba by ustawić na 0 czyli tyle na ile timer wskakuje po przepełnieniu. Jednym słowem z tym kwarcem timer samoczynnie generuje przerwania co sekundę. Jak nie wierzysz to sobie policz. Kwarc ten był stosowany w niektórych zegarach - to taki zagarowy2.

    Prawdę rzekłeś , ale nie całą.Nie zapominaj , że w M8 rozdzielczość timerów 1 i 2 można "regulować".Wprawdzie za pomocą timera nr.2 , nie da się wygenerować przerwania co jedną sekundę , ale za to timer 1 doskonale się do tego nadaje.Można za jego pomocą generować przerwania co 1 s przy wykorzystaniu kwarców 4,8,12,16 MHz.O wewnętrznym RC ustawionym na 4 lub 8 MHz nie wspominam , bo jest raczej mało stabilny :D

    Piotrek

    0
  • #16 13 Lis 2006 19:54
    M. S.
    Poziom 34  

    Cytat:
    Można za jego pomocą generować przerwania co 1 s przy wykorzystaniu kwarców 4,8,12,16 MHz.


    Tak, lecz wymaga to wpisania do timera wartości początkowej <>0
    Np przy kwarcu 4MHz na timerze 1 z prescalerem 64 trzeba do timera wpisać wartość początkową 3036.
    Zaś przy kwarcu 8MHz z prescalerm 256 wartość początkowa to 34286.
    Za pomocą doboru wartości początkowych można korygować też odchyłki kwarcu od częstotliwości znamionowej.

    0
  • #17 13 Lis 2006 20:21
    zumek
    Poziom 39  

    M. S. napisał:
    Tak, lecz wymaga to wpisania do timera wartości początkowej <>0 ...

    Czyżby :?:
    OCR1A=4000000/256-1,preskaler=256, Mode 4(CTC) i ... masz przerwanie co 1s , bez przeładowywania TCNT1 . To tylko jedna z kilku możliwych konfiguracji Timera1.

    Piotrek

    0
  • #19 13 Lis 2006 22:24
    jacynka84
    Poziom 26  

    No dobra , tylko jak powinien wyglądać timer "gotowy do użycia" ? timer,ładujemy początkową wartość ,on zlicza do niej i mamy 1sekundę, wtedy Incr Zmienna(sekunda) -
    jak ja mam to napisać??
    Nie mam pojęcia o Timer'ach!
    Kubbaz napisał coś o tym ale słabo czaję...

    0
  • #20 13 Lis 2006 22:31
    matgaw
    Poziom 15  

    Timer zawsze odmierza do końca swojego zakresu. Timer0 oraz Timer2 są 8-bitowe, czyli liczą do 256, natomiast Timer1 jest 16-bitowy i liczy do 65536. Czyli jak takiemu Timerowi1 ustawisz wartość początkową 5536, to on policzy 60 000 taktów (do 65536) i potem wygeneruje przerwanie, czyli skoczy do odpowiedniego fragmentu kodu który mu zadasz (kod obsługi przerwania), rozumiesz? :)
    Timery mogą być taktowane albo tym samym sygnałem co procesor, albo sygnałem procesora podzielonym przez 8, 64, 256 lub 1024 (Timer2 może być również przez 128, ponieważ wtedy przy kwarcu 32768 Hz osiąga przerwanie co 1s).

    0
  • #21 13 Lis 2006 23:54
    zumek
    Poziom 39  

    jacynka84 napisał:
    ...jak ja mam to napisać??
    Nie mam pojęcia o Timer'ach!
    Kubbaz napisał coś o tym ale słabo czaję...

    Pierwsze zdanie z postu kolegi matgaw , możesz włożyć między bajki , bo ma sie nijak do rzeczywistości , jeśli mówimy o ATMega8 i podobnych :D
    Poniżej dowód w postaci najprostszego zegarka na M32 , ale na M8 też powinien działać.
    Code:

    $regfile = "m32def.dat"
    $crystal = 11059200

    #if _xtal < 4000000
       Const Presc = 64
    #else
       Const Presc = 256
    #endif

    Const Maxval = _xtal / Presc -1

    'Config Lcd = 20 * 4
    'Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portd.7
    'Config Lcdpin = Pin , Db7 = Porta.7 , E = Portc.3 , Rs = Portc.2

    Dim S As Byte , M As Byte , H As Byte

    On Oc1a Sekunda
    Enable Oc1a
    Enable Interrupts
    Cursor Off
    Cls
    S = 0
    M = 59
    H = 23
    Pwm1a = Maxval

    #if Presc = 64
       Tccr1b = &B00001011
    #else
       Tccr1b = &B00001100
    #endif

    Do : Loop

    Sekunda:
    Incr S
    If S = 60 Then
       S = 0
       Incr M
       If M = 60 Then
          M = 0
          Incr H
          If H = 24 Then H = 0
       End If
    End If
    Locate 1 , 1 : Lcd Hex(makebcd(h)) ; ":" ; Hex(makebcd(m)) ; ":" ; Hex(makebcd(s));
    Return

    Jeśli to ma być coś więcej niż zegarek , to wyświetlanie czasu na LCD wywal do pętli głównej i użyj znacznika dla upływającej sekundy.
    Piotrek

    0
  • #22 14 Lis 2006 07:30
    jacynka84
    Poziom 26  

    Matgaw nieźle mi to wytłumaczył, potrzebuję jeszcze przykładu z komentami co do czego z Timer'em.
    Zumek , Ten kod jest "dość" niezrozumiały ,
    -po co Hex'y ,pwm ,i dlaczego OC1 ?

    1
  • #23 14 Lis 2006 12:33
    M. S.
    Poziom 34  

    Zumek zaproponował nam prace timera w trybie CTC (Clear Timer on Compare match) - zerowanie licznika (i wywołanie przerwania OC1A) po wykryciu zgodności rejestru TCNTn z OCRn. Można w ten sposób "skrócić" timer do potrzebnej wielkości. Odpowiada to mniej więcej "skracaniu" zakresu liczenia timera przez wprowadzenie wartości początkowej tyle, że licznik pracuje od 0 do OCRn (Pwmn), a nie od wartości początkowej do przepełnienia.
    Aby skonfiguroweć timer manipulowano przy rejestrze Tccr1b. Tym sposobem poznaliśmy trochę taktyki używanej podczas programowania w "C" i asemblerze. Bascom umożliwia także stosowne ustawienie timera przez Config Timer (parametr CLEAR TIMER).
    No to chyba byłyby wszystkie sposoby znęcania się nad timerem aby zmusić go do odmierzania 1s. i chyba magiczne 2²² jest najprostsze gdy częstotliwość taktowania uC nie jest krytyczna.

    0
  • #24 14 Lis 2006 14:59
    medicb
    Poziom 28  

    Na noc wprogramowałem ten "ostatni zegarek" do atmegi z kwarcem 8MHz, oczywiście wstawiłem poprawkę ... i śmiga :D po kilkunastu godzinach na moje oko chodzi równo z sekundnikiem budzika na biurku.

    0
  • #25 14 Lis 2006 15:52
    jacynka84
    Poziom 26  

    Ile powinien wynosić Load Timer1 na kwarc 11.059?
    powinien byc na Prescale ,i ile? 256 ?
    Tak to ma wyglądać ?

    Code:
     
    
    Config Timer1 = Timer , Prescale = 256

    Dim Godz As Byte
    Dim Mint As Byte
    Dim Sek As Byte

    Enable Timer1
    Enable Interrupts
    On Timer1 Timer1_int
    Load timer1 , xxxxxx
    Start Timer1

    Do

     If Sek = 60 Then
     Sek = 0
     Incr Mint
     End If

      If Mint = 60 Then
      Mint = 0
      Incr Godz
      End If

    Cls
    Cursor Off

    Locate 1 , 1
    Lcd "" ; Sek
    Locate 1 , 4
    Lcd "" ; Mint
    Locate 1 , 7
    Lcd "" ; Godz
    Loop Until Godz = 24

    Timer1_int:
       Incr Sek
    Return

    0
  • #26 14 Lis 2006 17:55
    M. S.
    Poziom 34  

    Proponuję ściągnąć z sieci program do obliczania parametrów timerów np. kalk.exe. I musisz odróżnić Load timer 1, ? od Timer1 = ?. Za pomocą pierwszego wskazujesz ile timer ma odliczyć a za pomocą drugiego od jakiej wartości ma zacząć odliczanie aż do przepełniena.

    0
  • #27 14 Lis 2006 19:11
    jacynka84
    Poziom 26  

    Ok , łapie coś. a ten kod co dałem teraz jest dobry nie licząc Load timer?
    wyliczyło że dla q 11.059Mhz ma być w load timer1 22.336 .
    Dobrze?

    0
  • #28 14 Lis 2006 21:19
    M. S.
    Poziom 34  

    Wartość dobra jako Timer1 = 22336 a nie Load Timer1, 22336
    Co do programu to wpisz w uC i zobacz. Jak coś będzie nie tak to poprawisz.

    0
  • #29 14 Lis 2006 22:42
    jacynka84
    Poziom 26  

    Dopiero za jakieś 2 dni będzie coś wiadomo - robię płytkę testową , a raczej 2wie :]
    mam pytanie OT - odnośnie irda -
    normalnie poprzez tranzystor podłączam diode odb. ,ale ze zmianą odległości ,sygnał jest np. coraz słabszy ,a przecierz jest wymagane na TXD - TTL 0-1
    jak to zrobić by był w odległości ok 2metrów ciągle taki sam poziom ?? Max232 może? Odb to BP104 (fajny ,liniowy jakiś taki).

    0
  • #30 14 Lis 2006 23:10
    M. S.
    Poziom 34  

    My już dawno tego tak nie robimy. Udaj się do elektronicznego po scalony odbiornik podczerwieni TFMS5360, albo inny leżący obok (mały czarny z trzema nogami). To ustrojstwo daje na wyjściu sygnał "pasujący" bezpośrednio do wejścia uC. Nie podłączej tego w trybie UART (RS232). W Bascomie są specjalne instrukcje do dekodowania sygnału RC5. Mozna również nadawać RC5 i inne.

    0