Forum: Mikrocontroller und Digitale Elektronik C, String und Uart Problem.


von Matthias (Gast)


Lesenswert?

Servus Leute,

ich hab ein paar kleinere Problem mit C auf meinem Atmega16...
Und zwar will ich vom Uart rechnerseitig einen Befehl reinschicken und 
damit meinen Datenstring abhohlen (digitale Zustände und Analogwerte), 
doch irgendwie hauts nicht so hin wie ich will.

Wenn ichs so wie im Code unten mache, krieg ich Probleme bei dem Wert 
für den AD Wandler. Es kommt zwar der Zahlenwert an, aber danach noch 
teilweise 2 3 oder mehr Mistzeichen.

Deshalb wollte ich die Daten in ein char Array schmeissen und das dann 
komplett ausgeben. Warum? Weil ich denke das zwischendrin irgendwelche 
undefinierten Sachen in den Uartpuffers des Rechners kommen bevor der MC 
die nächsten Daten schickt und zwar in der for Schleife welche den 
string der itoa Funktion auswertet.
Ausserdem wenn ich die Daten in das Char Array schreiben will egal ob 
Hexwert oder als Buchstabe kommt diese Fehlermeldung und am Uart kommt 
nur ein Zeichen welches zufällig auszusehen scheint.

../Main.c:76: warning: array subscript has type 'char'

Bau ich irgendwo mist? Wahrscheinlich sonst würds ja gehen :-)


Hier mal der Code:
*--------------------------------------------
void Datenuebertragung()
{
  //--Char Array für Übertragungsdaten definieren
  //char DatenArray[20];
  //int DatenArray_Index = 0;

  //--Variablen für den AD Wandler
  uint16_t adcval;           //--Variable für den Wert am AD Wandler
  char string[7];          //--Hilfsvariable für die Übertragung
  char i;              //--Hilfsvariable für die Übertragung

  //--Auslesen des AD Wandlers
  adcval=ReadChannel(2);
  //--Umwandeln des Intwertes in String Variable für Übertragung
  itoa(adcval,string,10);


  //--Beginn des Datenprofils der Messwerte in Datenarray schreiben
  //DatenArray[DatenArray_Index]="<";
  //DatenArray_Index++;
  //DatenArray[DatenArray_Index]=0x3B;
  //DatenArray_Index++;

  usart_putc(0x3C);  //-- < Senden
  usart_putc(0x3B);  //-- ; Senden

  //--Übertragung Analogwert 1
  for(i=0;i<7;i++)
  {
    if(string[i]==0x60) //--Abruch falls Stringende des Intwertes 
erreicht ist
    {
      break;
    }
    //DatenArray[DatenArray_Index]=string[i];
    //DatenArray_Index++;
    usart_putc(string[i]); //-- Senden des AD Wertes
  }

  //DatenArray[DatenArray_Index]=0x3B;
  //DatenArray_Index++;

  usart_putc(0x3B);  //-- ; Senden

  //--Todo zweiter AD Wandler
  //--Bis dahin Standardwert 0 schicken
  //DatenArray[DatenArray_Index]=0x30;
  //DatenArray_Index++;
  //DatenArray[DatenArray_Index]=0x3B;
  //DatenArray_Index++;

  usart_putc(0x30); //-- 0 Senden
  usart_putc(0x3B);  //-- ; Senden

  //--Digitale Zustände erkennen und Senden
  //--Zustand 1
  if (bit_is_set(PINB,0))
  {
    //DatenArray[DatenArray_Index]=0x31;
    //DatenArray_Index++;
    usart_putc(0x31);
  }
  else
  {
    //DatenArray[DatenArray_Index]=0x30;
    //DatenArray_Index++;
    usart_putc(0x30);
  }

  //DatenArray[DatenArray_Index]=0x3B;
  //DatenArray_Index++;
  usart_putc(0x3B);  //-- ; Senden

  //--Zustand 2
  if (bit_is_set(PINB,1))
  {
    //DatenArray[DatenArray_Index]=0x31;
    //DatenArray_Index++;
    usart_putc(0x31);
  }
  else
  {
    //DatenArray[DatenArray_Index]=0x30;
    //DatenArray_Index++;
    usart_putc(0x30);
  }

  //DatenArray[DatenArray_Index]=0x3B;
  //DatenArray_Index++;
  usart_putc(0x3B);  //-- ; Senden  //--Zustand 3
  if (bit_is_set(PINB,2))
  {
    //DatenArray[DatenArray_Index]=0x31;
    //DatenArray_Index++;
    usart_putc(0x31);
  }
  else
  {
    //DatenArray[DatenArray_Index]=0x30;
    //DatenArray_Index++;
    usart_putc(0x30);
  }

  //DatenArray[DatenArray_Index]=0x3B;
  //DatenArray_Index++;
  usart_putc(0x3B);  //-- ; Senden

  //--Datensatz abschluss senden
  //DatenArray[DatenArray_Index]=0x3E;
  //DatenArray_Index++;
  usart_putc(0x3E);  //-- < Senden

  //--Senden des Datenstrings
//  for (i=0;i<DatenArray_Index;i++);
//  {
//    usart_putc(DatenArray[i]);
//  }

}

von Johannes M. (johnny-m)


Lesenswert?

Die Warnmeldung soll Dich möglicherweise darauf aufmerksam machen, dass 
es zu Nebenwirkungen kommen kann, wenn man vorzeichenbehaftete Variablen 
als Array-Index verwendet...

Abgesehen bietet dieses Forum die Möglichkeit, C-Code vernünftig zu 
formatieren, um ihn lesbarer zu machen. Diese Möglichkeit solltest Du 
nutzen...

von Compy (Gast)


Lesenswert?

1
 uint16_t adcval;           //--Variable für den Wert am AD Wandler
2
  char string[7];          //--Hilfsvariable für die Übertragung
3
4
5
/*### tu da mal unsigned draus machen:*/
6
//  char i;              //--Hilfsvariable für die Übertragung
7
unsigned char i;
8
/*### oder sag deinem Compiler, er soll für "char" grundsätzlich */
9
/*### 'unsigned' annehmen */
10
11
  //--Auslesen des AD Wandlers
12
  adcval=ReadChannel(2);
13
  //--Umwandeln des Intwertes in String Variable für Übertragung
14
  itoa(adcval,string,10);
15
16
17
  //--Beginn des Datenprofils der Messwerte in Datenarray schreiben
18
  //DatenArray[DatenArray_Index]="<";
19
  //DatenArray_Index++;
20
  //DatenArray[DatenArray_Index]=0x3B;
21
  //DatenArray_Index++;
22
23
  usart_putc(0x3C);  //-- < Senden
24
  usart_putc(0x3B);  //-- ; Senden
25
26
  //--Übertragung Analogwert 1
27
  for(i=0;i<7;i++)
28
  {
29
/*### Hier wird er wohl sonst meckern: */
30
/*### Negative Array-Indizes sind zwar erlaubt, aber selten gewünscht */
31
32
    if(string[i]==0x60) //--Abruch falls Stringende des Intwertes
33
erreicht ist
34
    {
35
      break;
36
    }
37
    //DatenArray[DatenArray_Index]=string[i];
38
    //DatenArray_Index++;
39
    usart_putc(string[i]); //-- Senden des AD Wertes
40
  }

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
 //--Übertragung Analogwert 1
2
  for(i=0;i<7;i++)
3
  {
4
    if(string[i]==0x60) //--Abruch falls Stringende des Intwertes
5
erreicht ist
6
    {
7
      break;
8
    }
9
    //DatenArray[DatenArray_Index]=string[i];
10
    //DatenArray_Index++;
11
    usart_putc(string[i]); //-- Senden des AD Wertes
12
  }

ist doch Müll. Warum fragst du ausgerechnet auf 0x60 ab?
(BTW: 0x60 ist ein Zeichen wie jedes andere. Weder für
atoi noch für irgendeine andere String-Funktion hat dieses
Zeichen irgendeine spezielle Bedeutung)

Jeder gültige String in C ist mit einem '\0' Character
abgeschlossen. Das kannst du auch ausnutzen, indem du die
komplette Schleife darauf aufbaust.
1
  i = 0;
2
  while( string[i] != '\0' )
3
    usart_putc( string[i++] );

Dieses Prinzip ist so universell, dass es sich lohnt für
die Ausgabe von Strings, gleich mal eine eigene Funktion
zu schreiben:
1
void usart_puts( const char* Text )
2
{
3
  unsigned int i = 0;
4
5
  while( Text[i] != '\0' )
6
    usart_putc( Text[i++] );
7
}

und in weiterer Folge mit dieser Funktion zu arbeiten
1
  usart_putc(0x3C);  //-- < Senden
2
  usart_putc(0x3B);  //-- ; Senden
3
4
  //--Übertragung Analogwert 1
5
  usart_puts( string );
6
7
  usart_putc(0x3B);  //-- ; Senden

Weiters. Gewöhn dir das herumschmeissen mit ASCII Codes
gleich wieder ab.
Es gibt absolut keinen Grund

    usart_putc(0x30);

zu schreiben, wenn du

    usart_putc( '0' );

meinst. Der Unterschied zwischen den beiden Schreibweisen dürfte
offensichtlich sein. Gibst du den ASCII Code 0x3B aus, so wird
wohl so ziemlich jeder in einer ASCII Tabell nachsehen müssen,
welches Zeichen denn den Code 0x3B hat. Schreibst du aber

  usart_putc( ';' );

dann braucht niemand irgendeine Tabelle, um zu erkennen, dass
du einen ; ausgeben willst. Dann brauchst du auch keinen
Kommentar mehr, ala.

  usart_putc(0x3E);  //-- < Senden

schreib was du meinst:

  usart_putc( '<' );

von Simon K. (simon) Benutzerseite


Lesenswert?

Karl heinz Buchegger wrote:
> dann braucht niemand irgendeine Tabelle

Und was ist mit dem Compiler? ;) …

von Matthias (Gast)


Lesenswert?

Servus,

warum Ascii...weil mir immer eingehämmert wurde ein Programmierer hat 
diese im Kopf zu haben und zu Nutzen. Angeblich schneller...obs stimmt 
weis ich net.

<Jeder gültige String in C ist mit einem '\0' Character
<abgeschlossen. Das kannst du auch ausnutzen, indem du die
<komplette Schleife darauf aufbaust.
Also brauch ich auch für jeden String 2 Zeichen mehr. Für einen String 
mit 19 Zeichen brauch ich dann 21 damit das \0 noch mit reinpasst.

Das schöne ist so kommt am Uart dann alles korrekt an soweit, aber mein 
C# läuft 2 mal in die Abfrageschleife rein...aber vorher mit Bascom lief 
sie einmal rein, deshalb wollte ich halt die Variablen in nen String 
schmeissen und auf einmal ausgeben. Gibts aber nur ein !-Zeichen aufn 
Hyperterminal.

Theoretisch könnte ich ja auf die 2 mal in C# warten, aber was ist wenn 
die Verbindung zwischendrin abreisst, dann wartet der Rechner ewig.
So sieht die Zuweisung aus.
1
DatenArray[DatenArray_Index]='<';
2
DatenArray_Index++;
3
DatenArray[DatenArray_Index]=';';
4
DatenArray_Index++;
Senden wollte ichs so
1
for (i=0;i<DatenArray_Index;i++);
2
{
3
  usart_putc(DatenArray[i]);
4
}

MfG
Matthias

von Karl H. (kbuchegg)


Lesenswert?

Matthias wrote:
> Servus,
>
> warum Ascii...weil mir immer eingehämmert wurde ein Programmierer hat
> diese im Kopf zu haben und zu Nutzen. Angeblich schneller...

Das ist Unsinn.

  uart_putc( 32 );
  uart_putc( 0x20 );
  uart_putc( ' ' );

ist exakt dasselbe. Es sind nur 3 verschiedene Schreibweisen
für immer dasselbe: Die Funktion uart_putc wird aufgerufen
und ihr wird der ASCII Code für ' ' übergeben. Nur in den
ersten beiden Fällen musst du selbst den ASCII Code wissen
und im letzten Fall setzt der Compiler für dich ein.
Es gibt noch ein anderes Argument, welches zugegebenermassen
auf den hier benutzten Systemen nicht wirklich wichtig ist:
Die letzte Version ist portabel!
Wenn du je auf einem IBM Mainframe programmieren musstest (oder
irgendwann musst) wirst du lernen, dass ASCII nicht die einzige
Codierung ist, die es gibt. IBM Mainframes benutz(ten) EBCDIC.
Und dort hat ' ' einen ganz anderen Code als 0x20.
Der Compiler dort weiss das und ersetzt ' ' mit dem richtigen
Code wenn du ' ' benutzt. Nicht jedoch, wenn du 0x20 schreibst.
>
> <Jeder gültige String in C ist mit einem '\0' Character
> <abgeschlossen. Das kannst du auch ausnutzen, indem du die
> <komplette Schleife darauf aufbaust.
> Also brauch ich auch für jeden String 2 Zeichen mehr.

1 mehr.

> Für einen String
> mit 19 Zeichen brauch ich dann 21 damit das \0 noch mit reinpasst.

Du brauchst 20.

In ein Array der Länge 10

  char Text[10];

passt ein String mit 9 druckbaren Zeichen. Zb. "abcdefghi"

   +---+---+---+---+---+---+---+---+---+---+
   | a | b | c | d | e | f | g | h | i | \0|
   +---+---+---+---+---+---+---+---+---+---+

>
> Das schöne ist so kommt am Uart dann alles korrekt an soweit, aber mein
> C# läuft 2 mal in die Abfrageschleife rein...aber vorher mit Bascom lief
> sie einmal rein, deshalb wollte ich halt die Variablen in nen String
> schmeissen und auf einmal ausgeben.

Den (auskommentierten) Teil hab ich mir nicht weiter angesehen.

> Gibts aber nur ein !-Zeichen aufn
> Hyperterminal.
>
> Theoretisch könnte ich ja auf die 2 mal in C# warten, aber was ist wenn
> die Verbindung zwischendrin abreisst, dann wartet der Rechner ewig.
> So sieht die Zuweisung aus.
>
>
1
> DatenArray[DatenArray_Index]='<';
2
> DatenArray_Index++;
3
> DatenArray[DatenArray_Index]=';';
4
> DatenArray_Index++;
5
>
> Senden wollte ichs so
>
1
> for (i=0;i<DatenArray_Index;i++);
2
> {
3
>   usart_putc(DatenArray[i]);
4
> }
5
>
>

selbiges auch hier:
Mach den "String" mal zu einem richtigen C-String.
Verpass ihm ganz zum Schluss ein \0 Zeichen und
benutze die String Funktionen.

Ich denke aber nicht, dass das dein Problem lösen wird.
Ob du die Ausgabe in kleinen Happen schickst oder in einem
Schwall macht ja keinen Unterschied.

Dein Fehler wird wohl auf C# Seite liegen.

von Martin K. (mkohler)


Lesenswert?

Matthias wrote:
> <Jeder gültige String in C ist mit einem '\0' Character
> <abgeschlossen. Das kannst du auch ausnutzen, indem du die
> <komplette Schleife darauf aufbaust.
> Also brauch ich auch für jeden String 2 Zeichen mehr.

Hinweis: das Zeichen "backslash null", '\0' ist ein einzelnes Zeichen, 
nicht zwei bestehend aus "backslash" '\' und "null" '0'.
Es handelt sich um den sogenannten Null-Terminator mit ASCII-Wert 0x00. 
Die Schreibweise mit dem vorangestellten Backslash ist nur so gewählt, 
um das Ding nicht mit dem Zeichen "Null" '0' zu verwechseln.

Gruss, Martin

von Matthias (Gast)


Lesenswert?

Servus,

etz bin ich wenigstens Zwecks Ascii schlauer. Aber für den Lehrer gabs 
nur die Welt von Intel und MS, der Rest hat ihn net interessiert. Man 
merkt schon wie MS um jeden Kunden kämpft, wir kriegen die meisten MS 
Produkte kostenlos. Seis Windows, Compiler oder Office. Wie sagte schon 
Bill Gates...er sieht lieber 1000 Rechner mit illegalem Windows drauf 
als einen mit Linux oder der gleichen drauf.
Naja ist ja etz egal jetzt weis ichs ja besser.
Danke soweit.

Fehler bei C#...wäre nicht der erste, der mir auf die Nerven geht.
Ich Tipp fast drauf das die kurze Pause zwischen dem Ausgeben des 
AD-Wandlerwertes C# schon veranlasst die ersten Zeichen zu hohlen die im 
Uartpuffer rechnerseitig drin sind. Wobei die Pause wohl im µs Bereich 
liegen dürfte.

Wegen dem String...also ich glaub dir was du sagst.
Jedoch warum sind \0 als ein Zeichen gesehen?
Für mich ist beides jeweils ein Zeichen...
Naja das Buch welches ich hab schweigt sich da leider auch sehr aus.

Ich merk schon die 4 Jahre wo ich mal für ein halbes Jahr C hatte und 
kaum mehr als ein "Hallo World" Programm erstellt habe reichen hier wohl 
lange nicht...aber es wird dank euer Hilfe immer besser.

Jetzt wenn ich die Kamera noch so zum laufen krieg wie sie sollte und 
das Display anzeigt was es soll dann wäre ja alles gut.

Also dank euch derweilen...
MfG
Matthias

von Martin K. (mkohler)


Lesenswert?

Matthias wrote:
> Wegen dem String...also ich glaub dir was du sagst.
> Jedoch warum sind \0 als ein Zeichen gesehen?
> Für mich ist beides jeweils ein Zeichen...

http://www.gidf.de/ ;-)

Zitat aus http://en.wikipedia.org/wiki/Null_character :
"The character has special significance in C and its derivatives, where 
it serves as a reserved character used to signify the end of strings. 
The null character is often represented as '\0' in source code (in 
reality an octal escape sequence). Strings ending in a null character 
are said to be null-terminated."

Edit: Das ist wie der "new line" character beim printf Befehl, dieser 
ist "backslash 'n'" , '\n' und repräsentiert auch nur ein Zeichen, 
nämlich "new line"

von Karl H. (kbuchegg)


Lesenswert?

Matthias wrote:
> Wegen dem String...also ich glaub dir was du sagst.
> Jedoch warum sind \0 als ein Zeichen gesehen?

Weil es sonst keine (schöne) Möglichkeit gäbe diverse
Sonderzeichen zu bilden.
Du schreibst ja auch \n für einen Zeilenvorschub und
das ist dann nur ein einziges Zeichen. Oder \t für
einen Tabulator und das ist auch nur ein einzelnes
Zeichen. Und so hat halt \0 auch eine spezielle Bedeutung
und ist trotzdem nur ein einzelnes Zeichen.
Es gibt noch mehr dieser sog. Escape-Zeichen. Will man
tatsächlich einen einzelnen Back-Slash haben, so lautet
das 'Zeichen' dafür dann \\

> Für mich ist beides jeweils ein Zeichen...

Für dich vielleicht. Nicht jedoch für den Compiler.
Und der Compiler hat das Sagen.

> Naja das Buch welches ich hab schweigt sich da leider auch sehr aus.

Ehrlich?
Schmeiss es weg und kauf dir ein Vernünftiges.

>
> Ich merk schon die 4 Jahre wo ich mal für ein halbes Jahr C hatte und
> kaum mehr als ein "Hallo World" Programm erstellt habe reichen hier wohl
> lange nicht...aber es wird dank euer Hilfe immer besser.

(Ist nicht böse gemeint:)

Das ist allerdings richtig. Ich geh mal davon aus, dass du mit
'halbes Jahr' ein Schulsemester meinst. Das entspricht, wenn man
die Stunden rechnet, gerade mal 1 bis 2 Wochen Programmierung.
Damit bist du bestenfalls gerade mal im mittleren Anfängerstadium.
Da wartet noch vieles auf seine Entdeckung durch dich.

Aus dem Anfängerstadium bist du in ein paar (realen) Wochen
raus. In 5 bis 6 Monaten bist du Fortgeschrittener. Profi
wird man nach ein paar Jahren. Und Experte wird man eigentlich
nie. Es gibt immer wieder was zu lernen. Selbst nach 20 Jahren
hält C noch so manche Überraschung für mich bereit.

von Matthias (Gast)


Lesenswert?

Servus,

also halbes Jahr C und dann gings mit den anderen Sprachen los.
Zuerst mal VB, SQL und dann zum Schluss etz halt C#.Net.
C# mach ich jetzt schon 2 Jahre da kommt ich relativ gut hin.

C hat mir vorallem wegen dem Zeigersachen nicht sonderlich gefallen 
(Lehrer war ein Freak davon). Ein Zeiger auf Zeiger von einem 4dim. 
Array auf Zeigern...*würg*.
Habs damals sogar geschafft meinen Rechner Betriebssystemmässig zu 
killen mit dem Zeigerzeug in den Übungen. In den praktischen Stunden 
ging bei mir dort reihenweise der Dr.Watson Virenscanner an. :-)

MfG
Matthias

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.