Przerwanie od Timera w Atmega168

Tutaj mozesz poruszać tematy ogólne powiązane z elektroniką, np. dyskusje na temat podzespołów, układów, zasad ich działania. Czyli można pisać o wszystkim czego nie da się przyporządkować do innych działów.
Awatar użytkownika
Kulpina
Użytkownik
Posty: 2037
Rejestracja: 28 lip 2005, 16:57
Lokalizacja: Sanok
Kontakt:

Przerwanie od Timera w Atmega168

Post autor: Kulpina » 01 wrz 2010, 15:01

Mam problem z przerwaniem w Atmega168.
Procesor chodzi na wewnętrznym kwarcu 128kHz. Wg moich wyliczeń i kalkulatora do timerów przerwanie powinno być zgłaszane co 1s, natomiast jest zgłaszane co 8s...
Taka głupota, ale sprawdzam te cyferki już któryś raz i nie widze żadnego błędu.
Mógłby ktoś rzucić okiem? Może przeoczyłem tylko jakąś głupote...
Program:

#include <avr\io.h>
#include <avr\signal.h>
#include <avr\interrupt.h>
#include <inttypes.h>




int main(void)
{
DDRB = 0xFF; //jako wyjscia
DDRC = 0xFF;
DDRD = 0xFF;

TCCR1A = 0x00;
TCCR1B = 0x04; //prescale = 256
TIMSK1 = 0x01; //przerwanie wywoluje przepelnienie timera
TCNT1 = 65036;
sei(); //globalne zezwolenie na przerwania

for(;;)
{
}
return 0;
}

SIGNAL(SIG_OVERFLOW1)
{
TCNT1 = 65036; //wartość początkowa - timer odlicza tylko do 500
if(PORTB) PORTB = 0x00; else PORTB = 0x08; //po prostu miganie diodą
}

Awatar użytkownika
kayron
Użytkownik
Posty: 2088
Rejestracja: 21 wrz 2008, 12:53
Lokalizacja: Poland
Kontakt:

Post autor: kayron » 01 wrz 2010, 16:15

A nie masz w fusach włączonego dzielnika zegara przez 8 :?: wtedy by pasowało 8sek zamiast 1.

Awatar użytkownika
c4v2
Użytkownik
Posty: 426
Rejestracja: 22 lis 2005, 15:14
Lokalizacja: z przed monitora

Post autor: c4v2 » 01 wrz 2010, 16:36

Mikrokontroler Mega168 ma fusebit CKDIV8 którego fabrycznie ustawienie powoduje dzielenie częstotliwości zegara systemowego niezależnie czy będzie to wewnętrzny RC czy zewnętrzny RC, kwarc, czy generator.
Ciekawa realizacja bascomowego Toogle, tyle że w C to tylko trochę na terminal pisałem i nie rozumiem gdzie jest warunek instrukcji "if"?
Ostatnio zmieniony 01 wrz 2010, 16:46 przez c4v2, łącznie zmieniany 1 raz.

Awatar użytkownika
Kulpina
Użytkownik
Posty: 2037
Rejestracja: 28 lip 2005, 16:57
Lokalizacja: Sanok
Kontakt:

Post autor: Kulpina » 01 wrz 2010, 16:42

W życiu bym na to nie wpadł :mrgreen:
Dzięki wieklie za pomoc, oczywiście był ten bit ustawiony ^^
Teraz wszystko działa :)

Możecie mi jeszcze powiedzieć co daje ten fusebit? Po co dzielić częstotliwość w tym wypadku?

Awatar użytkownika
c4v2
Użytkownik
Posty: 426
Rejestracja: 22 lis 2005, 15:14
Lokalizacja: z przed monitora

Post autor: c4v2 » 01 wrz 2010, 16:50

CKDIV8 przy każdym zerowaniu mikrokontrolera ładuje do rejestru CLKPR (preskaler częstotliwości zegara) liczbę 3 co w konsekwencji dzieli częstotliwość zegara przez 8.

Awatar użytkownika
c4r0
Moderator
Posty: 2150
Rejestracja: 13 kwie 2004, 19:56
Lokalizacja: z lasu
Kontakt:

Re: Przerwanie od Timera w Atmega168

Post autor: c4r0 » 01 wrz 2010, 17:16

Pozwolcie, ze sie podlacze z glupim pytaniem :mrgreen:
Ten fragment kodu:

Kod: Zaznacz cały

if(PORTB) PORTB = 0x00; else PORTB = 0x08;
Mozna zapisac tak:

Kod: Zaznacz cały

PORTB = PORTB ? 0x00 : 0x08;
Czym sie te dwie formy roznia po kompilacji? Tej drugiej formy zbyt czesto nie widze - czy to jest jakis przezytek, ktorego nie powinno sie stosowac?

Awatar użytkownika
c4v2
Użytkownik
Posty: 426
Rejestracja: 22 lis 2005, 15:14
Lokalizacja: z przed monitora

Post autor: c4v2 » 01 wrz 2010, 17:29

Ja bym to widział tak po pascalowemu w c: :smile:

Kod: Zaznacz cały

if (PORTB==0x00)
  {
  PORTB=0x08;
  }
else
  {
  PORTB=0x00;
  }


[ Dodano: 2010-09-01, 19:03 ]
Podobno ?: jest operatorem porównania w c ale czym się obie formy różnią po kompilacji to nie wiem.
Czy

Kod: Zaznacz cały

PORTB=PORTB ? 0x00 : 0x08
znaczy to samo co

Kod: Zaznacz cały

PORTB=(PORTB==0x08) ? 0x00 : 0x08
Przeżytek to pewnie nie jest, tylko kod staje się mniej czytelny.

keruseykaryu

Post autor: keruseykaryu » 01 wrz 2010, 21:05

A wystarczyło napisać PORTB ^= 0x08; By się koledzy może jakiś operatorów pouczyli? Dziś 1 września, zatem najwyższy czas.
c4r0 pisze:Czym sie te dwie formy roznia po kompilacji?
c4v2 pisze:Podobno ?: jest operatorem porównania w c ale czym się obie formy różnią po kompilacji to nie wiem.
Symulator i debugger prawdę Ci powie.

if(PORTB) PORTB = 0x00; else PORTB = 0x08; //po prostu miganie diodą

Kod: Zaznacz cały

+00000061:   B185        IN        R24,0x05       In from I/O location
+00000062:   2388        TST       R24            Test for Zero or Minus
+00000063:   F011        BREQ      PC+0x03        Branch if equal
+00000064:   B815        OUT       0x05,R1        Out to I/O location
+00000065:   C002        RJMP      PC+0x0003      Relative jump
+00000066:   E088        LDI       R24,0x08       Load immediate
+00000067:   B985        OUT       0x05,R24       Out to I/O location
PORTB = PORTB ? 0x00 : 0x08;

Kod: Zaznacz cały

+00000061:   B185        IN        R24,0x05       In from I/O location
+00000062:   2388        TST       R24            Test for Zero or Minus
+00000063:   F411        BRNE      PC+0x03        Branch if not equal
+00000064:   E088        LDI       R24,0x08       Load immediate
+00000065:   C001        RJMP      PC+0x0002      Relative jump
+00000066:   E080        LDI       R24,0x00       Load immediate
+00000067:   B985        OUT       0x05,R24       Out to I/O location
PORTB ^= 0x08;

Kod: Zaznacz cały

+00000061:   B185        IN        R24,0x05       In from I/O location
+00000062:   E098        LDI       R25,0x08       Load immediate
+00000063:   2789        EOR       R24,R25        Exclusive OR
+00000064:   B985        OUT       0x05,R24       Out to I/O location
A teraz pytanie. Która wersja jest najbardziej efektywna?

---

Baj de wej. Kulpina:
- SIGNAL() zastąp przez ISR(), bo SIGNAL() może znienacka zniknąć (jak sławne cbi, sbi);
- Licznik w CTC sam liczy i nie trzeba przeładowywać, jak chcesz uzyskać odpowiednią dokładność to tego trybu użyj;
- Nie pisz tak: TCCR1B = 0x04; bo to nie ładnie. Lepiej TCCR1B = (1<<CS12); Przynajmniej wiadomo co masz ustawione.

Teraz czas na poprawną wersję:

Kod: Zaznacz cały

#include <avr\io.h> 
#include <avr\interrupt.h> 

ISR(TIMER1_COMPA_vect) 
{ 
	PORTB ^= 0x08;
}

int main(void) 
{ 
	DDRB = 0xFF;					//jako wyjscia 
	DDRC = 0xFF; 
	DDRD = 0xFF; 

	TCCR1B = (1<<CS12)|(1<<WGM12);	//prescale = 256, jako CTC
	TIMSK1 = (1<<OCIE1A);			//przerwanie z zerowania timera (tu) 
	OCR1A = 499;					//skracamy licznika

	sei();							//globalne zezwolenie na przerwania 

	while(1){
	}
	
	return 0; 
} 

Awatar użytkownika
c4r0
Moderator
Posty: 2150
Rejestracja: 13 kwie 2004, 19:56
Lokalizacja: z lasu
Kontakt:

Post autor: c4r0 » 01 wrz 2010, 23:02

keruseykaryu pisze:A wystarczyło napisać PORTB ^= 0x08; By się koledzy może jakiś operatorów pouczyli? Dziś 1 września, zatem najwyższy czas.
Ja tego "?" glownie uzywam przy stringach. np:

Kod: Zaznacz cały

bool fail;
[...]
Label1->Text = "Test " + (fail ? "failed!" : "passed.");
[...]
W takim przypadku duzo prostsze i krotsze niz kombinacje z IF-em, i tez lepiej czytelne moim zdaniem.
keruseykaryu pisze: Symulator i debugger prawdę Ci powie.

if(PORTB) PORTB = 0x00; else PORTB = 0x08; //po prostu miganie diodą

Kod: Zaznacz cały

+00000061:   B185        IN        R24,0x05       In from I/O location
+00000062:   2388        TST       R24            Test for Zero or Minus
+00000063:   F011        BREQ      PC+0x03        Branch if equal
+00000064:   B815        OUT       0x05,R1        Out to I/O location
+00000065:   C002        RJMP      PC+0x0003      Relative jump
+00000066:   E088        LDI       R24,0x08       Load immediate
+00000067:   B985        OUT       0x05,R24       Out to I/O location
PORTB = PORTB ? 0x00 : 0x08;

Kod: Zaznacz cały

+00000061:   B185        IN        R24,0x05       In from I/O location
+00000062:   2388        TST       R24            Test for Zero or Minus
+00000063:   F411        BRNE      PC+0x03        Branch if not equal
+00000064:   E088        LDI       R24,0x08       Load immediate
+00000065:   C001        RJMP      PC+0x0002      Relative jump
+00000066:   E080        LDI       R24,0x00       Load immediate
+00000067:   B985        OUT       0x05,R24       Out to I/O location
Aha, czyli praktycznie rzecz biorac "?" i "if" prawie sie nie roznia? A jak wyglada sprawa elegancji uzycia tego typu warunku w dzisiejszych czasach? Chodzi mi cos takiego jak z poleceniem goto - istnieje i dziala, ale wiele osob twierdzi ze nie powinno sie go w ogole uzywac bo to sie nie godzi z proceduralna struktura programu :P Jak jest w przypadku takiego warunku? Pytam, bo nieczesto go widze w uzyciu a bardzo mi sie on podoba, bo np. w takich przypadkach ze stringami jak podalem wyzej na prawde oszczedza duzo kombinowania.

Awatar użytkownika
c4v2
Użytkownik
Posty: 426
Rejestracja: 22 lis 2005, 15:14
Lokalizacja: z przed monitora

Post autor: c4v2 » 02 wrz 2010, 0:15

Obydwie instrukcje różnią się interpretacją flagi Z w SRGEG czy jest ustawiona czy nie.
Co do (wariacji "if") vs (XOR) to efektywność zależy czy wymagana jest szybkość wykonywania programu kosztem dodatkowego rejestru roboczego. Czy też można pozwolić sobie na dłuższe wykonywanie programu a w rejestrze roboczym przechować jakąś inną zmienną (R25).
Operatorów rzeczywiście muszę się pouczyć.
c4r0 pisze:Ja tego "?" glownie uzywam przy stringach. np:

Kod: Zaznacz cały

bool fail;
[...]
Label1->Text = "Test " + (fail ? "failed!" : "passed.");
[...]
Podstawienie tekstu pod Label1 to chyba już c++ a nie ansi c.

------------------------------
Poprawilem uzycie cytatu
- c4r0
Ostatnio zmieniony 02 wrz 2010, 1:21 przez c4v2, łącznie zmieniany 1 raz.

Awatar użytkownika
c4r0
Moderator
Posty: 2150
Rejestracja: 13 kwie 2004, 19:56
Lokalizacja: z lasu
Kontakt:

Post autor: c4r0 » 02 wrz 2010, 1:19

No to niech bedzie strcat(xxx, fail ? "failed!" : "passed.");, chodzi mi o sam warunek wiec to chyba bez roznicy.

keruseykaryu

Post autor: keruseykaryu » 02 wrz 2010, 8:39

R24, R25 to przecież stratchpad, nagminnie używany przez kompilator. Nie ma obaw o ten rejestr, należy do grupy rejestrów niechronionych. Co innego taki R1, w którym zawsze jest 0.
c4r0 pisze:A jak wyglada sprawa elegancji uzycia tego typu warunku w dzisiejszych czasach?
Tu nie chodzi o elegancję tylko o późniejszą czytelność takiego zapisu. Proste wyrażenie warunkowe (tak się to nazywa na prawdę) to żaden problem, ale jak tam połączysz kilka takich wyrażeń i do tego jeszcze wskaźniki, to przy analizie kodu za miesiąc widzisz sieczkę.
No ale trzeba jedno zapamiętać: Wyrażenie warunkowe to nie to samo co if. If testuje warunek i podejmuje działania. Samo w sobie nie zwraca wartości. Wyrażenie warunkowe sprawdza warunek i do tego zwraca wartość, albo tą przed dwukropkiem, albo tą za dwukropkiem. Zachowuje się zatem jak funkcja.

Awatar użytkownika
c4v2
Użytkownik
Posty: 426
Rejestracja: 22 lis 2005, 15:14
Lokalizacja: z przed monitora

Post autor: c4v2 » 02 wrz 2010, 14:00

Instrukcja "if" zwraca wynik tyle że logiczny (bit Z w SREG)
i na podstawie wartości logicznej podejmuje działania.
Wyrażenie warunkowe "?:" to taka funkcja inline?

[ Dodano: 2010-09-02, 15:43 ]
Zarówno w instrukcji "if" jak i wyrażeniu warunkowym "?:" występuje logiczny wynik porównania.

keruseykaryu

Post autor: keruseykaryu » 02 wrz 2010, 14:55

Definicja ANSI C mówi o wyrażeniu warunkowym w stosunku do ? :. Porównanie do funkcji nie jest może dobre, bo się powinno to porównać z normalnym wyrażeniem, np: a = b + c, tyle, że mamy też coś co decyduje albo-albo. Bo w1 ? re1 : re2 najpierw wyliczy w1, a na podstawie tego zwróci re1 jak w1 == TRUE albo re2 jak w1 == FALSE.
Może więc, od tej pory nie nazywajmy tego funkcją, tylko normalnie jak ANSI C nakazuje. Mniej zamieszania. Porównanie miało na celu pokazać, że ? : coś zwraca.
c4v2 pisze:Zarówno w instrukcji "if" jak i wyrażeniu warunkowym "?:" występuje logiczny wynik porównania.
No to co się stanie jak napiszesz bool = if(a==0) a++; else --a;? Powinien być byk.

Awatar użytkownika
c4v2
Użytkownik
Posty: 426
Rejestracja: 22 lis 2005, 15:14
Lokalizacja: z przed monitora

Post autor: c4v2 » 02 wrz 2010, 15:10

Trochę nieprecyzyjnie się wyraziłem z tym wynikiem. Chodzi mi oto że po deasemblacji zarówno "if" jak i "?:" ma wynik logiczny porównania w SREG. (BREQ, BRNE).

ODPOWIEDZ