Adressierung von Registern mit I2C STM32F0 HAL-Bibliotheken

Ich bin sehr neu in der Verwendung der CUBE- und HAL_libraries von STM. Ich verwende einen STM32F0-Mikrocontroller mit 32 Pins. Der Schaltplan für I2C ist korrekt. Also brauche ich hier ein wenig Hilfe.

Ich habe einen kapazitiven Sensor ( FDC1004 ), der I2C-Kommunikation verwendet. Ich muss diese Register schreiben, um die Daten zu lesen.

Wie könnte ich die START-Anfrage vom Master korrekt an den Slave senden (Slave-Adresse ist A0)?

Wie setze ich den Zeiger auf das 0x0C-Register?

  • Datenblatt siehe (Register 0x0C:bit[7:4]) zu 1.) Ich weiß nicht, wie das geht? Und schließlich, wie kann man aus demselben Register LESEN?
  • Außerdem muss ich auf das DONE_x-Feld (Register 0x0C:bits[3:0]) warten, bevor ich es lese?

Aber ich weiß nicht, ob ich die richtigen Register anspreche! Denn ich bekomme keine Daten vom Sensor zurück!

Hier ist mein Code:

int I2Ccomm ()
{

    HAL_I2C_Master_Transmit(&hi2c1,0xA1,0x0C, 10, 100); //start bit and pointer to register
    HAL_Delay(50);
    HAL_I2C_Master_Transmit(&hi2c1,0xA1,0x054, 10, 100); // setting the register
    HAL_Delay(50);

    HAL_I2C_Master_Receive(&hi2c1, 0xA0, 0x0C, 10, 100); //read from this register
    HAL_Delay(50);
    HAL_I2C_Master_Receive(&hi2c1, 0xA0, 0x02, 10, 100); //read data from register

    return ReadREG[1];
}
Bitte stellen Sie eine spezifischere Frage(n). like Wie spreche ich X Register richtig an? Das ist eine schlecht formulierte Frage. Weitere Richtlinien finden Sie unter electronic.stackexchange.com/help/how-to-ask
Ist es dann besser, eine neue Frage zu schreiben oder nur diese zu bearbeiten?
Besser zu bearbeiten, weniger Fragen und wir müssen diese nicht schließen.

Antworten (1)

Beginnen wir mit der HAL_I2C_Master_Transmit()Funktion. Wenn Sie seine Deklaration überprüfen:

 HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  1. Kleineres Problem mit dem 2. Parameter, der Slave-Geräteadresse. Die Slave-Geräteadresse lautet, b1010000wenn wir sie im 8-Bit-Format vervollständigen 0xA0, genau wie Sie sagten. Wenn Sie dies nun an HAL_I2C_Master_Transmit()Sie weitergeben, müssen Sie das R/W-Bit nicht manuell setzen, HAL erledigt dies für Sie. Wenn Sie also HAL_I2C_Master_Transmit()das übertragene R/W-Bit aufrufen, ist es automatisch 0, was einen Schreibvorgang anzeigt, und wenn Sie das übertragen, HAL_I2C_Master_Receive()ist das übertragene R/W-Bit automatisch 1, was einen Schreibvorgang anzeigt . Sie haben die R / W-Werte gemischt, aber ich denke, es handelt sich um ein irrelevantes Bit für die Funktion, sodass es sich nicht um einen tatsächlichen Fehler in Ihrem Code handelt.

  2. Der 3. Parameter ( uint8_t *pData) ist ein Zeiger auf einen Puffer , der die zu sendenden Daten enthält . Nun, in Ihrem Aufruf ist der 3. Parameter 0x0CIhre eigentlichen Daten, die Registeradresse. Das Problem ist, dass es als Zeiger (von HAL_I2C_Master_Transmit()) auf einen Speicherort interpretiert wird, an dem einige undefinierte Daten zu finden sind.

  3. Der 4. Parameter ist die Größe des Puffers , die Anzahl der zu sendenden Bytes. Wenn Sie ein einzelnes Byte senden möchten, sollte dieser Parameter 1 und nicht 10 sein.

Beim Arbeiten mit ich 2 C Am besten besorgen Sie sich das Datenblatt des Slave-Geräts und schlagen in der Dokumentation der Schreib- und Leseoperationen nach.

Register schreiben

Hier ist das entsprechende Diagramm aus dem Datenblatt.

Geben Sie hier die Bildbeschreibung ein

Nach dem Senden der Slave-Adresse an den Bus sollten also drei weitere Bytes übertragen werden: Registerzeiger , MSB-Byte , LSB-Byte . Eine allgemeine Implementierung mit HAL, die 16-Bit-Register schreibt:

void write_register(uint8_t register_pointer, uint16_t register_value)
{
    uint8_t data[3];

    data[0] = register_pointer;     // 0x0C in your example
    data[1] = register_value>>8;    // MSB byte of 16bit data
    data[2] = register_value;       // LSB byte of 16bit data

    HAL_I2C_Master_Transmit(&hi2c1, 0xA0, data, 3, 100);  // data is the start pointer of our array
}

Beispiel mit deinen Werten:write_register(0x0C, 0x0054);

Alternativ kann auch eine HAL-definierte Registerschreibfunktion verwendet werden, die zusätzliche Parameter zum Übergeben von Registeradresse und Adressgröße hat.

void write_register(uint8_t register_pointer, uint16_t register_value)
{
    HAL_StatusTypeDef status = HAL_OK;

    status = HAL_I2C_Mem_Write(&hi2c1, 0xA0, (uint16_t)register_pointer, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&register_value), 2, 100); 

    /* Check the communication status */
    if(status != HAL_OK)
    {
        // Error handling, for example re-initialization of the I2C peripheral
    }
}

Jetzt ist die HAL_I2C_Master_Receive()Funktion fast die gleiche wie die andere.

HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

Der einzige Unterschied besteht darin, dass der 3. Parameter ein Zeiger auf den Puffer ist, in dem die empfangenen Daten gespeichert werden. Es ist 0x02in Ihrem Code und ich weiß nicht, was Sie damit bezweckt haben, aber es wird als Zeiger interpretiert (leider auf einen zufälligen Speicherort).

Register lesen

Geben Sie hier die Bildbeschreibung ein

Um ein Register zu lesen, muss es mit einem ausgewählt werden ich 2 C Schreibvorgang durch Senden des entsprechenden Registerzeigers (Beachten Sie, dass Sie, wenn Sie dieses Register direkt vor dem Lesen geschrieben haben, seine Adresse nicht erneut an das Zeigerregister senden müssen, da Sie sie bereits während des Schreibens festgelegt haben). Dann mit einem ich 2 C Lesevorgang, lesen Sie die 16-Bit-Daten zurück.

void read_register(uint8_t register_pointer, uint8_t* receive_buffer)
{
    // first set the register pointer to the register wanted to be read
    HAL_I2C_Master_Transmit(&hi2c1, 0xA0, &register_pointer, 1, 100);  // note the & operator which gives us the address of the register_pointer variable

    // receive the 2 x 8bit data into the receive buffer
    HAL_I2C_Master_Receive(&hi2c1, 0xA0, receive_buffer, 2, 100);   
}

Beispiel:

uint8_t reg_ptr = 0x0C;
uint8_t buffer[2];

read_register(reg_ptr, buffer);

// the register content available in the buffer

Es gibt auch eine HAL-definierte Register-Lesefunktion, die hat.

uint16_t read_register(uint8_t register_pointer)
{
    HAL_StatusTypeDef status = HAL_OK;
    uint16_t return_value = 0;

    status = HAL_I2C_Mem_Read(&hi2c1, 0xA0, (uint16_t)register_pointer, I2C_MEMADD_SIZE_8BIT, &return_value, 2, 100);

    /* Check the communication status */
    if(status != HAL_OK)
    {

    }

    return return_value;
}

Lesen Sie Abschnitt 8.5 Programmierung des Datenblatts für weitere Einzelheiten.

Danke für deine Antwort, jetzt funktioniert es endlich. Aber noch eine Frage? Muss ich ein paar Millisekunden auf das Lesen warten oder kann ich ohne Verzögerung lesen?
Ich denke nicht, dass eine Verzögerung erforderlich ist, Sie könnten es zuerst ohne Verzögerung versuchen.
Sie müssen nicht warten, I2C beinhaltet das Schleifen des Taktsignals, bis der Slave fertig ist.