Forum: Mikrocontroller und Digitale Elektronik Verschachtelte Interrupts


von David P. (chavotronic)


Lesenswert?

Hallo,

Ich habe eine Lageregelung (Atmega 644p) implementiert, die mit dem 
TIMER0_COMPA_vect x-mal pro Sekunde aufgerufen wird. Nun möchte ich 
einige Variablen gerne über die serielle Schnittstelle rausschicken 
(Interruptbasierte Uart Library), allerdings wird die Übertragung durch 
die Timer Routine unterbrochen. Ich kann ja nun schlecht die Interrupts 
deaktivieren vor dem schicken, da ja dann auch das serielle nicht mehr 
läuft.
Was gibt es da für Lösungsansätze? Kann man zB die Timerinterrupts 
einzeln deaktivieren?

Vielen Dank,

David

von Karl H. (kbuchegg)


Lesenswert?

David P. schrieb:

> Was gibt es da für Lösungsansätze? Kann man zB die Timerinterrupts
> einzeln deaktivieren?

Wenn dir die durch den UART Interrupt verurschte Interrupt Latenz die 
Regelung ausser Tritt bringt, wirst du wohl schweren Herzens auf eine 
Interrupt getriebene UART verzichten müssen. Gerade bei der UART ist das 
auch nicht so der Beinbruch, wenn man die eigentliche 
Zeichen-Senderoutine aus der Hauptschleife heraus zyklisch aufruft.


> Nun möchte ich einige Variablen gerne über die serielle
> Schnittstelle rausschicken (Interruptbasierte Uart Library),
> allerdings wird die Übertragung durch die Timer Routine unterbrochen.

Dein Problem klingt allerdings nach einem Denkfehler:
Du kannst nicht innerhalb der Regelschleife jedesmal einen Satz 
Messwerte ausgeben, wenn die Ausgabe grundsätzlich schon mal länger 
dauert als von einem Aufruf der Regelschleife zur nächsten vergeht.

von David P. (chavotronic)


Lesenswert?

Hallo Karl-Heinz,

Ich würde diese Werte auch nur 1x pro Sekunde rausgeben wollen.
Es ist übrigens umgekehrt, das senden der Zeichen wird von der Regelung 
unterbrochen (und macht danach auch nicht weiter ..)

von Karl H. (kbuchegg)


Lesenswert?

David P. schrieb:
> Hallo Karl-Heinz,
>
> Ich würde diese Werte auch nur 1x pro Sekunde rausgeben wollen.
> Dann muss ich wohl auf die Uart Interrupt verzichten...

Ehe du das umbaust: Hast du es schon ausprobiert.
So eine UART Interrupt Routine ist ja im Normalfall eine von der kurzen 
Art: Zeichen aus Rungbuffer holen und aufs UDR zuweisen.

Klar das ist ein Arrayzugriff, ein Index erhöhen und ein paar Abfragen.

Summa summarum nichts was den µC länger als ein paar zig-Tatzyklen 
beschäftigen sollte. Wenn deine Regelschleife diese Verzögerung abkann, 
ist doch alles in Butter.

von Karl H. (kbuchegg)


Lesenswert?

> Es ist übrigens umgekehrt, das senden der Zeichen wird von der
> Regelung unterbrochen (und macht danach auch nicht weiter ..)

Zeig mal.
Das klingt nach einem Designflaw.

von Bernhard R. (barnyhh)


Lesenswert?

Hallo David,
dann debugge bitte Dein Programm. Das von Dir beschriebene Verhalten 
deutet auf Designfehler bzw Programmfehler hin.
Meine Glaskugel sagt: Zeile 42.

Bernhard

Edit: Da war wer schneller.

von David P. (chavotronic)


Lesenswert?

Ich poste mal das Wichtigste:
1
int main(void) {
2
  
3
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
4
  uint16_t chk;
5
  char i = 0;
6
  
7
  DDRA = 0x00;
8
  PORTA = 0x00;
9
  
10
  DDRB = 0x00;
11
  PORTB = 0xFF;
12
  
13
  DDRC = 0xFF;
14
  DDRD = 0xFE;
15
  
16
  
17
  // motorcontroller disabled / PWM-Signals to zero//
18
  PORTD |= _BV(PD2);
19
  OCR1A = 255;
20
  OCR1B = 0;
21
    
22
  init();
23
  
24
25
  PORTD &= ~_BV(PC7);
26
  
27
  *Dazwischen einige Routinen mit Lesen aus dem Eeprom usw*
28
29
  TCCR0B |= _BV(CS00) | _BV(CS02);
30
  TCCR0A |= _BV(WGM01);
31
  TCCR0A = (1<<WGM01);
32
  OCR0A = 155;
33
    
34
  TIMSK0 = _BV(OCIE0A); // compare interrupt
35
36
  
37
  sei();
38
  uart_puts("Teststring");
39
  
40
  while (1) {}
41
  }
42
}
43
ISR (TIMER0_COMPA_vect) {
44
45
* Hier werden dann Regelungsfunktionen aufgerufen * 
46
  TCNT0 = 0; 
47
}

Der Teststring kommt nicht komplett an. Lib ist übrigens die von Peter 
Fleury.

: Bearbeitet durch Admin
von Detlev T. (detlevt)


Lesenswert?

Interruptroutinen sollte man immer so kurz wie möglich machen. Nur das 
machen, was sofort passieren muss, dann ein Flag setzen, damit die 
Hauptschleife weiß, dass es neue Daten zum Verarbeiten gibt.

von David P. (chavotronic)


Lesenswert?

Müsste er nicht wenigstens nach dem Timer-Interrupt zurückspringen und 
die fehlenden Zeichen ausgeben?

von Karl H. (kbuchegg)


Lesenswert?

David P. schrieb:
> Müsste er nicht wenigstens nach dem Timer-Interrupt zurückspringen und
> die fehlenden Zeichen ausgeben?

Müsste er und tut er im Normalfall auch.
Irgendwas hast du da verbockt.

von David P. (chavotronic)


Lesenswert?

Ich mach mich mal ans debuggen...

von Karl H. (kbuchegg)


Lesenswert?

Was ich mir zb vorstellen könnte:
Dass deine Reglungsfunktionen viel zu lange brauchen.
Dadurch steckt der µC praktisch nur noch in der Regelung und für das 
Drumherum bleibt keine Zeit mehr übrig.

von Joe (Gast)


Lesenswert?

Du kannst auch eine Zeitscheibe programmieren.

Beitrag "Genaue Sekunde und Zeitscheibe mit Timer0 erzeugen"


Oder auch am Ende eines jeden Interrupts innerhalb der Interruptroutine 
jeweils ein Zeichen über UART übertragen, falls noch ein Zeichen zur 
Ausgabe vorhanden ist die Zeit noch reicht.

Oder aber deine Interruptroutine so kurz machen und nur Flags setzen, so 
dass die serielle Schnittstelle nur geringfügige Fehler erhält.
Deine IRQ-Aufgaben werden dann außerhalb der IR_Routine erledigt.

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.