PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C Verständnisprobleme



Ezalo
31.03.2011, 23:11
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

#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_transmissio nError);
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

#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

RolfD
01.04.2011, 00:35
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

Dirk
03.04.2011, 19:36
@Ezalo:
In diesem Thread:
https://www.roboternetz.de/community/showthread.php?46152-RP6-I2C/page2
... sind ein paar Beispiele für eine einfache Datenübertragung.

Ezalo
05.04.2011, 21:03
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 :)

RP6fahrer
19.04.2011, 16:56
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

Dirk
19.04.2011, 18:03
@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.

RolfD
20.04.2011, 11:43
@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

RP6fahrer
20.04.2011, 12:12
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

RolfD
20.04.2011, 14:15
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

RP6fahrer
20.04.2011, 18:12
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.

RolfD
20.04.2011, 19:08
Zu Teil 1 , richtig, so müsste das sein.
Zu Teil 2 , zum Teil richtig wobei I2CTWI_readRegisters das auch und quasi in einem Rutsch erledigen würde. Aber genau so funktionierts im Prinzip.
Da es aber einen Schreib- und einen Lesezeiger gibt, kannst du glaube ich nicht den Lesezeiger mit einer Schreiboperation setzen. Da bin ich mir aber grade sehr unsicher. Kann sein das es doch geht. Für sowas ist jedenfalls I2CTWI_readRegisters vorgesehen.

Ich muss dazu sagen, ich bin grade an einer anderen Baustelle und kann das hier grade nicht praktisch nachvollziehen - ich mach also Trockenübungen.
RP6data ist ein StringBuffer im Master... und hat mit dem Slave nur so viel zu tun als das I2CTWI_readBytes diesen mit Daten anfüllt. In deinem Fall 1 Byte.

Irgendwo später im Programm bzw. in der I2CmasterLib werden die Bytes sicher aus dem Buffer ausgelesen und in ein Byte oder 16 bit Int gewandelt.
#define meltbytes(hvar,lvar) ((hvar << 8) | lvar) // get 16bit from two 8 bit (hi/lo)
Das müsste etwa so aussehen da adc Werte 10 Bit haben, was für ein Byte zu klein wäre. Daher aufgeteilt in High und Low Byte. Wie das Kind heisst ist dabei egal so lange die Funktionen, die später den Buffer convertieren darauf zugreifen können.
Den Buffer bzw. Vars kannst du dir mit
writeString(stringbuffer);writeChar('\n');
oder
writeInteger(variable, DEC);writeChar('\n');
auf die Konsole ausgeben lassen... beim Buffer vorausgesetzt, da sind druckbare Zeichen drin... eine Ausgabe per Hex und Schleife ist ggf. praktischer
Die RP6Control_I2CMasterLib dürfte die Werte so bereit stellen wie sie auch in der Base bereit liegen. Spätestens da ist als garantiert auch besagte Wandlung zu finden.
LG Rolf

Dirk
20.04.2011, 19:21
@RP6fahrer,


... welche Funktion hat RP6data?
Das ist eine uint8_t Variable, die den Wert des/der gelesenen Register enthält. Wenn du mehrere Register liest, müßte das ein Array sein.
Wenn alle Register da rein passen sollen: uint8_t RP6data[32];
Wenn du nur 1 Register liest, kann das auch eine einfache 8-bit Variable sein oder du nimmst Var = I2CTWI_readByte(I2C_RP6_BASE_ADR);

Anzeigen: Einfach die Variable z.B. mit writeInteger() ausgeben.

Mit der RP6Control_I2CMasterLib kannst du die ADCs tatsächlich mit den Variablen adc0 / adc1 anzeigen. Neu werden die Werte aber nur angezeigt, wenn du sie mit der Funktion readAllRegisters() eingelesen hast. Diese Funktion müßtest du dann regelmäßig aufrufen.
Wenn du nicht immer alle Register der Base lesen willst, müßtest du z.B für die ADCs eine eigene Lesefunktion schreiben.
Die sieht dann so aus, wie z.B. die für die Lichtsensoren (readLightSensors), aber ohne die Ausgabe.

RP6fahrer
21.04.2011, 17:25
@Rolf
Ja, danke. Kannst dich erstmal um deine Baustelle kümmern. Ich habe da nicht so ein stress.

Also, zum Problem ADC. In meinem Programm steht das hier so:



void task_test(void)
{
I2CTWI_transmitByte(10, 23); Also hier erfolgt die Anfrage an das Register 23 von Slave(adresse 10)
uint8_t result1 = I2CTWI_readByte(10); und hier wird es eingelesen
writeString_P("\n ADC0 High : ");
writeIntegerLength(result1, DEC, 3); Und hier wird er über die serielle Schnittstelle ausgegeben.
mSleep(500);

I2CTWI_transmitByte(10, 25);
uint8_t ergebnis = I2CTWI_readByte(10);
writeString_P("\n ADC1 High : ");
writeIntegerLength(ergebnis, DEC, 3);
mSleep(500);

I2CTWI_transmitByte(10, 22);
uint8_t ergebniss = I2CTWI_readByte(10);
writeString_P("\n Batterie High : ");
writeIntegerLength(ergebniss, DEC, 3);
mSleep(500);

writeString_P(" | BAT:");writeIntegerLength(adcBat,DEC,4);
writeString_P(" | AD0:");writeIntegerLength(adc0,DEC,4);
writeString_P(" | AD1:");writeIntegerLength(adc1,DEC,4);
writeChar('\n');

}
/**
* Timed Watchdog display only - the other heartbeat function
* does not work in this example as we use blocked moving functions here.
*/
void watchDogRequest(void)
{
static uint8_t heartbeat2 = false;
if(heartbeat2)
{
clearPosLCD(0, 14, 1);
heartbeat2 = false;
}
else
{
setCursorPosLCD(0, 14);
writeStringLCD_P("#");
heartbeat2 = true;
}
}

/************************************************** ***************************/
// I2C Requests:

/**
* The I2C_requestedDataReady Event Handler
*/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}

/************************************************** ***************************/
// I2C Error handler

/**
* This function gets called automatically if there was an I2C Error like
* the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
*/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}

void I2C_requestedDataReady(uint8_t dataRequestID)
{
// We need to check if this is an INT0 Request from the Robot Base unit.
// The Function call inside the if condition returns true if it was an
// interrupt request, so we have to negate it here and if it was NOT
// an interrupt request from the Robot base we can check any other sensors
// from which you may have requested data...
if(!checkRP6Status(dataRequestID))
{
// Here you can Check other sensors/microcontrollers with their own
// request IDs - if there are any...
}
}

/************************************************** ***************************/
// Main function - The program starts here:

int main(void)
{
initRP6Control();
initLCD();

writeString_P("\n\nRP6 CONTROL M32 I2C Master Example Program!\n");
writeString_P("\nMoving...\n");

// ---------------------------------------
WDT_setRequestHandler(watchDogRequest);

// ---------------------------------------
// Init TWI Interface:
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

sound(180,80,25);
sound(220,80,25);

setLEDs(0b1111);

showScreenLCD("################", "################");
mSleep(500);
showScreenLCD("I2C-Master", "Movement...");
mSleep(1000);
setLEDs(0b0000);

WDT_setRequestHandler(watchDogRequest);

// ---------------------------------------
//I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
//writeString_P("ACS Power ist medium\n");
//mSleep(500);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, true);
writeString_P("WDT ist true\n");
mSleep(500);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT_RQ, true);
writeString_P("WDT-RQ ist true\n");
mSleep(500);
//I2CTWI_transmit3Bytes(10, 0, 6, FWD);

I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);

while(true)
{
task_I2CTWI();
task_test();

}
return 0;
}
Das Problem ist jetzt, dass der Wert diese ADC0 normal (durch Lichtsensor) 780 ist, aber über das M32 sind dass nur 230 ungefähr. mache ich da noch was falsch?
Und beu ubat zeigt er mir 000 an.
Und dann würde ich noch gern wissen wollen, was das wdt und wdt_RQ ist.
LG

Dirk
21.04.2011, 17:50
Wenn du diese 2 Funktionen benutzt, liest du adc0 und adc1 richtig ein.

void getADC0(void)
{
I2CTWI_readRegisters(I2C_RP6_BASE_ADR, I2C_REG_ADC_ADC0_L, RP6data, 2);
adc0 = RP6data[0] + (RP6data[1]<<8);
}

void getADC1(void)
{
I2CTWI_readRegisters(I2C_RP6_BASE_ADR, I2C_REG_ADC_ADC1_L, RP6data, 2);
adc1 = RP6data[0] + (RP6data[1]<<8);
}
RP6data müßtest du als uint8_t RP6data[2] deklarieren.
Für Ubat sieht die Funktion genauso aus. Der 2. Parameter in der I2C-Lesefunktion wäre dann I2C_REG_ADC_UBAT_L.

RolfD
21.04.2011, 17:50
Ich bin mir sehr sicher, das dies Übertragungsfehler verursacht durch I2C sind. Genau solche Fehler treten z.B. auch mit Remotrol auf, einer Steuersoftware für den RP6. Wenn es dich wirklich interssiert, schau mal in den Thread:
https://www.roboternetz.de/community/showthread.php?51816-Dicker-Fehler-in-der-RP6I2CmasterTWI.h-der-RP6Lib-Bugfix
LG Rolf

Dirk
21.04.2011, 18:42
Ich bin mir sehr sicher, das dies Übertragungsfehler verursacht durch I2C sind.
Bevor man das sagen kann, muss das Testprog erst mal funktionieren:
1. Von Ubat wird nur das Highbyte gelesen und das sollte zwar auch nicht 0 sein, aber das müßte man noch checken.
2. Von ADC0 und ADC1 wird nur das Lowbyte gelesen, da kann man nicht mit den direkt ermittelten 16-Bit-Werten vergleichen.

RolfD
21.04.2011, 18:50
@Dirk
Welchen Grund sollte es sonst haben das Werte bei der Übertragung ab und zu verloren gehen.. und zwar ausgerechnet die spät gelesenen Register so ca. ab pos 20?
Ausserdem funktioniert das Testprogramm schon was länger.
Is aber auch egal. Mein Bot macht was er soll...

Edit: Sorry, das war wohl ein Missverständnis zwischen mir und Dirk

Dirk
21.04.2011, 19:06
Ausserdem funktioniert das Testprogramm schon was länger.
Ich habe vom Testprog von RP6fahrer (17:25) "task_test" gesprochen.

RP6fahrer
21.04.2011, 19:12
@Dirk
Ja, dein Vorschlag hat funktioniert. Jetzt zeigt er die richtigen Werte an. Ich habe allerdings dazu noch ein paar fragen

I2CTWI_readRegisters(10, I2C_REG_ADC_ADC0_L, RP6data, 2);
adc0 = RP6data[0] + (RP6data[1]<<8);
I2CTWI_readRegisters ist der Befehl zum Lesen der Register
10 die Adresse des Slave
I2C_REG_ADC_ADC0_L das Register zum Lesen des Adc0 Registers -- Warum nicht I2C_REG_ADC_ADC0_H?
RP6data ne Variable?
2 wozu ist die gut?

RP6data[0] + (RP6data[1]<<8) und was hat das im einzelnen zu sagen?

Ich hoffe ich nerve euch nicht damit. Aber ich finde irgendwie nirgendwo eine einfache Erklärung zu den ganzen Aufrufen.

Naja, denn noch nen schönen Abend und schöne Ostern
LG RP6fahrer

Dirk
21.04.2011, 19:24
@RP6fahrer:
I2C_REG_ADC_ADC0_L ist nur eine Konstante, die ist in der RP6Control_I2CMasterLib.h als 23 definiert.
Du könntest also auch I2CTWI_readRegisters(10, 23, RP6data, 2); schreiben.

Damit liest du 2 Bytes, das erste ist der Low Wert von ADC0 (aus Register 23), der wird in RP6data[0] gespeichert.
Das 2. Byte ist der High Wert von ADC0 (aus Register 24), der wird in RP6data[1] gespeichert.

I2C_REG_ADC_ADC0_H braucht man nicht, weil das 2. Byte automatisch aus Register 24 gelesen wird, wenn man 2 Bytes einliest.

Der komplette adc0-Wert errechnet sich als: adc0 = Low Wert + (256 * High Wert), also:
adc0 = RP6data[0] + (RP6data[1] * 256);

Anstelle von *256 kann man auch achtmal nach links schieben: <<8

RP6data iat eine Variable.

RP6fahrer
21.04.2011, 19:43
Ach, danke, diesen habe ich jetzt verstanden. Also nochmals danke.
Ich werd jetzt das Wochenende noch zum einarbeiten nutzen.

Eine Frage habe ich allerdings noch: gibt es ein Buch oder sowas, wo man das noch unterstützend lernen/ verstehen kann. Oder wie habt ihr das so gut gelernt?

Na dann. Schönen Abende und schöne Ostern
LG RP6fahrer

Dirk
21.04.2011, 20:17
Hier:
http://info.baeumle-courth.eu/ansic.html
findest du ein ANSI-C Tutorial von Prof. Bäumle-Courth.

In der Anleitung zum RP6 gibt es auch eine basale Einführung in GCC und vor allem eine Beschreibung der I2C-Befehle des RP6.

Im RN-Wissen:
http://www.rn-wissen.de/index.php/C-Tutorial
findest du auch ein C-Tutorial, ähnliches auch hier:
http://www.c-programmieren.com/C-Lernen.html

RP6fahrer
23.04.2011, 11:10
Nochmals Danke, Langsam verstehe ich die Materie. Ich habe es durch eure Hilfe jetzt geschafft, dass mein Liniensensor wieder richtig funktioniert und der Roboter die Linie abfährt.
Als nächstes wollte ich eigentlich versuchen, den rp über rc5 zu steuern. Habe allerdings irgendwie Probleme dabei.
Aber für heute reichts mir dann erst mal.

Schönes Wochenende

RP6fahrer
27.04.2011, 14:14
Hallo!
Ich habe jetzt versucht, das Programm zur RC5 Steuerung umzuschreiben.
Hier mal das ganze Programm:

/************************************************** ***************************/
// Includes:

#include "RP6ControlLib.h" // The RP6 Control Library.
// Always needs to be included!

#include "RP6I2CmasterTWI.h" // I2C Master Library

#include "RP6Control_I2CMasterLib RC.h"


/************************************************** ***************************/

#define I2C_RP6_BASE_ADR 10 // The default address of the Slave Controller
// on the RP6 Mainboard

/************************************************** ***************************/
/************************************************** ***************************/


// If you only want to look at the RC5 Keycodes received from the Remote
// Control, uncomment this line:
#define DO_NOT_MOVE
// The RP6 will not move then!



/************************************************** ***************************/

// These are the same command definitions as you can find them in the
// I2C Bus Slave Example program for RP6Base:

#define I2C_REG_STATUS1 0
#define I2C_REG_STATUS2 1
#define I2C_REG_MOTION_STATUS 2
#define I2C_REG_POWER_LEFT 3
#define I2C_REG_POWER_RIGHT 4
#define I2C_REG_SPEED_LEFT 5
#define I2C_REG_SPEED_RIGHT 6
#define I2C_REG_DES_SPEED_LEFT 7
#define I2C_REG_DES_SPEED_RIGHT 8
#define I2C_REG_DIST_LEFT_L 9
#define I2C_REG_DIST_LEFT_H 10
#define I2C_REG_DIST_RIGHT_L 11
#define I2C_REG_DIST_RIGHT_H 12
#define I2C_REG_ADC_LSL_L 13
#define I2C_REG_ADC_LSL_H 14
#define I2C_REG_ADC_LSR_L 15
#define I2C_REG_ADC_LSR_H 16
#define I2C_REG_ADC_MOTOR_CURL_L 17
#define I2C_REG_ADC_MOTOR_CURL_H 18
#define I2C_REG_ADC_MOTOR_CURR_L 19
#define I2C_REG_ADC_MOTOR_CURR_H 20
#define I2C_REG_ADC_UBAT_L 21
#define I2C_REG_ADC_UBAT_H 22
#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
#define I2C_REG_RC5_ADR 27
#define I2C_REG_RC5_DATA 28
#define I2C_REG_LEDS 29

#define CMD_POWER_OFF 0
#define CMD_POWER_ON 1
#define CMD_CONFIG 2
#define CMD_SETLEDS 3
#define CMD_STOP 4
#define CMD_MOVE_AT_SPEED 5
#define CMD_CHANGE_DIR 6
#define CMD_MOVE 7
#define CMD_ROTATE 8
#define CMD_SET_ACS_POWER 9
#define CMD_SEND_RC5 10
#define CMD_SET_WDT 11
#define CMD_SET_WDT_RQ 12

#define ACS_PWR_OFF 0
#define ACS_PWR_LOW 1
#define ACS_PWR_MED 2
#define ACS_PWR_HIGH 3

/************************************************** *************************/
//Einige Definitionen:
#define RC_RFT

#ifdef RC_RFT // RC Type: RFT Videorecorder Fernbedienung
#define RC5_KEY_LEFT 4
#define RC5_KEY_RIGHT 6
#define RC5_KEY_FORWARDS 2
#define RC5_KEY_BACKWARDS 8
#define RC5_KEY_STOP 12
#define RC5_KEY_CURVE_LEFT 1
#define RC5_KEY_CURVE_RIGHT 3
#define RC5_KEY_CURVE_BACK_LEFT 7
#define RC5_KEY_CURVE_BACK_RIGHT 9
#define RC5_KEY_LEFT_MOTOR_FWD 10
#define RC5_KEY_LEFT_MOTOR_BWD 29
#define RC5_KEY_RIGHT_MOTOR_FWD 62
#define RC5_KEY_RIGHT_MOTOR_BWD 13
#define RC5_KEY_Lighton 32
#define RC5_KEY_Lightoff 33

#endif
/************************************************** ***************************/
uint8_t light = 0;

// Speed values:

#define MAX_SPEED_MOVE 200
#define MAX_SPEED_TURN 100

#define MAX_SPEED_CURVE 120
#define MAX_SPEED_CURVE2 40
#define ACCELERATE_CURVE 10
#define ACCELERATE_CURVE2 4
#define DECELERATE_CURVE 4
#define DECELERATE_CURVE2 2

#define MAX_SPEED_1_MOTOR 120

#define ACCELERATE_VALUE 8
#define DECELERATE_VALUE 4

uint8_t max_speed_left; // Maximum speed variable left
uint8_t max_speed_right; // Maximum speed variable right
uint8_t acl_left;
uint8_t acl_right;
uint8_t decl_left;
uint8_t decl_right;

/************************************************** ***************************/

/**
* Just a small helper function to set speed params.
*/
void setDefaultSpeedParameters(void)
{
max_speed_left = MAX_SPEED_MOVE;
max_speed_right = max_speed_left;
acl_left = ACCELERATE_VALUE;
acl_right = ACCELERATE_VALUE;
decl_left = DECELERATE_VALUE;
decl_right = DECELERATE_VALUE;
uint16_t tmp = (getDesSpeedLeft() + getDesSpeedRight())/2;
moveAtSpeed(tmp , tmp);
}

/************************************************** ***************************/
// Einige uint8_t:
uint8_t rc5;
uint8_t dir = 0;
uint8_t runLEDs = 1;


/************************************************** ***************************/
void receiveRC5Data(RC5data_t rc5data)
{
// Output the received data:
writeString_P("RC5 Reception Toggle Bit:");
writeChar(rc5data.toggle_bit + '0');
writeString_P(" | Device Address:");
writeInteger(rc5data.device, DEC);
writeString_P(" | Key Code:");
writeInteger(rc5data.key_code, DEC);
rc5 = rc5data.key_code;
writeChar('\n');


#ifndef DO_NOT_MOVE // used to disable movement if you want to
// look at the received RC5 codes only (s. above).

uint8_t movement_command = false; // used to store if we have received
// a movement command.
// Any other key is ignored!

// Check which key is pressed:
switch(rc5data.key_code)
{

case RC5_KEY_Lightoff: // Licht aus:
writeString_P("Licht Aus\n");
light = 0;
setRP6LEDs(0b011000);
break;
case RC5_KEY_Lighton: // Licht an:
writeString_P("Licht\n");
light = 1;
setRP6LEDs(0b111111);
break;
case RC5_KEY_LEFT: // Turn left:
writeString_P("LEFT\n");
setDefaultSpeedParameters();
max_speed_left = MAX_SPEED_TURN;
max_speed_right = max_speed_left;
changeDirection(LEFT);
setRP6LEDs(0b100000);
movement_command = true; // Store that we have received a movement command!
break;
case RC5_KEY_RIGHT: // Turn right:
writeString_P("RIGHT\n");
setDefaultSpeedParameters();
max_speed_left = MAX_SPEED_TURN;
max_speed_right = max_speed_left;
changeDirection(RIGHT);
setRP6LEDs(0b000100);
movement_command = true;
break;
case RC5_KEY_FORWARDS: // Move forwards
writeString_P("FORWARDS\n");
setDefaultSpeedParameters();
changeDirection(FWD);
setRP6LEDs(0b100100);
movement_command = true;
break;
case RC5_KEY_BACKWARDS: // Move backwards
writeString_P("BACKWARDS\n");
setDefaultSpeedParameters();
changeDirection(BWD);
setRP6LEDs(0b001001);
movement_command = true;
break;
case RC5_KEY_STOP: // Stop!
writeString_P("STOP\n");
max_speed_left = 0;
max_speed_right = max_speed_left;
moveAtSpeed(0,0);
setRP6LEDs(0b011011);
movement_command = true;
break;
case RC5_KEY_CURVE_LEFT: // Drive curve left - forwards
writeString_P("CURVE LEFT FWD\n");
max_speed_left = MAX_SPEED_CURVE2;
max_speed_right = MAX_SPEED_CURVE;
acl_left = ACCELERATE_CURVE2;
acl_right = ACCELERATE_CURVE;
decl_left = DECELERATE_CURVE2;
decl_right = DECELERATE_CURVE;
changeDirection(FWD);
setRP6LEDs(0b110100);
movement_command = true;
break;
case RC5_KEY_CURVE_RIGHT: // Drive curve right - forwards
writeString_P("CURVE RIGHT FWD\n");
max_speed_left = MAX_SPEED_CURVE;
max_speed_right = MAX_SPEED_CURVE2;
acl_left = ACCELERATE_CURVE;
acl_right = ACCELERATE_CURVE2;
decl_left = DECELERATE_CURVE;
decl_right = DECELERATE_CURVE2;
changeDirection(FWD);
setRP6LEDs(0b100110);
movement_command = true;
break;
case RC5_KEY_CURVE_BACK_LEFT: // Drive curve left - backwards
writeString_P("CURVE LEFT BWD\n");
max_speed_left = MAX_SPEED_CURVE2;
max_speed_right = MAX_SPEED_CURVE;
acl_left = ACCELERATE_CURVE2;
acl_right = ACCELERATE_CURVE;
decl_left = DECELERATE_CURVE2;
decl_right = DECELERATE_CURVE;
changeDirection(BWD);
setRP6LEDs(0b011001);
movement_command = true;
break;
case RC5_KEY_CURVE_BACK_RIGHT: // Drive curve right - backwards
writeString_P("CURVE RIGHT BWD\n");
max_speed_left = MAX_SPEED_CURVE;
max_speed_right = MAX_SPEED_CURVE2;
acl_left = ACCELERATE_CURVE;
acl_right = ACCELERATE_CURVE2;
decl_left = DECELERATE_CURVE;
decl_right = DECELERATE_CURVE2;
changeDirection(BWD);
setRP6LEDs(0b001011);
movement_command = true;
break;
case RC5_KEY_LEFT_MOTOR_FWD: // Only left motor on - forwards
writeString_P("MOTOR LEFT FWD\n");
max_speed_left = 0;
max_speed_right = MAX_SPEED_1_MOTOR;
acl_left = 4;
acl_right = 4;
decl_left = 4;
decl_right = 4;
changeDirection(FWD);
setRP6LEDs(0b110000);
movement_command = true;
break;
case RC5_KEY_LEFT_MOTOR_BWD: // Only left motor on - backwards
writeString_P("MOTOR LEFT BWD\n");
max_speed_left = 0;
max_speed_right = MAX_SPEED_1_MOTOR;
acl_left = 4;
acl_right = 4;
decl_left = 4;
decl_right = 4;
changeDirection(BWD);
setRP6LEDs(0b101000);
movement_command = true;
break;
case RC5_KEY_RIGHT_MOTOR_FWD: // Only right motor on - forwards
writeString_P("MOTOR RIGHT FWD\n");
max_speed_left = MAX_SPEED_1_MOTOR;
max_speed_right = 0;
acl_left = 4;
acl_right = 4;
decl_left = 4;
decl_right = 4;
changeDirection(FWD);
setRP6LEDs(0b000110);
movement_command = true;
break;
case RC5_KEY_RIGHT_MOTOR_BWD: // Only right motor on - backwards
writeString_P("MOTOR RIGHT BWD\n");
max_speed_left = MAX_SPEED_1_MOTOR;
max_speed_right = 0;
acl_left = 4;
acl_right = 4;
decl_left = 4;
decl_right = 4;
changeDirection(BWD);
setRP6LEDs(0b000101);
movement_command = true;
break;
}

if(movement_command) // Did we receive a move command?
{
// Accelerate if neccessary:
if(getDesSpeedLeft() < max_speed_left) // If we have not reached the left maximum speed...
{ // ... accelerate!
moveAtSpeed(getDesSpeedLeft()+acl_left, getDesSpeedRight());
if(getDesSpeedLeft() < 10)
moveAtSpeed(10, getDesSpeedRight());
}
if(getDesSpeedRight() < max_speed_right) // If we have not reached the right maximum speed...
{
// ... accelerate!
moveAtSpeed(getDesSpeedLeft(), getDesSpeedRight()+acl_right);
if(getDesSpeedRight() < 10)
moveAtSpeed(getDesSpeedLeft(), 10);
}

// Start Stopwatch 2 - it starts decceleration after 250ms of no RC5 reception! (s. below)
setStopwatch2(0);
startStopwatch2();
}
#endif

}


/************************************************** ******************************/
void deccelerate(void)
{
if(getStopwatch2() > 250) // After 250ms with no reception...
{
if(getDesSpeedLeft() <= 10) // If left speed is less or equal than 10...
moveAtSpeed(0, getDesSpeedRight()); // ... stop the left motor
else // Otherwise continue to deccelerate:
moveAtSpeed(getDesSpeedLeft()-decl_left, getDesSpeedRight());

if(getDesSpeedRight() <= 10) // If right speed is less or equal than 10...
moveAtSpeed(getDesSpeedLeft(), 0); // ... stop the right motor
else // Otherwise continue to deccelerate:
moveAtSpeed(getDesSpeedLeft(), getDesSpeedRight()-decl_right);

if (getDesSpeedRight() == 0 && getDesSpeedLeft() == 0)
stopStopwatch2(); // Decceleration has finished!

max_speed_left = getDesSpeedLeft(); // Update max_speed value
max_speed_right = getDesSpeedRight(); // Update max_speed value
setRP6LEDs(0b000000); // and clear LEDs
setStopwatch2(0);
}

// Make sure we don't move after Direction has changed and key is released too fast.
// This prevents the RP6 from moving when the direction has just changed and temporary saved
// speed value is written back again in the task_motionControl function.
if(getDesSpeedLeft() > max_speed_left)
{
if(getDesSpeedLeft() <= 10) // If left speed is less or equal than 10...
moveAtSpeed(0, getDesSpeedRight()); // ... stop the left motor
else // decelerate:
moveAtSpeed(getDesSpeedLeft()-decl_left, getDesSpeedRight());
}
if(getDesSpeedRight() > max_speed_right)
{
if(getDesSpeedRight() <= 10) // If right speed is less or equal than 10...
moveAtSpeed(getDesSpeedLeft(), 0); // ... stop the right motor
else // decelerate:
moveAtSpeed(getDesSpeedLeft(), getDesSpeedRight()-decl_right);
}
}


/************************************************** ******************************/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
// We need to check if this is an INT0 Request from the Robot Base unit.
// The Function call inside the if condition returns true if it was an
// interrupt request, so we have to negate it here and if it was NOT
// an interrupt request from the Robot base we can check any other sensors
// from which you may have requested data...
if(!checkRP6Status(dataRequestID))
{
// Here you can Check other sensors/microcontrollers with their own
// request IDs - if there are any...
}
}
/************************************************** ***************************/
void task_LCDHeartbeat(void)
{
static uint8_t heartbeat = false;
if(getStopwatch1() > 500)
{
if(heartbeat)
{
clearPosLCD(0, 15, 1);
heartbeat = false;
}
else
{
setCursorPosLCD(0, 15);
writeStringLCD_P("*");
heartbeat = true;
}
setStopwatch1(0);
}
}

/************************************************** ***************************/
// I2C Error handler

/**
* This function gets called automatically if there was an I2C Error like
* the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
* The most common mistakes are:
* - using the wrong address for the slave
* - slave not active or not connected to the I2C-Bus
* - too fast requests for a slower slave
* Be sure to check this if you get I2C errors!
*/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}
/************************************************** **************************/
void task_lauflicht(void)
{
if(getStopwatch4() > 100)
{
setLEDs(runLEDs);
if(dir == 0)
runLEDs <<= 1;
else
runLEDs >>= 1;

if(runLEDs > 7 )
dir = 1;
else if (runLEDs < 2 )
dir = 0;
setStopwatch4(0);
}

}
/************************************************** ***************************/


/************************************************** ***************************/
// Main function - The program starts here:

int main(void)
{
initRP6Control(); // Always call this first! The Processor will not work
// correctly otherwise.

initLCD();

writeString_P("\n\nRP6 CONTROL M32 I2C Master Beispiel Programm!\n");
writeString_P("\nInterrupts und RC5 Steuerung\n");

// IMPORTANT:
I2CTWI_initMaster(100); // Initialize the TWI Module for Master operation
// with 100kHz SCL Frequency

// Also very important in this example:
// Register the event handlers:
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
IRCOMM_setRC5DataReadyHandler(receiveRC5Data);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);

sound(180,80,25);
sound(220,80,25);

setLEDs(0b1111);

showScreenLCD("################", "################");
mSleep(500);
showScreenLCD("I2C-Master", "Example Program 2");
mSleep(1000);
setLEDs(0b0000);
showScreenLCD("ACS Status:", "");

// ---------------------------------------

// Set ACS to medium power:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
// Enable Software Watchdog timer on Slave:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, true);
// (This timer stops all operations of the Slave if the Master Controller
// does not react on interrupt requests after a few seconds. This can
// prevent damage if the Master controller locks up but the Slave has still
// the order to drive at high speed... it would maybe crash against a wall
// at high speeds or worser things... )

// ---------------------------------------

startStopwatch1(); // For LCDHeartbeat function
startStopwatch4(); // Für Lauflicht

while(true)
{
// You need to call task_I2CTWI frequently out of the
// main loop - otherwise the I2C Bus request functions don't work.
task_checkINT0();
deccelerate(); // Call the deceleration function.

//test();
task_I2CTWI();
task_LCDHeartbeat();
task_lauflicht();
}
return 0;
}

Ich habe das schritt für schritt aufgebaut, und jeweils immer probiert. Das Resultat ist, dass er schon auf die verschiedenen Tasten reagiert, allerdings das fahren klappt überhaupt nicht. Er steuert immer nur kurz den den rechten Motor an (Speed ungefähr 10), aber das beschleunigen klappt überhaupt nicht. Ich hoffe, ihr könnt mir auch hierbei helfen.
Meine Vermutung ist ja, dass die Übertragung des I2C zu lange dauert und der Motor sozusagen auf 10 springt, abfällt, auf 10 springt, usw. Kann man das vielleicht beheben.
Vielen Dank
MfG RP6fahrer

RP6fahrer
01.05.2011, 18:06
Okay. Problem hat sich geklärt. Es funktioniert jetzt fast einwandfrei.
Also nochmal vielen dank für Eure Hilfe !