if Anweisung + Interrupt

Gast #3503041
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?
Angehängte Dateien:
Gast #3503056
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.
#3503065
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?
Gast #3503090
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.
#3503127
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.
#3503133
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.
#3503149
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.
#3503177
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.
Gast #3504698
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
#3505489
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 :-).

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren