使用 I2C STM32F0 HAL 库寻址寄存器

电器工程 微控制器 i2c stm32 stm32f0 图书馆
2022-01-24 08:45:19

我对使用 STM 的 CUBE 和 HAL_libraries 非常陌生。我正在使用一个 32 针的 STM32F0 微控制器。I2C 的原理图是正确的。所以我在这里需要一点帮助。

我有一个使用 I2C 通信的电容式传感器 ( FDC1004 )。我必须写这些寄存器来读取数据。

我怎样才能正确地将 START 请求表单发送到从站(从站地址为 A0)?

如何将指针设置为 0x0C 寄存器?

  • 数据表中看到 (Register 0x0C:bit[7:4]) 为 1。)我不知道,该怎么做?最后如何从同一个寄存器读取?
  • 另外,在阅读之前我必须等待 DONE_x 字段(寄存器 0x​​0C:bits[3:0])?

但我不知道我是否正在寻址正确的寄存器!因为我没有从传感器得到任何数据!

这是我的代码:

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];
}
1个回答

让我们从HAL_I2C_Master_Transmit()函数开始。如果您检查其声明:

 HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  1. 第二个参数的小问题,从设备地址。从设备地址是b1010000,如果我们将其完成为8位格式,它将是0xA0,就像你说的那样。现在,当将其传递给HAL_I2C_Master_Transmit()您时,不必手动设置 R/W 位,HAL 会为您完成。因此,当您调用HAL_I2C_Master_Transmit()发送的 R/W 位时,将自动为 0 表示写操作,当您调用HAL_I2C_Master_Receive()发送的 R/W 位时,将自动为1 表示写操作您已经混合了 R/W 值,但我认为这对函数来说是一个无关紧要的位,因此它不是您的代码中的实际错误。

  2. 第三参数 ( uint8_t *pData) 是指向包含要发送的数据的缓冲区的指针。现在,在您的调用中,第三个参数是0x0C您的实际数据,即寄存器地址。问题是,它将被解释为指向HAL_I2C_Master_Transmit()内存位置的指针(由 ),可以在其中找到一些未定义的数据。

  3. 4 个参数是缓冲区的大小,要发送的字节数。如果要发送单个字节,则此参数应为1而不是 10。

使用\$ \small I^2C \$时,最好的办法是获取从设备的数据表并查找写入和读取操作的文档。

写寄存器

这是数据表中的相应图表。

在此处输入图像描述

所以在发送从机地址到总线后,还要传输三个字节:寄存器指针MSB 字节LSB 字节HAL 写入 16 位寄存器的一般实现:

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
}

您的价值观示例:write_register(0x0C, 0x0054);

或者,也可以使用 HAL 定义的寄存器写入函数,它具有用于传递寄存器地址和地址大小的附加参数。

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
    }
}

现在,HAL_I2C_Master_Receive()功能几乎与另一个相同。

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

唯一的区别是第三个参数是一个指向缓冲区的指针,接收到的数据将存储在该缓冲区中。0x02在您的代码中,我不知道您使用它的目的是什么,但它将被解释为一个指针(不幸的是指向一个随机内存位置)。

读取寄存器

在此处输入图像描述

要读取一个寄存器,必须使用\$ \small I^2C \$写入操作通过发送适当的寄存器指针来选择它(请注意,如果您在读取之前写入了该寄存器,那么您不必再次发送它的指向指针寄存器的地址,因为您已经在写入期间设置了它)。然后用\$ \small I^2C \$读操作,读回 16 位数据。

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);   
}

例子:

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

read_register(reg_ptr, buffer);

// the register content available in the buffer

还有一个 HAL 定义的寄存器读取函数,它有。

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;
}

通读数据表的8.5 编程部分了解更多详细信息。