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?
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.
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.
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.
..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
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); /* SlaveAdresse 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
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.
>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
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.
>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.
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.
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
charc[5];
6
inttemp0=20.0;
7
8
voidsetup()
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
voidloop()
17
{
18
delay(100);
19
}
20
21
voidrequestEvent()
22
{
23
Wire.send("hello");
24
Serial.println("hallo gesendet");
25
}
26
27
voidreceiveEvent(inthowMany)
28
{
29
inti=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
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.
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.
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.
> 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.