Forum: Compiler & IDEs USART und Interrupt


von Fragender (Gast)


Lesenswert?

Hallo,
ich kann erfolgreich DAten versenden mit dem USART, nur mit dem 
Empfangen klappt es noch nicht :( Im folgenden Code wird irgendwie nie 
die Interrupt Routine angesprungen, obwohl der andere µC was schickt, 
ebenfalls mit 2400 Baud.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
void delay_ms(int delay) {
6
        int i;
7
        for (i=0;i<=delay;i++) {
8
                _delay_ms(1);
9
        }
10
}
11
12
13
void init_usart(void) 
14
{ 
15
 uint8_t HighByte = (416 >> 8);   // Baudrate 2400
16
 uint8_t LowByte = 416 & 0xFF;
17
 UBRRL |= LowByte;
18
 UBRRH |= HighByte;
19
 UCSRB = (1<<TXEN) | (1<<RXEN) | (1<<RXCIE);
20
 UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
21
}
22
23
void send_char(unsigned char s) 
24
{ 
25
 while (!(UCSRA & (1<<UDRE))); 
26
 UDR = s; 
27
} 
28
29
void send_string(char *s) 
30
{ 
31
 while(*s != '\0') 
32
  { 
33
   send_char(*s); 
34
   s++; 
35
  } 
36
} 
37
38
ISR(USART_RXC_vect) {
39
    uint16_t test;
40
    test = UDR;
41
  send_string("Interrrupt!!!");
42
}
43
44
45
int main(void) 
46
{
47
sei();
48
init_usart();
49
DDRB = 0xFF;
50
while(1)
51
{
52
  send_string("test");
53
  delay_ms(1000);
54
}
55
return 0;
56
}

von Fragender (Gast)


Lesenswert?

Muss mich korrigieren, es geht nachdem ich eine gemeinsame Masse 
zwischen den beiden COntrollern hergestellt habe... Mein Ziel ist aber 
eine Datenübertragung per Infrarot, da habe ich ja auch keine gemeinsame 
MAsse???

von omfgrtfm (Gast)


Lesenswert?

dafür nimmt man dann lichtleichter

von Mike J. (Gast)


Lesenswert?

@ Fragender
Dein Signal vom TX-Pin hat einen Masse-Bezug!
Also der Strom fließt vom TX-Pin nach Masse.

Wenn du den + Pol deiner Autobatterie anfasst bekommst du doch auch 
keine gewischt, es sei denn du hast deine Hand an der Karosserie 
(Masse).

von Fragender (Gast)


Lesenswert?

Stimmt,danke!

von Fragender (Gast)


Lesenswert?

Bin jetzt soweit dass ich eigentlich ganze Strings empfangen sollte,
leider klappt es wieder nicht...
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#define PUFFER_GROESSE 100
5
volatile char *schreibzeiger;
6
volatile char *lesezeiger;
7
volatile char puffer[PUFFER_GROESSE];
8
9
void delay_ms(int delay) {
10
        int i;
11
        for (i=0;i<=delay;i++) {
12
                _delay_ms(1);
13
        }
14
}
15
16
17
void init_usart(void) 
18
{ 
19
 uint8_t HighByte = (416 >> 8);   // Baudrate 2400
20
 uint8_t LowByte = 416 & 0xFF;
21
 UBRRL |= LowByte;
22
 UBRRH |= HighByte;
23
 UCSRB = (1<<TXEN) | (1<<RXEN) | (1<<RXCIE);
24
 UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
25
}
26
27
void send_char(unsigned char s) 
28
{ 
29
 while (!(UCSRA & (1<<UDRE))); 
30
 UDR = s; 
31
} 
32
33
void send_string(char *s) 
34
{ 
35
 while(*s != '\0') 
36
  { 
37
   send_char(*s); 
38
   s++; 
39
  } 
40
} 
41
42
ISR(USART_RXC_vect) {
43
  *schreibzeiger=UDR;
44
  schreibzeiger++;
45
  if(schreibzeiger==puffer+PUFFER_GROESSE) schreibzeiger=puffer;
46
  
47
}
48
49
int main(void) 
50
{
51
uint8_t datenbyte = 0;;
52
sei();
53
init_usart();
54
lesezeiger=puffer;
55
schreibzeiger=puffer;
56
while(1)
57
{
58
  if(schreibzeiger != lesezeiger) {
59
    datenbyte = *lesezeiger;
60
    lesezeiger++;
61
    if(lesezeiger==puffer+PUFFER_GROESSE) lesezeiger=puffer;
62
    send_string(datenbyte);
63
    }
64
65
  
66
}
67
return 0;
68
}

Die (woanders abgeschaute)Idee dabei ist,dass die empfangenen Daten in 
einen Ringpuffer geschrieben werden, und sobald Lese- und Schreibzeiger 
verschieden sind, ausgegeben werden sollen. Leider kommt gar nichts am 
Pc an, gesendet wird definitiv und der der Interupt wird auch ausgelöst.

von Stefan E. (sternst)


Lesenswert?

1)
send_string(datenbyte);
->
send_char(datenbyte);

2)
Du schreibst in den Puffer, ohne zu überprüfen, ob darin überhaupt noch 
Platz ist.

3)
Du schaltest die Interrupts ein, bevor schreibzeiger initialisiert 
ist.

4)
In main muss der Zugriff auf schreibzeiger vor der Unterbrechung durch 
den Interrupt geschützt werden. Und wenn du den Sourcecode bezüglich 2) 
änderst, auch die Zugriffe auf lesezeiger.

von Fragender (Gast)


Lesenswert?

Ok, hab die SAchen berücksichtigt, bis auf die Paltzfrage im Puffer, 
aber zumindest amAnfang müsste es ja so gehn, gehts aber leider immer 
noch nicht :( Die andere SEite sendet im Sekundentakt "hallo\0"

[c]
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define PUFFER_GROESSE 100

volatile char *schreibzeiger;
volatile char *lesezeiger;
volatile char puffer[PUFFER_GROESSE];

void delay_ms(int delay) {
        int i;
        for (i=0;i<=delay;i++) {
                _delay_ms(1);
        }
}

void init_usart(void)
{
 uint8_t HighByte = (416 >> 8);   // Baudrate 2400
 uint8_t LowByte = 416 & 0xFF;
 UBRRL |= LowByte;
 UBRRH |= HighByte;
 UCSRB = (1<<TXEN) | (1<<RXEN) | (1<<RXCIE);
 UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
}

void send_char(unsigned char s)
{
 while (!(UCSRA & (1<<UDRE)));
 UDR = s;
}

void send_string(char *s)
{
 while(*s != '\0')
  {
   send_char(*s);
   s++;
  }
}

ISR(USART_RXC_vect) {
  *schreibzeiger=UDR;
  schreibzeiger++;
  if(schreibzeiger==puffer+PUFFER_GROESSE) schreibzeiger=puffer;

}

int main(void)
{
uint8_t datenbyte = 0;;
sei();
lesezeiger=puffer;
schreibzeiger=puffer;
init_usart();
while(1)
{
  if(schreibzeiger != lesezeiger) {
    cli();
    datenbyte = *lesezeiger;
    lesezeiger++;
    if(lesezeiger==puffer+PUFFER_GROESSE) lesezeiger=puffer;
    send_char(datenbyte);
    sei();
    }
}
return 0;
}[/]

von Fragender (Gast)


Lesenswert?

Kann es sein, dass Schreibzeiger immer auf den Anfang vom Array zeigt? 
wenn ich in der ISR direkt send_string(*schreibzeiger) einfüge,bekomme 
ich hallo, dann hallohallo, dann hallohallohallo etc. ??

von Fragender (Gast)


Lesenswert?

Ach und wenn ich in der ISR send_char einfüge,kommt es nur einmal, die 
if-schleife in der main-funktion wird trotzdem nciht angesprungen

von Stefan E. (sternst)


Lesenswert?

Die Deklaration von schreibzeiger ist falsch. Der Zeiger selber muss 
volatile sein, nicht das Ziel.

volatile char *schreibzeiger;
->
char * volatile schreibzeiger;

(die beiden anderen volatiles sind im aktuellen Code übrigens 
überflüssig)


> wenn ich in der ISR direkt send_string(*schreibzeiger) einfüge

"send_string(*schreibzeiger)" ist schlicht Unsinn, genau wie das 
"send_string(datenbyte)" im vorigen Code.

von Fragender (Gast)


Lesenswert?

Super, geht jetzt! Hier der Code falls jemand mal das gleiche Problem 
hat:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
#define PUFFER_GROESSE 100
6
7
char *volatile schreibzeiger;
8
char *volatile lesezeiger;
9
volatile char puffer[PUFFER_GROESSE];
10
11
void delay_ms(int delay) {
12
        int i;
13
        for (i=0;i<=delay;i++) {
14
                _delay_ms(1);
15
        }
16
}
17
18
void init_usart(void) 
19
{ 
20
 uint8_t HighByte = (416 >> 8);   // Baudrate 2400
21
 uint8_t LowByte = 416 & 0xFF;
22
 UBRRL |= LowByte;
23
 UBRRH |= HighByte;
24
 UCSRB = (1<<TXEN) | (1<<RXEN) | (1<<RXCIE);
25
 UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
26
}
27
28
void send_char(unsigned char s) 
29
{ 
30
 while (!(UCSRA & (1<<UDRE))); 
31
 UDR = s; 
32
} 
33
34
void send_string(char *s) 
35
{ 
36
 while(*s != '\0') 
37
  { 
38
   send_char(*s); 
39
   s++; 
40
  } 
41
} 
42
43
void get_string(char *s) 
44
{ 
45
 while(*s != '\0') 
46
  { 
47
   send_char(*s); 
48
   s++; 
49
  } 
50
} 
51
52
ISR(USART_RXC_vect) {
53
  *schreibzeiger=UDR;
54
  schreibzeiger++;
55
  if(schreibzeiger==puffer+PUFFER_GROESSE) schreibzeiger=puffer;
56
  
57
}
58
59
60
int main(void) 
61
{
62
uint8_t datenbyte = 0;
63
char c;
64
sei();
65
lesezeiger=puffer;
66
schreibzeiger=puffer;
67
init_usart();
68
while(1)
69
{
70
  if(schreibzeiger != lesezeiger) {
71
    cli();
72
    datenbyte = *lesezeiger;
73
    while(*lesezeiger != '\0') {
74
      send_char(datenbyte);
75
        lesezeiger++;
76
      }
77
    if(lesezeiger==puffer+PUFFER_GROESSE) lesezeiger=puffer;
78
    sei();
79
    }
80
  
81
}
82
return 0;
83
}

von Fragender (Gast)


Lesenswert?

Arg,noch eine letzte Frage: Leider scheint der Zeiger nicht zum ANfang 
zurückzuspringen, nachdem der Puffer voll ist... D.h. wird hallo\0 
gesendet, kommt es bei puffer_groesse 50 9mal richtig an und beim 10. 
mal nur ein teil und dann nicht mehr richtig. muss ich da auch was 
anders deklarieren?

von Stefan E. (sternst)


Lesenswert?

Das liegt daran, dass du in main lesezeiger nicht richtig verwaltest. 
Spiel mal durch, was passiert, wenn bei Eintritt in den if-Block 
lesezeiger auf ein '\0' zeigt.

von STK500-Besitzer (Gast)


Lesenswert?

Wieso finde ich die Arbeitsweise mit Pointern bei einem Ringpuffer nur 
so umständlich?
Mit ein paar Variablen, die einfach die Indizes hochzählen, finde ich es 
wesentlich leichter. Zumindest funktionieren meine Ringpuffer-Routinen 
einwandfrei ohne Pointer-Operationen.

von Stefan E. (sternst)


Lesenswert?

Natürlich ginge es mit einem Index einfacher, insbesondere wenn er als 
Puffergröße auch noch eine 2er-Potenz wählen würde. Er wollte ja aber 
wissen, warum sein Ansatz nicht geht, und die Antwort darauf lautet ja 
nicht "mit Zeigern geht es gar nicht, nimm einen Index".

von STK500-Besitzer (Gast)


Lesenswert?

>und die Antwort darauf lautet ja nicht "mit Zeigern geht es gar nicht, nimm 
>einen Index".

Wohl wahr.
Klar geht es mit Zeigern. Nur sollte man schon etwas sicherer beim 
Umgang damit sein...

von Peter D. (peda)


Lesenswert?

STK500-Besitzer wrote:
> Wieso finde ich die Arbeitsweise mit Pointern bei einem Ringpuffer nur
> so umständlich?

Weil sie es ist.


> Mit ein paar Variablen, die einfach die Indizes hochzählen, finde ich es
> wesentlich leichter.

Und wenn ein Byte (0..255) als Index reicht, ist das sogar effizienter 
(weniger Code, schneller):

Beitrag "AVR-GCC: UART mit FIFO"


Peter

von Peter D. (peda)


Lesenswert?

Stefan Ernst wrote:
> insbesondere wenn er als
> Puffergröße auch noch eine 2er-Potenz wählen würde.

Das spart gerade mal einen Befehl ein, lohnt also nicht.


Peter

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.