Forum: Mikrocontroller und Digitale Elektronik WinAvr pointer Übergabe verändert char Array


von Markus W. (kornbanane)


Lesenswert?

Hallo Leute,

ich hab hier ein wohl einfaches Problem, wo ich einfach nicht 
weiterkomme. Ich programmiere einen Atmega16 in C mit WinAvr.

Mein Programm besteht im Moment nur darin ein vom PC gesendeten String 
über die serielle Schnittstelle aufzunehmen und zurückzugeben.
Das ganze Funktioniert auch soweit, deshalb denke ich brauche hier nicht 
dan ganzen Code zu posten.
Die vom PC empfangenen Daten werden in einem
1
char uart0_tx_buffer[255];
gespeichert. Dabei wird das Ende eines Telegramms vom PC mit einem 
Terminierungszeichen erkannt und eine Variable gesetzt, sodass die 
Hauptschleife weiß, wann es die Daten wieder zurücksenden soll.

In er Hauptschleife sieht das dann so aus:
1
while (1)
2
  {
3
  
4
  
5
    if(uart0_rxd_complete==1)
6
    {
7
      i=0;
8
      
9
      if(uart0_rxd_DataLength!=0)
10
      {
11
        putch('\r',0);
12
        putstring("\nFolgende Daten wurden empfangen: \n",0);      
13
        putch('\r',0);
14
      //  zahl=string_to_dec_value(uart0_rx_buffer);
15
        
16
        while(uart0_rx_buffer[i]!='\0')
17
        {
18
          putch(uart0_rx_buffer[i],0);
19
          i++;
20
        }
21
        putch('\r',0);
22
      }
23
  
24
      uart0_rxd_DataLength=0;
25
      uart0_rxd_complete=0;
26
      UCSRB |= (1<<RXCIE);      // Empfangsinterrupt wieder aktivieren
27
    }

Ihr seht die Zeile "zahl=string_to_dec_value(uart0_rx_buffer);" ist noch 
auskommentiert, denn genau hier ist mein Problem. Mit dieser Zeile will 
ich den uart0_rx_buffer, also das Array mit den Empfangenen Zeichen, per 
Pointer an die Funktion string_to_dec_value übergeben. Diese Funktion 
ist noch völlig leer:
1
unsigned int string_to_dec_value(char *inputStr)
2
{
3
4
  return 0;
5
}

Und trotzdem kommt nur Müll raus, wenn ich diese Zeile einbinde. Es ist 
so als ob das Array uart0_rx_buffer manipuliert wird, denn nach dem 
aufruf der Funktion string_to_dec_value kehre ich ja wieder zur 
Hauptschleife zurück und gebe das Array aus. Dann ist es aber so, das 
die Ausgabe manchmal ganz normal Funktioniert und manchmal Fehlen 
Zeichen oder wurden durch andere ersetzt, die ich garnicht gesendet 
hatte....

Ich möchte noch anmerken, das die Empfangsroutine und die Funktion 
string_to_dec_value in der Datei "uart.c" stehen und auch dort das Array 
"char uart0_tx_buffer[255];" definiert ist. Die Hauptschleife befindet 
sich in der "main.c" und das Array ist mit "extern char 
uart0_rx_buffer[];" eingebunden.

Also warum manipuliert der Funktionsaufruf mein Array ? Es sieht auch so 
aus, als währe immer nur das erste Zeichen im Array davon betroffen, 
aber es kann auch sein das ich mir das jetzt nur einbilde.
Ich bekomme auch übrigens keine Warnungen vom Compiler angezeigt.

Vielen Dank

von Oliver (Gast)


Lesenswert?

Das ist mal wieder so ein Fall, bei dem das Problem nicht im gezeigten 
Code liegt.

Wenn der Effekt wirklich tatsächlich nachweislich an der einen Zeile 
"zahl=..." liegt (du siehst, mir fehlt da etwas der Glaube), dann 
überschreibt die zurückgegebene Null andere Daten. Warum, musst du 
rausfinden. Das ist auf jeden Fall kein Problem von "zahl", sondern von 
den Buffern davor oder dahinter.

Es kann aber auch was ganz anderes sein.

Oliver

von Markus W. (kornbanane)


Lesenswert?

Also ich kann dir versichern dass das Problem nur besteht wenn die 
Funktion string_to_dec_value aufgerufen wird. Ich dachte halt deshalb, 
das es mit der Übergabe an die Funktion zusammenhängt also mit dem 
Pointer.

Und es passiert auch nicht immer. Sagen wir ich sende 10 mal den selben 
String, dann kommt er halt z.B.: 4 mal richtig zurück und 6 mal Fehlt 
das erste Zeichen oder wurde durch irgendetwas anderes ersetzt. Dachte 
zuerst es liegt an meinem USB zu RS232 Wandler der am PC hängt, aber ich 
habe es auch auf einem anderem PC mit "richtiger" RS232 Schnittstelle 
ausprobiert.

von Oliver (Gast)


Lesenswert?

Markus Wi*** schrieb:
> Also ich kann dir versichern dass das Problem nur besteht wenn die
> Funktion string_to_dec_value aufgerufen wird.

Nun, ich kann dir versichern, daß das Problem auch ohne diese Zeile 
besteht. Es äussert sich dann nur anders, und fällt vielleicht auch gar 
nicht direkt auf.

Du kannst davon ausgehen, das der Compiler sowohl Parameter als auch 
Rückgabewert richtig übergibt. Daran kann es nicht liegen.

Oliver

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Was stellt denn sicher, daß uart0_rx_buffer nicht außerhalb dieser 
Funktion verändert wird?

Wenn der beispielsweise von einer ISR befüllt wird ... nichts.

von Michael A. (micha54)


Lesenswert?

Hallo,

das oben beschriebene Programm enthält einige typische Fallstricke, die 
robuste Programme von Bastelprogrammen unterscheiden:

1) was passiert, wenn das Ende-Kennzeichen fehlt ? Rennt dann das 
Programm durch den Speicher und sucht die '\0' ?

2) ist i ein unsigned char ? Dann ist uart0_rx_buffer für i=255 zu kurz.

Gruß,
Michael

von Markus W. (kornbanane)


Lesenswert?

Michael Appelt schrieb:
> Hallo,
>
> das oben beschriebene Programm enthält einige typische Fallstricke, die
> robuste Programme von Bastelprogrammen unterscheiden:
>
> 1) was passiert, wenn das Ende-Kennzeichen fehlt ? Rennt dann das
> Programm durch den Speicher und sucht die '\0' ?
>
> 2) ist i ein unsigned char ? Dann ist uart0_rx_buffer für i=255 zu kurz.
>
> Gruß,
> Michael

1) Das Endezeichen wird durch meine Empfangsisr angehängt, siehe 
Quellcode unten (in uart.c)

2) Nein es ist ein Int


Rufus Τ. Firefly schrieb:
> Was stellt denn sicher, daß uart0_rx_buffer nicht außerhalb dieser
> Funktion verändert wird?
>
> Wenn der beispielsweise von einer ISR befüllt wird ... nichts.

Naja die einzigste Funktion bzw. ISR die darauf zugreift ist der 
Empfangsinterrupt. Diese wird aber eben nicht mehr aufgerufen, nachdem 
der PC die Daten an den µC gesendet hat. Anstonsten gibt eh halt noch 
nicht ;)

Hier mal der Code:

main.c:
1
#include <main.h>             // Headerdatei von main.c
2
  
3
  
4
//---------------------------------------------------------------------------
5
// main
6
//
7
// functiondescription: Startet Initialisierungen und kontrolliert den weiteren Programmablauf
8
//
9
// hand over:
10
//  - input parameters: nothing
11
// returns:
12
//  - return parameter: nothing
13
//---------------------------------------------------------------------------
14
  
15
  
16
int main(void)
17
{
18
    int i=0;
19
    unsigned int zahl;
20
      
21
    /// Initialisierungen der Ports
22
  
23
    DDRA = 0x00;                // Port A als Eingang
24
    PORTA = 0xFF;               // interne Pull-ups für Port A aktivieren
25
  
26
    DDRB = 0x00;                // Port B als Eingang
27
    PORTB = 0xFF;               // interne Pull-ups für Port B aktivieren
28
  
29
    DDRC = 0xFF;                // Gesamter Port C als Ausgang
30
    PORTC = 0x00;               // Port C auf 0 setzten, damit LED's an sind 
31
      
32
    DDRD = 0x00;                // Port D als Eingang
33
    PORTD = 0xFF;               // interne Pull-ups für Port D aktivieren
34
      
35
    Inituart0();                // Die UART Schnittstelle initialisieren
36
      
37
    sei();                      // Interrupts aktivieren
38
  
39
  
40
    putstring("\n\nHallo Welt !! !!\n\n",0);
41
      
42
          
43
  
44
    while (1)
45
    {
46
      
47
      
48
        if(uart0_rxd_complete==1)
49
        {
50
            i=0;
51
              
52
            if(uart0_rxd_DataLength!=0)
53
            {
54
                putch('\r',0);
55
                putstring("\nFolgende Daten wurden empfangen: \n",0);           
56
                putch('\r',0);
57
                zahl=string_to_dec_value(uart0_rx_buffer);
58
                  
59
                while(uart0_rx_buffer[i]!='\0')
60
                {
61
                    putch(uart0_rx_buffer[i],0);
62
                    i++;
63
                }
64
                putch('\r',0);
65
            }
66
      
67
            uart0_rxd_DataLength=0;
68
            uart0_rxd_complete=0;
69
            UCSRB |= (1<<RXCIE);          // Empfangsinterrupt wieder aktivieren
70
        }
71
   }
72
}


uart.c:
1
#include <uart.h>             // Headerdatei von uart.c
2
  
3
  
4
/// Für die Kommunikation über die UART0 Schnittstelle
5
//--Senden--//
6
char uart0_tx_buffer[255];                          // Sendebuffer
7
unsigned char uart0_tx_buffer_pointer=0;            // Zeigt auf den nächsten freien Speicherbereich im Sendebuffer
8
unsigned char uart0_txd_pointer=0;                  // Zeige auf das nächste zu sendende Zeichen im Sendebuffer
9
unsigned char uart0_txd_complete=0;                 // Zeigt an, ob Senden über UART0 im gange ist. 0 = Senden, 1 = Alle Zeichen gesendet
10
//--Empfangen--//
11
char uart0_rx_buffer[255];                          // Empfangsbuffer
12
unsigned volatile char uart0_rx_buffer_pointer=0;   // Zeigt auf den nächsten freien Speicherbereich im Empfangsbuffer
13
unsigned char uart0_rxd_complete=0;                 // Zeigt an, ob ein komplettes Telegramm (bis zum Endezeichen CR) von der UART0 Schnittstelle empfangen wurde
14
unsigned char uart0_rxd_DataLength=0;               // Gibt die Anzahl der empfangenen Daten an     
15
//--------------------------------------
16
  
17
  
18
unsigned char test2=0;
19
  
20
  
21
  
22
//---------------------------------------------------------------------------
23
// ISR(USART_TXC_vect)
24
//
25
// functiondescription: Interrupt für USART0 recieve. Schreibt die empfangenen Zeichen in einen Empfangsbuffer bis das Endezeichen (CR=0x0D) erkannt wurde
26
//
27
// hand over:
28
//  - input parameters: nothing
29
// returns:
30
//  - return parameter: nothing
31
//---------------------------------------------------------------------------
32
ISR(USART_RXC_vect)
33
{
34
    char dummy_read;
35
      
36
    dummy_read=UDR;         // UDR muss erst über dummy_read ausgelesen werden, da sonst unverhersehbares Verhalten
37
      
38
    if(dummy_read!=0x0D)    // Kein Endezeichen empfangen ?
39
    {
40
        uart0_rx_buffer[uart0_rx_buffer_pointer]=dummy_read;
41
        uart0_rxd_DataLength++;     // Wieder ein Datum mehr empfangen
42
          
43
          
44
        // Einzellne empfangene Zeichen anzeigen lassen
45
        /*
46
        putch('-',0);
47
        putch(uart0_rx_buffer[uart0_rx_buffer_pointer],0);
48
        putch('[',0);
49
        putdec((unsigned long)uart0_rx_buffer_pointer,0);
50
        putch(']',0);
51
        */
52
        // ------
53
          
54
        uart0_rx_buffer_pointer++;
55
        if(uart0_rx_buffer_pointer>255) uart0_rx_buffer_pointer=0;       // Zur Sicherheit, kann hier aber nicht passieren, da unsigned char sowieso überläuft 
56
          
57
    }
58
    else                // Wenn ein Endezeichen empfangen wurde
59
    {
60
        UCSRB &= ~(1<<RXCIE);                                             // Empfangsinterrupt deaktivieren                                   
61
        uart0_rx_buffer[uart0_rx_buffer_pointer]='\0';                  // Das String-Terminierungszeichen '\0' wird als letztes in den Empfangsbuffer geschrieben  
62
        uart0_rx_buffer_pointer=0;
63
        uart0_rxd_complete=1;
64
    }
65
}
66
  
67
  
68
  
69
//---------------------------------------------------------------------------
70
// ISR(USART_TXC_vect)
71
//
72
// functiondescription: Interrupt für USART0 Data Register Empty. Prüft, ob weitere Zeichen im Sendebuffer stehen und sendet diese
73
//
74
// hand over:
75
//  - input parameters: nothing
76
// returns:
77
//  - return parameter: nothing
78
//---------------------------------------------------------------------------
79
ISR(USART_UDRE_vect)
80
{
81
    if(uart0_txd_pointer!=uart0_tx_buffer_pointer)      // Es stehen noch ungesendete Zeichen im Sendebuffer
82
    {   
83
        UDR=uart0_tx_buffer[uart0_txd_pointer];
84
        uart0_txd_pointer++;
85
        if(uart0_txd_pointer>255) uart0_txd_pointer=0;   // Zur Sicherheit, kann hier aber nicht passieren, da unsigned char sowieso überläuft 
86
    }
87
    else                                                // Wenn keine zu sendende Zeichen mehr übrig sind
88
    {
89
        UCSRB &= ~(1<<UDRIE);                         // Den "Data register empty Interrupt" deaktivieren
90
        uart0_txd_complete=1;                           // Alle Zeichen gesendet
91
    }   
92
}
93
  
94
  
95
  
96
  
97
//---------------------------------------------------------------------------
98
// InitUART
99
//
100
// functiondescription: Initialisiert die UART Schnittstelle
101
//
102
// hand over:
103
//  - input parameters: nothing
104
// returns:
105
//  - return parameter: nothing
106
//---------------------------------------------------------------------------
107
void Inituart0(void)
108
{
109
    UCSRB=0xB8;                 // 8N1, RX und TX Enable, RX Interrupt; UDRE Interrupt (Data Register empty)
110
    UCSRC=0x86;                 // 8N1; Asynchron; kein Paritätsbit 
111
    UBRRH = 0;                  // Für 9600Baud@16Khz
112
    UBRRL = 103;                // Für 9600Baud@16Khz
113
}
114
  
115
  
116
  
117
  
118
//---------------------------------------------------------------------------
119
// putch
120
//
121
// functiondescription: Schreibt das zu sendende Zeichen in den Sendebuffer der jeweiligen Schnittstelle
122
//
123
// hand over:
124
//  - input parameters: Zu sendendes Zeichen; Schnittstelle über die gesendet werden soll
125
// returns:
126
//  - return parameter: nothing
127
//---------------------------------------------------------------------------
128
void putch(char character, unsigned char channel)
129
{
130
    switch (channel)
131
    {
132
        case 0:
133
        {
134
              
135
            uart0_txd_complete=0;                                       // Uart0 ist aktiv
136
            uart0_tx_buffer[uart0_tx_buffer_pointer]=character;         // Zeichen in den Sendebuffer kopieren
137
            uart0_tx_buffer_pointer++;                                  // Sendepuffer erhöhen
138
            if(uart0_tx_buffer_pointer>255) uart0_tx_buffer_pointer=0;   // Zur Sicherheit, kann hier aber nicht passieren, da unsigned char sowieso überläuft 
139
            UCSRB |= (1<<UDRIE);                                      // Den"Data register empty Interrupt" aktivieren
140
            break;
141
        }
142
          
143
        default: break;
144
          
145
    }
146
}
147
  
148
  
149
  
150
//---------------------------------------------------------------------------
151
// putstring
152
//
153
// functiondescription: Sendet den übergebenen String in den Sendebuffer der jeweiligen Schnittstelle mithilfe der Funktion putch
154
//
155
// hand over:
156
//  - input parameters: Zu sendenden String; Schnittstelle über die gesendet werden soll
157
// returns:
158
//  - return parameter: nothing
159
//-------------------------------------------------------------------------
160
  
161
void putstring(char *string, unsigned char channel)
162
{
163
    while (*string != '\0')
164
    { 
165
        if(*string == '\n')                  // CR senden ?  
166
        {
167
            putch('\r',channel);
168
            string++;
169
        }
170
        else
171
        {
172
            putch(*string,channel);       // Jedes Zeichen einzeln in den Sendebuffer schreiben
173
            string++;
174
        }
175
    }
176
}
177
  
178
 
179
//---------------------------------------------------------------------------
180
// string_to_dec_value
181
//
182
// functiondescription: Wandelt einen übergebenen String der Länge len in eine Zahl um und gibt diese zurück.
183
//
184
// hand over:
185
//  - input parameters: String der in eine Zahl umgewandelt werden soll; Länge des Strings
186
// returns:
187
//  - return parameter: nothing
188
//-------------------------------------------------------------------------
189
  
190
unsigned int string_to_dec_value(char *inputStr)
191
{
192
  
193
    return 0;
194
}


Die Variablen sind in der Uart.c deklariert und werden in der main.h wie 
folgt eingebungen

main.h
1
//-------------------
2
// begin extern vars 
3
//-------------------
4
  
5
extern volatile unsigned char uart0_txd_complete;
6
extern volatile unsigned char uart0_rxd_complete;
7
extern volatile char uart0_rx_buffer[];
8
extern volatile unsigned char uart0_rxd_DataLength;
9
extern volatile unsigned char uart0_txd_complete;   
10
extern unsigned char Anzeigenreset;
11
  
12
//-----------------
13
// end extern vars 
14
//-----------------

von Uwe (de0508)


Lesenswert?

Hi, dann läuft deine cpu zu langsam:
Für 9600Baud@16Khz

von Karl H. (kbuchegg)


Lesenswert?

Eine Frage noch.
Was läuft auf dem PC?
Sitzt du selber am Terminal und gibst ein, oder ist da ein Programm, 
welches den AVR über die UART versorgt?

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


Lesenswert?

Markus Wi*** schrieb:
> char uart0_tx_buffer[255];
Das ist ein Zeichen zu wenig für diese "Sicherheitsabfrage":
Markus Wi*** schrieb:
1
uart0_tx_buffer[uart0_tx_buffer_pointer]=character;
2
uart0_tx_buffer_pointer++; // Sendepuffer erhöhen
3
if(uart0_tx_buffer_pointer>255) uart0_tx_buffer_pointer=0; // Zur Sicherheit, kann hier aber nicht passieren, da unsigned char sowieso überläuft
Denn hier kann der Index ja erlaubterweise auch 255 werden. Du kannst 
also 256 Elemente adressieren. Blöd, wenn dein Array nur 255 Elemente 
reserviert hat...

: Bearbeitet durch Moderator
von Quack (Gast)


Lesenswert?

>             if(uart0_tx_buffer_pointer>255) uart0_tx_buffer_pointer=0;   // Zur 
Sicherheit, kann hier aber nicht passieren, da unsigned char sowieso überläuft

Wie du richtig kommentierst, sind diese Checks sinnlos. Aber was 
schlimmer ist, deine Puffer sind ein Byte zu klein:

> char uart0_rx_buffer[255];

Bei einem maximalen Index von 255 brauchst du 256 Byte.

von Oliver (Gast)


Lesenswert?

Deine extern-Definitionen und tatsächlichen Deklarationen unterschieden 
sich bzgl. volatile.

Wenn ich das richtig verstehe, sieht uart.c nur die uart.h, in der 
einige volatiles bei den Bufferindices fehlen, die sowohl in der TX-ISR 
und in putch benutzt werden. Ob das jetzt tatsächlich etwas ausmacht, 
darfst du selber herausfinden.

Oliver

von Quack (Gast)


Lesenswert?

Das sieht mal wieder nach Code aus, bei dem die Warnings ignoriert 
werden. :-/

von Markus W. (kornbanane)


Lesenswert?

Uwe S. schrieb:
> Hi, dann läuft deine cpu zu langsam:
> Für 9600Baud@16Khz

Na aber dann würde doch das Problem immer bestehen und nicht nur wenn 
ich die eine Funktion aufrufe

Karl Heinz schrieb:
> Eine Frage noch.
> Was läuft auf dem PC?
> Sitzt du selber am Terminal und gibst ein, oder ist da ein Programm,
> welches den AVR über die UART versorgt?

Ich nutze ein einfaches Terminalprogramm

Lothar Miller schrieb:
> Denn hier kann der Index ja erlaubterweise auch 255 werden. Du kannst
> also 256 Elemente adressieren. Blöd, wenn dein Array nur 255 Elemente
> reserviert hat...

Oh ja ... war natürlich etwas dämlich. Danke für den Tip, leider ändert 
es hieran nichts.

Oliver schrieb:
> Wenn ich das richtig verstehe, sieht uart.c nur die uart.h, in der
> einige volatiles bei den Bufferindices fehlen, die sowohl in der TX-ISR
> und in putch benutzt werden. Ob das jetzt tatsächlich etwas ausmacht,
> darfst du selber herausfinden.

und

Quack schrieb:
> Das sieht mal wieder nach Code aus, bei dem die Warnings ignoriert
> werden. :-/

Ja sorry, ich denk mal ihr meint die Variable uart0_rx_buffer weil sie 
in uart.c nicht als volatile steht aber in main.h. Ja da hab ich jetzt 
während dem "Basteln" mist kopiert. Sie sind an beiden Stellen NICHT 
volatile. Wenn ich sie als volatile deklariere, dann bekomme ich auch 
eine Warnung. Ich glaube das meintest du ?

Und ja. Die main.c sieht nur die main.h und die uart.c die uart.h

: Bearbeitet durch User
von Bastler (Gast)


Lesenswert?

In der Ausgabeschleife in main versuchst du den Ringbuffer als String 
auszugeben. Nimm mal ein Blatt Papier und einen Stift und mal den 
Ringbuffer mit seinen Pointern und den Fall "Daten beginnen hinten im 
Puffer und werden vorne weitergeführt". Da hilft kein \0 ans Ende 
schreiben, dann funktioniert nie.

von Karl H. (kbuchegg)


Lesenswert?

Bastler schrieb:
> In der Ausgabeschleife in main versuchst du den Ringbuffer als String
> auszugeben.

Nicht ganz.
Wegen
1
ISR(USART_RXC_vect)
2
{
3
    char dummy_read;
4
      
5
    dummy_read=UDR;
6
7
    if(dummy_read!=0x0D)    // Kein Endezeichen empfangen ?
8
    {
9
...
10
    }
11
    else                // Wenn ein Endezeichen empfangen wurde
12
    {
13
...
14
        uart0_rx_buffer_pointer=0;
15
...
16
    }
17
}

ist es kein wirklicher Ringbuffer.

: Bearbeitet durch User
von Bastler (Gast)


Lesenswert?

Stimmt!

von Markus W. (kornbanane)


Lesenswert?

Oh weia ich kann auflösen ...

So ein dummer Fehler ohne witz....

Wie ja schon Lothar Miller und Quack bemerkt hatten war mein 
uart0_rx_buffer ein Zeichen zu klein. Deshalb der Fehler und es sah 
wirklich die ganze Zeit so aus als würde es nur durch die Funktion 
aufreten. Verdammter misst ich sollte weniger trinken :D

Danke Danke Danke

von S. K. (hauspapa)


Lesenswert?

>ich sollte weniger trinken

Trinken ist eine sehr gesunde Sache und dem Denkvermögen sehr 
förderlich. Wasser wie es aus der Leitung kommt ist dafür aber 
eigentlich ausreichend. Verschiedene Zusatzstoffe können das natürlich 
wandeln.

Auch wenn die Sting-Problematik nicht ganz neu ist, hab ich mit 
Interesse mitgelesen. Man muss ja nicht immer nur durch eigene Fehler 
lernen.

besten Dank
Hauspapa

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.