大花科技
嵌入式开发原创教程嵌入式入门 05

I2C 与 SPI 传感器接入:读设备 ID 和完整寄存器

用两个最小实验理解 I2C 地址、寄存器读取、SPI 模式、片选和错误恢复。

I2C 与 SPI 传感器接入:读设备 ID 和完整寄存器

实验目标

  • 用 I2C 读取传感器设备 ID;
  • 用 SPI 读取一个寄存器;
  • 知道地址、模式、片选和超时分别怎么检查;
  • 在通信失败时能定位到硬件或软件层。

一、I2C 最小实验

假设传感器 7 位地址为 0x68,设备 ID 寄存器为 0x75。

ccode
uint8_t who_am_i = 0U;
HAL_StatusTypeDef status;

status = HAL_I2C_Mem_Read(&hi2c1,
                          (uint16_t)(0x68U << 1),
                          0x75U,
                          I2C_MEMADD_SIZE_8BIT,
                          &who_am_i,
                          1U,
                          100U);

if (status == HAL_OK)
{
    HAL_UART_Transmit(&huart2, (uint8_t *)"I2C OK\r\n", 8, 100);
}
else
{
    HAL_UART_Transmit(&huart2, (uint8_t *)"I2C FAIL\r\n", 10, 100);
}

I2C 检查顺序

  1. SDA/SCL 是否接反;
  2. 是否有上拉电阻;
  3. 设备地址是否左移;
  4. 寄存器地址是 8 位还是 16 位;
  5. 总线是否被拉低;
  6. 设备供电和地是否正常。

二、SPI 最小实验

假设从机设备 ID 寄存器为 0x75,读取时最高位置 1。

ccode
uint8_t tx[2] = { 0xF5U, 0x00U };
uint8_t rx[2] = { 0U, 0U };

HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);

HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(&hspi1,
                                                   tx,
                                                   rx,
                                                   2U,
                                                   100U);

HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);

if (status == HAL_OK)
{
    uint8_t device_id = rx[1];
    (void)device_id;
}

SPI 检查顺序

  • CPOL 和 CPHA 是否与从机一致;
  • 片选是否低有效;
  • MISO/MOSI 是否接反;
  • 时钟频率是否超过从机上限;
  • 数据位宽是否为 8 位;
  • 读写命令的最高位和地址长度是否匹配。

三、错误恢复

通信失败时不要无限重试。建议:

ccode
for (uint8_t retry = 0U; retry < 3U; retry++)
{
    if (sensor_read_once() == HAL_OK)
    {
        break;
    }

    HAL_Delay(10);
}

连续失败后记录错误码,不要在主循环里疯狂打印。

四、实验顺序

  1. 先只读设备 ID;
  2. 再读一个配置寄存器;
  3. 写入一个安全配置;
  4. 读回确认;
  5. 最后读取连续数据。

参考资料: