auslesen von slave device

Hallo und zwar möchte ich die register vom slave auslesen, in dene ich vom arduino aus die parameter sende.
Hab es mit requestfrom(int adr, int byteanzahl), doch es geht nicht, weil ich bekomme meine adr vom slave als byte die ich von der sd karte auslese. Wie kann ich das machen, dass ich den parameter int adr, variabel halte?

bzw wie kann ich von dem Slave etwas auslesen(also vom code her)? Hier noch das Datenblatt zu dem Maxim 16826

MAX16826.pdf (233 KB)

MAX16826EVKIT.pdf (601 KB)

requestfrom ((int)byteadress, XYZ)

Also beim Aufruf der Methode den benötigten Datentypen in Klammer davor stellen. "byte" ist ein "unsigned int" mit lediglich 8 Bit Adressraum - und somit aufwärtskompatibel.

ok danke werde es versuchen, wie meinst du aufwärtskompatibel (8 bit)?
und die fuction requestfrom(), regelt das alles mit dem Start /Stoppbit der an dem Slave gesendet wird?

Mit "aufwärtskompatibel" meine ich, dass eine 8-Bit Ganzzahl problemlos in einen 16-Bit Ganzzahlendatentyp hereinpasst, andersherum allerdings nicht.

Ok danke dir ist verstanden :D.

zu der Funktion requestfrom(adr,byteanzahl). Wenn ich in einem register einen Wert schreibe für i2c, dann ist der jeweils immer 1 byte, d.h. um diesen auszulesen, reicht, wenn ich doch als byteanzahl 1 agebe oder? weil wenn der nächste befehl eingetragen wird, wird doch der vorherige überschrieben oder täusche ich mich?

requestFrom() gibt ja nicht direkt die Daten zurück. Es werden nur die Daten angefordert (oder in einen Puffer geschrieben?). Um diese dann zu lesen musst du read() machen. Du kannst also mehr Daten anfordern und dann mehrmals read() machen. Dabei wird der Device-interne Adress-Pointer nach jedem Zugriff automatisch inkrementiert.

Hier z.B. aus einer RTC lib (gekürzt, aber funktionsfähig):

void DS1307RTC::getRAM(uint8_t rtc_addr, uint8_t* data, int size)
{
  Wire.beginTransmission(DS1307_CTRL_ID);
  Wire.write(rtc_addr); 
  Wire.endTransmission();

  Wire.requestFrom(DS1307_CTRL_ID, size);

  for(int i=0; i < size; i++)
  {
	  data[i] = Wire.read();
  }
}

Hierbei ist DS1307_CTRL_ID die Device-Adresse und rtc_addr das erste Register, das man auslesen will.

Du kannst auch mit available() abfragen wieviel Daten tatsächlich ausgelesen werden können.

ok danke dir. eine frage ind zwar wenn ich zb in dem register drei den wert 0aH schreibe und danach den wert 0BH wird doch der erste überschrieben , theoretisch müsste mir ein byte als size reichen oder täusche ich mich?

Ja. Das hängt davon ab wie viele Register dein Device hat und wie viele Daten du auf einmal auslesen willst. Ein Byte reicht um 255 Register zu adressieren. Wenn du immer nur ein Byte auf einmal auslesen willst reicht natürlich size = 1. Aber du könntest auch die Status-Register für alle 4 LEDs auf einmal lesen.

Bei dem RTC Beispiel oben, würde ein byte/uint8_t reichen, da die RTC nur 56 Byte RAM hat. Aber praktisch macht es hier eigentlich keinen Unterschied. Ein int hat auch nur 2 Byte. Ist also nicht so als ob da groß Speicher verschwendet würde.

EDIT: Sowie ich Seite 19 des Datenblatts verstehe läuft das bei deinem Ding genauso ab. Erst wird die Slave-Adresse und das Write-Bit geschickt (beginTransmission). Dann wird das Register adressiert (Command Byte mit write() schicken) und dann wird nochmal die Slave-Adresse geschickt, aber mit Read-Bit (requestFrom). Danach wird gelesen (read).

Um das nochmal klar zu machen: Der Device hat intern einen Pointer auf ein Register. Nach jedem read() oder write() wird dieser automatisch erhöht. Man gibt also nur die Start-Adresse an. Wenn man danach mehrmals etwas schreibt wird dieses immer in das nächste Register geschrieben (oder ausgelesen bei read()). Wenn du mehrmals auf das gleiche Register zugreifen willst, musst du jedes mal die Start-Adresse neu angeben.

Ok danke sehr :D. Ich mache es über die gui, d.h. da teil ich ihm mit, in welchem register ich die daten sende.
D.h. anhand der eingabe der Adresse, springt der pointer zu der übertragenden Adresse?
Und dann wird der wert mit dem neuen wert überschrieben?

So nun nehmen wir mal an, ich schreibe einaml in register 4 was und dann in register 1, geht das so einfach wie oben um die werte auszulesen oder eher nicht?

So nun habe ich die funktion , die die werte in den registern schreibt, wollte auch , dass er gleichzeitig dann bei schrieben das ausliset ud über serial ausgibt.

also wäre das obige beispiel für mich andwendbar?-> doch das was mir noch unklar ist, ist, ob ein byte für die requestfrom() reicht ? oder ob ich mehr brauche, sorry das verstehe ich noch nicht so :frowning:

So nun nehmen wir mal an, ich schreibe einaml in register 4 was und dann in register 1, geht das so einfach wie oben um die werte auszulesen oder eher nicht?

Wenn du die Methode zweimal aufrufst, ja. 100%ig sicher bin ich mir aber nicht. Der Code hier ist von einer RTC, aber laut deinem Datenblatt scheint die Prozedur gleich zu sein. Musst du ausprobieren. Aber selbst wenn es nicht gleich geht bist du damit schonmal auf dem richtigen Weg.

doch das was mir noch unklar ist, ist, ob ein byte für die requestfrom() reicht

Wenn du nur ein Register lesen willst geht das natürlich auch so:

uint8_t getData(uint8_t addr)
{
  Wire.beginTransmission(deviceAddress);
  Wire.write(addr);            // hier wird die Adresse des zu lesenden Registers gesetzt
  Wire.endTransmission();

  Wire.requestFrom(deviceAddress, 1); // 1 Byte anfordern

  return Wire.read();   // einmal lesen
}

Oder Schreiben:

void setData(uint8_t addr, uint8_t data)
{
  Wire.beginTransmission(deviceAddress);
  Wire.write(addr);
  
  Wire.write(data);

  Wire.endTransmission();
}

oder ob ich mehr brauche, sorry das verstehe ich noch nicht so

Das hängt nur davon ob, wie du das machen willst. Es bietet sich vielleicht an die Register für die 4 LED-Reihen auf einmal auszulesen. Das musst du aber nicht. Du kannst natürlich auch 4 getrennte Zugriffe machen, wenn das bei deiner Anwendung sinnvoller ist oder du es so magst.

Wenn man es auf einmal macht kann man das in zwei Zeilen so tun:

uint8_t data[] = { wert1, wert2, wert3, wert4 };
writeData(0, data, 4);

Oder zum Auslesen:

uint8_t data[4];
readData(0, data, 4);

Das aber beides mit dem ersten Code-Beispiel wo data ein Pointer auf byte ist und man das read/write in einer for-Schleife bis size macht.

Was man auch zusätzlich machen kann ist sowas:

  Wire.write(data);

  if (Wire.endTransmission() != 0) 
  {
    return false;
  }
  return true;

oder fürs lesen nach requestFrom():

  if(Wire.available() < 1) 
	  return false;

  data* = Wire.read();
  return true;

Dann hat man eine Bestätigung ob der Zugriff erfolgreich war. Braucht aber einen bool as return-Wert. Also muss bei getData wie im ersten Beispiel oben ein Pointer auf "data" übergeben werden. Wenn es ohne das funktioniert kannst du es weglassen, aber es ist vielleicht hilfreich falls es nicht geht.

D.h. anhand der eingabe der Adresse, springt der pointer zu der übertragenden Adresse? Und dann wird der wert mit dem neuen wert überschrieben?

Ja. Steht so im Datenblatt, Seite 19:

"The command is interpreted as the destination address (register file unit) and data is written in the addressed location. [...] If the address
is correct, the data byte is written to the addressed register. After the write, the internal address pointer is increased by one."

Den ganzen Kram mit ACK/NACK Bits und Start/Stop conditions kannst du ignorieren. Das macht Wire im Hintergrund. Aber die Reihenfolge für die Kommandos ist klar angegeben.

danke sehr für deine Mühe, mir das alles zu erklären :D.
Ich werde mich morgen dransetzen und es testen, melde mich um dir mal ein feedback zu geben . :smiley:

HI hab das mal ausprobiert und zwar sende ich zu register 4 eine 7f und lese es aus bekomme aber keine 7f sondern, 4e, 4f oder 50 .
Das verstehe ich nicht, warum bekomme ich nicht die 7 f?

Hast du mal probiert die Register direkt nach dem Reset auszulesen. Laut Datenblatt sollen die auf "0" initialisiert sein. Geht das?

Wie meinst du das , einfach mal meinen arduino reseten?

Wo steht das?
Ich hatte es so programiert, dass ich einen vereinzelten befehl an den register sende und diesen sofrt danach wieder auslese .
DIe stromregister 0-3 naja lassen sichh gut auslesen, kommt auch deas was ich sende aber bei register 4 nicht

Zum Beispiel. Ich meinte halt gleich mal auslesen bevor man was reinschreibt.

Aber, es handelt sich hierbei um ein 7-Bit Register!

"Adjustment of the switching regulator output. This isused for adaptive voltage optimization to improve overall efficiency. The switching regulator output is downward adjustable by changing its reference voltage. This uses a 7-bit register."

Das ist auch bei 0-3 und 9 so. Da musst du also eventuell das höchste Bit ausmaskieren. Das Ergebnis einmal mit 0x7F verunden. z.B:

return Wire.read() & 0x7F;

Weiß nicht ob das einen Unterschied macht

hmm ja das ist die range von 6:0) aber gibt es geine allgemine lösung für alle devices? was ist wen ich ein anderes device auslesne möchte?

Ja mit dem ausmaskieren, soll ich es einfach mit 0000 0000 verunden?

Das kann man auch nach dem Funktions-Aufruf machen. Verundung mit 0x00 würde alles auf 0 setzten. Mit 0x7F setzt er das höchste Bit auf 0. Ich weiß aber nicht ob das wirklich nötig ist. Theoretisch sollte er das 7. Bit einfach ignorieren. Außerdem schwankt dein Ergebnis auch nicht da sondern im LSB.

Oder ist es möglich, dass der Schaltregler-Wert von selbst etwas schwankt? Ist das nur in diesem Register? Weil so wie du das schreibst sind die 3 Werte nur jedes mal inkrementiert.

leider klappt es nicht :frowning: habe folgendes gemachr vlaue =Wire.read().
Ja jetztt wenn der baustein deaktiviert ist gibt er ff aus und wenn er aktiviert ist 0. verstehe nichts mehr :frowning:

Wire.read() geht ja für sich alleine nicht.

Stimmt deine Device-Adresse? Laut Datenblatt 0x58 für 7-Bit

Machst du auch "Wire.begin()" in setup()?

ja also device adresse stimmt. und mein wire.begin habe ich immer in meinen funktionen, die für das i2c sind nicht i n dem setup.