Adressierungsregister mit I2C STM32F0 HAL-Bibliotheken


12

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

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

Wie kann ich das START-Anforderungsformular Master korrekt an den Slave senden (Slave-Adresse ist A0)?

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

  • Datenblatt sieht (Register 0x0C: Bit [7: 4]) bis 1.) Ich weiß nicht, wie das geht? Und schließlich, wie man aus demselben Register liest?
  • Außerdem muss ich das Feld DONE_x (Register 0x0C: Bits [3: 0]) warten, bevor ich es lese?

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

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). Wie adressiere ich das X-Register richtig? Dies ist eine schlecht formulierte Frage. Weitere Richtlinien finden Sie unter electronic.stackexchange.com/help/how-to-ask
Voltage Spike

Ist es dann besser, eine neue Frage zu schreiben oder diese einfach zu bearbeiten?
yest111

Besser zu bearbeiten, weniger Fragen und wir müssen diese nicht schließen.
Spannungsspitze

Antworten:


16

Beginnen wir mit der HAL_I2C_Master_Transmit()Funktion. Wenn Sie die Erklärung überprüfen:

 HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  1. Kleines Problem mit dem 2. Parameter, der Slave-Geräteadresse. Die Adresse des Slave-Geräts lautet, b1010000wenn wir sie im 8-Bit-Format vervollständigen 0xA0, genau so, wie Sie es gesagt haben. Wenn HAL_I2C_Master_Transmit()Sie dies jetzt an Sie übergeben, 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 dies automatisch 0, was eine Schreiboperation anzeigt, und wenn Sie HAL_I2C_Master_Receive()das übertragene R / W-Bit aufrufen, ist es automatisch 1, was eine Schreiboperation anzeigt . Sie haben die R / W-Werte gemischt, aber ich denke, die Funktion ist mir egal, es handelt sich also nicht um einen tatsächlichen Fehler in Ihrem Code.

  2. Der 3. Parameter ( uint8_t *pData) ist ein Zeiger auf einen Puffer, der die zu sendenden Daten enthält . In Ihrem Aufruf ist der dritte Parameter, 0x0Cder Ihre tatsächlichen Daten sind, die Registeradresse. Das Problem ist, dass es als Zeiger (von der HAL_I2C_Master_Transmit()) auf einen Speicherort interpretiert wird , an dem einige undefinierte Daten gefunden werden können.

  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.

Wenn Sie mit am besten, das Datenblatt des Slave-Geräts abzurufen und die Dokumentation der Schreib- und Lesevorgänge nachzuschlagen.I2C

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 drei weitere Bytes übertragen werden: Registerzeiger , MSB-Byte , LSB-Byte . Eine allgemeine Implementierung mit HAL-16-Bit-Registern:

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 Ihren Werten: write_register(0x0C, 0x0054);

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

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 dieselbe 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 befindet sich 0x02in Ihrem Code und ich weiß nicht, was Ihr Zweck damit war, 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 einer Schreiboperation durch Senden des entsprechenden Registerzeigers ausgewählt werden (Beachten Sie, dass Sie, wenn Sie dieses Register direkt vor dem Lesen geschrieben haben, seine Adresse nicht erneut an den Zeiger senden müssen registrieren, wie Sie es bereits beim Schreiben eingestellt haben). Lesen Sie dann mit einer Leseoperation die 16-Bit-Daten zurück.I2CI2C

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 Registerlesefunktion, 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 durch 8.5 Programmierung Abschnitt des Datenblatt für weitere Details.


Vielen Dank für Ihre 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?
yest111

Ich denke nicht, dass eine Verzögerung notwendig ist, Sie könnten es ohne vorherige versuchen.
Bence Kaulics

1
Sie müssen nicht warten, bei I2C wird das Taktsignal wiederholt, bis der Slave abgeschlossen ist.
Mahmoud Al-Qudsi
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.