Forum: Compiler & IDEs Timer Compare Interrupt Problem


von Steffen (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
ich hab ein Problem mit meinem AT90S2313 und seinem Timer1.
Zum Programm:
Ich gebe am PortB eine Vorwahl an und je nachdem soll das Compare Match
Register mit einem Wert geladen werden.
Der Timer soll dan per externen Clock (zum testen verwende ich einen
Taster) bis zu dem entsprechendem Wert hochzählen und den Interrupt
ausführen.
Soweit die Theorie...

In der Praxis aber durchlaufe ich nicht die "if(pump==1)"-Anweisung,
was wahrscheinlich bedeutet das der Interrupt nicht auslöst. (Am PD0
hängt eine LED, zum testen)

Hab ich irgendwas übersehen?
sei() entspricht doch dem 'I'-Bit im SREG, oder?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Erstens hast du die FAQ nicht gelesen:

http://www.nongnu.org/avr-libc/user-manual/FAQ.html

Gleich der erste Punkt...

Zweitens:

SREG|=(1<<7);

Bitte nicht.  Bitte nimm #include <avr/interrupt.h> und
schreibe sei() dort hin.  Das ist nicht nur besser lesbar,
sondern auch schneller.

von Peter D. (peda)


Lesenswert?

Du verschwendest unnötig SRAM, Flash und Zeit, wenn Du int nimmst, wo
ein char dicke ausreicht.

Zusätzlich handelst Du Dir Probleme ein, da ein int nicht atomar
zugegriffen werden kann.

Ein int (long, float), welches ein Interrupt ändert, muß im main unter
Interruptsperre gelesen werden, damit es gültig ist.

Der Optimierer ist etwas zu übereifrig. Er möchte ein volatile sehen
bei globalen Variablen, die in Interrupts beeinflußt werden.

Bei den Timerregistern machst Du es Dir zu umständlich, der AVR-GCC
kann die nämlich 16-Bittig (einfach mal ins io***.h File sehen).


Peter

von Steffen (Gast)


Lesenswert?

Danke euch zwei.

der Tipp mit 'volatile' hat geholfen, der Interrupt wird ausgeführt.

Allerdings hab ich jetzt ein neues Problem. Da die LED jetzt durch die
"if(pump==1)"-Anweisung eingeschaltet wird, soll sie jetzt kurze Zeit
später wieder "gelöscht"werden.
Dazu hab ich das Programm wie folgt umgeschrieben:
while(1)
  {
    if(pump==1)
    {

      PORTD|=(1<<PB0);
      _delay_ms(50);
      PORTD|=(0<<PB0);
      pump=0;

    }
  }

Ich weiss 50ms sind zuwenig um das Leuchten wahrzunehmen...jedoch geht
sie an aber nicht wieder aus!?
Ich könnte mir nur vorstellen das die if-Anweisung immer wieder
durchlaufen wird, so das man das "löschen" nicht mehr wahrnimmt. Aber
wieso? Ich setze doch 'pump' auf 0 zurück und betätige auch nicht den
Taster zum hochzählen!

Ich hab int auch durch char ersetzt. Das mit dem 16-Bit Register wusste
ich nicht, werde ich demnächst mal ändern. ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> jedoch geht
> sie an aber nicht wieder aus!?

Weil das hier Unsinn ist:

PORTD|=(0<<PB0);

Die rechte Seite ist eine umständlich hingeschriebene 0.  Wenn
du eine Null in ein Byte ver-oderst, bleibt das Byte einfach
nur in voller Schönheit erhalten.

Du willst:

PORTD &= ~(1 << PB0);

haben.

Denk bei _delay_ms() an den gültigen Wertebereich.  Für alle
derzeit bei AVRs zulässigen Taktfrequenzen ist 10 ms immer ein
gültiger Wert (das ist meine Faustformel, weil ich mir das gut
merken konnte :), dann machst du 'ne Sekunde draus:

uint8_t i;
for (i = 0; i < 100; i++) _delay_ms(10);

von Steffen (Gast)


Lesenswert?

Oh man da hab ich den Wald vor lauter Bäumen nicht mehr gesehen.

OK soweit funktioniert das Programm jetzt einwandfrei. Vielen Dank!

von Steffen (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
ich muss mich leider nochmal melden :-( Ich habe ein neues seltsames
Problem.
Ich habe das Programm noch ein wenig erweitert, eigentlich nur um eine
Tasterabfrage und eine Vorwahlüberprüfung. (siehe Anhang)

Ich weiss das es mal ohne Probleme lief, hab zuerst vermutet den µC
geschossen zu haben. Aber auch ein neuer µC hat nichts gebracht.
Irgendwie werden die 'else if' Anweisungen nicht mehr durchlaufen.
Der Taster (an T1) löst komischerweise jedesmal den Interrupt aus,
anstatt hochzuzählen. Ab und zu funktioniert dann das zählen wieder
aber ich kann die Stufe quasi nicht mehr einstellen.
Ich weiss es ist schwierig zu erklären aber vielleicht habt ihr mein
Problem verstanden.

von johnny.m (Gast)


Lesenswert?

Wenn Du der Variablen 'vorwahl' eine Zahl größer als 9 zuweist, ist es
klar, dass die if-Abfragen ergebnislos bleiben. Wie sieht denn überhaupt
die Vorwahleingabe an Port B aus? Entweder PINB bei der Eingabe
maskieren. Wozu ist überhaupt der Pull-Up von PORTB.4 aktiviert? Wenn
da nix dranhängt (Pin offen), kriegste immer Zahlen größer als 9.
Ansonsten mal eine Default-Aktion einbauen (else...). Ich würde das
ganze aber eh mit einer switch...case-Anweisung machen. Ist weniger
Schreibarbeit und übersichtlicher!

Gruß

Johnny

von Steffen (Gast)


Lesenswert?

Also die Vorwahl geschieht über einen Hex-Drehschalter (0-9), also kann
'vorwahl' nie größer als 9 werden. Der Schalter hängt mit seinen vier
Pins an PB0 bis PB3.
An PB4 hängt ein Taster, zur manuellen Steuerung, der Masse schaltet.
Deshalb der Pullup.

...Ah! Jetzt geht mir auch ein Licht auf, es muss an dem Taster liegen.
Wenn ich PINB einlese wird dieser ja auch mitgelsen und da der immer auf
High (durch dien Pullup) liegt ändert das natürlich meine Zahl.
Da muss ich mir was einfallen lassen wie ich nur die ersten vier Pins
abfrage...?

von johnny.m (Gast)


Lesenswert?

Ah, der Euro fällt centweise:-)

Aber das mit dem 'einfallen lassen' ist ja wohl nicht so schwer,
oder? Habs ja oben schon gesagt: Maskieren!

Ansonsten viel Spaß noch beim Basteln. Und überleg bei Gelegenheit mal,
ob Du Deine if-Abfrage nicht wirklich besser durch ne switch-Anweisung
ersetzt. Solche if...else if...-Würmer sind einfach nicht schön.

Gruß

Johnny

von Steffen (Gast)


Lesenswert?

Ich hatte dabei an eine EXOR Verknüpfung gedacht. Also quasi PB4 mit
EXOR 1 auf Null setzten.
Wie war das noch gleich in C...?

von johnny.m (Gast)


Lesenswert?

Wieso EXOR?????

vorwahl = PINB & 0x0f;

Du solltest vielleicht wirklich mal C-Grundlagen pauken...

Gruß

Johnny

von Steffen (Gast)


Lesenswert?

Gut AND ist vielleicht etwas einfacher, aber EXOR geht auch!

von johnny.m (Gast)


Lesenswert?

Wenn Du aus einem Byte die vier LSB übernehmen und den Rest zu null
machen willst, dann mach es mit &. Alles andere ist völliger Käse. Und
mit Deinem EXOR setzt Du das Bit nur dann auf Null, wenn es vorher
gesetzt ist. Wenn es nämlich vorher null ist, dann setzt Du es auf
'1'! Deshalb scheidet das völlig aus.

Gruß

Johnny

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.