Forum: Compiler & IDEs UART String wird immer wieder gesendet


von R. S. (relaxed)


Lesenswert?

Hallo zusammen,


Ich habe folgendes Problem. Ich möchte von einem Atmega 328p einen 
String per UART ausgeben. Dies funktioniert ohne Probleme solange ich 
Interrupts nicht global aktiviere.

Wenn ich Interrupts global mit sei() aktiviere wird mir der String 
mehrmals oder sogar in einer Endlosschleife gesendet.

Anbei noch das Programm:


1
#define F_CPU 16000000UL
2
#define BAUD 9600
3
#define BRC ((F_CPU/16/BAUD) - 1)    //Calculation for setting baud rate
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <avr/interrupt.h>
8
9
10
volatile uint8_t flag = 0;
11
12
13
14
15
int main(void)
16
{
17
  
18
  interrupt_init();
19
  
20
  uart_init();  
21
  
22
  sei();
23
  
24
  
25
    while(1)
26
    {
27
  
28
    if (flag == 1)
29
    {
30
      uart_puts("Flag gesetzt");
31
      
32
      flag = 0;
33
    }
34
  
35
36
  }
37
     
38
     
39
     
40
}
41
42
void uart_putc( unsigned char data )
43
{
44
  
45
  while ( !( UCSR0A & (1<<UDRE0)))
46
  {
47
    
48
  }
49
  
50
  UDR0 = data;
51
  
52
}
53
54
void uart_puts (char *s)
55
{
56
  while (*s)
57
  {   // so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)"
58
    uart_putc(*s);
59
    s++;
60
  }
61
}
62
63
void uart_init()
64
{
65
  
66
  UBRR0H = (BRC >> 8);
67
  
68
  UBRR0L = BRC;
69
  
70
  UCSR0B = (1 << TXEN0) | (1 << TXCIE0);
71
  
72
  UCSR0C = (1 << UCSZ01)|(1 << UCSZ00);
73
  
74
}
75
76
void interrupt_init()
77
{
78
  //falling edge interrupt for INT0
79
  EICRA = (1<<ISC01);
80
  
81
  EIMSK = (1<<INT0);
82
  
83
}
84
85
86
ISR (INT0_vect)
87
88
{
89
  flag = 1;  
90
}


Danke und Gruss

: Bearbeitet durch User
von Bitflüsterer (Gast)


Lesenswert?

> Wenn ich Interrupts global mit sei() aktiviere wird mir der String
> mehrmals oder sogar in einer Endlosschleife gesendet.

Das ist so, weil im Interrupt immer wieder das Flag auf 1 gesetzt wird 
und in der while-Schleife immer wieder geprüft wird, ob das Flag 1 ist 
und die Ausgabe erfolgt. Wenn auch das Flag anschliessend auf 0 gesetzt 
wird, so wird es beim nächsten Interrupt wieder auf 1 gesetzt.

von R. S. (relaxed)


Lesenswert?

Aber wird der Interrupt nicht nur einmal ausgelöst, wenn sich die Flanke 
von High auf Low ändert?

Das Problem tritt auch bei folgendem Beispiel auf:


Es soll jede Sekunde einen String gesendet werden. Effektiv wird aber 
sobald einer gesendet wurde, ohne Pause wieder einen weiteren gesendet. 
Und immer so weiter.
Dies aber wie gesagt nur wenn ich die globalen Interrupts aktiviere. 
Ansonsten tut es was es soll.

Bin echt ein wenig ratlos.


1
#define F_CPU 16000000UL
2
#define BAUD 9600
3
#define BRC ((F_CPU/16/BAUD) - 1)    //Calculation for setting baud rate
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <avr/interrupt.h>
8
9
10
11
12
13
14
15
int main(void)
16
{
17
  
18
  interrupt_init();
19
  
20
  uart_init();  
21
  
22
  sei();
23
  
24
    while(1)
25
    {
26
    
27
    uart_puts("Flag gesetzt");
28
    
29
    _delay_ms(1000);
30
  
31
32
  
33
  
34
35
    }
36
     
37
     
38
     
39
}
40
41
void uart_putc( unsigned char data )
42
{
43
  
44
  while ( !( UCSR0A & (1<<UDRE0)))
45
  {
46
    
47
  }
48
  
49
  UDR0 = data;
50
  
51
}
52
53
void uart_puts (char *s)
54
{
55
  while (*s)
56
  {   // so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)"
57
    uart_putc(*s);
58
    s++;
59
  }
60
}
61
62
void uart_init()
63
{
64
  
65
  UBRR0H = (BRC >> 8);
66
  
67
  UBRR0L = BRC;
68
  
69
  UCSR0B = (1 << TXEN0) | (1 << TXCIE0);
70
  
71
  UCSR0C = (1 << UCSZ01)|(1 << UCSZ00);
72
  
73
}
74
75
void interrupt_init()
76
{
77
  //falling edge interrupt for INT0
78
  EICRA = (1<<ISC01);
79
  
80
  EIMSK = (1<<INT0);
81
  
82
}
83
84
85
ISR (INT0_vect)
86
87
{
88
  
89
}

von Rolf Magnus (Gast)


Lesenswert?

R. S. schrieb:
> UCSR0B = (1 << TXEN0) | (1 << TXCIE0);

Kein Wunder. Warum schaltest du denn auch den UART-Sende-Interrupt ein, 
wenn du gar keine ISR dafür hast?

von Bitflüsterer (Gast)


Lesenswert?

R. S. schrieb:
> Aber wird der Interrupt nicht nur einmal ausgelöst, wenn sich die Flanke
> von High auf Low ändert?

Das ist richtig. Aber bist Du auch sicher, dass es nur eine 
High-Low-Flanke gibt? Deiner Beschreibung nach, könnte es sein, das der 
Eingang offen ist oder mehr Flanken auftreten, als Du annimmst. Zeig uns 
mal die Schaltung, bitte.

> Das Problem tritt auch bei folgendem Beispiel auf:
Lass uns erstmal bei einem Problem bleiben, sonst verzetteln wir uns. 
Mach für das andere Problem später einen eigenen Thread auf.

von Bitflüsterer (Gast)


Lesenswert?

Leider fällt mir jetzt erst auf, das Du keinen Pin als Eingang 
konfiguriert hast. Hole das mal nach und poste den neuen Code.
Denke bitte auch an das Schaltbild.

von Rolf Magnus (Gast)


Lesenswert?

Bitflüsterer schrieb:
> Leider fällt mir jetzt erst auf, das Du keinen Pin als Eingang
> konfiguriert hast.

Wenn der Pin nicht explizit als Ausgang konfiguriert ist, ist er ein 
Eingang.

von R. S. (relaxed)


Lesenswert?

Das Problem war wirklich der eingeschaltete Sende-Interrupt.

Danke für die Hilfe.

Weiss denn einer wieso sich das Programm so verhält, wenn die ISR nicht 
im Programm ist?

Kann mal also sagen, es ist zwingend notwendig alle eingeschalteten 
Interrupts auch in einer ISR zu behandeln, auch wenn diese leer 
ist.(Natülich schaltet man die Interrupts nicht ein wenn man sie 
braucht. - Ist nur ne Verständnisfrage)

von Bitflüsterer (Gast)


Lesenswert?

R. S. schrieb:
> Das Problem war wirklich der eingeschaltete Sende-Interrupt.

Nein. War es nicht. In dem Code wurde der Sende-Interrupt garnicht 
eingeschaltet. (Nur in dem zweiten, den Du ja eigentlich erstmal 
beiseite lassen solltest).


> Weiss denn einer wieso sich das Programm so verhält, wenn die ISR nicht
> im Programm ist?
>
> Kann mal also sagen, es ist zwingend notwendig alle eingeschalteten
> Interrupts auch in einer ISR zu behandeln, auch wenn diese leer
> ist.
Ja. Richtig. Sonst wird irgendwelcher Unsinn gemacht.

(Natülich schaltet man die Interrupts nicht ein wenn man sie
> braucht. - Ist nur ne Verständnisfrage)
Im Gegenteil, wenn man sie braucht, schaltet man sie ein.

von R. S. (relaxed)


Lesenswert?

Bitflüsterer schrieb:
> Nein. War es nicht. In dem Code wurde der Sende-Interrupt garnicht
> eingeschaltet. (Nur in dem zweiten, den Du ja eigentlich erstmal
> beiseite lassen solltest).

Der ist doch bei beiden Programmen eingeschaltet?
Bei uart_init() steht bei beiden das Selbe.


Das mit dem nicht einschalten wenn man sie braucht war ein Schreibfehler 
:-/  Sollte natürlich heissen nur einschalten wenn man sie braucht.

von Bitflüsterer (Gast)


Lesenswert?

R. S. schrieb:
> Bitflüsterer schrieb:
>> Nein. War es nicht. In dem Code wurde der Sende-Interrupt garnicht
>> eingeschaltet. ...

> Der ist doch bei beiden Programmen eingeschaltet?
> Bei uart_init() steht bei beiden das Selbe.


Auweia. Entschuldigung. Dann ist es ja klar. :-)
(Wer rechnet auch mit sowas? :-) )

von Karl H. (kbuchegg)


Lesenswert?

R. S. schrieb:


> Weiss denn einer wieso sich das Programm so verhält, wenn die ISR nicht
> im Programm ist?

Weil dann der gcc einen Default-Handler einbaut, welcher - tada - einen 
Programm-Neustart durchführt.

Die Idee dahinter ist, dass ein eingeschalteter Interrupt, für den es 
keine ISR gibt, als Fehler zu behandeln ist. Denn wozu sollte man keine 
ISR haben, den Interrupt aber aktivieren?

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.