STM32F1标准库的硬件I2C驱动

完全实现HAL库的对应函数功能:

C语言版本

i2c.h 文件:

#ifndef __I2C_H
#define __I2C_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stm32f10x.h>

#include <stdint.h>

#define I2C_MAX_TIMEOUT 1000

typedef enum {
    I2C_STATUS_OK = 0,
    I2C_STATUS_ERROR,
    I2C_STATUS_TIMEOUT,
    I2C_STATUS_BUSY,
} I2C_StatusTypeDef;

typedef enum {
    I2C_MEM_ADDR_SIZE_8BIT = 0,
    I2C_MEM_ADDR_SIZE_16BIT,
} I2C_MemAddrSize;

I2C_StatusTypeDef I2C_MasterTransmit(I2C_TypeDef *I2Cx, uint8_t DevAddress, const uint8_t *pData, uint16_t Size);
I2C_StatusTypeDef I2C_MasterReceive(I2C_TypeDef *I2Cx, uint8_t DevAddress, uint8_t *pData, uint16_t Size);

I2C_StatusTypeDef I2C_Mem_Write(I2C_TypeDef *I2Cx, uint8_t DevAddress, uint16_t MemAddress,
                                I2C_MemAddrSize AddrSize, const uint8_t *pData, uint16_t Size);
I2C_StatusTypeDef I2C_Mem_Read(I2C_TypeDef *I2Cx, uint8_t DevAddress, uint16_t MemAddress,
                               I2C_MemAddrSize AddrSize, uint8_t *pData, uint16_t Size);

#ifdef __cplusplus
}
#endif

#endif /* __I2C_H */

i2c.c 文件:

#include "i2c.h"

#include <stm32f10x.h>

#include <stdint.h>

/**
 * @brief 带超时判断的 I2C 检查事件函数
 *
 * @param I2Cx I2C 外设
 * @param event I2C 事件
 * @return I2C_StatusTypeDef 检查事件的结果
 */
static I2C_StatusTypeDef I2C_CheckEvent_Timeout(I2C_TypeDef *I2Cx, uint32_t event)
{
    for (uint32_t timeout = 0; timeout < I2C_MAX_TIMEOUT; timeout++) {
        if (I2C_CheckEvent(I2Cx, event) == SUCCESS) {
            return I2C_STATUS_OK;
        }
    }
    return I2C_STATUS_TIMEOUT;
}

/**
 * @brief 带超时判断的等待 I2C 总线空闲函数
 *
 * @param I2Cx I2C 外设
 * @return I2C_StatusTypeDef 等待空闲的结果
 */
static I2C_StatusTypeDef I2C_Wait(I2C_TypeDef *I2Cx)
{
    for (uint32_t timeout = 0; timeout < I2C_MAX_TIMEOUT; timeout++) {
        if (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY) != SET) {
            return I2C_STATUS_OK;
        }
    }
    return I2C_STATUS_BUSY;
}

/**
 * @brief I2C 主机发送数据
 *
 * @param I2Cx I2C 外设
 * @param DevAddress 从机设备地址
 * @param pData 发送数据指针
 * @param Size 发送数据长度
 * @return I2C_StatusTypeDef 发送数据的结果
 */
I2C_StatusTypeDef I2C_MasterTransmit(I2C_TypeDef *I2Cx, uint8_t DevAddress, const uint8_t *pData, uint16_t Size)
{
    I2C_StatusTypeDef status = I2C_STATUS_OK;

    // 1. 等待总线空闲
    status = I2C_Wait(I2Cx);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 2. 生成起始条件
    I2C_GenerateSTART(I2Cx, ENABLE);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_MODE_SELECT);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 3. 发送设备地址(写模式)
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmitter);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 4. 发送数据
    while (Size > 0) {
        I2C_SendData(I2Cx, *pData);
        if (Size == 1) {
            // 如果是最后一个字节,则检查 I2C_EVENT_MASTER_BYTE_TRANSMITTED 事件
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
        } else {
            // 否则检查 I2C_EVENT_MASTER_BYTE_TRANSMITTING 事件
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
        }
        if (status != I2C_STATUS_OK) {      // 如果发生错误
            I2C_GenerateSTOP(I2Cx, ENABLE); // 产生停止条件
            return status;
        }

        pData++;
        Size--;
    }

    // 5. 生成停止条件
    I2C_GenerateSTOP(I2Cx, ENABLE);

    return status;
}

/**
 * @brief I2C 主机接收数据
 *
 * @param I2Cx I2C 外设
 * @param DevAddress 从机设备地址
 * @param pData 接收数据保存的地址
 * @param Size 接收数据长度
 * @return I2C_StatusTypeDef 接收数据的结果
 */
I2C_StatusTypeDef I2C_MasterReceive(I2C_TypeDef *I2Cx, uint8_t DevAddress, uint8_t *pData, uint16_t Size)
{
    I2C_StatusTypeDef status = I2C_STATUS_OK;

    // 1. 等待总线空闲
    status = I2C_Wait(I2Cx);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 2. 生成起始条件
    I2C_GenerateSTART(I2Cx, ENABLE);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_MODE_SELECT);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 3. 发送设备地址(读模式)
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Receiver);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 4. 读取数据
    while (Size > 0) {
        if (Size == 1) {
            // 如果是最后一个字节,则不应答,并提前产生停止条件
            I2C_AcknowledgeConfig(I2Cx, DISABLE); // 禁止ACK
            I2C_GenerateSTOP(I2Cx, ENABLE);       // 产生停止条件
        }
        // 等待数据接收完成
        status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED);
        if (status != I2C_STATUS_OK) {           // 如果发生错误
            I2C_AcknowledgeConfig(I2Cx, ENABLE); // 恢复ACK
            return status;
        }

        *pData = I2C_ReceiveData(I2Cx);
        pData++;
        Size--;
    }

    // 5. 恢复ACK
    I2C_AcknowledgeConfig(I2Cx, ENABLE);

    return status;
}

/**
 * @brief I2C 主机指定地址写入从机数据(支持8位/16位内存地址)
 *
 * @param I2Cx I2C 外设
 * @param DevAddress 从机设备地址
 * @param MemAddress 要写入的从机内部地址(8位或16位)
 * @param AddrSize 内存地址大小(I2C_MEM_ADDR_SIZE_8BIT 或 I2C_MEM_ADDR_SIZE_16BIT)
 * @param pData 要写入的数据指针
 * @param Size 要写入的数据长度
 * @return I2C_StatusTypeDef 写入数据的结果
 */
I2C_StatusTypeDef I2C_Mem_Write(I2C_TypeDef *I2Cx, uint8_t DevAddress, uint16_t MemAddress,
                                I2C_MemAddrSize AddrSize, const uint8_t *pData, uint16_t Size)
{
    I2C_StatusTypeDef status = I2C_STATUS_OK;

    // 1. 等待总线空闲
    status = I2C_Wait(I2Cx);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 2. 生成起始条件
    I2C_GenerateSTART(I2Cx, ENABLE);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_MODE_SELECT);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 3. 发送设备地址(写模式)
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmitter);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 4. 发送内存地址(根据 AddrSize 决定发送8位或16位)
    switch (AddrSize) {
        case I2C_MEM_ADDR_SIZE_16BIT:
            // 先发送高8位
            I2C_SendData(I2Cx, (uint8_t)(MemAddress >> 8));
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
            if (status != I2C_STATUS_OK) {
                return status;
            }
            // 再发送低8位
            I2C_SendData(I2Cx, (uint8_t)(MemAddress & 0xFF));
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != I2C_STATUS_OK) {
                return status;
            }
            break;
        case I2C_MEM_ADDR_SIZE_8BIT:
            // 8位地址模式
            I2C_SendData(I2Cx, (uint8_t)MemAddress);
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != I2C_STATUS_OK) {
                return status;
            }
            break;
        default:
            break;
    }

    // 5. 发送数据
    while (Size > 0) {
        I2C_SendData(I2Cx, *pData);
        if (Size == 1) {
            // 最后一个字节,等待传输完成
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
        } else {
            // 非最后一个字节,等待正在传输
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
        }
        if (status != I2C_STATUS_OK) {      // 如果发生错误
            I2C_GenerateSTOP(I2Cx, ENABLE); // 产生停止条件
            return status;
        }

        pData++;
        Size--;
    }

    // 6. 生成停止条件
    I2C_GenerateSTOP(I2Cx, ENABLE);

    return status;
}

/**
 * @brief I2C 指定地址读取从机数据(支持8位/16位内存地址)
 *
 * @param I2Cx I2C 外设
 * @param DevAddress 从机设备地址
 * @param MemAddress 要读取的从机内部地址(8位或16位)
 * @param AddrSize 内存地址大小(I2C_MEM_ADDR_SIZE_8BIT 或 I2C_MEM_ADDR_SIZE_16BIT)
 * @param pData 接收数据保存的地址
 * @param Size 接收数据长度
 * @return I2C_StatusTypeDef 读取数据的结果
 */
I2C_StatusTypeDef I2C_Mem_Read(I2C_TypeDef *I2Cx, uint8_t DevAddress, uint16_t MemAddress,
                               I2C_MemAddrSize AddrSize, uint8_t *pData, uint16_t Size)
{
    I2C_StatusTypeDef status = I2C_STATUS_OK;

    // 1. 等待总线空闲
    status = I2C_Wait(I2Cx);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 2. 生成起始条件
    I2C_GenerateSTART(I2Cx, ENABLE);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_MODE_SELECT);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 3. 发送设备地址(写模式)
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmitter);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 4. 发送内存地址(根据 AddrSize 决定发送8位或16位)
    switch (AddrSize) {
        case I2C_MEM_ADDR_SIZE_16BIT:
            // 先发送高8位
            I2C_SendData(I2Cx, (uint8_t)(MemAddress >> 8));
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
            if (status != I2C_STATUS_OK) {
                return status;
            }
            // 再发送低8位
            I2C_SendData(I2Cx, (uint8_t)(MemAddress & 0xFF));
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != I2C_STATUS_OK) {
                return status;
            }
            break;
        case I2C_MEM_ADDR_SIZE_8BIT:
            // 8位地址模式
            I2C_SendData(I2Cx, (uint8_t)MemAddress);
            status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != I2C_STATUS_OK) {
                return status;
            }
            break;
        default:
            break;
    }

    // 5. 再次生成起始条件
    I2C_GenerateSTART(I2Cx, ENABLE);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_MODE_SELECT);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 6. 发送设备地址(读模式)
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Receiver);
    status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
    if (status != I2C_STATUS_OK) {
        return status;
    }

    // 7. 读取数据
    while (Size > 0) {
        if (Size == 1) {
            // 如果是最后一个字节,则不应答,并提前产生停止条件
            I2C_AcknowledgeConfig(I2Cx, DISABLE); // 禁止ACK
            I2C_GenerateSTOP(I2Cx, ENABLE);       // 产生停止条件
        }
        status = I2C_CheckEvent_Timeout(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED);
        if (status != I2C_STATUS_OK) {           // 如果发生错误
            I2C_AcknowledgeConfig(I2Cx, ENABLE); // 恢复ACK
            return status;
        }

        *pData = I2C_ReceiveData(I2Cx);
        pData++;
        Size--;
    }

    // 8. 恢复ACK
    I2C_AcknowledgeConfig(I2Cx, ENABLE);

    return status;
}

C++版本

enum class Status 定义:

enum class Status {
    Ok,
    Error,
    Busy,
    Timeout,
};

i2c_handle.hpp 文件:

#pragma once

#include <array>
#include <cstddef>
#include <cstdint>
#include <span>

#include "main.hpp"
#include "stm32f10x.h"

class I2C_Handle
{
public:
    static constexpr uint32_t DefaultTimeout = 1000;

    enum class MemAddrSize {
        Size8Bit,
        Size16Bit,
    };

    explicit I2C_Handle(I2C_TypeDef *i2c_x = nullptr);

    operator bool() const;

    void set_i2c(I2C_TypeDef *i2c_x);
    void set_timeout(uint32_t timeout);

    auto i2c_handle() const;
    auto timeout() const;

    Status I2C_MasterTransmit(uint8_t device_address,
                              uint8_t transmit_byte);
    Status I2C_MasterTransmit(uint8_t                  device_address,
                              std::span<const uint8_t> transmit_buffer);

    Status I2C_MasterReceive(uint8_t  device_address,
                             uint8_t &receive_byte);
    Status I2C_MasterReceive(uint8_t            device_address,
                             std::span<uint8_t> receive_buffer);

    Status I2C_MemoryWrite(uint8_t     device_address,
                           uint16_t    memory_address,
                           MemAddrSize mem_addr_size,
                           uint8_t     write_byte);
    Status I2C_MemoryWrite(uint8_t                  device_address,
                           uint8_t                  memory_address,
                           MemAddrSize              mem_addr_size,
                           std::span<const uint8_t> write_buffer);

    Status I2C_MemoryRead(uint8_t     device_address,
                          uint16_t    memory_address,
                          MemAddrSize mem_addr_size,
                          uint8_t    &read_byte);
    Status I2C_MemoryRead(uint8_t            device_address,
                          uint8_t            memory_address,
                          MemAddrSize        mem_addr_size,
                          std::span<uint8_t> read_buffer);

private:
    I2C_TypeDef *i2c_x_;
    uint32_t     timeout_;

    Status I2C_CheckEvent(uint32_t event);
    Status I2C_WaitBus();
};

i2c_handle.cpp 文件:

#include "i2c_handle.hpp"

#include <cstdint>
#include <ranges>

#include "stm32f10x.h"

/**
 * @brief Construct a new i2c handle::i2c handle object
 *
 * @param i2c_x 绑定的I2C外设
 */
I2C_Handle::I2C_Handle(I2C_TypeDef *i2c_x)
    : i2c_x_{i2c_x},
      timeout_{DefaultTimeout}
{
}

I2C_Handle::operator bool() const { return this->i2c_x_ != nullptr; }

/**
 * @brief 设置I2C外设
 *
 * @param i2c_x 绑定的I2C外设
 */
void I2C_Handle::set_i2c(I2C_TypeDef *i2c_x) { this->i2c_x_ = i2c_x; }

/**
 * @brief 设置超时时间
 *
 * @param timeout 超时时间
 */
void I2C_Handle::set_timeout(uint32_t timeout) { this->timeout_ = timeout; }

auto I2C_Handle::i2c_handle() const { return this->i2c_x_; }

auto I2C_Handle::timeout() const { return this->timeout_; }

/**
 * @brief 主机发送单字节数据
 *
 * @param device_address    设备地址
 * @param transmit_byte     待发送数据
 * @return Status           发送状态
 */
Status I2C_Handle::I2C_MasterTransmit(uint8_t device_address, uint8_t transmit_byte)
{
    return this->I2C_MasterTransmit(device_address, {&transmit_byte, 1});
}

/**
 * @brief 主机发送数据
 *
 * @param device_address    设备地址
 * @param transmit_buffer   待发送数据
 * @return Status           发送状态
 */
Status I2C_Handle::I2C_MasterTransmit(uint8_t device_address, std::span<const uint8_t> transmit_buffer)
{
    auto status = Status::Ok;

    // 1. 等待总线空闲
    status = this->I2C_WaitBus();
    if (status != Status::Ok) {
        return status;
    }

    // 2. 生成起始条件
    I2C_GenerateSTART(this->i2c_x_, ENABLE);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT);
    if (status != Status::Ok) {
        return status;
    }

    // 3. 发送设备地址(写模式)
    I2C_Send7bitAddress(this->i2c_x_, device_address, I2C_Direction_Transmitter);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    if (status != Status::Ok) {
        return status;
    }

    // 4. 发送数据
    for (auto it = transmit_buffer.begin(); it != transmit_buffer.end(); it++) {
        I2C_SendData(this->i2c_x_, *it);
        if (std::next(it) == transmit_buffer.end()) {
            // 如果是最后一个字节,则检查 I2C_EVENT_MASTER_BYTE_TRANSMITTED 事件
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
        } else {
            // 否则检查 I2C_EVENT_MASTER_BYTE_TRANSMITTING 事件
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING);
        }
        if (status != Status::Ok) {                 // 如果发生错误
            I2C_GenerateSTOP(this->i2c_x_, ENABLE); // 产生停止条件
            return status;
        }
    }

    // 5. 生成停止条件
    I2C_GenerateSTOP(this->i2c_x_, ENABLE);

    return status;
}

/**
 * @brief 主机接收单字节数据
 *
 * @param device_address    设备地址
 * @param receive_byte      接收数据
 * @return Status           接收状态
 */
Status I2C_Handle::I2C_MasterReceive(uint8_t device_address, uint8_t &receive_byte)
{
    return this->I2C_MasterReceive(device_address, {&receive_byte, 1});
}

/**
 * @brief 主机接收数据
 *
 * @param device_address    设备地址
 * @param receive_buffer    接收缓冲区
 * @return Status           接收状态
 */
Status I2C_Handle::I2C_MasterReceive(uint8_t device_address, std::span<uint8_t> receive_buffer)
{
    auto status = Status::Ok;

    // 1. 等待总线空闲
    status = this->I2C_WaitBus();
    if (status != Status::Ok) {
        return status;
    }

    // 2. 生成起始条件
    I2C_GenerateSTART(this->i2c_x_, ENABLE);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT);
    if (status != Status::Ok) {
        return status;
    }

    // 3. 发送设备地址(读模式)
    I2C_Send7bitAddress(this->i2c_x_, device_address, I2C_Direction_Receiver);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
    if (status != Status::Ok) {
        return status;
    }

    // 4. 读取数据
    for (auto it = receive_buffer.begin(); it != receive_buffer.end(); it++) {
        if (std::next(it) == receive_buffer.end()) {
            // 如果是最后一个字节,则不应答,并提前产生停止条件
            I2C_AcknowledgeConfig(this->i2c_x_, DISABLE);
            I2C_GenerateSTOP(this->i2c_x_, ENABLE);
        }
        // 等待数据接收完成
        status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_RECEIVED);
        if (status != Status::Ok) {
            I2C_AcknowledgeConfig(this->i2c_x_, ENABLE);
            return status;
        }

        *it = I2C_ReceiveData(this->i2c_x_);
    }

    // 5. 恢复ACK
    I2C_AcknowledgeConfig(this->i2c_x_, ENABLE);

    return status;
}

/**
 * @brief 主机向从机内存地址写入数据
 *
 * @param device_address    设备地址
 * @param memory_address    从机的内存地址
 * @param write_byte        待写入数据
 * @return Status           写入状态
 */
Status I2C_Handle::I2C_MemoryWrite(uint8_t     device_address,
                                   uint16_t    memory_address,
                                   MemAddrSize mem_addr_size,
                                   uint8_t     write_byte)
{
    return this->I2C_MemoryWrite(device_address, memory_address, mem_addr_size, {&write_byte, 1});
}

/**
 * @brief 主机向从机内存地址写入数据
 *
 * @param device_address    设备地址
 * @param memory_address    从机的内存地址
 * @param write_buffer      待写入数据
 * @return Status           写入状态
 */
Status I2C_Handle::I2C_MemoryWrite(uint8_t                  device_address,
                                   uint8_t                  memory_address,
                                   MemAddrSize              mem_addr_size,
                                   std::span<const uint8_t> write_buffer)
{
    auto status = Status::Ok;

    // 1. 等待总线空闲
    status = this->I2C_WaitBus();
    if (status != Status::Ok) {
        return status;
    }

    // 2. 生成起始条件
    I2C_GenerateSTART(this->i2c_x_, ENABLE);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT);
    if (status != Status::Ok) {
        return status;
    }

    // 3. 发送设备地址(写模式)
    I2C_Send7bitAddress(this->i2c_x_, device_address, I2C_Direction_Transmitter);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    if (status != Status::Ok) {
        return status;
    }

    // 4. 发送内存地址(根据 mem_addr_size 决定发送8位或16位)
    switch (mem_addr_size) {
        case MemAddrSize::Size16Bit: {
            // 先发送高八位
            I2C_SendData(this->i2c_x_, memory_address >> 8);
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != Status::Ok) {
                return status;
            }
            // 再发送低八位
            I2C_SendData(this->i2c_x_, memory_address);
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != Status::Ok) {
                return status;
            }
            break;
        }

        case MemAddrSize::Size8Bit: {
            // 直接发送八位地址
            I2C_SendData(this->i2c_x_, memory_address);
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != Status::Ok) {
                return status;
            }
            break;
        }

        default:
            break;
    }

    // 5. 发送数据
    for (auto it = write_buffer.begin(); it != write_buffer.end(); it++) {
        I2C_SendData(this->i2c_x_, *it);
        if (std::next(it) == write_buffer.end()) {
            // 如果是最后一个字节,则检查 I2C_EVENT_MASTER_BYTE_TRANSMITTED 事件
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
        } else {
            // 否则检查 I2C_EVENT_MASTER_BYTE_TRANSMITTING 事件
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING);
        }
        if (status != Status::Ok) {
            I2C_GenerateSTOP(this->i2c_x_, ENABLE);
            return status;
        }
    }

    // 6. 生成停止条件
    I2C_GenerateSTOP(this->i2c_x_, ENABLE);

    return status;
}

/**
 * @brief 主机从从机内存地址读取数据
 *
 * @param device_address    设备地址
 * @param memory_address    从机的内存地址
 * @param read_byte         接收数据缓冲区
 * @return Status           读取状态
 */
Status I2C_Handle::I2C_MemoryRead(uint8_t     device_address,
                                  uint16_t    memory_address,
                                  MemAddrSize mem_addr_size,
                                  uint8_t    &read_byte)
{
    return this->I2C_MemoryRead(device_address, memory_address, mem_addr_size, {&read_byte, 1});
}

/**
 * @brief 主机向从机读取数据
 *
 * @param device_address    设备地址
 * @param memory_address    从机的内存地址
 * @param read_buffer       接收缓冲区
 * @return Status           读取状态
 */
Status I2C_Handle::I2C_MemoryRead(uint8_t            device_address,
                                  uint8_t            memory_address,
                                  MemAddrSize        mem_addr_size,
                                  std::span<uint8_t> read_buffer)
{
    auto status = Status::Ok;

    // 1. 等待总线空闲
    status = this->I2C_WaitBus();
    if (status != Status::Ok) {
        return status;
    }

    // 2. 生成起始条件
    I2C_GenerateSTART(this->i2c_x_, ENABLE);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT);
    if (status != Status::Ok) {
        return status;
    }

    // 3. 发送设备地址(写模式)
    I2C_Send7bitAddress(this->i2c_x_, device_address, I2C_Direction_Transmitter);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    if (status != Status::Ok) {
        return status;
    }

    // 4. 发送内存地址(根据 mem_addr_size 决定发送8位或16位)
    switch (mem_addr_size) {
        case MemAddrSize::Size16Bit: {
            // 先发送高八位
            I2C_SendData(this->i2c_x_, memory_address >> 8);
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != Status::Ok) {
                return status;
            }
            // 再发送低八位
            I2C_SendData(this->i2c_x_, memory_address);
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != Status::Ok) {
                return status;
            }
            break;
        }

        case MemAddrSize::Size8Bit: {
            // 直接发送八位地址
            I2C_SendData(this->i2c_x_, memory_address);
            status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
            if (status != Status::Ok) {
                return status;
            }
            break;
        }

        default:
            break;
    }

    // 5. 再次生成起始条件
    I2C_GenerateSTART(this->i2c_x_, ENABLE);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT);
    if (status != Status::Ok) {
        return status;
    }

    // 6. 发送设备地址(读模式)
    I2C_Send7bitAddress(this->i2c_x_, device_address, I2C_Direction_Receiver);
    status = this->I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
    if (status != Status::Ok) {
        return status;
    }

    // 7. 读取数据
    for (auto it = read_buffer.begin(); it != read_buffer.end(); it++) {
        if (std::next(it) == read_buffer.end()) {
            // 如果是最后一个字节,则不应答,并提前产生停止条件
            I2C_AcknowledgeConfig(this->i2c_x_, DISABLE);
            I2C_GenerateSTOP(this->i2c_x_, ENABLE);
        }
        status = this->I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_RECEIVED);
        if (status != Status::Ok) {
            I2C_AcknowledgeConfig(this->i2c_x_, ENABLE);
            return status;
        }

        *it = I2C_ReceiveData(this->i2c_x_);
    }

    // 8. 恢复ACK
    I2C_AcknowledgeConfig(this->i2c_x_, ENABLE);

    return status;
}

/**
 * @brief I2C检查事件,带超时判断
 *
 * @param event     待检查的事件
 * @return Status   检查结果
 */
Status I2C_Handle::I2C_CheckEvent(uint32_t event)
{
    for (uint32_t timeout = 0; timeout < this->timeout_; timeout++) {
        if (::I2C_CheckEvent(this->i2c_x_, event) == SUCCESS) {
            return Status::Ok;
        }
    }
    return Status::Timeout;
}

/**
 * @brief 等待I2C总线空闲
 *
 * @return Status 等待结果
 */
Status I2C_Handle::I2C_WaitBus()
{
    for (uint32_t timeout = 0; timeout < this->timeout_; timeout++) {
        if (I2C_GetFlagStatus(this->i2c_x_, I2C_FLAG_BUSY) != SET) {
            return Status::Ok;
        }
    }
    return Status::Busy;
}

posted @ 2026-01-18 00:21  ~夏至、微风~  阅读(2)  评论(0)    收藏  举报