Forum: Compiler & IDEs string buffer löschen


von patsch (Gast)


Lesenswert?

hallo zusammen
ich hab da ein problem mit einem kleinen i2c programm. ich kann mich mit 
dem slave austauschen, aber nur immer einmal. danach kommen immer die 
selben strings an. auch wenn ich die variabel mit einem neuen string 
überschreibe funktionierts nicht. hat jemand eine idee, was ich hier 
falsch mache?
1
#include <fcntl.h>
2
#include <linux/i2c-dev.h>
3
#include <sys/ioctl.h>
4
#include <stdio.h>
5
#include <string.h>
6
7
#define MAX_STRING_LEN 5
8
9
int file, i;
10
  /* strings are array of characters 
11
   * terminated by the NULL character
12
   * which is different from '0' */
13
unsigned char recive[MAX_STRING_LEN], send[MAX_STRING_LEN];
14
unsigned char inf [1];
15
16
int main()
17
        {
18
        file = open("/dev/i2c-1", O_RDWR); /* Device oeffnen  */
19
        ioctl(file, I2C_SLAVE, 0x04);  /* Slave­Adresse setzen */
20
21
        do      {
22
                read(file, recive, MAX_STRING_LEN);  /* Bytes lesen  */
23
//              usleep(100000); // 100ms
24
                } while (strcmp(recive,"hello") != 0);
25
26
        printf("Arduino:%s\n", recive); // 3. Print the buffer with %s
27
        recive[MAX_STRING_LEN] = "clear ";
28
//      while( (recive = fgetc( stdin )) != EOF && recive != '\n' );
29
//      free(recive);
30
        printf("recive var:%s\n", recive);
31
        close(file);
32
        }

von Karl H. (kbuchegg)


Lesenswert?

>         recive[MAX_STRING_LEN] = "clear ";

Ähm.
Nein.

Du brauchst zumindest ein C Buch, wenn deine C++ Ambitionen nicht hoch 
sind.

String-Verarbeitung in C

von Amateur (Gast)


Lesenswert?

Das ist bei dem von Dir verwendeten Prozessor ganz normal. Oder auch 
nicht. Kommt ganz darauf an.

Irgendwann, wenn man ein System ins Nirwana schickt, kommt es auch 
wieder daraus.
Bleibt also dir Frage: Was kommt nach main ()?
An gefühlten 1000 Stellen, hier im Forum, wird die Grundstruktur eines 
Programmes beschrieben. Dazu muss man allerdings lesen.

von PittyJ (Gast)


Lesenswert?

Oha -- meine ersten Gedanken.

Also: Die read() Funktion liefert im Normalfall auch einen Returnwert 
zurück. Den sollte man auch auswerten.

Und
 recive[MAX_STRING_LEN] = "clear ";
zeigt, dass das Array-Konzept in C noch nicht verstanden wurde.

Also
C-Lehrbuch kaufen. Und dort alle Übungen an einem PC erst mal 
durchführen.
Wenn man das Handwerkszeug beherrscht, dann kann man es auch für I2C 
verwenden.

von Mark B. (markbrandis)


Lesenswert?

patsch schrieb:
> hat jemand eine idee, was ich hier falsch mache?

Ja.

1.) "receive" ist falsch geschrieben.
2.) main() liefert in Deinem Code keinen Wert zurück. Der Rückgabewert 
ist aber als int deklariert (was auch korrekt ist).
3.) recive[MAX_STRING_LEN] = "clear ";
Meintest Du vielleicht dies hier:
strcpy(receive, "clear ");
Dann ist freilich das Array zu klein dimensioniert: MAX_STRING_LEN 
müsste so mindestens den Wert 7 haben.
Außerdem ist die Deklaration des Arrays als "unsigned char" unpassend. 
Für string arrays nimmt man einfach nur "char".
4.) inf[] wird deklariert, aber nicht verwendet.
5.) Ob tatsächlich alle Variablen global deklariert sein müssen, sei 
dahingestellt.
6.) Es gibt keine Fehlerbehandlung für den Fall, dass das Öffnen des 
Device /dev/i2c-1 fehlschlägt.
7.) Du hast kein Buch oder Vorlesungsskript über C gelesen und 
durchgearbeitet.

von tobi (Gast)


Lesenswert?

..und wenn er jetzt 2 weitere Zeile Code einfügt, hat er auch noch 
mindestens 2 weitere Fehler.

Mach einfach mal das was Karl-Heinz dir schon gesagt hat.

Gruss,
Tobi

von Rosa-Kleidchen (Gast)


Lesenswert?

oki,

>unsigned char recive[MAX_STRING_LEN], send[MAX_STRING_LEN];
>unsigned char inf [1];
soweit ok

>int main()
>        {
>        file = open("/dev/i2c-1", O_RDWR); /* Device oeffnen  */
>        ioctl(file, I2C_SLAVE, 0x04);  /* Slave­Adresse setzen */

>        do      {
>                read(file, recive, MAX_STRING_LEN);  /* Bytes lesen  */
>//              usleep(100000); // 100ms
>                } while (strcmp(recive,"hello") != 0);
strcmp vergleicht meines Wissens solange, bis ein Zeichen ungleich oder 
'\0' im String erreicht ist. Return = 0, wenn gleich, sonst ungleich! 
Sollte der empfangene String gleich "hello" sein, kann ein fehlendes 
'\n' im receive üble Folgen haben. Nimm mal strncmp (receive, "hello", 
MAX_STRING_LEN)! Das vergleicht wirklich nur MAX_STRING_LEN Zeichen.

>        printf("Arduino:%s\n", recive); // 3. Print the buffer with %s
>        recive[MAX_STRING_LEN] = "clear ";
ja, siehe Mark Brandis

>//      while( (recive = fgetc( stdin )) != EOF && recive != '\n' );
>//      free(recive);
?? receive wurde nicht dynamisch erzeugt...
>        printf("recive var:%s\n", recive);
>        close(file);

>        }

Mark Brandis@
>Ob tatsächlich alle Variablen global deklariert sein müssen, sei
>dahingestellt.
Doch, das ist wichtig. Per Definition werden globale Variablen im Heap 
angelegt. Lokale Variablen dagegen auf dem Stack. Je nach Größe des 
Stacks kann ein Stacküberlauf deutlich schneller auftreten. Ich lege 
alle Variablen auf einem embeded System global an. Hat noch den Vorteil, 
dass ich damit sicherstelle, dass alle Variablen tatsächlich Platz haben 
und zur Laufzeit keine bösen Überraschungen auftreten.
Rosa

von Peter II (Gast)


Lesenswert?

Rosa-Kleidchen schrieb:
> Ich lege
> alle Variablen auf einem embeded System global an.

dann hast du wohl keine Prozeduren oder funktionen mit Parametern? Denn 
diese liegen auf dem Stack. Alle Variable global zu machen hat auch 
nachteile in der optimierung. Sollte man also nicht machen.

von Rosa-Kleidchen (Gast)


Lesenswert?

>dann hast du wohl keine Prozeduren oder funktionen mit Parametern?
Doch, nur das nötigste der Lesbarkeit halber. Ein Funktionsaufruf kostet 
Zeit. Ok, gemäß der Komplexitätstheorie immer noch O(1) aber immerhin 
:-)

>Alle Variable global zu machen hat auch nachteile in der optimierung.
Ich gehe davon aus, das alle deklarierten Variablen auch gebraucht 
werden. Ist für das Debuggen auch sinnvoll. Die vielleicht häßlich 
Eigenart habe ich mir bei VHDL angewöhnt. Nimm nur syntetisierbare 
Signale...
Rosa

von Yalu X. (yalu) (Moderator)


Lesenswert?

Rosa-Kleidchen schrieb:
>> dann hast du wohl keine Prozeduren oder funktionen mit Parametern?
> Doch, nur das nötigste der Lesbarkeit halber. Ein Funktionsaufruf kostet
> Zeit. Ok, gemäß der Komplexitätstheorie immer noch O(1) aber immerhin
> :-)

Kleine Funktionen können als inline deklariert werden, dann ensteht kein 
Aufruf-Overhead. Bei großen Funktionen fällt der Aufruf-Overhead ohnehin 
kaum ins Gewicht.

>> Alle Variable global zu machen hat auch nachteile in der optimierung.
> Ich gehe davon aus, das alle deklarierten Variablen auch gebraucht
> werden. Ist für das Debuggen auch sinnvoll. Die vielleicht häßlich
> Eigenart habe ich mir bei VHDL angewöhnt. Nimm nur syntetisierbare
> Signale...
> Rosa

Lokale (automatische) Variablen können in Registern gehalten werden, was 
Geschwindigkeitsvorteile bringt.

von Rosa-Kleidchen (Gast)


Lesenswert?

>Kleine Funktionen können als inline deklariert werden, dann ensteht kein
>Aufruf-Overhead. Bei großen Funktionen fällt der Aufruf-Overhead ohnehin
>kaum ins Gewicht.
Inline ist aber wieder genau da einfügen, wo inline steht. Dadurch 
müssten sich die Referenzen auf die Variablen auch vervielfätign. Das 
weiss ich aber nicht genau.


>Lokale (automatische) Variablen können in Registern gehalten werden, was
>Geschwindigkeitsvorteile bringt.
Da wir uns hier im GCC-Forum befinden, müsste der Compiler grundsätzlich 
von Registern ausgehen, heutzutage. Vor nicht alzu langer Zeit sah das 
anders aus.

von patsch (Gast)


Lesenswert?

Hej wow, ihr habt Euch ja alle sehr ins Zeug gelegt. Vielen Dank für die 
nützlichen Tipps und Infos. Ich habe den C-Code wie folgt abgeändert und 
es scheint auch recht zuverlässig zu laufen.
1
#include <fcntl.h>
2
#include <linux/i2c-dev.h>
3
#include <sys/ioctl.h>
4
#include <stdio.h>
5
#include <string.h>
6
7
#define MAX_STRING_LEN 5
8
9
int file, i;
10
unsigned char recive[MAX_STRING_LEN], send[MAX_STRING_LEN], varchar[MAX_STRING_LEN], info[MAX_STRING_LEN];
11
12
int main() 
13
  {
14
  file = open("/dev/i2c-1", O_RDWR); /* Device oeffnen  */
15
  ioctl(file, I2C_SLAVE, 0x04);  /* Slave­Adresse setzen */
16
  
17
  strcpy (varchar, "hello");
18
  recivefromArduinoWhile(varchar);
19
20
  usleep(100000); // 100msec
21
22
  strcpy (varchar, "info");
23
  sendtoArduino(varchar);
24
  recivefromArduinoWhile(info);
25
26
27
  strcpy (varchar, "outc");
28
  sendtoArduino(varchar);
29
  recivefromArduinoWhile(varchar);
30
31
  close(file);
32
  return 0;
33
  }
34
35
int recivefromArduinoWhile()
36
  {
37
  do  {
38
    read(file, recive, MAX_STRING_LEN); 
39
    usleep(100000);
40
    } while (strcmp(recive,varchar) != 0);
41
  
42
  printf("Arduino to Raspberry: %s\n", recive);
43
  return 0;
44
  }
45
46
int sendtoArduino()
47
  {
48
  usleep(100000);
49
  write(file, (unsigned int)varchar, MAX_STRING_LEN);
50
  printf("Raspberry to Arduino: %s\n", varchar);
51
  return 0;
52
  }
Jetzt habe ich nur noch mit dem Arduino I2C Empfang Probleme, denn mit 
dem "Wire.onRequest" ist das so ein Ding... aber das ist ja wohl ein 
anderes Forum. Wenn nicht, hier der Code:
1
#include <Wire.h>
2
#define rasp 0x04
3
//include <I2C>
4
5
char c[5];
6
int temp0 = 20.0;
7
8
void setup()
9
{
10
  Wire.begin(4);                // join i2c bus with address #2
11
  Wire.onRequest(requestEvent); // register event
12
  Wire.onReceive(receiveEvent); // register event
13
  Serial.begin(57600);           // start serial for output
14
}
15
16
void loop()
17
{ 
18
  delay(100);
19
}
20
21
void requestEvent()
22
{
23
  Wire.send("hello");
24
  Serial.println("hallo gesendet"); 
25
}
26
27
void receiveEvent(int howMany)
28
{
29
  int i=0;
30
//  while(1 < Wire.available()) // loop through all but the last
31
  while(Wire.available())
32
  { c[i] = Wire.receive(); // receive byte as a character
33
    Serial.write(c[i]);         // print the character
34
    i += 1;
35
//    Serial.print("  ");
36
//    Serial.println(c[i], HEX);
37
//   int x = Wire.receive();    // receive byte as an integer
38
//  Serial.println();
39
//  Serial.println(x);         // print the integer
40
  } 
41
  
42
    Serial.println(" erhalten for:");
43
44
      for (int i = 0; i < 5; i++) {
45
      Serial.write(c[i]);
46
      }
47
48
    if (String(c).equals(String("info")))
49
    {
50
//      Wire.beginTransmission(rasp);
51
      Wire.send("blabb"); 
52
//      Wire.endTransmission();
53
      Serial.println("i gesendet");
54
    }
55
56
    if (String(c).equals(String("outc")))
57
    {
58
      Wire.send(9); 
59
      Serial.println("temp0 gesendet");
60
    }
61
62
    Serial.print("c= ");
63
    Serial.println(String(c));
64
}

von Karl H. (kbuchegg)


Lesenswert?

patsch schrieb:

> Ich habe den C-Code wie folgt abgeändert und
> es scheint auch recht zuverlässig zu laufen.

Was nicht viel heißt

> #define MAX_STRING_LEN 5

> unsigned char ... varchar[MAX_STRING_LEN], .....

>   strcpy (varchar, "hello");

und Peng.
Der String "hello" benötigt ein Array von mindestens der Länge 6.
5 Stellen für die Buchstaben + 1 Arrayelement für das 
String-obligatorische '\0' Zeichen am Ende des Strings. Macht 6 Zeichen.

Weiter hab ich momentan noch nicht geschaut.

von Karl H. (kbuchegg)


Lesenswert?

Tu dir selbst einen Gefallen

>   write(file, (unsigned int)varchar, MAX_STRING_LEN);

Nein.
in varchar ist ein String drinnen. Wenn du wissen willst, wie lang 
dieser String wirklich ist, dann benutz strlen um diese Länge 
festzustellen.

   write(file, (unsigned int)varchar, strlen(varchar) );



Und im übrigen definiere deine String-Arrays nicht so knapp! Du tust dir 
selbst keinen Gefallen, wenn du bei jedem Pipifax ständig die Arrays 
überläufst.

von Karl H. (kbuchegg)


Lesenswert?

Und sowas

>
1
>  do  {
2
>    read(file, recive, MAX_STRING_LEN); 
3
>    usleep(100000);
4
>    } while (strcmp(recive,varchar) != 0);

ich finde es immer noch nicht schlau, wenn man da mit Timeout und 
impliziten Stringvergleichen arbeitet.

Wenn du sowieso ASCII überträgst, dann definier dir doch, dass ein 
Kommando (oder eine Antwort) immer mit einem Carriage Return endet (\n). 
Der jeweilige Empfänger liest dahin, bis er ein \n Zeichen findet und 
sammelt alle Zeichen in einem Array. Und erst dann, wenn er anhand des 
\n festgestellt hat, dass er jetzt eine komplette Zeile beisammen hat, 
erst dann sieht er sich den String an, ob das ein Kommando ist und was 
man damit macht.
So funktioniert das seit der 'Steinzeit'. und es funktioniert gut.

von Karl H. (kbuchegg)


Lesenswert?

> aber das ist ja wohl ein anderes Forum. Wenn nicht, hier der Code:

Es ist wahrscheinlich im Prinzip genau das gleiche Problem.
Du gehst ständig davon aus, dass deine Strings 5 Zeichen haben und 
dimensioierst dir deine Arrays zu klein (bzw. viel zu knapp)

Lass den Quatsch!
Der Empfänger weiß nicht, wie lang der String ist, den er kriegen wird. 
Er weiß nur woran er erkennen kann, wenn er zu Ende ist. Zum Beispiel 
indem man mit dem Sender eine Abmachung trifft, dass der jedes Kommando 
mit einem vorher ausgemachten Zeichen beendet. Und das und nur das ist 
die Kennung für den Empfänger, dass jetzt eine 'Zeile' beisammen ist. 
Was immer die dann auch bedeutet.

Klar muss man sich die Arrays in irgendeiner Form dimensionieren. Das 
geht nicht anders. Aber nicht so auf knirsch! Und vor allen Dingen muss 
man das überwachen, dass man die Arrays nicht überläuft.


> String(c)

Wenn in c kein gültiger C-String enthalten ist, dann wird sich der 
String-Konstruktor schwer tun, dammit irgendwas sinnvolles anzufangen.

Für C-Strings gibt es Regeln! Und solange du dich um die nicht kümmerst, 
wird das alles nichts.

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.