-
I2C Verständnisprobleme
Guten Abend,
hänge nun schon ein paar Tage an einem Problem fest und weiß nicht mehr weiter.
Nichtmal die Sufu und die damit gefundenen Threads konnten mir weiterhelfen :(
Hier mal mein Code:
M32
Code:
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
uint8_t data[2];
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("I2C ERROR -->TWI STATE IS: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}
int main(void){
initRP6Control();
initLCD();
I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissionError);
while(1){
clearLCD();
I2CTWI_transmitByte(10,0);
writeString_P("transmit...."); //reine Testausgabe wo die Funktion hängen bleibt
data[0] = I2CTWI_readByte(10);
writeString_P("read...."); //reine Testausgabe wo die Funktion hängen bleibt
writeIntegerLCD(data[0],DEC);
}
return 0;
}
Base
Code:
#include "RP6RobotBaseLib.h"
#include "RP6I2CslaveTWI.h"
int main(void){
initRobotBase();
I2CTWI_initSlave(10);
int8_t data = 1;
while(1){
if(I2CTWI_writeRegisters[0] && !I2CTWI_writeBusy){
I2CTWI_readRegisters[0] = data;
data++;
}
}
}
Die Master Funktion läuft leider nur bis nach "I2CTWI_transmitByte" danach gehts nicht weiter. :(
Dabei will ich eigentlich erstmal nur einen festen Wert (data) übertragen. Erst wollte ich den Wert eines Lichtsensors übertragen, da dies aber scheiterte wollte ich erstmal mit was anderem (in meinen Augen leichteren) beginnen.
Hoffe mir kann jmd helfen. :)
MfG
Ezalo
-
Hallo,
in der M32 Seite fehlt dir der Aufruf von task_I2CTWI(); in der While Loop.
Das löst das Problem jedoch nicht komplett, da für ein Befehl das task_I2CTWI(); ggf. mehrfach aufgerufen werden muss.
Orientiere dich im Schleifenaufbau mehr an den beigelegten Masterprogrammen für die M32. Und berücksichtige, das die I2CTWI
Funktionen ggf. asyncron arbeiten. Das Datum wird also ggf. nicht 100% genau dann verschickt wenn du es erwartest sondern
erst beim Aufruf von task_I2CTWI(); Zum Verständniß, die TWI Befehle bestücken eigentlich nur die Vars mit Daten, die eigentliche Ausführung stößt task_I2CTWI(); an. Zumindest bei einigen TWI Befehlen mit Leseoperationen.
LG Rolf
-
@Ezalo:
In diesem Thread:
https://www.roboternetz.de/community...-RP6-I2C/page2
... sind ein paar Beispiele für eine einfache Datenübertragung.
-
In dem von dir genannten Beispiel geht es doch aber um die Datenübertragung von Master zu Slave. Ich möchte ja aber mit dem Master die Daten vom Slave lesen :)
-
Hallo!
Ich habe leider keinen anderen Beitrag gefunden, also versuche ich es hier. Ich habe seit letzter Woche ein RP6 Control M32. Ich habe mir alle Beispiel Programme angeschaut. Jetzt möchte ich aber genau wissen, wie ich den Austausch über den I²C Bus mache.
Ich habe herausgefunden, dass folgende Aufrufe auf jedem Fall zu machen sind: (laut Beispiel 06_I2CMaster.c)
#include "RP6I2CmasterTWI.h"
I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
So, mein erstes Problem ist, wie kann ich dem Roboter auf einfache Weise "sagen", dass er auf dem Base die LED 1 anschalten soll.
Ich habe mal im Programm geschaut und festgestellt, dass in der Zeile
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, 3, counter); die LEDs angesprochen werden.
ich hoffe ihr könnt mein Problem verstehen.
Ich danke schonmal für die Hilfe
Gruß RP6fahrer
PS: vielleicht ibt es irgendwo eine zusammenfassende Befehlsliste für den I²C des RP6
-
@RP6fahrer,
das Problem ist, dass du einerseits die I2C-Befehle des RP6 kennen must (die stehen aber in der Anleitung gut beschrieben!), andererseits must du auf der Control M32 DIE Befehle senden, die das RP6Base_I2CSlave Programm kennt.
Wenn du dich damit nicht beschäftigen willst, gibt es eine gute Möglichkeit:
Du bindest in deine M32-Programme auch noch die RP6Control_I2CMasterLib (du findest sie z.B. im Beispiel Example_10_Move2) ein. In dieser Lib hat SlyD fast alle Befehle, die es auf der Base (z.B. zur LED-Ansteuerung) gibt, für die M32 zur Verfügung gestellt. Da gibt es also z.B. die Funktion updateStatusLEDs() und setRP6LEDs() (anstelle von setLEDs der Base!). Die kannst du genau so benutzen, wie auf der Base (siehe Anleitung zur Base!). Wenn du dir die Funktionen in der RP6Control_I2CMasterLib ansiehst, kannst du lernen, wie du auch ohne diese Lib mit reinen I2C-Makrobefehlen z.B. LEDs schalten kannst.
-
@rp6fahrer
Eine "Befehlsübersicht" findet sich in den .h files zu den Libs, eine funktionelle Erklärung in den Handbüchern zur Base und M32 sowie im Quellcode der gut dokumentierten Libs, Detailfragen beantwoten z.B. die Datenblätter und Fragen zu allgemeinen Zusammenhängen wie I2C das RN-Wiki. Dirk hat es auch schon angeschnitten.
Was Dir leider niemand abnehmen kann, ist dich da durch zu graben um es zu verstehen damit du es ausbauen kannst. Ich hab mir den Programmteil nicht angesehen aber da Du ja schon rausgefunden hast, das die M32 der Base offensichtlich sagen kann das LEDs geschaltet werden, musst Du ja nur noch den passenden Wert counter für das Bit LED1 raus kriegen oder? Ein Blick in eine Zahlenconversionstabelle oder bissel Hirnakrobatik sollte Auskunft geben, welches LED-Bit zu welchem counter-wert führt. In dem Fall mit LED1 wohl 0 für aus und 1 für an... für weitere LEDs werden die Bits logisch verknüpft. Alles weitere steht bei Dirk. Man kann jetzt natürlich auch die von Dirk angesprochene RP6Control_I2CMasterLib nutzen und sich bissel Schreiberei sparen aber man sollte das Prinzip verstanden haben.
LG Rolf
-
Danke für eure Antworten. Die LEDs habe ich nun unter Kontrolle. Eine Frage habe ich allerdings noch dazu: I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, 3, counter) Das erste in der Klammer ist ja die Adresse, aber was bedeutet das 2. (0) und 3.(3)? Also wenn ich die 3 ändere, dann kann ich die LEDs nicht mehr steuern. Wo kann man herausfinden, was ich eintragen muss( also bei 2. und 3.) um jetzt z.B. die Motoren zu steuern.
Bin auch schon drüber, die RP6Control_I2CMasterLib durchzuarbeiten.
Werde es noch ein bisschen studieren.
Habe auch schon ein Programm geschrieben mit dieser Library.
Es ist ein ganz einfaches Programm zum Lesen von 2 ADCs
Hier ein Auszug aus dem Code
void task_ADClesen(void)
{
writeString_P("\nADC1: ");
writeIntegerLength(adc1, DEC, 3);
setRP6LEDs(0b001001);
writeString_P("\nADC0 : ");
mSleep(500);
writeIntegerLength(adc0, DEC, 3);
setRP6LEDs(0b110110);
mSleep(500);
}
Das Problem ist, dass er mir bei dem adc 0 und adc1 immer 000 anzeigt. Obwohl dort (auf dem Base) zwei Lichtsensoren angeschlossen sind. Wisst ihr warum er mir nicht den Wert der Lichtsensoren anzeigt? Allerdings der Befehl setRP6LEDs funktioniert.
Ich danke nochmal, dass ihr mir helft. Bei mir dauerts halt leider etwas länger, bis ich es komplett verstanden habe.
MfG RP6fahrer
-
Es ist doch egal wie lang es dauert so lange Du erreichst was Du vor hast.
Zum Befehl bzw. Parameter von I2CTWI_transmit3Bytes, er hat 4 Werte, erster ist die Zieladresse des i2c Gerätes. Betrachten wir das Ziel (RP6Base_I2CSlave.c) etwas genauer. Das was da übertragen wird ist schreibend eine Befehlssequenz die der Slave entschlüsseln muss und lesend ein Register.
Schaut man im Slave bei
// Command Registers - these can be written by the Master.
// The other registers (read registers) can NOT be written to. The only way to
// communicate with the Robot is via specific commands.
// Of course you can also add more registers if you like...
und
// Command processor:
// Commands:
nach, findet man das.
#define CMD_SETLEDS 3
Die 3 sagt also dem Slave das dies ein Befehl zum setzen von LEDs ist, da was anderes zu setzen macht nur Sinn wenn die restlichen Parameter passen. Siehe auch void task_commandProcessor(void). Der Wert counter sagt welche LEDs, vergleichbar mit setLEDs.
Übrigends ist das sehr unschön programmiert, besser und lesbarer wäre:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SETLEDS, counter);
Denn ändert man aus irgendwelchen Gründen den Define Wert, fliegt einem unnötiger Weise die halbe Software um die Ohren.
Liest man jedoch Werte aus (statt bisher schreibend vom Master aus gesehen), so muss man anders vorgehen. Dazu liest man Register aus, der Slave trägt die Werte dort ein. Welche Register, das sagen die Defines:
#define I2C_REG_ADC_ADC0_L 23
#define I2C_REG_ADC_ADC0_H 24
#define I2C_REG_ADC_ADC1_L 25
#define I2C_REG_ADC_ADC1_H 26
Grundsätzlich ist es nun so, das es einen bzw. 2 Zeiger gibt, der die Leseposition in den Registern anzeigt. Dieser wird pro gelesenem Byte erhöht. Beim schreiben ist es ebenso. Dieser Pointer wird normal durch den 2. Parameter in I2CTWI_transmit3Bytes gesetzt. 0 setzt also den Zeiger auf den Anfang, 5 würde ihn auf die 5 Stelle setzen so das als nächstes das 6.te byte gelesen wird. Das Verfahren entspricht auch grundsätzlich dem Lesen und Schreiben von eeproms nur das dort weit mehr Speicherzellen ansprechbar und adressierbar sind. Nachdem das gelesene low/high byte im Master wieder richtig zusammen gesetzt wurde, hat man einen Wert. Bekommt man keinen, hat man z.B. den Zeiger nicht richtig gesetzt, überlesen oder sonst was ist schief gegangen...
Ich hoffe das erklärt grob wie der Slave arbeitet bzw. was da wie und in welche Richtung übertragen wird. Durch entsprechende Änderungen kommst du auch an die Motorsteuerung. Dann noch eine Anmerkung, das I2C arbeitet mit diesen Libs nicht unbedingt stabil, es kann daher schon mal vorkommen das die ADCs keine Werte liefern, das muss aber nicht unbedingt ein Fehler in deinem Programm sein. Bevor man die Werte aus dem i2c nutzt, sollte man sie ggf. auf Plausibilität prüfen und nicht blind in Funktionen einspeisen. Das führt nur dazu, das man sich beim debuggen nen Wolf sucht.
Wenn Du verstehen willst wie Master und Slave zusammen arbeiten, wirst Du auch in beiden Programmteilen die Abläufe studieren müssen. Die emulierten Registersets sind der Schlüssel dazwischen. Müsste aber auch so aus dem Handbuch ersichtlich sein.
LG Rolf
-
Okay, also nochmal zum ersten Teil. wenn ich z.B. I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, 1, 1) kann ich dann die PowerON LED anschalten..
Bzw. zum Empfangen mit
I2CTWI_transmitByte(I2C_RP6_BASE_ADR, 23); Es beginnt also ab Register 23
I2CTWI_readBytes(I2C_RP6_BASE_ADR,RP6data, 1); wird ADC0_L gelesen
Aber welche Funktion hat RP6data? Es ist ja nur eine Definition, also theoretisch könnte ich dort auch RP6adc dort hinschreiben.
Und wie kann ich diesen Wert anzeigen lassen? Weil da sehe ich noch nicht so durch.
Ich hoffe, ich liege einigermaßen richtig.
Oder wenn ich die RP6Control_I2CMasterLib eingefügt habe, müsste doch trotzdem über adc0 / adc1 die Werte der ADCs angezeigt werden.