PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 2 ISR gleichzeitig?



DerSchatten
25.01.2010, 12:31
Kann man 2 ISR gleichzeitig laufen lassen? Macht das Sinn?

Ich verwende bereits einen Zeitgeber in meinem Programm der auf 10ms definiert ist, mit dem ich die Tasten abfrage (kurz oder lang gedrückt):



ISR(TIMER0_OVF_vect)
{
static uint8_t ct0, ct1, rpt;
uint8_t i;

TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);

i = key_state ^ ~KEY_PIN; // Taste geändert?
ct0 = ~(ct0 & i); // resete oder zähle CT0
ct1 = ct0 ^ (ct1 & i); // resete oder zähle CT1
i &= ct0 & ct1; // Überlauf gezählt?
key_state ^= i; // dann Entprellstatus ändern
key_press |= key_state & i; // 0->1: Tastendruck erkannt

if((key_state & REPEAT_MASK) == 0) // Überprüfe Tastenwiederholfunktion
rpt = REPEAT_START; // Starte Verzögerung
if(--rpt == 0)
{
rpt = REPEAT_NEXT; // Wiederhole Verzögerung
key_rpt |= key_state & REPEAT_MASK;
}
}


Jetzt bräuchte ich jedoch noch einen der mir eine Variable in einer frei definierten Zeit (mittels Variable) zwischen HI/LOW toggelt.[/code]

Ls4
25.01.2010, 12:54
zwei ISRs können meines Erachtens nicht gleichzeitig laufen.
Schau mal ins Datenblatt. Da ist eine Liste der Interruptprioritäten.
Heißt soviel wie:
wenn gerade eine ISR mit niedrigerer Priorität läuft und ein höherpriorisierter Interrupt eintrifft, wird die aktuelle ISR unterbrochen und die höherwertige abgearbeitet. Dann gehts in der anderen weiter.
Für mein Verstädnis sollte deine Lösung gut funktionieren. Hätte ich genauso gemacht und ist glaube ich Goldstandard

Gruß Tim

oberallgeier
25.01.2010, 13:15
Hi,


Kann man 2 ISR gleichzeitig laufen lassen? Macht das Sinn? ...Gleichzeitig geht bei Rechnern (fast) garnix.

Tim/Ls4 hat schon auf die unterschiedlichen Priorisierungen hingewiesen. Wenn zwei ISR "gleichzeitig" anfallen, dann wird die höher priorisierte zuerst gestartet. Ansonsten startet die, die zuerst aufgerufen wird und verbietet damit allen nachfolgenden einen neuerlichen Interrupt durchzuführen - der kommt auf ne Warteliste. Dieses Verfahren läuft in einigen meiner Projektchen völlig störungsfrei: Timer0, Timer1, LE D-blinken, ADC auslesen, extINT0 und extINT1 - also sozusagen "viele" Interrupts, die in mehr oder weniger zufälliger Reihenfolge daherkommen.

Deine Frage berührt noch etwas. WENN Du nun eine ISR hast, die beispielsweise (leider) nicht so hoch priorisiert ist, wie Du möchtest, dann kannst Du die trotzdem bevorzugen. Das Stichwort heißt "nested interrupts" - und braucht eine sehr saubere Organisation vor allem der in den jeweiligen ISRn behandelten Daten. Dabei wird beim Aufruf der ISR durch Deine Software das Interrupt enable bit gesetzt "sei();" - das ansonsten erst beim RETI von der controllerinternen Organisation gesetzt wird. JETZT kann ein beliebiger anderer Interrupt SEINE ISR aufrufen - die laufende ISR wird dann genauso unterbrochen, wie das "normale" Programm. Steht in den docs z.B. im Kapitel Reset and Interrupt Handling und liest sich so:


... When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a Return from Interrupt instruction – RETI – is executed ...

DerSchatten
25.01.2010, 13:30
Ok, ich habe gerade noch den Tip bekommen mehrere Aufgaben dem selben Timer zukommen zu lassen. D.h. man nimmt einfach die bereits definierte Timerzeit her und rechnet für seine zwecke die benötigte dann dazu.

oberallgeier
25.01.2010, 14:07
Puh, das klingt alles sehr komplex ...klingt nur so.


... Also wenn ich mit sei() den Interrupt starte wird zuerst der höher abgearbeitet. Wenn aber jetzt das Verhalten des ersten Interrupts nie eintritt wird der niedere nie abgearbeitet?Wieso das denn? Wenn Du am ersten Platz der Warteliste stehst - und beim Aufruf nicht erscheint - dann darf doch der nächste mitfliegen/fahren/etc - oder nicht? GENAUSO ist es bei den Interrupts.

Der Interrupt wird abgearbeitet:
a) wenn er erlaubt ist : sei();
b) wenn ein Auslöser kommt
b1) der kann z.B. in einer Initialisierungsroutine - z.B. init_TC0 - Initialisiere Timer Counter 0 vorbereitet werden
c) wenn keine andere ISR läuft
d) wenn nicht gleichzeitig ein anderer, höher priorisierter IR kommt
e) wenn eine ISR da ist. Kommt schon mal vor dass ein IR kommt - und keine ISR da ist - dann gibts ein bisschen Konfusion (aber das behandeln wir später)
f) wenn der Rechner/Controller (noch) läuft *ggg*


... Also wenn ich mit sei() den Interrupt starte ...Du weißt sicher, dass dies nicht die einzige Startbedingung ist - das kann variieren. DENN sei(); ist eine notwendige, aber nicht immer eine hinreichende Bedingung. Manchmal sind weitere Initialisierungen und Interrupt enable Flags notwendig oder sonstwiewasauchimmer.

Ls4
25.01.2010, 14:11
Hi Schatten,

du kannst auch z.b. wenn du einen Timer im CTC Modus laufen hast 2 verschiedene compare Matches auslösen.
einmal für OCRxA und einmal für OCRxB. Das geht natürlich nicht für jede Anwendung, sondern nur wenn die Zeiten passen (da der Timer ja nur einmal resettet wird)

Gruß Tim

DerSchatten
25.01.2010, 15:14
Sagt, wie toggle ich zwischen 0x00 und 0x01?

So gehts ja nicht:



if( cntTicks == Fire ) // zb nach <Fire> mal 10ms
{
repeatMask ^= 0x01; // von 0x00 nach 0x01
// und umgekehrt: von 0x01 nach 0x00
cntTicks = 0;
}

oberallgeier
25.01.2010, 15:41
... Sagt, wie toggle ich zwischen 0x00 und 0x01 ... Ich mach das meistens "zweiteilig":
#define rLED 3 // Rote LED auf PB3
#define ToggleBit(ADDR,BIT) ((ADDR) ^= (1<<(BIT))) // Toogelt Bit
Dann kann man irgendwo dies machen - und das liest sich recht gut:
ToggleBit (PB, rLED); //
ToggleBit ( repeatMask, 0 ) // Toggelt Bit 0
Ansonsten gehts eben so (WENN repeatMask ein Byte ist) :
PORTC ^= (1<<PC4); // Port PC4 toggeln
repeatMask ^= (1<<0);

DerSchatten
25.01.2010, 17:36
Danke, das mit dem Tooglen ist nun klar.

Ich hab noch ein kelines Problem wo ich nicht weiß wie ich das lösen soll:

Mittels Tabelle weise ich bestimmten Eingänge, bestimmte Ausgänge zu:



#define LED0 (1<<PC0)
#define LED1 (1<<PC1)
#define LED2 (1<<PC2)
#define LED3 (1<<PC3)
#define LED4 (1<<PC4)
#define LED5 (1<<PC5)

#define NR_KONFIGS 9
#define NR_KEYS 6

uint8_t Pattern[NR_KONFIGS][NR_KEYS] PROGMEM =
{
{LED0,LED1,LED2,LED3,LED4,LED5}, // Konfiguration 0
{LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 1
{LED2,LED0,LED4,LED1,LED3,LED5}, // Konfiguration 2
{LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 3
{LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 4
{LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 5
{LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 6
{LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 7
{LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 8
};


Die dann im main abgerufen wird:



while(1)
{
Summe = 0;

if(!(KEY_PIN & 0x01)) // Wenn Taste PortB.0 auf HIGH
Summe |= pgm_read_byte(&Pattern[nKeyPress][0]);
if(!(KEY_PIN & 0x02)) // Wenn Taste PortB.1 auf HIGH
Summe |= pgm_read_byte(&Pattern[nKeyPress][1]);
if(!(KEY_PIN & 0x04)) // Wenn Taste PortB.2 auf HIGH
Summe |= pgm_read_byte(&Pattern[nKeyPress][2]);
if(!(KEY_PIN & 0x08)) // Wenn Taste PortB.3 auf HIGH
Summe |= pgm_read_byte(&Pattern[nKeyPress][3]);
if(!(KEY_PIN & 0x10)) // Wenn Taste PortB.4 auf HIGH
Summe |= pgm_read_byte(&Pattern[nKeyPress][4]);
if(!(KEY_PIN & 0x20)) // Wenn Taste PortB.5 auf HIGH
Summe |= pgm_read_byte(&Pattern[nKeyPress][5]);

OUT_PORT = Summe; // sonst nur definierte Konfiguration ausgeben


Jetzt soll das Togglen des PortC.0 da inkludiert werden falls eine Taste gedrückt wird. Jedoch nur wenn eine Variable auf 1 gesetzt ist.

Ich dachte mir das zuerst so:



if(Dauerfeuer= 1) // Wenn Dauerfeuer aktiv
{
OUT_PORT = Summe | repeatMask; // Definierte Konfiguration mit Dauerfeuer an Ausgang PortC.0 ausgeben
}
else
{
OUT_PORT = Summe // sonst nur definierte Konfiguration ausgeben
}


Der Toggleeffekt funktioniert zwar, geht jedoch natürlich sofort los, auch wenn keine Taste gedrückt ist.

Wie kann ich das am ellegantesten lösen?

askazo
25.01.2010, 18:07
Ist fast ok, da ist nur der Vergleichsoperator falsch.
Ersetze einfach

if (Dauerfeuer=1)
durch

if (Dauerfeuer==1)
//oder noch einfacher
if (Dauerfeuer)

Gruß,
askazo

DerSchatten
25.01.2010, 18:29
danke, da war noch ein denkfehler drinn.
Behebt aber das eigentlich noch nicht.

XBert
25.01.2010, 20:44
...
Jetzt soll das Togglen des PortC.0 da inkludiert werden falls eine Taste gedrückt wird. Jedoch nur wenn eine Variable auf 1 gesetzt ist.
...


if(variable == 1 && (PortC & (1<<BIT)) )
{
//tu was
}

MFG

DerSchatten
25.01.2010, 21:59
Also wenn die Variable 1 ist und der Ausgangsport auf einem bestimmten Anschluss HIGH ist?
Aber welcher Anschluss?

oberallgeier
26.01.2010, 07:37
...
6. Lern mal die Grundlagen der Programmierung von Mikrocontrollern in C - sonst wirst Du noch mehr verzweifeln. Zu Grundlagen der Programmierung von Mikrocontrollern gibts hier etliche Empfehlungen (klick). (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=413294&sid=aafd8dbbcb2cf373be63c4a240127aa1#413294)...Das ist nun fast zwei Wochen her - und Du hast es immer noch nicht gemacht. Und diese Empfehlung von mir war nur EIN Punkt von vielen. (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=480304&sid=9de562a5dc49cd50a448f779ce064f05#480304)
... nun so ganz unwissend bin ich ja nun auch nicht.
Hab schon einiges mit C herumexperimentiert.
Ich lerne eben am besten wenn ich mir anhand von Beispielen die Funktion klar mache ...DU machst diese Beispiele leider nicht DIR klar - sondern WIR sollen sie Dir Bit für Bit vorkauen.

DerSchatten
26.01.2010, 08:29
...
6. Lern mal die Grundlagen der Programmierung von Mikrocontrollern in C - sonst wirst Du noch mehr verzweifeln. Zu Grundlagen der Programmierung von Mikrocontrollern gibts hier etliche Empfehlungen (klick). (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=413294&sid=aafd8dbbcb2cf373be63c4a240127aa1#413294)...Das ist nun fast zwei Wochen her - und Du hast es immer noch nicht gemacht. Und diese Empfehlung von mir war nur EIN Punkt von vielen. (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=480304&sid=9de562a5dc49cd50a448f779ce064f05#480304)
... nun so ganz unwissend bin ich ja nun auch nicht.
Hab schon einiges mit C herumexperimentiert.
Ich lerne eben am besten wenn ich mir anhand von Beispielen die Funktion klar mache ...DU machst diese Beispiele leider nicht DIR klar - sondern WIR sollen sie Dir Bit für Bit vorkauen.
Ok, sorry.
Dachte das Forum wäre auch für Anfänger da.
Dann werd ich mich alleine über die Runden schlagen.

Trotzdem danke für eure Unterstützung.

oberallgeier
26.01.2010, 09:48
Hmmm, seltsame Antwort, muss man da nicht schlucken? Noch etwas: Ich bin nicht das Forum, es gibt sicher Leute, die geduldiger sind als ich. Aber das meiste, das ich Dir bisher erklärt hatte, ist sehr verständlich und gut zugriffbereit in den Tutorials beschrieben.
... Ich lerne eben am besten wenn ich mir anhand von Beispielen die Funktion klar mache ...Siehe oben.In den Tutorails gibts Beispiele - jede Menge. Der Vorteil der Tutorials ist ausserdem, dass Du mit denen Deine Fragen dann beantworten kannst, wenn sie auftreten. Ich schaue jedenfalls öfters in den verschiedenen Unterlagen nach, wenn ich eine Frage habe - obwohl ich weiß, dass die meisten Fragen von sehr vielen hier sehr schnell beantwortet werden könnten. Aber wenn ICH mir alles vorkauen liesse, dann würde ich erheblich weniger lernen.