Forum: Mikrocontroller und Digitale Elektronik Problem mit Zeiger auf Array


von tantal.lpt (Gast)


Lesenswert?

Hi,

ich bin grad dabei mir eine kleine uart-empfangsroutine zu schreiben und 
häng an einem Problem fest.

Also die uart läuft ohne probleme und löst auch interrupts aus.
1
#define rx_buffer_len 32
2
3
unsigned char rx_buffer[rx_buffer_len];
4
unsigned char *ptr_read = rx_buffer;
5
unsigned char *ptr_write = rx_buffer;
6
7
8
void init_uart (void){
9
  UBRRH = (unsigned char)(bauddivider>>8);
10
  UBRRL = (unsigned char)bauddivider;
11
12
  UCSRA = (1<<U2X);
13
  UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
14
  UCSRC = (1<<UCSZ1)|(1<<UCSZ0);
15
16
}
17
18
19
void uart_putchar(unsigned char c)
20
{
21
  while( !( UCSRA & (1<<UDRE)));
22
  UDR = c;
23
}
24
25
26
27
ISR(USART_RX_vect)
28
{
29
  *ptr_write= UDR;
30
  ptr_write++;
31
  if(ptr_write == rx_buffer + rx_buffer_len) ptr_write = rx_buffer;
32
33
    while ( !( UCSRA & (1<<UDRE)) );
34
35
}
36
37
38
int main(void){
39
40
  DDRB = 0x1F;
41
  PORTB = 0xFF;
42
43
  DDRD = 0x30;
44
  PORTD = 0x00;
45
46
  init_uart();
47
48
  sei();
49
50
  while(1){
51
52
    for(unsigned char i = 0 ; i < rx_buffer_len ; i++)
53
      uart_putchar(rx_buffer[i]);
54
55
56
    uart_putchar(*ptr_write);
57
    uart_putchar(*ptr_read);
58
59
60
    _delay_ms(5000);
61
62
63
  }
64
65
}

also wie schon erwähnt senden und empfangen funtioniert sehr gut.
wenn ich das programm starte bekomm ich folgendes auf dem 232-Term:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00

also der Buffer-inhalt + die zwei zeigerinhalte alles 00 ... soweit so 
gut
sende ich jetzt ein zeichen (z.B. 0xAA) bekomm ich so etwas:

AA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 AA AA

das Zeichen 0xAA steht am anfang vom Buffer. Der lesezeiger (ptr_read) 
zeigt auf das erste element, was auch so sein soll ... aber wiso zeigt 
der zweite Zeiger auf das gleiche Zeichen?
wenn ich jetzt aber 0xff sende bekomm ich folgendes:

AA FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 AA AA

der ptr_write zeigt also immer auf das nächste element im speicher.. 
aber nur in der ISR .. sonst immer auf das erste... kamm mir da einer 
weiterhelfen? Was mache ich da falsch?

gruß Mathias

von Peter (Gast)


Lesenswert?

volatil vergessen, Variabeln die in einer ISR und in Main verwendet 
werden müssen als Volatil gekennzeichnet werden.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

tantal.lpt schrieb:
> der ptr_write zeigt also immer auf das nächste element im speicher..
> aber nur in der ISR .. sonst immer auf das erste...
Sichwort "volatile"...

> Was mache ich da falsch?
Du hast eine unnötig komplizierte Pointerverwaltung deines Puffers...

von tantal.lpt (Gast)


Lesenswert?

Danke für die schnelle Antwort! also mit volatile hab ich schon versucht 
... da hat sich nix verbessert.

Es geht mir jetzt zwar in erster linie darum wiso das nicht funktioniert 
damit ich beim nächsten mal bescheid waiß, aber wie könnte ich denn die 
Pointerverwaltung meines Puffers verbessern?

gruß Mathias

von TheMiB (Gast)


Lesenswert?

also die ISR an sich sieht nicht sonderlich durchdacht aus.
1
if(ptr_write == rx_buffer + rx_buffer_len) ptr_write = rx_buffer;

hier vergleichst du die adresse des pointers ptr_write mit dem Wert von 
rx_buffer[0]+rx_buffer_len? bringt wohl nichts...also ich denke du 
willst prüfen ob du das ende erreicht hast und dann den pointer zurück 
aufs erste element setzen...also müsste es heißen:
1
if(ptr_write == &rx_buffer + rx_buffer_len) ptr_write = &rx_buffer;

als nächstes...die while-schleife gehört nicht in eine ISR!! Also nur 
aufs ereignis warten...pointer, etc. setzen und weiter im Text.

Bei Fehlern möge man mich bitte korrigieren...

mfg
TheMiB

von tantal.lpt (Gast)


Lesenswert?

Hi

also bei mir klappt es so mit der end of buffer erkennung ... ich mein 
auch das " *ptr = array " das gleiche ist wie " *ptr = &array[0] "

gut mit der while-schleife in der ISR is net so ganz schön .. hatte ich 
irgendwann zwischendurch eingefügt um den fehler zu finden bevor ich mir 
den ganzen puffer hab ausprinten lassen wo ich dann gesehen hab das 
soweit alles klappt mit den Puffer befüllen ...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

TheMiB schrieb:
> also müsste es heißen:
> &rx_buffer
Wenn das nur nicht mal die Adresse des Pointers zurückgibt...
Die Adresse des ersten Elements ist  &rx_buffer[0],
und das ist das selbe wie  rx_buffer

> rx_buffer
Ist nämlich schon ein Pointer. Nämlich auf rx_buffer[0]...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

tantal.lpt schrieb:
> also mit volatile hab ich schon versucht ... da hat sich nix verbessert.
Zeig mal, wie du das versucht hast. Hast du einen Pointer auf einen 
volatilen char gemacht oder einen volatilen Pointer auf einen char?

von tantal.lpt (Gast)


Lesenswert?

also ich habs so gemacht:
1
volatile unsigned char *ptr_read;
2
volatile unsigned char *ptr_write;

habs aber auch mal so probiert (?) :
1
unsigned char volatile *ptr_read;
2
unsigned char volatile *ptr_write;

oder macht man das bei pointern noch anders?

von Stefan E. (sternst)


Lesenswert?

In beiden Fällen ist nicht der Pointer selber volatile, sondern das, 
worauf er zeigt (die beiden Varianten sind tatsächlich identisch).

Volatile Pointer:
1
typ * volatile ptr;

von tantal.lpt (Gast)


Lesenswert?

aaahhh ... ok das wusste ich nicht. Jetzt funktionierts!!

Danke euch für die schnelle hilfe!

gruß Mathias

von MagIO (Gast)


Lesenswert?

Du solltest nochmal über die ISR nachdenken.

Genauer: was passiert, wenn die Daten schneller ankommen, als sie 
gelesen werden? Sprich der ptr_write läuft einmal in Kreis und an 
ptr_read vorbei.

von tantal.lpt (Gast)


Lesenswert?

Hi,

ja hab ich auch schon bemerkt ... besonders blöd wird es wenn genau 32 
Bytes kommen .. dann steht der Pointer genau an der selben stelle und 
man kann nicht mehr mit einem pointervergleich sehen ob was gekommen ist 
oder nich ... hab jetzt eine abbruchbedingung nach Buffer_len -1 gemacht 
... alles was dann kommt ignorier ich dann einfach ... in meinem fall 
kommen aber eh nie so viele daten auf einmal ...

trozdem danke für den Hinweis!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

tantal.lpt schrieb:
> besonders blöd wird es wenn genau 32 Bytes kommen
Ja nun, dann ist dein Puffer zu klein. So einen Buffer-Overrun kannst du 
eigentlich niemals richtig gut abfangen...

von Karl H. (kbuchegg)


Lesenswert?

Und darüber
1
ISR(USART_RX_vect)
2
{
3
  *ptr_write= UDR;
4
  ptr_write++;
5
  if(ptr_write == rx_buffer + rx_buffer_len) ptr_write = rx_buffer;
6
7
    while ( !( UCSRA & (1<<UDRE)) );
8
9
}

solltest du auch noch einmal nachdenken. (Ich meine die letzte while 
Schleife in der ISR)

von tantal.lpt (Gast)


Lesenswert?

ja wie gesagt ich bekomm eh nur max 5 Byte auf einmal und das auch nur 
max ein mal pro sec. also sollten die 32 Byte locker reichen!

die while schleife ist auch schon raus ... wie gesagt hatte sie nur bei 
der fehlersuche rein gemacht ... aber jetzt läuft alles wie es soll ..

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.