- fchao-Sinus-Wechselrichter AliExpress         
Ergebnis 1 bis 10 von 25

Thema: I2C Verständnisprobleme

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Benutzer Stammmitglied
    Registriert seit
    10.09.2010
    Beiträge
    74
    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
    Geändert von RP6fahrer (20.04.2011 um 11:42 Uhr)

  2. #2
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    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
    Geändert von RolfD (20.04.2011 um 15:15 Uhr)
    Sind Sie auch ambivalent?

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    10.09.2010
    Beiträge
    74
    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.

  4. #4
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    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
    Sind Sie auch ambivalent?

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.803
    @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.
    Gruß
    Dirk

  6. #6
    Benutzer Stammmitglied
    Registriert seit
    10.09.2010
    Beiträge
    74
    @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:


    Code:
    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_requestedDataReady);
        I2CTWI_setTransmissionErrorHandler(I2C_transmissionError);
    
        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_requestedDataReady);
        
        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
    Geändert von RP6fahrer (21.04.2011 um 16:32 Uhr)

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.803
    Wenn du diese 2 Funktionen benutzt, liest du adc0 und adc1 richtig ein.
    Code:
    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.
    Gruß
    Dirk

  8. #8
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    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...-RP6Lib-Bugfix
    LG Rolf
    Geändert von RolfD (21.04.2011 um 17:09 Uhr)
    Sind Sie auch ambivalent?

  9. #9
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.803
    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.
    Gruß
    Dirk

Ähnliche Themen

  1. Verständnisprobleme -> Drehmomentrechner
    Von selan im Forum Motoren
    Antworten: 9
    Letzter Beitrag: 13.11.2006, 14:25
  2. Verständnisprobleme über die Funktionsweise eines Interrupts
    Von electrofux im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 31.10.2006, 16:14
  3. Syntax - Verständnisprobleme
    Von R2D3212 im Forum C - Programmierung (GCC u.a.)
    Antworten: 8
    Letzter Beitrag: 05.07.2006, 01:41
  4. Serielle Verständnisprobleme
    Von steffenvogel im Forum Software, Algorithmen und KI
    Antworten: 6
    Letzter Beitrag: 09.04.2006, 13:23
  5. Antworten: 17
    Letzter Beitrag: 01.01.2006, 17:33

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests