Forum: Mikrocontroller und Digitale Elektronik Noob braucht Hilfe bei Timerinterrupt in C


von edgar 3. (edgar339)


Lesenswert?

Auch ich muss euch mit Anfängerfragen belästigen und diese hier ist 
besonders lächerlich :)

Ich bekomme es nämlich einfach nicht hin, in C(GCC) ein Programm zu 
schreiben, dass den Timer0 dazu bringt, Overflow-Interrupts auszulösen. 
Als µC dient mir der ATmega8 (Ja ja, Cliché-Controller und veraltet, ich 
weiß). Meine Überlegungen:
1
#include <avr/interrupts>
der muss doch sicher rein
1
SREG |= 0b10000000
globale Interrupts einschlaten, oder kann ich da direkt
1
sei()
nehmen?
1
TOIE0 |= 0b00000001
Interrupt zulassen, geht das so?
1
TCCR0 = 0b00000101
Timer mit Prescaler 1024 einschalten, richtig?
1
ISR (TIMER0_OVF_vect)
2
{
3
  PORTD0=0b00000001   //Led anschalten
4
}
So die ISR?

Ich danke euch schon mal.

Edgar

von Leonhard K. (leonhard_k)


Lesenswert?

Bitte poste deinen kompletten Code, dann kann dir besser geholfen 
werden.

von edgar 3. (edgar339)


Lesenswert?

Gerne.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/delay.h>
4
5
int main(void)
6
{  
7
  DDRD = 0b11111111;
8
  SREG |= 0b10000000;
9
  TOIE0 |= 0b00000001;
10
  TCCR0 = 0b00000101;
11
  
12
    while(1)
13
    {
14
    _delay_ms(100);      //Trödeln
15
    PORTD = 0b00000000;    //Led ausschalten
16
    }
17
  
18
  ISR (TIMER0_OVF_vect)
19
  {
20
    PORTD=0b00000001;     //Led anschalten
21
  }
22
}
Mir ist auch klar, dass die LED immer nach einer unterschiedlichen Zeit 
wieder aus geht, aber das ist mir derzeit egal.

von edgar 3. (edgar339)


Lesenswert?

Ach da sehe ich schon was:
das heißt nicht [c]TOIE0 |= 0b00000001;[c/]sondern[c]TIMSK |= 
0b00000001;[c/]

von Hmm (Gast)


Lesenswert?

Poste bitte ohne Fehler und Warnungen kompilierbaren Code.

von Ohmann (Gast)


Lesenswert?

Mach mal die ISR aus der main raus

von Timmo H. (masterfx)


Lesenswert?

> SREG |= 0b10000000;
-Interrupts schaltet mal mit "sei()" an.
-am SREG brauchst du nicht rumfummeln

> TOIE0 |= 0b00000001;
TOIE0 ist ein Bit im Register TIMSK
also:
1
TIMSK |= (1<<TOIE0);
>TCCR0 = 0b00000101;
besser leserlich:
1
TCCR0 = (1<<CS2) | (1<<CS0);
>  ISR (TIMER0_OVF_vect)
>  {
>    PORTD=0b00000001;     //Led anschalten
>  }
Die ISR gehört nicht IN die main-funktion

von Leonhard K. (leonhard_k)


Lesenswert?

edgar 339 schrieb:
>   TOIE0 |= 0b00000001;

Ich nehme mal stark an, das du in TIMSK(Timer/Counter Interrupt Mask 
Register schreiben wolltest. In etwa so:
1
TIMSK |= (1<<TOIE0);

Anstatt
1
  SREG |= 0b10000000;

kann auch
1
sei();

verwendet werden.

Timmo war schneller :)

von Vuvuzelatus (Gast)


Lesenswert?

Warum nicht einfach so:
1
ISR (TIMER0_OVF_vect)
2
  {
3
  i++;
4
  PORTD=i     
5
  }

Dann passiert das an und aus ganz von selbst, und für die acht Pins am 
Port sogar mit unterschiedlichen Frequenzen.

Im AVR-GCC-Tutorial sind übrigens viele schöne Beispielprogramme. 
Studier mal jenes im Abschnitt "Overflow Interrupt", dann dürfen sich 
einige Fragen von selbst beantworten.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

PS: Und benutz (auch in Deinem eigenen Interesse) die Bitnamen - dazu 
hat man sie erfunden.

von Hubert G. (hubertg)


Lesenswert?

Man schreibt sei();
Du hast im TIMSK nichts gesetzt.

Wenn du so schreiben würdest:
TCCR0= (1<<CS00)|(1<<CS02);
Dann kann man gleich erkennen welchen Teiler du gesetzt hast. Bei 
anderen Register ist das noch krasser.

von edgar 3. (edgar339)


Lesenswert?

Sehe ich das richtig, wenn ich
1
TIMSK |= (1<<TOIE0)
 als "Schiebe eine 1 an TOIE0 und verknüpfe ODER-weise" und nicht als 
"Schiebe eine 1 so oft nach links, wie der Wert von TOIE0 ist" 
interpretiere?
Das würde so einiges erklären...

von edgar 3. (edgar339)


Lesenswert?

Ich toggle mal damit:
1
PORTD ^= (1<<PD0);

von troll (Gast)


Lesenswert?


von edgar 3. (edgar339)


Lesenswert?

Entschuldige die Unhöflichkeit, aber wenn ich sowas wie PORTD ^= 
(1<<PD0);
schreibe, habe ich das sicher schon durchgelesen, oder?...

von Hmm (Gast)


Lesenswert?

>Entschuldige die Unhöflichkeit...

Wenn Du bis zum ^-Operator gelesen hättest, dann würde 90% Deines Codes 
vom ersten Posting ganz anders aussehen. Spar Dir also die Sprüche und 
die Entschuldigungen. Das Ganze ist nur noch lächerlich.

von edgar 3. (edgar339)


Lesenswert?

>...diese hier ist
>besonders lächerlich

Gebe ich zu...
Ich gebe auch zu das nicht ganz gelesen bzw. verstanden zu haben, doch 
das ich diesen Artikel kenne hätte man sich denken können (von mir aus 
auch mit dem Beispiel SREG |= 0b10000000;), weshalb sein Beitrag das 
alles hier nicht weiterbringt.



Der derzeitige Code sieht so aus:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/delay.h>
4
5
int main(void)
6
{  
7
  DDRD = 0b11111111;
8
  sei();
9
  TIMSK |= 0b00000001;
10
  TCCR0= (1<<CS00)|(1<<CS02);
11
  
12
    while(1)
13
    {
14
    _delay_ms(100);      //Trödeln
15
    }
16
}
17
18
ISR (TIMER0_OVF_vect)
19
{
20
  PORTD ^= (1<<PD0);     //Led togglen
21
}

Edgar

von edgar 3. (edgar339)


Lesenswert?

Geht wunderbar, danke an alle, die mir geholfen haben!

Edgar

von edgar 3. (edgar339)


Lesenswert?

Nachtrag an alle Anfänger, die das gleiche Problem hatten: Statt
1
TIMSK |= 0b00000001;
bitte
1
TIMSK |= 1<<TOIE0;
schreiben, denn das ist, wie Vuvuzelatus schon geschrieben hat, 
übersichtlicher.

>Vuvuzelatus schrieb:
>PS: Und benutz (auch in Deinem eigenen Interesse) die Bitnamen - dazu
>hat man sie erfunden.

Ich spiele jetzt einfach mal Moderator und mache den Thread zu, da alles 
geklärt wurde.

---------------------------Thread zu!---------------------------

von Timmo H. (masterfx)


Lesenswert?

edgar 339 schrieb:
> Nachtrag an alle Anfänger, die das gleiche Problem hatten: Statt
> TIMSK |= 0b00000001;
> bitte TIMSK |= 1<<TOIE0; schreiben,
> denn das ist, wie Vuvuzelatus schon geschrieben hat, übersichtlicher.
Wurde ja auch erst drei mal geschrieben. Gut dass du es nochmal 
schreibst.

von edgar 3. (edgar339)


Lesenswert?

>Wurde ja auch erst drei mal geschrieben. Gut dass du es nochmal
>schreibst.

Sicher ist sicher! :D

von Thomas E. (thomase)


Lesenswert?

edgar 339 schrieb:
> als "Schiebe eine 1 an TOIE0 und verknüpfe ODER-weise" und nicht als
> "Schiebe eine 1 so oft nach links, wie der Wert von TOIE0 ist"
> interpretiere?
> Das würde so einiges erklären...
So kann man das interpretieren.
Tatsächlich wird natürlich mit dem Wert geschoben, mit dem TOIE0 
definiert ist. Aber nicht auf dem Controller sondern das macht der 
Compiler auf der 3-GHz-Quadcore-Granate unter dem Tisch.

mfg.

von edgar 3. (edgar339)


Lesenswert?

Gut, danke das das nochmals geklärt wird. Im Artikel Bitmanipulation 
steht nämlich "(1 << n) : Zuerst wird durch die '<<'-Ausdrücke eine "1" 
n-mal nach links geschoben.", es wäre besser wenn es "...auf Bit n 
geschoben." lauten würde.

Edgar

von Karl H. (kbuchegg)


Lesenswert?

edgar 339 schrieb:
> Gut, danke das das nochmals geklärt wird. Im Artikel Bitmanipulation
> steht nämlich "(1 << n) : Zuerst wird durch die '<<'-Ausdrücke eine "1"
> n-mal nach links geschoben.", es wäre besser wenn es "...auf Bit n
> geschoben." lauten würde.

Das erste ist (allgemein gesehen) richtig.
das zweite ist deine Interpretation, die in diesem Fall (eine 1 wird 
geschoben) auf dasselbe rausläuft.

von Vuvuzelatus (Gast)


Lesenswert?

Mein Vorschlag für eine erschöpfende, nicht missverstehbare Auskunft 
darüber, was 1<<n ist:

1<<0 = 0b00000001 = 0x01 = 2^0 = 1
1<<1 = 0b00000010 = 0x02 = 2^1 = 2
1<<2 = 0b00000100 = 0x04 = 2^2 = 4
1<<3 = 0b00001000 = 0x08 = 2^3 = 8
1<<4 = 0b00010000 = 0x10 = 2^4 = 16
1<<5 = 0b00100000 = 0x20 = 2^5 = 32
1<<6 = 0b01000000 = 0x40 = 2^6 = 64
1<<7 = 0b10000000 = 0x80 = 2^7 = 128

wobei das ^ die Potenzierung bezeichnet ("hoch").

von edgar 3. (edgar339)


Lesenswert?

>Das erste ist (allgemein gesehen) richtig.
Aber auch nur, wenn man keine Bitnamen einsetzt...

>1<<0 = 0b00000001 = 0x01 = 2^0 = 1
>1<<1 = 0b00000010 = 0x02 = 2^1 = 2
>1<<2 = 0b00000100 = 0x04 = 2^2 = 4
>1<<3 = 0b00001000 = 0x08 = 2^3 = 8
>1<<4 = 0b00010000 = 0x10 = 2^4 = 16
>1<<5 = 0b00100000 = 0x20 = 2^5 = 32
>1<<6 = 0b01000000 = 0x40 = 2^6 = 64
>1<<7 = 0b10000000 = 0x80 = 2^7 = 128

Das falsch zu verstehen wird wirklich schwer :D
Wirklich gute Idee!

von Rolf M. (rmagnus)


Lesenswert?

edgar 339 schrieb:
>>Das erste ist (allgemein gesehen) richtig.
> Aber auch nur, wenn man keine Bitnamen einsetzt...

Die "Bitnamen" sind auch nichts weiter als Präprozessor-Makros, für die 
eine Zahl eingesetzt wird. TOIE0 ist in der avr-libc für den atmega8 
z.B. so definiert:
1
#define TOIE0   0

Also ist
1
1 << TOIE0;
genau das gleiche wie:
1
1 << 0;

Man könnte auch
1
12 << TOIE0;
schreiben, auch wenn das in dem Fall keinen Sinn ergeben würde. Dann 
würde eben eine 12 um TOIE0 bits nach links geschoben statt einer 1.

von amateur (Gast)


Lesenswert?

@edgar 339

Schon auf der Einstiegsseite findest Du unter AVR ein: AVR-GCC-Tutorial.

Denk mal darüber nach, warum man sich sehr viel Arbeit gemacht hat, um 
dort einen Einstieg in die C-Programmierung zu geben.

von edgar 3. (edgar339)


Lesenswert?

>Die "Bitnamen" sind auch nichts weiter als Präprozessor-Makros...

Danke nochmals, das sollte eventuell im Artikel "Bitmanipulation" 
erwähnt werden... Doch das überlasse ich lieber anderen, es ist zu 
wahrscheinlich, das ich irgend etwas Falsches rein schreibe...

>Denk mal darüber nach, warum man sich sehr viel Arbeit gemacht hat, um
>dort einen Einstieg in die C-Programmierung zu geben.

Och komm schon, wenn das dort ausführlich erklärt wäre, würde ich nicht 
fragen... Ich habe durchaus einige Zeit verbracht, um die Antwort 
alleine zu finden, habe es aber nicht geschafft, da die Erklärung dazu 
über drei Artikel verteilt ist(Bitmanipulation, AVR-GCC-Tutorial/Die 
Timer und Zähler des AVR, AVR-GCC-Tutorial). Wenn man schon weiß wie es 
geht, dann versteht man die Erklärung auch, aber für einen, der es 
gerade lernen will, ist das kaum möglich. Ich will nicht sagen, dass die 
Personen, die diese Artikel geschrieben haben, schlechte Arbeit 
geleistet haben(ganz im Gegenteil, sie haben freiwillig und ohne Lohn zu 
verlangen ein riesiges Projekt auf die Beine gestellt, Respekt!), aber 
als Eingeweihter kann man einfach nicht an alles denken, was ein Neuling 
falsch verstehen könnte.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.