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

浙公网安备 33010602011771号