为什么要使用LL库,因为生成的固件大小可以小很多很多,MCU贵呀,可以省很多成本了。
uint8_t i2c_read_len(I2C_TypeDef *I2Cx, uint8_t Addr , uint8_t Reg, uint8_t len,uint8_t *buf);
uint8_t i2c_write_len(I2C_TypeDef *I2Cx, uint8_t addr , uint8_t reg, uint8_t len,uint8_t *buf);
实现这两个函数,理论上全部写需求都好了,网上的例子不知道为什么不可用,同时网上的例子也不支持多字节读写,参考了HAL I2C的代码实现,调通可用,如下:
uint8_t i2c_read_len(I2C_TypeDef *I2Cx, uint8_t Addr , uint8_t Reg, uint8_t len,uint8_t *buf)
{
/* 1.保证I2C外设不在使用中. */
while(LL_I2C_IsActiveFlag_BUSY(I2Cx));
/* Check if the I2C is already enabled */
if ((I2Cx->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
{
/* Enable I2C peripheral */
LL_I2C_Enable(I2Cx);
}
/* Disable Pos */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_POS);
/* Enable Acknowledge */
SET_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* 2.发送START信号 */
LL_I2C_GenerateStartCondition(I2Cx);
while(!LL_I2C_IsActiveFlag_SB(I2Cx));
/* 2.写器件地址 */
LL_I2C_TransmitData8(I2Cx, Addr);
/* Wait until ADDR flag is set */
while(!LL_I2C_IsActiveFlag_ADDR(I2Cx)){};
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
/* Wait until TXE flag is set */
while(!LL_I2C_IsActiveFlag_TXE(I2Cx));
/* 4.发送器件寄存器地址. */
LL_I2C_TransmitData8(I2Cx, Reg);
while(!LL_I2C_IsActiveFlag_TXE(I2Cx));
/* 5.提供RESTART信号. */
// LL_I2C_GenerateStopCondition(I2Cx);
LL_I2C_GenerateStartCondition(I2Cx);
while(!LL_I2C_IsActiveFlag_SB(I2Cx));
/* 6.重新发送地址,并附带读标记. */
LL_I2C_TransmitData8(I2Cx, Addr | 0x01);
/* Wait until ADDR flag is set */
while(!LL_I2C_IsActiveFlag_ADDR(I2Cx)){};
//
if (len == 0U)
{
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
/* Generate Stop */
LL_I2C_GenerateStopCondition(I2Cx);
}
else if (len == 1U)
{
/* Disable Acknowledge */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
/* Generate Stop */
LL_I2C_GenerateStopCondition(I2Cx);
/* Re-enable IRQs */
__enable_irq();
}
else if (len == 2U)
{
/* Enable Pos */
SET_BIT(I2Cx->CR1, I2C_CR1_POS);
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
/* Disable Acknowledge */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* Re-enable IRQs */
__enable_irq();
}
else
{
/* Enable Acknowledge */
SET_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
}
while (len > 0U)
{
if (len <= 3U)
{
/* One byte */
if (len == 1U)
{
/* Wait until RXNE flag is set */
while(!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
}
/* Two bytes */
else if (len == 2U)
{
/* Wait until BTF flag is set */
while(!LL_I2C_IsActiveFlag_BTF(I2Cx)){}
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Generate Stop */
LL_I2C_GenerateStopCondition(I2Cx);
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
/* Re-enable IRQs */
__enable_irq();
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
}
/* 3 Last bytes */
else
{
/* Wait until BTF flag is set */
while(!LL_I2C_IsActiveFlag_BTF(I2Cx)){}
/* Disable Acknowledge */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
/* Wait until BTF flag is set */
while(!LL_I2C_IsActiveFlag_BTF(I2Cx)){}
/* Generate Stop */
LL_I2C_GenerateStopCondition(I2Cx);
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
/* Re-enable IRQs */
__enable_irq();
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
}
}
else
{
/* Wait until RXNE flag is set */
while(!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
if (LL_I2C_IsActiveFlag_BTF(I2Cx))
{
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
}
}
}
return 0;
}
uint8_t i2c_write_len(I2C_TypeDef *I2Cx, uint8_t addr , uint8_t reg, uint8_t len,uint8_t *buf)
{
int i=0;
/* 1.保证I2C外设不在使用中. */
while(LL_I2C_IsActiveFlag_BUSY(I2Cx));
/* Check if the I2C is already enabled */
if ((I2Cx->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
{
/* Enable I2C peripheral */
LL_I2C_Enable(I2Cx);
}
/* Disable Pos */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_POS);
/* 2.发送START信号 */
LL_I2C_GenerateStartCondition(I2Cx);
while(!LL_I2C_IsActiveFlag_SB(I2Cx));
/* 2.写器件地址 */
LL_I2C_TransmitData8(I2Cx, addr);
LL_mDelay(1);
while(!LL_I2C_IsActiveFlag_ADDR(I2Cx));
LL_I2C_ClearFlag_ADDR(I2Cx);
/* 3.地址位已经置位,通常TXE也会完成,为了谨慎,再查一下. */
while(!LL_I2C_IsActiveFlag_TXE(I2Cx)){}
/* 4.发送器件寄存器地址. */
LL_I2C_TransmitData8(I2Cx, reg);
i = len;
while(i>0)
{
while(!LL_I2C_IsActiveFlag_TXE(I2Cx)){};
/* 5.写入寄存器内容 */
LL_I2C_TransmitData8(I2Cx, *buf);
buf++;
i--;
if(LL_I2C_IsActiveFlag_BTF(I2Cx)==SET && i!=0)
{
LL_I2C_TransmitData8(I2Cx, *buf);
buf++;
i--;
}
}
while(!LL_I2C_IsActiveFlag_BTF(I2Cx)){}
/* 6.传送结束条件. */
LL_I2C_GenerateStopCondition(I2Cx);
return 0;
}