www.mikrocontroller.net

Forum: Compiler & IDEs Timer Compare Interrupt Problem


Autor: Steffen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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. ;-)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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);

Autor: Steffen (Gast)
Datum:

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

OK soweit funktioniert das Programm jetzt einwandfrei. Vielen Dank!

Autor: Steffen (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso EXOR?????

vorwahl = PINB & 0x0f;

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

Gruß

Johnny

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut AND ist vielleicht etwas einfacher, aber EXOR geht auch!

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.