I2C 传输函数 - STM32 LL 库实现
void I2CTransfer(uint16_t deviceAddr, uint8_t cmdArray[], uint8_t dataArray[], uint16_t cmdLen, uint16_t dataLen, uint16_t flag)
{
// 初始化I2C外设
LL_I2C_InitTypeDef I2C_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
if(deviceAddr == BQ27441_G1_ADDR)
{
// 使能I2C外设时钟
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
// 配置I2C外设参数
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
I2C_InitStruct.Timing = 0x00707CBB;
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_DISABLE;
I2C_InitStruct.DigitalFilter = 0;
I2C_InitStruct.OwnAddress1 = 0;
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
LL_I2C_Init(I2C1, &I2C_InitStruct);
// 配置I2C外设GPIO
GPIO_InitStruct.Pin = LL_GPIO_PIN_6 | LL_GPIO_PIN_7;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
// 开始I2C传输
LL_I2C_Enable(I2C1);
// 发送起始条件
LL_I2C_GenerateStartCondition(I2C1);
// 等待起始条件设置完成
while(!LL_I2C_IsActiveFlag_SB(I2C1));
// 发送器件地址
LL_I2C_TransmitData8(I2C1, deviceAddr << 1);
// 等待地址发送完成
while(!LL_I2C_IsActiveFlag_ADDR(I2C1));
LL_I2C_ClearFlag_ADDR(I2C1);
// 发送命令
for(uint16_t i = 0; i < cmdLen; i++)
{
LL_I2C_TransmitData8(I2C1, cmdArray[i]);
while(!LL_I2C_IsActiveFlag_TXE(I2C1));
}
// 等待数据发送完成
while(!LL_I2C_IsActiveFlag_TXE(I2C1));
// 发送停止条件
LL_I2C_GenerateStopCondition(I2C1);
// 等待停止条件设置完成
while(!LL_I2C_IsActiveFlag_STOP(I2C1));
LL_I2C_ClearFlag_STOP(I2C1);
// 读取或写入数据
if(flag == I2C_FLAG_WRITE_READ)
{
// 发送起始条件
LL_I2C_GenerateStartCondition(I2C1);
// 等待起始条件设置完成
while(!LL_I2C_IsActiveFlag_SB(I2C1));
// 发送器件地址
LL_I2C_TransmitData8(I2C1, deviceAddr << 1 | 1);
// 等待地址发送完成
while(!LL_I2C_IsActiveFlag_ADDR(I2C1));
LL_I2C_ClearFlag_ADDR(I2C1);
// 读取数据
for(uint16_t i = 0; i < dataLen; i++)
{
if(i == dataLen - 1)
{
LL_I2C_AcknowledgeNextValue(I2C1, LL_I2C_NACK);
}
while(!LL_I2C_IsActiveFlag_RXNE(I2C1));
dataArray[i] = LL_I2C_ReceiveData8(I2C1);
}
// 发送停止条件
LL_I2C_GenerateStopCondition(I2C1);
// 等待停止条件设置完成
while(!LL_I2C_IsActiveFlag_STOP(I2C1));
LL_I2C_ClearFlag_STOP(I2C1);
}
else if(flag == I2C_FLAG_WRITE_WRITE)
{
// 发送起始条件
LL_I2C_GenerateStartCondition(I2C1);
// 等待起始条件设置完成
while(!LL_I2C_IsActiveFlag_SB(I2C1));
// 发送器件地址
LL_I2C_TransmitData8(I2C1, deviceAddr << 1);
// 等待地址发送完成
while(!LL_I2C_IsActiveFlag_ADDR(I2C1));
LL_I2C_ClearFlag_ADDR(I2C1);
// 写入数据
for(uint16_t i = 0; i < dataLen; i++)
{
LL_I2C_TransmitData8(I2C1, dataArray[i]);
while(!LL_I2C_IsActiveFlag_TXE(I2C1));
}
// 发送停止条件
LL_I2C_GenerateStopCondition(I2C1);
// 等待停止条件设置完成
while(!LL_I2C_IsActiveFlag_STOP(I2C1));
LL_I2C_ClearFlag_STOP(I2C1);
}
// 禁用I2C传输
LL_I2C_Disable(I2C1);
}
使用说明:
deviceAddr: 器件地址,左移一位用于设置7位地址模式cmdArray: 命令数组dataArray: 数据数组cmdLen: 命令数组长度dataLen: 数据数组长度flag: 传输类型,I2C_FLAG_WRITE_READ为写命令后读数据,I2C_FLAG_WRITE_WRITE为写命令后写数据
代码说明:
- 函数首先初始化 I2C 外设和 GPIO,并使能 I2C 时钟。
- 然后发送起始条件和器件地址。
- 根据传输类型,发送命令数组和数据数组。
- 最后发送停止条件,并等待传输完成。
注意事项:
- 确保 I2C 时钟频率和 I2C 传输速度匹配器件的要求。
- 注意 I2C 传输过程中可能会出现错误,需要添加错误处理机制。
- 该代码示例仅供参考,实际应用中可能需要进行修改和调整。
原文地址: https://www.cveoy.top/t/topic/nggT 著作权归作者所有。请勿转载和采集!