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
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?
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
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.
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?
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?
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
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);
}
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
bytesrc,
3
bytedst,
4
bytetype,
5
bytereserve,// optional, macht aber bei 32 Bit Maschinen das alignement besser und somit den Zugriff schneller
6
intlength,
7
bytearrray[1024],
8
intcrc
9
}data;
befüllen über
1
data.src=0x01;// master has id 1, slave = 2, ....
2
data.dst=0xFF;// broadcast?
3
data.type=0x00;/allgemeineDatentyp
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
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.
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?
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.
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
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).
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.
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
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
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ß
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
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)
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.
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"
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
}
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));
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.
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.
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.
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.
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.
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.
> 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.
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?
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
> 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.
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.
Ist Dir klar, wie viele Bytes du hier empfängst und wie sich char versus
int hier auswirkt?
1
voidreceiveEvent(inthowMany){
2
while(1<Wire.available()){// loop through all but the last
3
charc=Wire.read();// receive byte as a character
4
Serial.print(c);// print the character
5
}
6
intx=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.
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.
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
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?
> 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:
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?
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
Per schrieb:
> PS: Hier nochmal die Funktionierenden Programme
Warum nicht einfach die Beispiele auf der Arduino-Seite übernehmen?!
Die sind wenigstens kommentiert bzw. dokumentiert.
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.
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.
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.
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.
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
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.
@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.
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
typedefunsignedcharbyte;
für sinnvoller halten. Was ein Byte ist weis auch jeder.
Für uint16_t würde das Gleiche gelten:
statt :
1
typedefunsignedshortintuint16_t;
besser:
1
typedefunsignedshortintword;
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.
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.
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.
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.
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
typedefunsignedcharuint8_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
typedefunsignedcharbyte;
> 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.
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.
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
luzia schrieb:> Unglaublich!
Ja unglaublich, nach fast 5 Monaten auf so unpassende Art nachzutreten!
Wie sieht denn dein vorbildlich hilfreicher Beitrag aus?
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...
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.