Forum: Mikrocontroller und Digitale Elektronik Atmega16 USART_UDRE_vect interrupt


von Markus W. (kornbanane)


Lesenswert?

Hallo Leute,

ich hab die Kommunikation über UART mit meinem Atmega16 über einen 
Ringbbuffer gelöst. Dabei wird mithilfe des Interruptvektors 
USART_UDRE_vect jedesmal ein neues Zeichen ins Senderegister geschoben, 
wenn das Senderegister leer ist. Im Datenblatt steht zu diesem Interruot 
folgendes:
1
 • Bit 5 – UDRE: USART Data Register Empty
2
The UDRE Flag indicates if the transmit buffer (UDR) is ready to receive new data. If UDRE is
3
one, the buffer is empty, and therefore ready to be written. The UDRE Flag can generate a Data
4
Register empty Interrupt (see description of the UDRIE bit).
5
UDRE is set after a reset to indicate that the transmitter is ready.
6
7
8
9
Bit 5 – UDRIE: USART Data Register Empty Interrupt Enable
10
Writing this bit to one enables interrupt on the UDRE Flag. A Data Register Empty Interrupt will
11
be generated only if the UDRIE bit is written to one, the Global Interrupt Flag in SREG is written
12
to one and the UDRE bit in UCSRA is set.

So weit so gut, es funktioniert auch, aber ich habe ein 
Verständnissproblem. Und zwar steht im Datenblatt, das der Interrupt 
aufgerufen wird, sobalt das Senderegister leer ist. Wenn nun aber sagen 
wir das Senderegister jetzt die nächsten 10 minuten leer bleibt, wird 
dann zig 1000 mal die Interruptroutine aufgerufen ? Weil das ginge am 
eigendlichen sinn der Sache vorbei (is ja auch wieder polling). Oder 
wird sie nur einmal aufgerufen, nachdem das Senderegister leer ist und 
dann ist Ruhe ?

Gruß Markus

von Manuel S. (steinerhippo)


Lesenswert?

Markus Wi*** schrieb:
> Wenn nun aber sagen
> wir das Senderegister jetzt die nächsten 10 minuten leer bleibt, wird
> dann zig 1000 mal die Interruptroutine aufgerufen ?

Ja, der Interrupt muss nach dem Sendevorgang deaktiviert werden. Siehe 
dazu auch:

http://www.mikrocontroller.net/articles/Interrupt#UART_mit_Interrupts

In
1
ISR(USART_UDRE_vect)
 steht foldendes:
1
char data;
2
3
// Ende des nullterminierten Strings erreicht?
4
if (data==0 ) {        
5
    UCSRB &= ~(1<<UDRIE);       // ja, dann UDRE Interrupt ausschalten
6
    ...
7
    ...
8
}

von Markus W. (kornbanane)


Lesenswert?

Danke erst mal soweit, das hat mir schon weiter geholfen.

Habe es nun so umgesetzt:
1
/// Für die Kommunikation über die UART0 Schnittstelle
2
unsigned char uart0_tx_buffer[255];      // Sendebuffer
3
unsigned char uart0_tx_buffer_pointer=0;  // Zeigt auf den nächsten freien Speicherbereich im Sendebuffer
4
unsigned char uart0_txd_pointer=0;      // Zeige auf das nächste zu sendende Zeichen im Sendebuffer
5
unsigned char uart0_tdx_complete=0;      // Zeigt an, ob alle Zeichen gesendet wurden (=1)
6
7
8
//---------------------------------------------------------------------------
9
// ISR(USART_TXC_vect)
10
//
11
// functiondescription:  Interrupt für USART0 Data Register Empty. Prüft, ob weitere Zeichen im Sendebuffer stehen und sendet diese
12
//
13
// hand over:
14
//  - input parameters: nothing
15
// returns:
16
//  - return parameter: nothing
17
//---------------------------------------------------------------------------
18
ISR(USART_UDRE_vect)
19
{
20
  if(uart0_txd_pointer!=uart0_tx_buffer_pointer)    // Es stehen noch ungesendete Zeichen im Sendebuffer
21
  {  
22
    //while(UDRE!=1);
23
    UDR=uart0_tx_buffer[uart0_txd_pointer];
24
    //PORTC = uart0_tx_buffer[uart0_txd_pointer];
25
    uart0_txd_pointer++;
26
    if(uart0_txd_pointer>255) uart0_txd_pointer=0;  // Zur Sicherheit, kann hier aber nicht passieren, da unsigned char sowieso überläuft 
27
  }
28
  else
29
  {
30
    UCSRB &= ~(1<<UDRIE);                 // den UDRE Interrupt ausschalten
31
    uart0_tdx_complete=1;              // Alle Zeichen gesendet
32
    PORTC = 0x0A;
33
  }  
34
}
35
36
37
38
39
//---------------------------------------------------------------------------
40
// InitUART
41
//
42
// functiondescription:  Initialisiert die UART Schnittstelle
43
//
44
// hand over:
45
//  - input parameters: nothing
46
// returns:
47
//  - return parameter: nothing
48
//---------------------------------------------------------------------------
49
void Inituart0(void)
50
{
51
  UCSRB=0x4C;          // 8N1, RX und TX Enable, RX Interrupt
52
  UCSRC=0x86;          // 8N1; Asynchron; kein Paritätsbit  
53
  UBRRH = 0;          // Für 9600Baud@16Khz
54
  UBRRL = 103;        // Für 9600Baud@16Khz
55
}
56
57
58
59
60
//---------------------------------------------------------------------------
61
// putch
62
//
63
// functiondescription:  Schreibt das zu sendende Zeichen in den Sendebuffer der jeweiligen Schnittstelle
64
//
65
// hand over:
66
//  - input parameters: Zu sendendes Zeichen; Schnittstelle über die gesendet werden soll
67
// returns:
68
//  - return parameter: nothing
69
//---------------------------------------------------------------------------
70
void putch(unsigned char character, unsigned char channel)
71
{
72
  switch (channel)
73
  {
74
    case 0:
75
    {
76
      
77
      uart0_tdx_complete=0;                    // Uart0 ist aktiv
78
      uart0_tx_buffer[uart0_tx_buffer_pointer]=character;      // Zeichen in den Sendebuffer kopieren
79
      uart0_tx_buffer_pointer++;                  // Sendepuffer erhöhen
80
      if(uart0_tx_buffer_pointer>255) uart0_tx_buffer_pointer=0;  // Zur Sicherheit, kann hier aber nicht passieren, da unsigned char sowieso überläuft 
81
      break;
82
    
83
    }
84
    
85
    default: break;
86
  }
87
88
}
89
90
91
92
//---------------------------------------------------------------------------
93
// puts
94
//
95
// functiondescription:  Sendet den übergebenen String in den Sendebuffer der jeweiligen Schnittstelle mithilfe der Funktion putch
96
//
97
// hand over:
98
//  - input parameters: Zu sendenden String; Schnittstelle über die gesendet werden soll
99
// returns:
100
//  - return parameter: nothing
101
//---------------------------------------------------------------------------
102
void puts(unsigned char *string, unsigned char channel)
103
{
104
  
105
  while (*string != '\0')
106
  { 
107
    if(*string == '\n')           // CR senden ?  
108
    {
109
      putch('\r',channel);
110
      string++;
111
    }
112
    else
113
    {
114
      putch(*string++,channel);       // Jedes Zeichen einzeln in den Sendebuffer schreiben
115
    }
116
  }
117
  
118
  UCSRB |= (1<<UDRIE);
119
  
120
}

In meiner main funktion rufe ich jetzt ein mal auf
1
puts("\n\nHallo Welt !! !!\n\n",0);

Die Funktion puts übergibt jedes Zeichen einzeln an die Funktion putch. 
Diese läd dann den Sendebuffer. Am Ende der Funktion puts aktiviere ich 
dann noch den Interrupt. Im Interrupt wird überprüft, ob es noch 
ungesendete Zeichen gibt (uart0_txd_pointer!=uart0_tx_buffer_pointe) und 
diese gesendet, falls das der Fall ist. Wenn nicht, wird der Interupt 
wieder deaktiviert. Sollte doch so funktionieren.

Aber ich bekomme meine Textausgabe in einer Dauerschleife !! Wieso ?! 
Resettet sich der µC etwa ständig ? Hab sonst nix drinn im Programm, 
kein Watchdog kein garnix :( :(

Vom Aufbau her ist es doch das selbe wie bei dem verlinktem Artikel

: Bearbeitet durch User
von Stefan E. (sternst)


Lesenswert?

Markus Wi*** schrieb:
> Resettet sich der µC etwa ständig ?

Ja, und der Grund liegt hier:
1
  UCSRB=0x4C;          // 8N1, RX und TX Enable, RX Interrupt
Gutes Beispiel, warum diese Schreibweise nicht sehr sinnvoll ist.

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.