RTC i avr

Mam pytanie, bo juz szukam i szukam, ale jakos porzadnej odpowiedz nie moge znalesc.. Da sie zrobic na zewnetrzym kwarcu 8MHz porzadny zegar czasu rzeczywistego?? Narazie napisalem sobie taki programi z obsluga przepelnienia (preskaler 32):

SIGNAL (SIG_OVERFLOW2){ TCNT2=6; if(licznik++==1000){ //1000 przepelnien odpowiada 1 s licznik=0; sekundy++; }

}

No ale po 1 h to juz ma jakies 3 sekundy spoznienia... Cos zle napisalem, czy po prostu nie da sie na takim kwarcu tego zrobic dokladnie?? Czytalem ze powodem tego mzoe byc ustawianie wartosci TCNT2 w przerwaniu.. Ale nadal nie wiem czy to wogole jest mozliwe???? I jeszcze jedno pytanie.. Bo tez na to nie znalazlem odpowiedzi :) EEPROM to pamiec nieulotna, tzn ze nawet jak odlacze zasilanie to dane zostaja w niej.. Tak? I nie ma zadnych problemow zeby z programu cos do niej zapisac??

Reply to
Pan Samochodzik
Loading thread data ...
Reply to
Bogdan Gutknecht
8Mhz zewnetrze jest ustawione, to wewnetrzne to "prawie nie dziala" :)

Co to znaczy automatyczne przeladowywanie?? Mozesz troche prosciej??

Reply to
Pan Samochodzik

Wybacz, ale nie dam rady tego , jedyne co to moge na oko.. Tak sadzilem ze cos kolo 3-4 s, wiec napisz jak zmienic, zeby bylo ok...

Reply to
Pan Samochodzik

Dnia 18 May 2006 07:09:31 -0700, Pan Samochodzik napisał(a):

To znaczy, że będziesz mógł pominąć tę instrukcję: TCNT2=6; Procesor zrobi to za ciebie automatycznie. Reszta w manualu, bo nawet typu procesora nie podałeś.

Pozdrawiam Marcin Stanisz

Reply to
Marcin Stanisz

Pan Samochodzik snipped-for-privacy@tlen.pl napisał(a):

Uruchom timer w trybie CTC , jeśli takowy tryb posiada ;)

Piotrek

Reply to
Piotrek Sz.

Ok, przerobilem na tryb CTC, teraz funkcja wlaczajaca i przerwanie wygladaja tak:

void timer2_init (void) { //wlaczamy timer2

TCCR2 |= (1 << CS21); //preskaler 32 dla timer2 TCCR2 |= (1 << CS20); TCCR2 |= (1 << WGM21); //Clear Timer on Compare (z OCR2) OCR2 = 250; //zerowanie kiedy osiagnie 250 a nie 255

licznik=0; sekundy=0; minuty=0; godziny=0;

TIMSK |= (1 << OCIE2); //wlaczamy przerwanie dla CTC TIMSK |= (1 << TOIE2); //wlaczamy przerwanie dla timera2

}

I przerwanie:

SIGNAL (SIG_OUTPUT_COMPARE2){

if(licznik++==1000){ //1000 przepelnien odpowiada 1 s licznik=0; sekundy++; zmien++; }

}

Biore sie za testowanie.. Ale jezeli widzicie jakis blad to krzyczcie :)

Reply to
Pan Samochodzik

No dobra, to powiedzmy ze to nawet bedzie dzialac, ale zapomnialem dodac jednej rzeczy... Bo tak na prawde to chce wlozyc ten zegarek to urzadzenia, ktore odbiera podczerwien itp.. No i uzywam tam przerwan z INT0 i INT1 w momencie odbierania sygnalu podczerwieni ( niezbyt czesto, powiedzmy 20 razy na dobe). Czy przy takich warunkach jest jest taki zegar w stanie normalnie funkcjonowac, czy jednak powinienem dolozyc zewnetrzny kwarc zegarkowy???? Program na tej samej zasadzieby byl, prawda?? A tak wogole to chyba uklad bedzie na ATmega 8, albo 16 jezeli mi zabraknie pinow...

Reply to
Pan Samochodzik

No i nie dziala.. po godzinie to juz jakies 10 sekund roznicy jest.... :/

Reply to
Pan Samochodzik

Piotr Galka przemówił ludzkim głosem:

Taka różnica _może_ być spowodowana przez tą linię:

zmienna licznik jest inkrementowana po zakończeniu porównania, a powinna być przed.

Reply to
Zbych

Pan Samochodzik snipped-for-privacy@tlen.pl napisał(a):

Bo nie chce Ci sie pomyśleć(policzyc) :) void timer2_init (void) { //wlaczamy timer2

TCCR2 |= (1 << CS21); //preskaler 32 dla timer2 TCCR2 |= (1 << CS20); TCCR2 |= (1 << WGM21); //Clear Timer on Compare (z OCR2) OCR2 = 249; //zerowanie też "trwa" ;) asm("sei"); licznik=0; sekundy=0; minuty=0; godziny=0;

TIMSK |= (1 << OCIE2); //wlaczamy przerwanie dla CTC TIMSK |= (1 << TOIE2); //wlaczamy przerwanie dla timera2

}

SIGNAL (SIG_OUTPUT_COMPARE2){

if(++licznik==1000){ //na to zwrócił uwagę któryś z kolegów licznik=0; sekundy++; zmien++; }

}

Piotrek

Reply to
Piotrek Sz.

No wiem wiem, juz to zmienilem i sprawdzam.. Jutro sie okaze :) A jak z tymi kwestiami juz nie dotyczacymi samego zegara?? Moze to tak dzialac rownolegle do innych przerwan??

Reply to
Pan Samochodzik

jak juz napisalem:

No wiem wiem, juz to zmienilem i sprawdzam.. Jutro sie okaze :) A jak z tymi kwestiami juz nie dotyczacymi samego zegara?? Moze to tak dzialac rownolegle do innych przerwan??

Odpowie mi ktos ??

Reply to
Pan Samochodzik
Reply to
Michal Lankosz

Napisz kod tak, aby wartość wpisywana do licznika była jak najmniejsza gdy licznik liczy w górę, albo jak największa gdy licznik liczy w dół. Zalecałbym też napisanie obsługi przerwania w assemblerze z modyfikatorami funkcji, które spowodują, że kompilator nie utworzy żadnej instrukcji procesora, nawet "reti"; poniżej przykładowy kod który ma wykonać 2 instrukcje TCNT0 = TIMERINITIALVALUE; ++g_byTicks;

__attribute__ ((naked)) SIGNAL( SIG_OVERFLOW0 ) { asm volatile( "push r17" "\n\t" // store r17 register "in r17, __SREG__" "\n\t" // store Flags in r17 "push r16" "\n\t" // store r16 register "ldi r16, %1" "\n\t" "out %0, r16" "\n\t" // TCNT0 = TIMERINITIALVALUE; "lds r16, g_byTicks" "\n\t" "inc r16" "\n\t" "sts g_byTicks, r16" "\n\t" // ++g_byTicks "pop r16" "\n\t" // restore r16 register "out __SREG__, r17" "\n\t" // restore Flags from r17 "pop r17" "\n\t" // restore r17 register "reti" "\n\t" : : "I" ( _SFR_IO_ADDR( TCNT0 ) ), "M" ( TIMERINITIALVALUE ) ); }

Powyżej wykorzystałem r17 do przechowania stanu flag __SREG__, a r16 służy mi do wykonania operacji: wpisania wartości do timera oraz inkrementacji g_byTicks.

A poniżej kod funkcji w C oraz wygenerowany z niej kod assemblerowy

SIGNAL( SIG_OVERFLOW0 ) { TCNT0 = TIMERINITIALVALUE; ++g_byTicks; }

1397 /* prologue: frame size=0 */ 1398 0616 1F92 push __zero_reg__ 1399 0618 0F92 push __tmp_reg__ 1400 061a 0FB6 in __tmp_reg__,__SREG__ 1401 061c 0F92 push __tmp_reg__ 1402 061e 1124 clr __zero_reg__ 1403 0620 8F93 push r24 1404 /* prologue end (size=6) */ 1405 .LM161: 1406 0622 84E5 ldi r24,lo8(84) 1407 0624 82BF out 82-0x20,r24 1408 .LM162: 1409 0626 8091 0000 lds r24,g_byTicks 1410 062a 8F5F subi r24,lo8(-(1)) 1411 062c 8093 0000 sts g_byTicks,r24 1412 /* epilogue: frame size=0 */ 1413 0630 8F91 pop r24 1414 0632 0F90 pop __tmp_reg__ 1415 0634 0FBE out __SREG__,__tmp_reg__ 1416 0636 0F90 pop __tmp_reg__ 1417 0638 1F90 pop __zero_reg__ 1418 063a 1895 reti

Zobacz że procesor wkłada dodatkową pracę w odkładanie/zdejmowanie rejestrów __zero_reg__ i __tmp_reg__ na stos, co mogłem spokojnie pominąć w moim kodzie assemblerowym.

Reply to
MariuszC

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.