EV3Basic: allgemeine Kommunikation mit I2C Geräten

NXC, C/C++, Lejos, pbLua, RobotC...

Moderator: Moderatoren

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 25. Sep 2015 20:33

Es gibt auf dem Arduino keine Register! Und der EV3 hat auch noch wie was davon gehört. Und I2C genausowenig.
Register sind nur eine Konvention, an die man sich für seine Protokolle halten kann, wenn man einen I2C-Slave definiert.
Dein Protokoll tut das offenbar nicht, weil du ja immer diesen ganzen Datenblock hin- und herschicken willst. Wenn du im EV3-Basic 30 Bytes im Array zusammenbaust und an den Slave schickst, bekommt der dann auch genau diese 30 Bytes heraus (seine eigene Addresse sieht er genausowenig, wie man die beim Senden ins Array packen muss).
Vergiss die Sache mit den Registern in diesem Zusammenhang bitte ganz schnell wieder.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5377
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 25. Sep 2015 20:47

du schriebst doch oben selber, dass das 1. Byte [0] die Registeradresse enthalten müsse? Daher meine Frage. Sonst wäre ich nie darauf gekommen. Klar hat der Arduino keine Register (aber der PCF8574 hätte z.B welche, oder der CMPS11. Die können ja auch am Bus mit dran hängen.)
Und wenn kein spezielles reg adressiert werden muss, ist es eben 0.

Wie muss denn jetzt deiner Meinung nach der SendArray laut deiner EV3Basic Funktion aussehen, um sie zum Arduino zu schicken?
(bei Arduino zu Arduino wäre es völlig simpel, weil ich 2 verschiedene Funktionen und 2 verschiedene Events habe...)

der Aufbau der msg ist - so wie ihn der Arduino empfangen soll - :
Die ersten 4 Bytes sollen Kontrollzwecke erfüllen:
1. Byte: 0xff zur Start- und Verbindungs-Erkennung (sync byte control)
2. Byte: eine Checksum (Summe aller Byte-Werte ab 5.Byte-30.Byte, davon dann das LowByte) (data transmission control)
3. Byte: eine ID des Slaves (transmission direction control)
4. Byte: Acknowlege-Flag-Byte: Ok=1 => sende neue Daten, wiederholen=127 => sende alte Daten erneut (msg order control)
Der Rest sind beliebige zu versendende Daten-Bytes.
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 26. Sep 2015 11:53

Ja, ich habe mich in einem vorigen Post dazu hinreißen lassen, ausführlich zu erklären, wie die Register auf diesen Geräten verwendet werden, die eben Register haben (wie z.B. der CMPS11 - der PCF8574 hat wiederum keine). Register sind nur eine Art Konvention, die von manchen Geräten auf I2C draufgesetzt wird.

Zur Frage:
Das Array muss so aussehen:

Code: Alles auswählen

X[0] = 255                 ' Small Basic kennt keine Hexadezimalschreibweise
X[1] = checksumme
X[2] = slave_id
X[3] = acknowledge byte
X[4] = ..
...
X[29]= ..

Dann kannst du das ganze mit

Code: Alles auswählen

Y = Sensor.CommunicateI2C (1, 47,  30, 30, X)

zum Arduino schicken und auch gleich eine Antwort abholen, die dabei als Array in die Variable Y geschrieben wird.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5377
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 26. Sep 2015 12:38

PCF8574 hat keine register ?
das ist mit neu... die Werte (Bitmask-Byte) stehen so weit ich weiß in Register 1, Register 0 enthält ein ack byte:

Code: Alles auswählen

#include <Wire.h>

#define ADDR_PCF8574  0x30


void setup() {
   Wire.begin();
   writei2cbyte(ADDR_PCF8574, 0xff);  // init  PCF8574: write HIGH to device address
   //...
}


void writei2cbyte(int addr, byte data) {
  Wire.beginTransmission(addr);
  Wire.write(data);
  Wire.endTransmission();
  delay(5);
}


uint8_t readi2cbyte(uint8_t addr, uint8_t reg) {
  uint8_t  bdata;

  Wire.beginTransmission(addr);
  Wire.write(reg);                   // target data register number (PCF8574==1)
  Wire.endTransmission();

  Wire.requestFrom(addr, 1);           // Request 1 byte  (berichtigt)
  while(Wire.available() < 1);           // Wait for byte to become available
  bdata = Wire.read();     
  return(bdata);
}


void loop()  {
  //...
  uint8_t bitmask = readi2cbyte(ADDR_PCF8574, 1);  // read all btn states (bitmask) at register  0x01
  if(bitRead(bitmask,1) {...}
  else
  if(bitRead(bitmask,2) {...} 
  //...
 
}
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 26. Sep 2015 14:27

Wenn ich die Spec (http://www.nxp.com/documents/data_sheet/PCF8574.pdf) für den Bauteil richtig lese, dann ist das Blödsinn.
Der zweite Parameter von Wire.requestFrom() ist auch keine Registernummer, sondern die Anzahl der angeforderten Bytes. Das ist in dem Fall sozusagen zufällig 1 und damit gehts halt. Der Slave liefert beim Lesen eben immer ein einzelnes Byte, das genau dem Zustand des Ports entspricht.

Wenn der Slave ein einzelnes Byte kriegt, dann setzt er den Port entsprechend des Bitmusters auf Weak HIGH (1) oder Strong LOW (1). Bei den Pins, wo er ein Weak HIGH ausgibt, kann er von der angeschlossenen Elektronik auf 0 runtergezogen werden. Durch dieses System braucht man nicht extra die Richtungen der Pins definieren.

Nur eines verstehe ich bei deinem Code echt nicht: Anscheinend wird jedesmal vor dem Lesen des Ports eine 1 an das Gerät geschickt, mit dem eigentlich alle Pins außer Pin 1 auf Strong LOW gezogen werden. Wenn man dann den Eingang lesen will, kriegt man fast sicher nur 0en auf diesen Bits. Außer die angeschlossene Elektronik zieht den Pegel wiederum so stark nach oben, dass er den Eingang mit Gewalt auf high kriegt. Das wäre aber echt arg und wahrscheinlich überlebt das der PDF8574 nicht lange.

Hast du den Code wirklich ausprobiert? Auch zum Lesen der Eingänge, oder nur zum Schreiben? (Schreiben dürfte zufälligerweise gehen)

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5377
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 26. Sep 2015 14:40

Was das reg byte [1] angeht:
nein, nicht selber ausprobiert, der Code ist allgemeines Sketch-Lib-Kulturgut ;)
Beim NXT wurde allerdings auch immer das Reg.-Byte[1] ausgelesen, da habe ich es ähnlich gemacht.

Was die generelle Funktion der Wire Klasse angeht: das funktioniert bei Arduino tatsächlich immer so.
Erst schreibt man da gewünschte Reg-Byte an die dev adresse

Code: Alles auswählen

   Wire.beginTransmission(addr);
   Wire.write(reg);                   // target data register number (PCF8574==1)
   Wire.endTransmission();


Danach wird dann gelesen - (berichtigt)

Code: Alles auswählen

   byte bdata;
   Wire.requestFrom(addr, 1);           // Request 1 byte)
   while(Wire.available() < 1);           // Wait for 1 byte to become available
   bdata = Wire.read();                   // get it !


bei mehreren Bytes (n) ab Adresse reg=x würde dieser Teil dann heißen

Code: Alles auswählen

   byte n, bdata[n];
   int i = 0;
   Wire.requestFrom(addr, n);           // Request n bytes from reg number   
   while(Wire.available() < n);           // Wait for x bytes to become available
   while(i<n) bdata[i++] = Wire.read();         // get 'em !
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5377
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 26. Sep 2015 14:49

Fehler, bei Wire.requestFrom(address, quantity) wars die Anzahl, nicht die Adresse, falsch kopiert und kommentiert!
den anderen Code habe ich gerade ins blaue geschrieben, es ging aber eigentlich nur ums Register beim PCF8574.
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 26. Sep 2015 15:34

Ist immer noch ein Blödsinn.
Wenn du an den PCF8574 ein Byte schickst, dann benutzt er das sofort um die Ausgangspins anzusteuern.
Und wenn du ein Byte liest, dann kriegst du genau den aktuellen Zustand der Pins.
Dieser Bauteil hat keine Register.

Wie gesagt, beim CMPS11 stimmt das mit den Registern. Und bei vielen anderen I2C-Bauteilen wahrscheinlich auch.
Aber eben nicht beim PCF8574 und schon gar nicht bei einem selbstgebauten Arduino-Slave (außer natürlich, du implementierst eben so eine Register-Lösung)

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5377
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 26. Sep 2015 16:01

gut, ich geb dir Recht - es stand halt so im Sketch-Beispiel, und ich habe es für bare Münze gehalten. Überprüfen kann ich momentan den Code aber sowieso jetzt nicht
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 27. Sep 2015 21:39

Du hast immer noch die "verdoppelte" Slave-Addresse (also 8) im EV3Basic-Programm hardcoded im Aufruf. Da nützt es gar nichts, wenn du oben die Konstante änderst. Habe ich beim vorigen mal drüberschauen auch übesehen.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5377
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 28. Sep 2015 08:12

nein, da steht doch
I2CSLVADDR = 4 '// devaddr=0x04
also NICHT verdoppelt!
das war die letzte Version, aber bei der vorletzten hatte ich es noch verdoppelt, und es hat auch nicht funktioniert (wechselweise auskommentiert).
Es klappt mit keiner Slave Adresse, egal welcher - wschl liegt der Fehler also woanders.

(habe es übrigens auch mit MEGA statt DUE getestet, selbes Ergebnis. Trotzdem kann es natürlich auch an Hardware-Problemen liegen: kannst du es vllt mal auf einem Uno etc. testen? ich besitze leider keinen.)
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re:EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 28. Sep 2015 12:20

Lies, bitte, was ich schreibe! Du hast zwar diese Konstante im Programm geändert, verwendest sie aber nicht!
Du hast da die Zahl 8 direkt in den Befehl geschrieben.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5377
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re:EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 28. Sep 2015 14:39

das hatte ich nicht verstanden mit "hardcoded".
Muss ich mir später mal ansehen, danke!

edit, update:
ja, jetzt weiss ich was du mit "hardcoded in den Befehl geschrieben" meintest!
Allerdings würde ich erwarten, dass er auch dann wartet, wenn er den Slave nicht erreicht, denn er kann ja dort nichts abliefern und kriegt auch keinen Rückgabewert!
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 28. Sep 2015 14:48

I2C funktioniert nicht so. Wenn der Master mit seinem Request ins Leere geht, dann erhält er kein Acknowledge und weiß sofort, dass es keinen Slave gibt und er nicht mehr weiter warten muss. Das ganze Protokoll ist überhaupt komplett anders als eine normale UART-Verbindung und ich empfehle weiterhin dringend, die I2C-Spezifization zu lesen.
Überhaupt scheint mir dein ganzes Übertragungspaket einige Sachen zu enthalten, die bei I2C komplett überflüssig sind: Sychronisationsbyte braucht man ganz sicher nicht. Und die ID des Slaves ist auch unnütz, weil I2C ja selbst den Slave addressiert. Das Acknowledge könntest du dir wahrscheinlich auch sparen, weil I2C ja von Haus aus ein Challenge-Response Protokoll mit fix eingebautem Handshake ist.
Ich sage es Nochmal: Bitte versuche I2C zu verstehen.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5377
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re:EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 28. Sep 2015 15:18

Das sync byte habe ich drin, weil ich den Array auch für UART verwende mit identischem Aufbau. Hier ist er nur ein zusätzlicher Transmission-Check, denn i2c ist sehr Übertragungsfehler-anfällig. Das gleiche gilt für die Slave-Adresse als Zusatz-Check bei mehreren Slaves am Bus.
Was ich aber brauche, ist: auf das ack warten, denn er soll auf keinen Fall weitermachen, wenn er den Slave nicht erreicht hat.
Ich war der Meinung, man könnte den Rückgabe-Array quasi als ack verwenden, worauf er dann warten muss.
Aber auch wenn er ihn erreicht, muss er unbedingt warten, bis alle 30 Bytes gesendet und neue 30 Bytes empfangen wurden, bevor er weitermacht.
Arduino-seitig erreiche ich das mit Wire.available(), das als Rückgabewert die Anzahl der verfügbaren Bytes im Puffer angibt. So kann ich warten, bis 30 voll sind.
Wie das technisch funktioniert, ist weniger interessant - ich brauche die Steuerkommandos für EV3Basic, genau wie für Sketch (auch da muss ich mich mit low-level-i2c ja nicht befassen, die Wire lib nimmt mir den low-level-Teil ja ab).
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E


Zurück zu „textbasierte Programmiersoftware“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 40 Gäste

Lego Mindstorms EV3, NXT und RCX Forum : Haftungsauschluss