Forum: Mikrocontroller und Digitale Elektronik Interrupt in Endlosschleife


von P. F. (pfuhsy)


Lesenswert?

Hallo,

ich hab ein Problem mit meinen Interrupt. Er soll auslösen, sobald ein 
Zeichen über die UART empfangen wird. Das funktionert, doch wenn er 
einmal in der ISR-Routine ist, verlässt er diese nicht mehr und sendet 
den Text "Interrupt immer und immer weider. Ich versende lediglich ein 
einziges Zeichen. Ich hab schon einige Befehle durchprobiert, doch ich 
kriege das nicht hin. Was mache ich falsch ?


Gruss

1
#define F_CPU 3686400      //Taktfrquenz
2
#define BAUD 9600        //einstellte Baudrate
3
//-----------------------------
4
#include <string.h>
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <avr\io.h>
8
#include <avr\delay.h>
9
#include <avr/interrupt.h>
10
//----------------------------------------------------------------------
11
void Senden(char buffer[]);
12
void Debug(char buffer[]);
13
//----------------------------------------------------------------------
14
15
void initPorts() 
16
{
17
  DDRB   = 11111111;                     // PORTB = Ausgang
18
  DDRC   = 11111111;                     // PORTC = Ausgang
19
  DDRD   = 00000000;                     // PORTD = Eingang
20
  PORTD  = 00001000;              // PORTD = PULL-UP für den Taster
21
}
22
23
void initUART() 
24
{
25
  UBRRL  = (F_CPU / BAUD - 16) / 16;    //Baudberchnnung
26
  UCSRB  = 0x98;                   //Transmitter/Receiver/Receiver Interrupt Enable
27
  sei();                  // Interrupts zulassen
28
}
29
30
ISR(USART_RXC_vect) 
31
{
32
  Debug("Interrupt");
33
}
34
35
//----------------------------------------------------------------------
36
void putChar(char data) 
37
{
38
  while (!(UCSRA&32));        //warte bis UDR leer ist
39
  UDR = data;              //senden
40
}
41
//----------------------------------------------------------------------
42
char getChar()
43
{
44
  char data=0;
45
  while (!(UCSRA&128)); //warte bis RX-complete RXC UCSRA
46
  data=UDR; //empfangen
47
48
  return data;
49
}
50
//----------------------------------------------------------------------
51
void Senden(char buffer[]) 
52
{
53
  for (int i=0 ; buffer[i] !=0 ; i++)
54
    putChar(buffer[i]);
55
}
56
57
void Debug(char buffer[])
58
{
59
  Senden(buffer);
60
}
61
62
//----------------------------------------------------------------------
63
//----------------------------------------------------------------------
64
main()
65
{
66
  initPorts();
67
  initUART();
68
69
  int i=0;
70
  char text[5];
71
  do
72
  {
73
    /*
74
    char zeichen;
75
    zeichen = getChar();
76
    text[i] = getChar();
77
    i++;
78
    */
79
80
    //Debug ("main");
81
    //wenn 5 Zeichen (z.B. BTR1C) geschrieben sind, wird die variable zurückgesetzt
82
    if(i==5) 
83
    {
84
      i=0;
85
86
      if (text[3] == '1') 
87
      {
88
        PORTB |= (1 << PB0);
89
        Senden("BTR11A\n");
90
91
        waitMs(1000);
92
        PORTB &= ~(1 << PB0);
93
        Senden("BTR10A\n");
94
      }
95
96
      if (text[3] == '2') 
97
      {
98
        PORTB |= (1 << PB1);
99
        Senden("BTR21A\n");
100
101
        waitMs(1000);
102
        PORTB &= ~(1 << PB1);
103
        Senden("BTR20A\n");  
104
      }
105
106
      if (text[3] == '3') 
107
      {
108
        PORTB |= (1 << PB2);
109
        Senden("BTR31A\n");
110
111
        waitMs(1000);
112
        PORTB &= ~(1 << PB2);
113
        Senden("BTR30A\n");  
114
      }
115
116
    }
117
  }
118
  while (true);
119
}

von Michel (Gast)


Lesenswert?

Wenn du den UART Transmit Interrupt freigibts, erzeugt das erste 
empfangene Zeichen einen explodierenden Rattenschwanz von 
Transmit-Interrupts, weil für jedes Zeichen deiner Debug-Ausgabe nach 
erfolgreichem Aussenden ein neuer Transmit Interrupt ausgelöst wird, der 
wieder den Text "Interrupt" aussenden möchte.
MfG

von P. F. (pfuhsy)


Lesenswert?

Und wie kann ich den sagen, dass er die Routine nur einmal ausführen 
soll ?

von Karl H. (kbuchegg)


Lesenswert?

Michel schrieb:
> Wenn du den UART Transmit Interrupt freigibts,

Hat er ja gar nicht

@Peter

Du musst das Zeichen in der ISR auch abholen.
Erst durch das Auslesen von UDR wird die Interruptanforderung wieder 
gelöscht.

von Karl H. (kbuchegg)


Lesenswert?

Das hier

  UCSRB  = 0x98;

ist fast due dümmste SChreibweise, die du wählen kannst. Noch dümmer 
wäre nur noch eine Dezimalangabe

Warum nicht
1
  UCSRB = ( 1 << RXEN ) | ( 1 << TXEN ) | ( 1 << RXCIE );

da würde man auf einen Blick sehen, was du eigentlich eingestellt und 
freigegeben hast.

von P. F. (pfuhsy)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Warum nicht  UCSRB = ( 1 << RXEN ) | ( 1 << TXEN ) | ( 1 << RXCIE );
>
> da würde man auf einen Blick sehen, was du eigentlich eingestellt und
> freigegeben hast.

Danke für den Tipp, das werde ich verwenden.

Karl Heinz Buchegger schrieb:
> Du musst das Zeichen in der ISR auch abholen.
> Erst durch das Auslesen von UDR wird die Interruptanforderung wieder
> gelöscht.

Wie hole ich das empfangene Zeichen den ab ?

von Josef D. (jogedua)


Lesenswert?

nicht direkt zum Problem,
aber das hier

  DDRB   = 11111111;                     // PORTB = Ausgang

soll ja wohl

  DDRB   = 0b11111111;                     // PORTB = Ausgang

heißen

von P. F. (pfuhsy)


Lesenswert?

Wie hole ich das empfangende Zeichen denn jetzt ab, damit die 
Interrupt-Routine beendet wird ?

von Timmo H. (masterfx)


Lesenswert?

Indem du in der ISR getChar() aufrufst bzw. einfach data=UDR;

von Josef D. (jogedua)


Lesenswert?

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART

kurz:

  data=UDR; //empfangen

gehört in die ISR. Diese muss das Zeichen (z.B. in einem Ringpuffer) 
speichern.

char getChar()... muss dann jeweils ein Zeichen aus dem Ringpuffer 
zurückgeben statt selbst die UART auszulesen.

von Josef D. (jogedua)


Lesenswert?

ich benutze stattdessen die
 UART library
aus
 http://homepage.hispeed.ch/peterfleury/avr-software.html

das Studium der Quelltexte ist auch sehr lehrreich.

von P. F. (pfuhsy)


Lesenswert?

Sehr schön, danke für die Tipps. Hab es ausprobiert, funktioniert. 
Vielen dank für die Unterstützung.

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.