Forum: Mikrocontroller und Digitale Elektronik if Anweisung + Interrupt


von ggggast (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Ein Interrupt setzt flag=1 => ok.

In der while Schleife wird i hochgezählt und sollte Port B7 toggeln => 
nicht ok.

Habe es testhalber mit einem anderen Interrupt probiert, in beiden 
Interrupts toggelt B7 korrekt.

Beim Durchlesen der Forensuche bin ich leider nicht fündig geworden.

Wie kann ich den Fehler weiter eingrenzen?

von pitschu (Gast)


Lesenswert?

Du hast sowohl OC1A als auch OC1B interrupts aktiviert, jedoch keinen 
handler dafür.

von ggggast (Gast)


Lesenswert?

korrekt.

Will nachher in der while Schleife OCR1A und OCR1B Registerinhalte 
ändern und die beiden PWM-Kanäle des Timer1 nutzen.

Es ist ein fehlerfrei kompilierbares Testprogramm für eine Attiny 2313, 
um den Fehler nachzuvollziehen.

Aus diesem Grund sind Programmteile enthalten, die ich später ev. noch 
nutzen werde.

von Walter (Gast)


Lesenswert?

ggggast schrieb:
> korrekt.

nein, nicht korrekt!

von Achim K. (aks)


Lesenswert?

1
ISR (TIMER1_CAPT_vect) {
2
3
  //PORTB ^= (1 << PB7);
4
  flag = 1;
5
6
7
  }

Bei welcher Gelegenheit sollte den der Interrupt gerufen werden? Ich bin 
mir da nicht sicher, ob dass wirklich der gewünschte ist.

Bei
1
if (flag) {
2
    flag = 0;
kann es natürlich sein, dass Du ab- und zu ein "flag" verlierst.

Welcher Prozessor wird den benutzt?

: Bearbeitet durch User
von ggggast (Gast)


Lesenswert?

Hallo Achim,

danke für deine Antwort.

Das Register ICR1 (InputCaptureRegister1) ist TOP im gewählten 
PWM-Modus.
In der Interruptliste des Datenblatts habe ich den TIMER1_CAPT_vect 
gefunden.

Wenn der Wert ICR1 verändert wird, ändert sich aliquot die Periodendauer 
der angezeigten Rechteckspannung am Oszi, PORTB ^= (1 << PB7) natürlich 
entkommentiert.

Wenn PORTB ^= (1 << PB7) in der Schleife steht, zeigt das Oszi dieselbe 
Rechteckspannung.

Controller ist der Attiny2313.

von Achim K. (aks)


Lesenswert?

Schau mal
1
http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
2
3
Catch-all interrupt vector
4
5
If an unexpected interrupt occurs (interrupt is enabled and no handler is installed, which usually indicates a bug), then the default action is to reset the device by jumping to the reset vector. You can override this by supplying a function named BADISR_vect which should be defined with ISR() as such. (The name BADISR_vect is actually an alias for __vector_default. The latter must be used inside assembly code in case <avr/interrupt.h> is not included.)
6
7
#include <avr/interrupt.h>
8
9
ISR(BADISR_vect)
10
{
11
    // user code here
12
}

an. Wenn ich das richtig interpretiere, bekommst Du Resets für die 
Interrupts ohne ISR. Das war wohl auch der Hinweis von Walter.

von Thomas E. (thomase)


Lesenswert?

ggggast schrieb:
> korrekt.
Nein.
> Will nachher in der while Schleife OCR1A und OCR1B Registerinhalte
> ändern und die beiden PWM-Kanäle des Timer1 nutzen.
Man baut keine Sachen halb ein, die man später nutzen will. Das ist 
halbgar.
> Es ist ein fehlerfrei kompilierbares Testprogramm für eine Attiny 2313,
> um den Fehler nachzuvollziehen.
Der Compiler ist böse. Der lässt dich mit deinen fehlenden und falschen 
ISRs voll auf die Schnauze fliegen. Wahrscheinlich grinst er sogar noch 
dabei.
> Aus diesem Grund sind Programmteile enthalten, die ich später ev. noch
> nutzen werde.
S.o: halbgar!
> In der Interruptliste des Datenblatts habe ich den TIMER1_CAPT_vect
> gefunden.
Schön. Da sind noch mehr drin. Bau die doch auch mit ein.

Wenn du einen Interrupt möchtest, der bei TOP zuschlägt, also wenn 
TCNT1==ICR1, dann nimmst du den Overflow:
1
ISR (TIMER0_OVF_vect) 
2
{
3
  //PORTB ^= (1 << PB7);
4
  //b++;
5
6
  //PORTB ^= (1 << PB7);
7
  flag = 1;
8
}

Siehe auch Datenblatt, Table 16-4, Mode 14, rechte Spalte.

Und schalte die Interrupts, für die keine ISR vorhanden ist, ab. Auch 
wenn die später noch benutzt werden sollen. Oder benutz den Würgaround 
mit BADISR.

mfg.

: Bearbeitet durch User
von Achim K. (aks)


Lesenswert?

Eigentlich nutzt er ja Timer 1, da ist TIMER0_OVF_vect u.U. nicht 
passend.

In der Doku steht auch bei Fast PWm Mode (Figure 46)
1
OCRnx/TOP Update and
2
TOVn Interrupt Flag Set and
3
OCnA Interrupt Flag Set
4
or ICFn Interrupt Flag Set
5
(Interrupt on TOP)

Könnte also auch mit dem Capture Interrupt tun.

P.S.: Atmel hat neue Dokus gemacht, ohne Kapitelnummern. Daher kann es 
sein, dass die "Figure" in den bisherigen Dokus auch anderst heißt.

von Thomas E. (thomase)


Lesenswert?

Achim K. schrieb:
> Eigentlich nutzt er ja Timer 1, da ist TIMER0_OVF_vect u.U. nicht
> passend.
Autsch. Ist mir beim Kopieren gar nicht aufgefallen.
Dann natürlich so:
1
ISR (TIMER1_OVF_vect) 
2
{
3
  //PORTB ^= (1 << PB7);
4
  flag = 1;
5
}

> In der Doku steht auch bei Fast PWm Mode (Figure 46)
>
>
1
> OCRnx/TOP Update and
2
> TOVn Interrupt Flag Set and
3
> OCnA Interrupt Flag Set
4
> or ICFn Interrupt Flag Set
5
> (Interrupt on TOP)
6
>
>
> Könnte also auch mit dem Capture Interrupt tun.
Mag sein. Aber 2 IRQs für dieselbe Sache sind irgendwie unsinnig. Beim 
Overflow-Int stürzt der natürlich ohne ISR ab.

mfg.

: Bearbeitet durch User
von ggggast (Gast)


Lesenswert?

Danke für die vielen Antworten!

Habe nun die "halbgaren" Programmteile vom Attiny2313 entfernt und es 
funktioniert.

Sowohl der Capture Interrupt als auch der Overflow Interrupt des Timer1 
führen zum Programmaufruf alle 20ms und die Variable in der while 
Schleife wird raufgezählt =>ok.

@ Thomas Eckmann:
Dass der Capture Interrupt ein Fehlgriff ist, kann ich nicht 
nachvollziehen. Mit welcher Umgebung hast du den Code getestet?

@all:
Welche Stolpersteine gibt es sonst noch auf die Schnelle, auf die ich 
aufpassen sollte?

mfg

von Stefan F. (Gast)


Lesenswert?

Alle Variablen, die in Interrupt Routinen geändert werden und im 
Hauptprogram gelesen werden (oder auch umgekehrt) müssen volatile sein. 
Das hast Du ja schon richtig gemacht.

von Achim K. (aks)


Lesenswert?

> @all:
> Welche Stolpersteine gibt es sonst noch auf die Schnelle, auf die ich
> aufpassen sollte?

Ich nehme immer die Typen aus "<stdint.h>", dann weiß ich, wie viele 
Bytes es sind. Außerdem nehme ich natürlich auch immer den kleinsten 
Typ, in den die benötigten Werte passen. Also nicht
1
volatile int flag = 0;
sondern
1
volatile int8_t flag = 0;

Wenn man die 2 Byte Werte braucht und mit einem Interrupt teilt, dann 
reicht "volatile" oft nicht aus, man muss "cli(); .... ; sei();" (oder 
analoges) benutzen, sonst sieht man u.U. unerwartete "Geisterwerte". Das 
gilt auch für 16 Bit I/O SFRs, wenn man die 16 Bit Register oder einen 
Teil davon auch aus dem Interrupt nutzt. Und für "read and modify" gilt 
dies natürlich auch.

Bei besonderen I/O Operationen mit "Zeitfenster" (z.B. Watchdog füttern, 
System Clock Prescaler ändern) sollte man die entsprechenden Funktionen 
verwenden. Wenn man es, aus welchem Grund auch immer, selber 
programmieren möchte, muss man inline Assembler nehmen.

Da der CPU Core bei vielen Applikationen nur wartet, versuche ich 
möglichst mit "sleep" etwas Energie zu sparen. Man muss natürlich die
Doku beachten, sonst schläft der Core vielleicht länger, als man
wollte :-).

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.