Forum: Mikrocontroller und Digitale Elektronik Wie kann ich ein Array über I2C übertragen?


von Per (Gast)


Lesenswert?

Hallo,
ich arbeite an einem Projekt, bei dem mehrere Arduinos miteinander 
kommunizieren müssen um Input-Arduinos, Output-Arduinos und eventuell 
auch noch ein Anzeigen RaspberryPi zu benutzen.

Das Endziel ist es, einen Mega"Input"(Slave) mit 16 Potentiometer und 50 
Tastern zu füttern, der die Daten als Array an einen verwaltenden und 
LEDs schaltenden Mega"Center"(Master) liefert, der die Daten dann an 
einen oder mehrere Nanos"Output"(Slave, selbe Adresse) sendet, die sich 
dann bestimmte Stellen des von dem Mega"Center" erzeugten Arrays (z.B. 
1.Array[0]-Array[511], 2.Array[512]-Array[1023], usw.) raussuchen und 
über RS-485 ausgeben.

Nun habe ich das Problem, dass ich lediglich bytes über I2C senden kann.

Hier also meine Frage: Wie kann ich ein Array (Array[1024]) über I2C 
versenden?

PS: Ich bin kein Arduino oder C++ Anfänger, aber hab kaum Erfahrungen 
mit I2C

von Stefan F. (Gast)


Lesenswert?

Das Prinzip wird wohl darauf beruhen, mit einer for-Schleife über das 
Arrays zu iterieren und dann innerhalb der Schleife ein Byte nach dem 
Anderen zu senden.

Was hat das mit RS485 zu tun?

von Kalle (Gast)


Lesenswert?

Per schrieb:
> ich arbeite an einem Projekt, bei dem mehrere Arduinos miteinander
> kommunizieren müssen um Input-Arduinos, Output-Arduinos und eventuell
> auch noch ein Anzeigen RaspberryPi zu benutzen.

Das klingt, als hätte dein Projekt noch nicht genug Arduinos.

Per schrieb:
> Nun habe ich das Problem, dass ich lediglich bytes über I2C senden kann.
> Hier also meine Frage: Wie kann ich ein Array (Array[1024]) über I2C
> versenden?

Indem du mehrere einzelne Bytes nacheinander versendest. Am besten noch 
eine Frame-Synchronisation drum und fertig.

Per schrieb:
> PS: Ich bin kein Arduino oder C++ Anfänger, aber hab kaum Erfahrungen
> mit I2C

ok

von Christian M. (Gast)


Lesenswert?

Per schrieb:
> Slave, selbe Adresse

Das geht schon mal nicht! Jeder Slave braucht eine eigene Adresse!

Gruss Chregu

von Stefan F. (Gast)


Lesenswert?

Ich halte es für eine schlechte Idee, für den Anfang sowohl Master als 
auch Slave selber zu programmieren. Mache deine ersten Übungen erstmal 
mit einem fertigen Slave IC, zum Beispiel einem PCF8574 und einem I²C 
EEprom. Dann kannst du dich zuerst auf die Programmierung des Master 
konzentrieren. Beim PCF8574 lernst du den Umgang mit START, STOP, und 
Adressierung. Beim EEprom lernst du den Umgang mit Multi-Byte 
Transaktionen, NACK und ACK.

Erst wenn du mit der Programmierung des I²C Master vertraut bist, 
solltest du dich an die Programmierung von I²C Slaves wagen.

von STK500-Besitzer (Gast)


Lesenswert?

Per schrieb:
> aber hab kaum Erfahrungen mit I2C

Bei I²C sendet nur der Master von sich aus. Die Slaves müssen erst dazu 
überredet werden. Dazu gibt der Master nach der Adressierung des 
gewünschten Slaves den Takt vor und reagiert auf ACK/NAK-Signale.

Per schrieb:
> Nun habe ich das Problem, dass ich lediglich bytes über I2C senden kann.

DAS ist bei jeder byteorganisierten Kommunikation so.

Wie sieht denn deine Kommunikationsroutine bis jetzt aus?

von Per (Gast)


Lesenswert?

Christian M. schrieb:
> Das geht schon mal nicht! Jeder Slave braucht eine eigene Adresse!

Warum? Aber ok, das sollte nicht das Problem sein.

>Indem du mehrere einzelne Bytes nacheinander versendest. Am besten noch
>eine Frame-Synchronisation drum und fertig.

Ok, ich habe versucht, das Array Stück für Stück zu senden, in etwa nach 
dem Prinzip:

for (int i=0;i<=9;i++){
  Wire.beginTransmission(8);
  Wire.write(Array[i]);
  Wire.endTransmission();
}

Aber irgendwie funktioniert das nicht. Und was meinst du mit 
Frame-Synchronisation?

von Kalle (Gast)


Lesenswert?

Per schrieb:
> Aber irgendwie funktioniert das nicht. Und was meinst du mit
> Frame-Synchronisation?

Vom Prinzip sieht das richtig aus, zu den Arduino Funktionen kann ich 
nichts sagen.

Mit Framesynchronisation ist gemeint, dass du nicht einfach permanent 
dein Array sendest, sondern Beginn und Ende des Arrays noch mit 
bestimmten Steuerzeichen oder anderweitig kennzeichnest sodass die 
Slaves sich immer auf den Beginn des Arrays synchronisieren können

von Per (Gast)


Lesenswert?

selbst mit einer simplen beispielroutine wie dieser funktioniert es 
nicht.

void Update(){
  Wire.beginTransmission(8);
  Wire.write(300);             //Als Markierung, damit der Slave den 
Anfang registriert.
  Serial.println("restart");
  Wire.endTransmission();
  delay(1);
  Wire.beginTransmission(8);
  Wire.write(Array[0]);
  Wire.endTransmission();
  delay(1);
  Wire.beginTransmission(8);
  Wire.write(Array[1]);
  Wire.endTransmission();
  delay(1);
  Wire.beginTransmission(8);
  Wire.write(Array[2]);
  Serial.println(blue);
  Wire.endTransmission();
  delay(1);
}

von Benjamin S. (recycler)


Lesenswert?

Sieh es mal so. In deinem Speicher hast du das Array ja auch abgelegt.
Also liegt an Adresse 0x1000 ein 1024 Byte großer Bytestream.
Zum Übertragen startest du den I2C transfer bei 0x1000 und schon sind 
die Daten drüben.
Schwieriger ist es auf der Empfangsseite. Dort bekommst du 1024 Daten. 
Jetzt musst du wissen, was das ist (welcher Typ). Dafür brauchst du 
Steuerinformation z.B. Ursprung (Source) und Ziel (Destination). Auch 
noch gut wäre, wenn du Länge und eine Prüfsumme (CRC) drinnen hast. 
Vielleicht noch eine Art Typ, weil es können 1024 Byte sein oder 256 
Integer.
Somit hast du ein Protokoll.

Somit wäre es am einfachsten du definierst dir ein Struct (Pseudocode)
1
struct _data {
2
byte src,
3
byte dst,
4
byte type,
5
byte reserve, // optional, macht aber bei 32 Bit Maschinen das alignement besser und somit den Zugriff schneller
6
int length,
7
byte arrray[1024],
8
int crc
9
} data;

befüllen über
1
data.src = 0x01; // master has id 1, slave = 2, ....
2
data.dst = 0xFF; // broadcast?
3
data.type = 0x00; / allgemeine Datentyp
4
data.length = 1024; // ohne header und CRC
5
data.crc = 0x00 // wer lust hat kann es selber berechnen
6
7
i2c.send(i2c_addr, &data, sizeof(struct _data);
jetzt kannst du dir noch überlegen, ob 1024 Byte immer sauber über den 
Bus gehen. Wenn nicht, dann kannst du mit Chunks arbeiten und ggf. das 
im Typ kodieren oder die Daten nochmals anfordern.

Du kannst das auch lösen, in dem du mehrere I2C sends macht und jeweil 
die einzelnen Daten wie SRC und DST nacheinander sendest.

Hoffe das hilft weiter

von STK500-Besitzer (Gast)


Lesenswert?

Per schrieb:
> Warum?

Weil I²C nun mal so aufgebaut ist.

Per schrieb:
> for (int i=0;i<=9;i++){
>   Wire.beginTransmission(8);
>   Wire.write(Array[i]);
>   Wire.endTransmission();
> }

Sogar Arduino hat die Repeated-Start-Condition implementiert.
Lies dir einfach mal die Doku zur I²C-Schnittstelle auf der 
Arduino-Seite durch!
Ansonsten müsstes du eh noch die Register-Adresse mit übertragen.

von Kalle (Gast)


Lesenswert?

Per schrieb:
> selbst mit einer simplen beispielroutine wie dieser funktioniert es
> nicht.

Dazu müsste man wissen, was genau die Arduinofunktionen machen. Ich 
würde mal vermuten, dass du mehrere Bytes auf einmal writen kannst.

Was heißt denn "es funktioniert nicht", kommt gar nichts an?

von Einer K. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Das Prinzip wird wohl darauf beruhen, mit einer for-Schleife über
> das
> Arrays zu iterieren und dann innerhalb der Schleife ein Byte nach dem
> Anderen zu senden.

Wire kennt: Wire.write(data, length)
Das könnte die Situation etwas vereinfachen.

Per schrieb:
> mit 16 Potentiometer und 50
> Tastern zu füttern,
Arduino Wire hat einen 32Byte Buffer
Das könnte knapp werden.

von Per (Gast)


Lesenswert?

Wie verwende ich Wire.write(data, lenght) ? Ich habe mir die Arduino 
Referenz dazu angeschaut, aber irgendwie klappt das nicht.
Und ich muss ja auch nicht alle daten die ich hab au einmal senden. Z.B. 
erst das ArrayOne für 16xFader und 15xTaster und dann das ArrayTwo für 
35xTaster

von Per (Gast)


Angehängte Dateien:

Lesenswert?

Hier einmal ne kurze skizze zu meinem Aufbau

von Kalle (Gast)


Lesenswert?

Per schrieb:
> Wie verwende ich Wire.write(data, lenght) ? Ich habe mir die Arduino
> Referenz dazu angeschaut, aber irgendwie klappt das nicht.

Ich lehne mich mal aus dem Fenster und behaupte, du übergibst ein Array 
und die gewünschte Länge in Bytes.

Wenn das "irgendwie nicht klappt", musst du dem auf den Grund gehen. 
Wird nichts gesendet oder wird nicht richtig empfangen (Oszi 
anschließen).

von Per (Gast)


Lesenswert?

Wie würdest du die entsprechende Zeile schreiben?

Wire.write(Array, 512);
?

von Kalle (Gast)


Lesenswert?

Ja, oder mal 32 probieren. Vielleicht ist die Funktion nicht-blockierend 
und jemand hat geschrieben, der interne Buffer sei nur 32 Byte groß.

von Zeno (Gast)


Lesenswert?

Bevor hier weiter die Glaskugeln bemüht werden, wäre erst mal 
interessant was das für ein Array ist, also welchen Datentyp die 
Arrayelemente haben.
Dann muß man eigentlich nur noch wissen wie groß der jeweilige Datentyp 
ist und schon geht es los. Bei 1Byte Typen sollte es kein Problem sein, 
die anderen muß man halt entsprechend zerlegen.

von Einer K. (Gast)


Lesenswert?

Ich kann nicht verstehen, dass man die Doku zu den Dingen nicht liest, 
welche man benutzt.
Wie will man denn so erfolgreich programmieren?

> The Wire library implementation uses a 32 byte buffer,
> therefore any communication should be within this limit.
> Exceeding bytes in a single transmission will just
> be dropped.
Aus: https://www.arduino.cc/en/Reference/Wire

von Per (Gast)


Lesenswert?

das Array besteht aus integer, immer nur max. 256 groß

von Kalle (Gast)


Lesenswert?

Zeno schrieb:
> wäre erst mal
> interessant was das für ein Array ist, also welchen Datentyp die
> Arrayelemente haben.

Das ist ja erst mal unerheblich. Sobald die Übertragung von mehreren 
Bytes klappt, kann man sich dann ja weitere Gedanken machen, wie man die 
Information verpackt.

Für 16 Potentiometer braucht man selbst bei 16bit Abtastung ja nur 32 
Byte brauchen und 50 Taster passen in 7 Byte. Das 1024er-Array kann man 
also eh vergessen

von Per (Gast)


Lesenswert?

Das 1024 Array hätte ich für meine 2 Nanos auf der gleichen adresse 
benutzt, aber das fällt ja wphl weg, also sind die Größten Arrays die 
ich übertragen wollen würde 512 groß

von Per (Gast)


Lesenswert?

Wenn ich im Testprogramm

Wire.write(Array[], 10);

eingebe kommt folgende Fehlermeldung:

error: expected primary-expression before ']' token
   Wire.write(Array[], 10);
                    ^
exit status 1
expected primary-expression before ']' token

und wenn ich die [] weglasse:

(sehr viel shit und:)
exit status 1
no matching function for call to 'TwoWire::write(int [10], int)'

was mach ich falsch, das Array besteht nur aus 10 integern

von Kalle (Gast)


Lesenswert?

Per schrieb:
> PS: Ich bin kein Arduino oder C++ Anfänger, aber hab kaum Erfahrungen
> mit I2C

guck dir doch mal den Prototypen von Wire.write an. Der wird wohl einen 
char-Pointer erwarten. Auch wenn mir nicht klar ist, warum du ein 
integer-Array senden möchtest, geht das mit

reinterpret_cast<char*>(array)

von Einer K. (Gast)


Lesenswert?

So ist es!

int test[10];

// und in einer Funktion dann:
 Wire.write(reinterpret_cast<byte*>(test),sizeof(test));

von Per (Gast)


Lesenswert?

Das klingt sehr gut, aber wie empfange ich das dann?

von Wolfgang (Gast)


Lesenswert?

Per schrieb:
> Christian M. schrieb:
>> Das geht schon mal nicht! Jeder Slave braucht eine eigene Adresse!
>
> Warum?

Weil sich die Slaves sonst beim Ack in die Quere kommen.

von Per (Gast)


Lesenswert?

Wenn ich das Array dann empfange, kriege ich nur so etwas:
         0
         0
         0
         0
         0
         0
         0
         0
Wie kann ich das korrekt empfangen?

von Jim M. (turboj)


Lesenswert?

Du hast einen Fehler in Zeile 42.

von Kalle (Gast)


Lesenswert?

Hast du das Array initialisiert? Sonst werden wohl nur nullen 
drinstehen.

von Einer K. (Gast)


Lesenswert?

Per schrieb:
> Das klingt sehr gut, aber wie empfange ich das dann?

Der Empfang erfolgt in einer ISR.
Also beachte die Stichworte "volatile" und "atomic"

von Per (Gast)


Lesenswert?

was meinst du mit volatile und atomic?

Und ja, ich habe das Array[10] = {255, 0, 0, 0, 255, 0, 0, 0, 0, 255} 
initialisiert.

von Per (Gast)


Lesenswert?

Dennoch lautet die Ausgabe:
⸮   ⸮   ⸮0
⸮   ⸮   ⸮0
⸮   ⸮   ⸮0
⸮   ⸮   ⸮0
⸮   ⸮   ⸮0
⸮   ⸮   ⸮0
 Was mache muss ich zum Empfangen schreiben?

von Kalle (Gast)


Lesenswert?

Per schrieb:
>  Was mache muss ich zum Empfangen schreiben?
Was schreibst du denn bisher zum empfangen?

von Per (Gast)


Lesenswert?

Ich habe zur Zeit das Beispielprogramm, da ich kein Plan habe, wie 
sonst:
void receiveEvent(int howMany) {
  while (1 < Wire.available()) { // loop through all but the last
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

von Kalle (Gast)


Lesenswert?

Ich dachte, du seist kein C++ anfänger? Was erwartest du denn wenn du 
255 als char printest? Außerdem musst du deine Bytes ja wieder zu ints 
zusammenfügen wenn du das gleiche Array wieder rausbekommen möchtest. 
Probier einfach erst mal

Serial.print(static_cast<int>(c));

von Karl M. (Gast)


Lesenswert?

Per,

Du betreibst eine "Salami Taktik" die Helfer sehen nicht direkt, was Du 
da machst und auf welchem Level Sie dir vielleicht helfen könnten.

Dann streut der Eine oder Andere einen wichtigen (!) Hinweis, wie "was 
meinst du mit volatile und atomic?" und man sieht, wo es an Wissen 
fehlt.

Besser wäre es diese "Stichworte" sich zu erarbeiten und dann kritisch 
an das eigene Handeln heran zu gehen und zu äußern, was im eigene 
Codeteil falsch ist.

Ach ja wir können nicht nachvollziehen, das Du da machst, keiner von uns 
steht direkt neben Dir!

Klar?

Du musst unbedingt ALLES zeigen, sehr genau beschreiben was ist und Du 
erwartete. Sehr genau wären dann auch alle Antworten zu lesen.

Es gibt eine Sprichwort "es ist noch kein Meister vom Himmel gefallen."

Alles braucht seine Zeit: Sprachkenntnisse, Logik, Erfahrungen und 
Programm Engineering.

von Einer K. (Gast)


Lesenswert?

Per schrieb:
> was meinst du mit volatile und atomic?

Aua!

Ich habe dir diese Stichworte geliefert, damit du eine Chance hast dich 
darüber kundig zu machen.

Du könntest sie also mit dem Wort "Arduino", oder "AVR gcc" garniert, in 
eine Suchmaschine deiner Wahl eingeben.

von Einer K. (Gast)


Lesenswert?

Per schrieb:
> Ich habe zur Zeit das Beispielprogramm, da ich kein Plan habe, wie
> sonst:
> void receiveEvent(int howMany) {
>   while (1 < Wire.available()) { // loop through all but the last
>     char c = Wire.read(); // receive byte as a character
>     Serial.print(c);         // print the character
>   }
>   int x = Wire.read();    // receive byte as an integer
>   Serial.println(x);         // print the integer
> }
Es ist wirklich ungut, in einer ISR Funktionen/Methoden zu nutzen, 
welche ihrerseits Interrupts benötigen.

Du stellst damit eine Falle auf, und tappst dann selber da rein.
Baust einen Zufallsgenerator, ohne Wiederkehr.

von Stefan F. (Gast)


Lesenswert?

Wie gesagt, programmiere nicht Sender und Empfänger gleichzeitig. Zwei 
Baustellen mit vielen Unbekannten sind zu viel, um strukturiert voran zu 
kommen.

Außerdem solltest du dir einen Logic Analyzer besorgen um zu sehen, was 
auf deinem I²C Bus passiert. Die billigen 8CH Geräte für 10-20€ reichen 
dazu schon aus.

von Per (Gast)


Angehängte Dateien:

Lesenswert?

Ich möchte mich erst mal für dieses offene und ehrliche Feedback 
bedanken.
Es ist noch kein Meister vom Himmel gefallen ist Teil meiner 
Lebensphilosophie und der Grund, weshalb ich mich immer so überfordere, 
denn nur so wird aus einem Lehrling der Meister.

Ich habe mich in volatile eingelesen (zumindest kurz), weiß aber dennoch 
net, wie ich das in meinem Arduino Programm einbinden kann, da ich dafür 
noch kein annähernd gutes Beispiel gefunden habe und es immer in die 
Hose geht, wenn ich mich an so etwas versuche.

Ich kann euch gerne meine Programme anhängen und dann seht ihr ja, was 
ich da mache.

von Zeno (Gast)


Lesenswert?

Per schrieb:
> das Array besteht aus integer, immer nur max. 256 groß

Wenn es mit int deklariert wurde, dann ist ein Arrayelement 2Byte 
unabhängig davon ob Du 0, 256 oder größer dem Arrayelement zuweist.
Also mußt Du für jedes Arrayelement für length 2 angeben. Dann sollte es 
funktionieren.

von Stefan F. (Gast)


Lesenswert?

> int Array[10] = { 255, 0, 0, 0, 255, 0, 0, 0, 0, 255 };

Ist Dir bewusst, aus wie vielen Bytes dieses Array besteht?
Es sind 20 Bytes, weil ein int aus zwei bytes besteht.

> int x = Wire.read();

Diese Funktion wird daher nicht 10x sondern 20x ausgeführt. Denn 
Wire.read() liest einzelne Bytes.

Wenn du das wieder in den Datentyp in int umwandeln willst, würde ich 
Dir empfehlen die Daten zuerst in ein Array zurück zu lesen, das genau 
so strukturiert ist, wie beim Sender. Wenn das Array voll ist, dann erst 
gibst du es mit Serial.print() aus.

von Per (Gast)


Lesenswert?

Nachdem ich bei dem Sender-Programm die Länge verdoppelt habe und im 
Empfängerprogramm das char zum integer gemacht habe bekomme ich ein sehr 
interessantes wie lustiges Ergebnis im Seriallen Monitor:

255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071
255000000025500000000025500000130123902512071

Das scheint ja einigermaßen zu funktioniert haben. Aber wie kann ich 
daraus jetz meine 2Byte Werte bekommen?

von Kalle (Gast)


Lesenswert?

Wieso willst du überhaupt 2-Byte Werte? Was willst du denn für 
Information kodieren?

von Per (Gast)


Lesenswert?

ich möchte werte von 0-255 übermitteln, da das Resultat eine Ausgabe 
über RS-485 an DMX-Geräte sein soll, die bekanntlich mit Werten von 
0-255 kontrolliert werden. Und 256 Werte sind bekanntlich mehr als ein 
Byte

von Stefan F. (Gast)


Lesenswert?

> Aber wie kann ich daraus jetz meine 2Byte Werte bekommen?

Habe ich Dir geschrieben.

Du hast ein Array gesendet, dann empfange auch in ein gleich 
strukturiertes Array, bevor du es weiter verarbeitest. Das ist die 
einfachste und deppensichere Vorgehensweise.

von Kalle (Gast)


Lesenswert?

Per schrieb:
> Und 256 Werte sind bekanntlich mehr als ein
> Byte

Ach so

von Einer K. (Gast)


Lesenswert?

Per schrieb:
> Und 256 Werte sind bekanntlich mehr als ein
> Byte

Bist du dir da sicher...?

von STK500-Besitzer (Gast)


Lesenswert?

Per schrieb:
> Und 256 Werte sind bekanntlich mehr als ein Byte
Nö. Es passen genau 256 "Werte" in ein Byte.

Per schrieb:
> Ich bin kein Arduino oder C++ Anfänger

Solche Aussagen solltest du in Zukunft unterlassen.

von Stefan F. (Gast)


Lesenswert?

Ist Dir klar, wie viele Bytes du hier empfängst und wie sich char versus 
int hier auswirkt?
1
void receiveEvent(int howMany) {
2
  while (1 < Wire.available()) { // loop through all but the last
3
    char c = Wire.read(); // receive byte as a character
4
    Serial.print(c);         // print the character
5
  }
6
  int x = Wire.read();    // receive byte as an integer
7
  Serial.println(x);         // print the integer
8
}

Zuerst empfängst du ein Byte weniger als im Empfangspuffer steht und 
gibst jedes einzelne als char aus. Dann müsste z.B. aus dem Byte-Wert 65 
ein "A" werden. 0 und 255 sind beide nicht als Zeichen darstellbar, da 
außerhalb der ASCII Definition.

Danach liest du noch das letzte Byte aus dem Empfangspuffer und 
interpretierst es als Integer Zahl. Diese gibst du dann zusammen mit 
einem Zeilenumbruch aus.

von Per (Gast)


Lesenswert?

Ich werde es der Person, die mir die datentypen und speichertypen 
erklärt hat zurückmelden...

von Per (Gast)


Lesenswert?

Deswegen hab ich das char ja auch durch ein integer ersetzt

von Stefan F. (Gast)


Lesenswert?

Du solltest auch mal die Werte von howMany und Wire.available() printen. 
Außerdem füge zwischen Jedes Zeichen und jede Zahl ein Trennzeichen 
(z.B. Komma) ein, damit man erkennen kann, was zusammen gehört.

von STK500-Besitzer (Gast)


Lesenswert?

Per schrieb:
> Deswegen hab ich das char ja auch durch ein integer ersetzt

Die fehlt der DoWhatIwantOrWhatImean-Compiler

von Per (Gast)


Lesenswert?

Und mit der aktualisierten version:

void receiveEvent(int howMany) {
  while (1 < Wire.available()) { // loop through all but the last
    Array[count] = Wire.read(); // receive byte as a character
    Serial.println(Array[count]);
    ++count;
  }
  Serial.println();
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
  count=0;
}

kommt folgendes Ergebnis heraus:

1
255
0
0
0
0
0
0
0
255
0
0
0
0
0
0
0
0
0
255
0
0
0
0
0
130
1
239
0
25
1
207

1

Irgendwas stimmt da doch noch nicht

von Einer K. (Gast)


Lesenswert?

Per schrieb:
> Ich werde es der Person, die mir die datentypen und speichertypen
> erklärt hat zurückmelden...

Bitte selber denken!

Vergleich:
Wenn du einen großen Schubladenschrank hättest....
Und du würdest die Schublanden mit Zahlen von 0 bis 255 beschriften.
Wieviel Schubladen hättest du dann beschriftet?

von Stefan F. (Gast)


Lesenswert?

> int x = Wire.read();    // receive byte as an integer

Das tut nicht das, was daneben steht.

Dein Byte wird auf Integer gGöße aufgeblasen, indem es mit Nullen 
aufgefüllt wird. Wenn das Byte z.B. den Wert 255 hat, dann passiert mit 
den Bits dies:

Wire.read liefert: 11111111
Die Zuweisung zur int Variable macht daraus: 0000000011111111

Du hast hier keineswegs zwei bytes zu einem Int zusammengefügt, sondern 
zusätzliche 0-Bits hinzugefügt.

Das ist keinesfalls die Umkehrung der Sende-Operation. Beim Senden hast 
du Integer Werte in ein Array geschrieben.

> int Array[10] = { 255, 0, 0, 0, 255, 0, 0, 0, 0, 255 };

Das sind 10 Integer Werte, also 20 Bytes:
1
       erstes Bytes zweites byte
2
255 =  11111111     00000000
3
4
       drittes Byte viertes Byte 
5
0 =    00000000     00000000

und so weiter.

von Per (Gast)


Lesenswert?

Und was würdest du mir dann vorschlagen? Nur Bytes in das Array 
schreiben?

von Stefan F. (Gast)


Lesenswert?

Ich habe Dir schon zweimal vorgeschlagen, dass du auf der Empfängerseite 
alles in ein gleich strukturiertes Array empfangen sollst bevor du es 
auswertest.

Also jetzt schon zum dritten mal.

Du könntest Dich auch einfach auf Bytes beschränken, aber ich weiß ganz 
genau was dann als nächste Frage kommt: Wie kann ich xyz in bytes 
umwandeln?

von Per (Gast)


Lesenswert?

Ne, diese Frage brauch ich nicht

von Per (Gast)


Angehängte Dateien:

Lesenswert?

An dieser Stelle ein riesengroßes Dankeschön an alle Beteiligte dieser 
(teils sehr heiklen) Diskussion, es funktioniert jetzt zumindest 
halbwegs.

Ich denke ab jetzt kann ich das ganze für meinen Zweck optimieren und 
"das wird schon klappen!" xD
Vielen Dank, falls irgendwas net so ganz will, kann ich euch dann ja 
einfach weiternerven ;)

Möge dieser Beitrag allen anderen Arduino_Dummies helfen!

PS: Hier nochmal die Funktionierenden Programme

von Einer K. (Gast)


Lesenswert?

Per schrieb:
> Möge dieser Beitrag allen anderen Arduino_Dummies helfen!

Und sie in die Irre leiten....
:-(

von STK500-Besitzer (Gast)


Lesenswert?

Per schrieb:
> PS: Hier nochmal die Funktionierenden Programme

Warum nicht einfach die Beispiele auf der Arduino-Seite übernehmen?!

von STK500-Besitzer (Gast)


Lesenswert?

Per schrieb:
> PS: Hier nochmal die Funktionierenden Programme

Warum nicht einfach die Beispiele auf der Arduino-Seite übernehmen?!
Die sind wenigstens kommentiert bzw. dokumentiert.

von Zeno (Gast)


Lesenswert?

Per schrieb:
> ich möchte werte von 0-255 übermitteln, da das Resultat eine Ausgabe
> über RS-485 an DMX-Geräte sein soll, die bekanntlich mit Werten von
> 0-255 kontrolliert werden. Und 256 Werte sind bekanntlich mehr als ein
> Byte

Nö das ist genau 1Byte. Denmzufolge wäre ein Bytetyp der richtige Daten. 
Da C/C++ den Datentyp "byte" nicht kennt nimmt man halt "unsigned char". 
Der geht von 0 .. 255.

von Stefan F. (Gast)


Lesenswert?

Eigentlich nimmt man dann uint8_t aus der stdint.h.

auch wenn das letztendlich mit unsigned char identisch ist. Es zeigt 
aber besser die Absicht des Autors.

von Zeno (Gast)


Lesenswert?

STK500-Besitzer schrieb:
> Per schrieb:
>> Ich bin kein Arduino oder C++ Anfänger

Doch! Die grundlegenden Datentypen sollte man schon kennen.

Per schrieb:
> Ich werde es der Person, die mir die datentypen und speichertypen
> erklärt hat zurückmelden...

Nee, selber die Dokumentation lesen. Die Dokumentation der Arduino-IDE 
erklärt schon die einzelnen Datentypen.


Das C/C++ keinen dedizierten Bytedatentyp kennt macht es halt für das 
Verständnis etwas schwieriger. char kann eben genau das sein was man 
nach der Bezeichnung vermutet aber es kann eben auch eine Zahl sein. 
Manche C-Compiler unterscheiden noch zwischen signed char (-127...127) 
und unsigned char (0..255) was die Sache für den Anfänger nicht 
unbedingt leichter macht.

von Zeno (Gast)


Lesenswert?

Per schrieb:
> Und was würdest du mir dann vorschlagen? Nur Bytes in das Array
> schreiben?

Ja!

von Zeno (Gast)


Lesenswert?

Stefanus F. schrieb:
> Eigentlich nimmt man dann uint8_t aus der stdint.h.
>
> auch wenn das letztendlich mit unsigned char identisch ist. Es zeigt
> aber besser die Absicht des Autors.

Ich weis nicht ob das in der Arduino IDE irgendwo vereinbart ist.
Du hast schon recht das es damit deutlicher wird und man sofort weis was 
gemeint ist.
Ich persönlich mag diese uint's nicht. Es sind keine echten Datentypen, 
sondern lediglich ein Alias für einen anderen Datentyp. Man gaukelt da 
zwar einen Bytedatentyp, aber es ist eigentlich unsigned char. C kennt, 
im Gegensatz z.B. zu Pascal, eben keinen numerischen Datentyp der ein 
Byte darstellt. In der stdint.h wird unsigned char lediglich auf uint8_t 
umgebogen.

von Zeno (Gast)


Lesenswert?

Nachtrag: Man könnte sich natürlich auch einen eigenen byte Typ 
deklarieren, oder besser einen Alias erzeugen.

von Stefan F. (Gast)


Lesenswert?

Zeno schrieb:
> Ich weis nicht ob das in der Arduino IDE irgendwo vereinbart ist.

Das ist C Standard, also auch in C++ enthalten und somit auch in der 
Arduino IDE nutzbar. Wenn man einen Blick in die Quelltexte der Arduino 
Libraries wirft, sieht man, dass sie selbst auch von den Standard 
Integer Typen Gebrauch machen.

Der 2. Vorteil dieser Aliase ist, dass sie auf allen Computern die 
erwartete Größe haben.

int8_t und uint8_t ist immer 8 Bit groß.
int16_t und uint16_t ist immer 16 Bit groß.
int32_t und uint32_t ist immer 32 Bit groß.
int64_t und uint14_t ist immer 64 Bit groß.

Bei den Standard Typen (in diesem Fall char) ist das nicht der Fall. Auf 
einem anderen Computer kann ein char größer als ein byte sein. Ebenso 
ist die Größe von int nicht festgelegt.

https://de.wikipedia.org/wiki/Datentypen_in_C#Integer

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Zeno schrieb:
> Man gaukelt da zwar einen Bytedatentyp, aber es ist eigentlich unsigned
> char.

Ich würde sagen, daß Du das falsch interpretierst. Mit uint8_t ist ganz 
klar und eindeutig gesagt, was gemeint ist, mit unsigned char hingegen 
nicht, das kann je nach Zielhardware und Compiler was völlig anderes 
sein.

Bei char begegnen einem diese Ausnahmen ja eher selten, aber bereits 
bei int, short oder long gibt es auf verbreiteten Plattformen 
reale Unterschiede. Da sind die (u)intXX_t-Typen ein deutlicher 
Fortschritt.

Wenn es für die Funktionalität des Programmes irrelevant ist, kann man 
nach wie vor int oder short verwenden, aber sobald es auf den 
darstellbaren Wertebereich ankommt, muss so etwas eigens geprüft und 
angepasst werden.

Stell Dir 'ne schicke Arduino-""""Library"""" vor, die jemand auf einem 
Arm-Arduino geschrieben hat, und die int verwendet, um damit Zahlen im 
Bereich von bis zu ein paar Millionen zu verarbeiten. Funktioniert 
wunderbar, bis jemand auf die Idee kommt, diese """"Library"""" auf 
einem AVR-Arduino einsetzen zu wollen.

von Zeno (Gast)


Lesenswert?

@Rufus
@Stefanus

Das int auf verschiedenen Systemen unterschiedlich ist schon klar - ist 
halt mit den Systemen "gewachsen".
Bei char war mir das bisher nicht so bewußt. In Delphi, womit ich 
hauptsächlich programmiere, ist (zumindest bis BDS2006), Char mit 8 Bit 
implementiert und entspricht dem Grundtyp AnsiChar. Es gibt noch den Typ 
WideChar der 16 Bit groß ist. Ab XE Version 10 ist char allerdings mit 
WideChar verknüpft und damit 2 Byte groß. Unter Delphi ist das aber kein 
Problem da dort Char gnau das ist was man sich unter Char vorstellt, 
nämlich 1 Zeichen.

Für Zahlen gibt es extra den Typ Byte mit 8 Bit und den Typ Word mit 16 
Bit.
Es gibt auch noch LongWord das sind je nach System 32 oder 64 Bit.

Das ist aber alles ein anderes Thema - wollte es nur mal erwähnt haben.

von Zeno (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Ich würde sagen, daß Du das falsch interpretierst. Mit uint8_t ist ganz
> klar und eindeutig gesagt, was gemeint ist, mit unsigned char hingegen

Da interpretiere ich gar nichts falsch. In der stdint.h 
(https://sites.uclouvain.be/SystInfo/usr/include/stdint.h.html) steht es 
doch eindeutig drin:
1
typedef unsigned char                uint8_t;

Nach Deiner Leseart ist dann unsigned char auf einem anderen System was 
ganz anders? Kann eigentlich nicht sein. unsigned char ist immer 8 Bit.
signed char ist vom System abhängig. Es gilt lediglich diese Regel:
signed char ≤ short int ≤ int ≤ long int ≤ long long int

Alles andere macht auch keinen Sinn. Die Frage, wo char angebunden ist - 
an signed oder unsigned. Im 2.Fall wäre es immer 8 Bit.

Im übrigen würde ich die Zuordnung
1
typedef unsigned char                byte;
für sinnvoller halten. Was ein Byte ist weis auch jeder.
Für uint16_t würde das Gleiche gelten:
statt :
1
typedef unsigned short int        uint16_t;
besser:
1
typedef unsigned short int        word;
Auch das weis jeder das ein Wort ein Doppelbyte und damit 16 Bit lang 
ist.

Byte und Wort sind Begriffe die es schon immer Rechnersystemen gibt. 
Lest mal Literatur aus der Anfangszeit, da werden die Begriffe Bit, 
Byte, Wort und Doppelwort ausführlichst besprochen und erklärt. C in 
seinen ganzen Variationen hat es halt bis heute nicht geschafft die 
logischen Datentypen Byte und Word in den Sprachumfang mit aufzunehmen. 
Statt dessen macht man so kryptische Verrenkungen wie uint8_t usw.
Das ist letztendlich das was es dem Anfänger (TO) so schwer macht. Wenn 
dann in einem Tutorial steht 32Byte muß der nämlich erst mal überlegen, 
wie  er diese auf die vorhandenen Datentypen/Aliase abbilden kann. Der 
TO ist genau hierüber gestolpert.

von Einer K. (Gast)


Lesenswert?

Zeno schrieb:
> C in
> seinen ganzen Variationen hat es halt bis heute nicht geschafft die
> logischen Datentypen Byte und Word in den Sprachumfang mit aufzunehmen.

Das hast du gut erkannt!
Denn die Breite eines Bytes ist unbestimmt.
(wikipedia erklärt dir das)


5 Bit breite Byte, oder 9 Bit pro Byte,  C kann das.

von Zeno (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Zeno schrieb:
>> C in
>> seinen ganzen Variationen hat es halt bis heute nicht geschafft die
>> logischen Datentypen Byte und Word in den Sprachumfang mit aufzunehmen.
>
> Das hast du gut erkannt!
> Denn die Breite eines Bytes ist unbestimmt.
> (wikipedia erklärt dir das)


Volltreffer! Du erfindest die Datentypen neu. 1 Byte ist gleich 8 Bit. 
Steht sogar in dem Artikel auf den Du Dich beziehst. Lies Dir selbigen 
nochmals genau durch.
Ja, 1 Byte kann auch die kleinste adressierbare Einheit in einem 
Datensystem sein und die kann natürlich von 8Bit abweichen.
Das hat aber nichts mit einem Byte bei Programmiersprachen zu tun. Nenne 
mir doch einfach mal ein aktuelles System/eine aktuell 
Programmiersprache wo man mit 5 Bit breiten Bytes arbeitet.
Schon im legendären Z80 waren die Register genau 8Bit = 1Byte groß. " 
Register wurden zu einem Paar zusammengefaßt und das war dann 1 Wort = 2 
Byte =16 Bit groß.

Arduino Fanboy D. schrieb:
> 5 Bit breite Byte, oder 9 Bit pro Byte,  C kann das.
C kann an dieser Stelle gar nichts. C kennt noch nicht einmal einen 
Datentyp Boolean = 1 Bit. Allerdings belegt auch dieser Datentyp intern 
1Byte also 8Bit. Auch Dein imaginärer Datentyp mit 5Bit Länge würde 
1Byte belegen. Dein Datentyp mit 9Bit würde 1Wort=2Byte=16Bit belegen. 
Natürlich kann ich per typedef einen Datentyp mit 5 oder 9 Bit 
definieren. Das ist aber kein Alleinstellungsmerkmal von C - das können 
andere Programmiersprachen auch. Abgesehen davon erhebt sich die Frage 
der Sinnhaftigkeit. Aber bring doch einfach mal ein Beispiel für eine 5 
bzw. 9 Bit breiten Datentyp.

Es hat schon einen Grund warum die Datentypen in den Programmiersprachen 
Potenzen zur Basis 2 entsprechen. 5 und 9 waren nochmal welche 2'er 
Potenz? Zwischen 2^0 und 2^4 ergibt keine Potenz 5 oder 9.
Bring doch mal ein Beispiel für Deine Datentypen.

von Einer K. (Gast)


Lesenswert?

Dein Geheule hilft dir nicht!

von Zeno (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Dein Geheule hilft dir nicht!

Ich heule nicht, ich stelle nur fest.

Du hast den Käse mit den Byte angefangen, weil Du offensichtlich nicht 
in der Lage bist den Wikipediaartikel mit der nötigen Sorgfalt zu zu 
lesen und die falschen Schlüsse ziehst. Ist aber nicht weiter schlimm - 
ist sehr wahrscheinlich Deinem eher jugendlichen Alter zu zuschreiben.

Warte aber gern noch auf ein Beispiel von Dir - also ein 5Bit und einen 
9Bit breiten Datentyp - man lernt ja nie aus.

von Stefan F. (Gast)


Lesenswert?

Zeno schrieb:
>> Ich würde sagen, daß Du das falsch interpretierst. Mit uint8_t
>> ist ganz klar und eindeutig gesagt, was gemeint ist, mit
>>> unsigned char hingegen
>
> Da interpretiere ich gar nichts falsch. In der stdint.h
> (https://sites.uclouvain.be/SystInfo/usr/include/stdint.h.html) steht es
> doch eindeutig drin:
>
1
typedef unsigned char                uint8_t;
>
> Nach Deiner Leseart ist dann unsigned char auf einem anderen
> System was ganz anders?

Du verdrehst meine Worte.

Wenn ich ein Zeichen speichern möchte, benutze ich dafür den Datentyp 
char. Und eine Zeichenkette gehört folglich in ein Array von char.

Wenn ich Messwerte im Bereich 0-255 speichern möchte, benutze ich dafür 
den Datentyp uint8_t. Und ein Menge solcher Messwerte gehört in ein 
Array von uint8_t.

Wenn also im Quelltext steht:
1
char[100] message;
Dann kann das nur ein Text sein. Eine "Message" aus Messwerten würde ich 
hingegen in
1
unti8_t[100] message;
speichern (mal abgesehen davon dass der Name der Variable suboptimal 
ist).

Wenn ich das so konsequent mache, ist es auch völlig egal, wie groß ein 
Char auf dem System ist. Beim uint8_t ist mit die Größe aber wichtig, 
und deswegen schreibe ich sie auch ausdrücklich hin.

> Im übrigen würde ich die Zuordnung
>
1
typedef unsigned char                byte;
> für sinnvoller halten. Was ein Byte ist weis auch jeder.

Ja, so habe ich das auch im Sinn. Aber ich weiß, dass die Breite eines 
"byte" eben nicht auf 8 Bit festgelegt ist, so wie ein Word auch nicht 
auf 16 Bit festgelegt ist.

> Byte und Wort sind Begriffe die es schon immer Rechnersystemen gibt.

Ja schon, aber schon unter den allerersten Computern gab es welche, bei 
denen nicht alles glatt durch 8 teilbar ist.

Glaube mir, wenn du jetzt nach der Größe des word (Wort) fragst, wirst 
du hier eine Diskussion mit weiteren 50 Beiträgen lostreten. Das ist 
nämlich eben nicht auf 16 Bit festgelegt.

> Statt dessen macht man so kryptische Verrenkungen wie uint8_t usw.
> Das ist letztendlich das was es dem Anfänger (TO) so schwer macht.

Was ist daran Schwer. Ein uint8_t besteht aus 8 Bits und kann folglich 
2^8 unterschiedliche Werte aufnehmen. Das war schon immer so und das 
lernt jeder in der 6. oder 7. Schulklasse. Den begriff "byte" lernen die 
Kinder aber nicht im Mathe Unterricht. Den muss man erstmal auswendig 
lernen, als byte=8 Bit.

Deine Annahme char=8 Bit und word=16 Bit gilt jedenfalls beides nicht 
allgemein. Es gilt für die Computer, die du kennst, aber eben nicht für 
alle.

> Wenn  dann in einem Tutorial steht 32Byte muß der nämlich erst
> mal überlegen, wie  er diese auf die vorhandenen Datentypen/Aliase
> abbilden kann. Der TO ist genau hierüber gestolpert.

Ich denke man kann schon verlangen, dass ein angehender Programmierer 
byte = 8 Bit auswendig lernt. Ganz besonders einer, der Hardwarenah 
programmiert. Früher oder später muss man sich ohnehin mit den 
Wertebereichen der Datentypen auseinandersetzen. Es ist ja auch nicht 
so, dass die üblichen Tabellarischen Auflistungen verwirrend wären. Ganz 
im Gegenteil. Wer die verwirrend findet, sollte lieber Bäume Pflanzen.

von Stefan F. (Gast)


Lesenswert?

Ich zitiere aus Wikipedia:

"Das Byte ist eine Maßeinheit der Digitaltechnik und der Informatik, 
welches meist für eine (binäre) Folge aus 8 Bit steht."

Da steht nicht, dass es immer 8 Bit sind!

Weiter heißt es verstärkend:

"Um ausdrücklich auf eine Anzahl von 8 Bit hinzuweisen, wird auch die 
Bezeichnung Oktett verwendet."

Darunter folgt eine Auflistung von Systemen, wo ein Byte eben nicht 8 
Bit groß ist (z.B. Telex, das kenne ich noch ganz gut).

Du hast also Byte mit Oktett verwechselt.

Wir könnten das jetzt auch noch für dein Word durchkauen, aber dazu habe 
ich keine Lust.

von luzia (Gast)


Lesenswert?

Unglaublich!

Da will jemand wissen wie er Daten via I2C aus einem Array versendet. 
Dann melden sich eine ganze Menge Trolle, die nicht gewillt sind eine 
klare Antwort darauf zu geben. Vielleicht weil sie selbst keine echte 
Ahnung von der Materie haben.

Luzi

von Stefan F. (Gast)


Lesenswert?

luzia schrieb:
> Unglaublich!

Ja unglaublich, nach fast 5 Monaten auf so unpassende Art nachzutreten!

Wie sieht denn dein vorbildlich hilfreicher Beitrag aus?

von Einer K. (Gast)


Lesenswert?

Tipp:
Die einfachste Methode einen Troll zu erkennen, ist zu schauen ob 
er/sie/es andere als Trolle bezeichnet.

Alternativ:
Wäge die gezeigte Fachkompetenz, gegen die gezeigte Angriffslust auf.


--
Ob es hier wieder die Roth Anomalie ist?
Es riecht danach...

von luzia (Gast)


Lesenswert?

Hallo,

seid mal nicht so empfindlich. Männer!!! Lest Euch die ganze Sache noch 
einmal durch und macht Euch eigene Gedanken darüber.

Ich hätte zum Beispiel eine Antwort erwartet wie z. B.

Auf einem Uno gehen üblicherweise 32 Byte a 8 bit über I2C. Wenn Du 16 
bit übertragen willst, musst du höherwertiges Byte und niedrigwertiges 
Byte getrennt übertragen und beim Empfänger wieder zusammensetzen. 
H-Byte * 256 + L-Byte. Pro Schleife im Loop wird nur ein Byte 
übertragen. Also schön das Array abzählen und die Werte speichern.

Wie gesagt, ein Beispiel,  aus dem sich aber ein vernüftiger Dialog 
entwickeln kann.

Nichts für ungut.
Luzi.

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.