PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I²C Bus - Erklärung zu I2CTWI_transmit3Bytes



aircode
03.12.2009, 21:15
Hi Leute,

die Funktion I2CTWI_transmitByte verstehe ich ja grundsätzlich... einfach 1 Byte an eine Adresse senden...

die Funktion I2CTWI_transmit3Bytes verstehe ich demnach ja auch... nur steht ja in der Anleitung, dass hier Daten im Format "Slave Adresse – Kommandoregister – Kommando – Parameter1" gesendet werden.

Kann mir das bitte jmd genauer erklären! (Slave Adresse ist mir übrigens klar :-))

Nur wie kann man sich etwas unter Kommandoregister, Kommando & Parameter1 vorstellen? Könnte man das in einer Excel-Tabelle darstellen!?

P.S.: RP6_Manuel Seite 108

THX

radbruch
03.12.2009, 21:43
Hallo

Der 3-Byte-Befehl sendet natürlich auch nur drei Bytes an einen Slave. Wie diese Bytes gedeutet werden hängt vom Aufbau des Protokolls ab. Viele I2C-Bausteine besitzen intern verschiedene Register die man mit Werten füllen muss. Deshalb steht in meiner RP6-Anleitung (vom 17.7.07) auf Seite 107 folgendes:

Diese Funktion braucht man häufig, denn viele I²C Geräte erwarten die Daten im Format:
Slave Adresse – Registeradresse – Daten

void I2CTWI_transmit3Bytes(uint8_t adr, uint8_t data1, uint8_t data2, uint8_t data3)

Alles klar?

Gruß

mic

aircode
03.12.2009, 22:10
Danke mal für den ersten Hilfeversuch...

Dass der Befehl auch nur 3 Bytes sendet war mir auch klar... aber was bedeutet das in meinem Beispiel? Ich verwende das RP6 Controll M32 als Master und das RP6 Robot Base als Slave.

Habe an den Libs auch nix geändert... also alles "Auslieferungszustand".

Geladen hab ich in den Master das Beispielprogramm "RP6Control_06_I2CMaster"...

Und unklar ist mir die Zeile 204 -> I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, 3, counter);

Also schreibt der Master in meinem Beispiel bei Tastendruck als erstes eine
eine 1 in das Komandoregister 0, Kommando 3 auf Paramter 1.

Beim nächsten Tastendruck eine 2 in das Komandoregister 0, Kommando 3 auf Paramter 1... usw...

Und um auf meine Frage zurückzukommen,... ich verstehe noch
immer niocht was in mienem Fall Komando Register bzw. Komando bedeutet - sorry

aircode
03.12.2009, 22:45
oder probieren wir es mal anders: kann mir jemand den code so umschreiben, dass ich ihn auf das Erweiterungsboard spiele... am RP6 Basis möchte ich die mitgelieferte "RP6Base_I2CSlave"-Datei verwenden!

Vielleicht würde ich mir an Hand eines Beispiels leichter tun!?



// ************************************************** *************************************
//
// Steuerbar sind:

// - LED an ADC1 - "einfache Helligkeitssteuerung" über eine Fernbedienung
//
// ---------------------------
//
// Stand: 03.12.2009
//
// ************************************************** *************************************


#include "RP6RobotBaseLib.h"

uint8_t led_rechts_high = 20; // ADC1 20ms auf high
uint8_t led_rechts_low = 20; // ADC1 20ms auf low

void receiveRC5Data (RC5data_t rc5data)
{

switch (rc5data.key_code)
{

// LED auf ADC1 heller oder dünkler

case 10:
if (led_rechts_high < 40)
{
led_rechts_high++;
led_rechts_low--;
}
break;

case 62:
if (led_rechts_high > 0)
{
led_rechts_high--;
led_rechts_low++;
}
break;

}

}


void led_rechts (void)
{
PORTA |= ADC1; // ADC1 auf High setzen
sleep(led_rechts_high);
PORTA &=~ADC1; // ADC1 auf Low setzen
sleep(led_rechts_low);
}


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


int main(void)
{

initRobotBase(); // AVR Microcontroller initialisieren
powerON(); // ACS, IRCOMM und Motorregelung einschalten

IRCOMM_setRC5DataReadyHandler(receiveRC5Data); // Event Handler für IRCOMM starten

DDRA |= ADC1; // ADC1 als Ausgang definieren


while(true)
{
task_RP6System();
led_rechts();
}
return 0;
}


THX

radbruch
03.12.2009, 23:20
Hallo

Ich bin mir nicht ganz sicher ob ich dein Problem verstanden habe. Du willst eine LED am ADC1-Pin der Base dimmen und den PWM-Wert dafür vom M32 per I²C senden? Dann initialisierst du die Base als Slave, sendest mit dem M32 ein Byte das die Base einließt und zur LED weiterleitet:
void I2CTWI_transmitByte(uint8_t adr, uint8_t helligkeit)

Bei einer zusätzlichen LED an ADC0 könnte man nun ein zweites Byte übertragen das die entsprechende LED kennzeichnet:
void I2CTWI_transmit2Bytes(uint8_t adr, uint8_t led_nummer, uint8_t helligkeit)

Und nun wollen wird die LEDs noch zusätzlich mit 1 Hz blinken lassen:
void I2CTWI_transmit3Bytes(uint8_t adr, uint8_t led_nummer, uint8_t helligkeit, uint8_t blinken_1hz)

Nun haben led_nummer, helligkeit und blinken_1hz für uns einen Sinn, für I²C sind es aber weiterhin normale Bytes. Wir hätten sie natürlich auch Kommandoregister, Kommando oder Parameter nennen können.

Oje, es wird leider nicht besser...

Gruß

mic

aircode
04.12.2009, 16:49
1. Du liegst mit deiner Annahme richtig (Led soll gedimmt werden über PWM, usw...)

2. Danke für deinen Denkansatz - komme schön langsam dahinter wie's geht und habe deshalb mal versucht ein ganz einfaches Programm zu schreiben, welches den I2C Bus verwendet - im Grunde genommen ist ja eh nix dabei... verstehen muss man's nur einmal ;-)

3. Also, der Master-Code sieht so aus:


#include "RP6ControlLib.h"

#include "RP6I2CmasterTWI.h"

void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}

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

int main(void)
{
initRP6Control();

initLCD();

I2CTWI_initMaster(100);

I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

uint8_t adresse = 10;
uint8_t data1_master = 0;
uint8_t data2_master = 50;
uint8_t data3_master = 80;

while(true)
{
uint8_t key = checkReleasedKeyEvent();

if(key)
{
switch(key)
{
case 1:
I2CTWI_transmit3Bytes(adresse, data1_master, data2_master, data3_master);
break;
}
}
}
return 0;
}

Der Slave-Code so:


#include "RP6RobotBaseLib.h"
#include "RP6I2CslaveTWI.h"

int main(void)
{
initRobotBase();
I2CTWI_initSlave(10);
powerON();

uint8_t data1_slave;
uint8_t data2_slave;
uint8_t data3_slave;


while(true)
{
if(I2CTWI_writeRegisters[0] && !I2CTWI_writeBusy)
{
data1_slave = I2CTWI_writeRegisters[0];
data2_slave = I2CTWI_writeRegisters[1];
data3_slave = I2CTWI_writeRegisters[2];

writeString_P("data1_slave: ");writeInteger(data1_slave, DEC);writeChar('\n');
writeString_P("data2_slave: ");writeInteger(data2_slave, DEC);writeChar('\n');
writeString_P("data3_slave: ");writeInteger(data3_slave, DEC);writeChar('\n');
writeChar('\n');

I2CTWI_writeRegisters[0] = 0;

}
}

return 0;
}


Frage A) Eigentlich funzt alles. Nur verstehe ich nicht, warum wenn ich für data1_master=0, für data2_master=50 und für data3_master 80 verwende, dass der Slave dann aber in der Ausgabe (Terminal)

data1_slave: 50
data2_slave: 80
data3_slave: 0

ausgibt!?

Sollte doch eigentlich

data1_slave: 0
data2_slave: 50
data3_slave: 80

ausgeben, oder?

Frage B) Und warum muss der Wert "data1_master" unbedingt 0 (Null) sein? Ansonsten funztt mein Beispielprogramm nämlich nicht!? :-)

Aber ich denke, ich komme der Sache schön langsam näher..

Dirk
04.12.2009, 21:55
Hallo aircode,

wenn du Daten vom Master zum Slave übertragen willst, muss beim Empfänger (Slave) ja klar sein, wann er die "richtigen" Daten hat.

Dazu kann man I2CTWI_writeRegisters[0] benutzen. Ist das erste gesendete Byte z.B. != 0, wird es in data1_slave übernommen und die weiteren Bytes aus I2CTWI_writeRegisters[n] (N = 1..max. Bytezahl) in die Variablen dataX_slave. Das klappt so nur, wenn I2CTWI_writeRegisters[0] sofort auf 0 gesetzt wird, wenn es als != 0 empfangen wurde.
Und man fragt dann den Wert von data1_slave ab, um zu klären, ob die Daten verwendet werden können.
Man kann z.B. als erstes 99 senden, beim Slave testet man dann im Zweig
if(I2CTWI_writeRegisters[0] && !I2CTWI_writeBusy),
ob data1_slave 99 ist.
Wenn ja, können die weiteren Daten ausgegeben werden.

Also: Bei dieser Form des Empfangs kann man das 1. Byte (bei dir data1_master) nicht als 1. Datenbyte nehmen, sondern es dient quasi als Startmarke und Erkennung, dass jetzt die Daten kommen.

Sieh dir in der Anleitung zum RP6 das Beispiel auf S. 106 noch einmal an!

Gruß Dirk

aircode
05.12.2009, 23:21
OK, also sagen wir mal so... ich habe mich damit abgefunden ;-)

erstes Byte also als Startmarke, alle weiteren Bytes kann ich verwenden. Hab auch schon jetzt Programme geschrieben, wo ich das so verwende!

Danke mal für eure Hilfe...

Aircode

SlyD
06.12.2009, 11:54
Beim normale I2C Slave Programm was bei den Beispielprogrammen dabei ist, wird Register 0 als Kommandoregister verwendet - Kommando 5 steht dann z.B. für "CMD_MOVE_AT_SPEED" also Geschwindigkeit setzen und als Parameter folgen die neuen Geschwindigkeitswerte für links und rechts...

MfG,
SlyD