STM32 讀取 BQ27541 電量

STM32 讀取 BQ27541 這是個人最近所接到的案子,要讀取電池包中的SOC,花了幾天終於完成了經驗總結如下:

TI bq27541 datasheet 對I2C介面的讀取如下圖,
                                                                        圖1 
我要採用的是(c) 1 byte-read,
用的是ST 範例程式 M24C08 EEPROM讀取的範例來寫:
用的是 MultiByteRead中這函式來讀取。

main 中用的是
I2C_EE_MultiByteRead(Rx1 ,0x2c, u16 NumByteToRead)   註 0x2c 是BQ27541讀取 SOC

           而圖1 的時序我把它拆成下面七個步驟
Host Generated
 指令
Fuel Gauge Generated

1
Start,
I2C_GenerateSTART(I2C1, ENABLE);


  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 
2
ADDR[6:0] 0
I2C_Send7bitAddress(I2C1, 0xaa, I2C_Direction_Transmitter);
     
Acknowledge

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
3
CMD[7:0]
I2C_SendData(I2C1, (u8)ReadAddr);
Acknowledge

    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
4
Start,
  I2C_GenerateSTART(I2C1, ENABLE);


   while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
5
ADDR[6:0] 1
I2C_Send7bitAddress(I2C1, 0xab, I2C_Direction_Receiver);
Acknowledge


    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
for (i = NumByteToRead; i > 0; i--,pBuffer++)
    {
………………………………..
}
DATA[7:0]
6
No Acknowledge
I2C_AcknowledgeConfig(I2C1, DISABLE);


                 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
7
Stop
I2C_GenerateSTOP(I2C1, ENABLE);




 而在 i2c_ee.c 中的 void I2C_EE_MultiByteRead 的程式則被我改成如下:

void I2C_EE_MultiByteRead(u8* pBuffer, u16 ReadAddr, u16 NumByteToRead)

  u8 i = 0;
  /* Send STRAT condition */
  I2C_GenerateSTART(I2C1, ENABLE);

  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 

  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C1, 0xaa, I2C_Direction_Transmitter);
 
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
     
  /* Send the EEPROM's internal address to read from */

  I2C_SendData(I2C1, (u8)ReadAddr);
 
  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));


  /* Send STRAT condition */
  I2C_GenerateSTART(I2C1, ENABLE);

  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  /* Send EEPROM address for read */
  I2C_Send7bitAddress(I2C1, 0xab, I2C_Direction_Receiver);

 
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

      for (i = NumByteToRead; i > 0; i--,pBuffer++)
    {
        if (i == 1)
                {
                I2C_AcknowledgeConfig(I2C1, DISABLE);
                 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); 
                *pBuffer = I2C_ReceiveData(I2C1);
                I2C_AcknowledgeConfig(I2C1, ENABLE);

                }
        else
            {
                I2C_AcknowledgeConfig(I2C1, ENABLE);
                 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); 
                *pBuffer = I2C_ReceiveData(I2C1); 
                i=i;
                }
    }

  /* Send STOP condition */
  I2C_GenerateSTOP(I2C1, ENABLE);


}


下面是我用網路上找的一個 GPIO 模擬 I2C 的讀取EEPRO 範例來修改 上面的字義更足以描述整個流程

 main 中用的是

I2C_ReadByte(Tx1_Buffer,   0x01,     0x2c,  0xAB);
--------------------------------------------------------------------------------------------

bool I2C_ReadByte(u8* pBuffer,   u8 length,     u16 ReadAddress,  u8 DeviceAddress)
{
 if(!I2C_Start())return FALSE;

    I2C_SendByte(0xAA& 0xFFFF);  //這是重點
    if(!I2C_WaitAck())
 {I2C_Stop();
      return FALSE;}
      I2C_SendByte(0x2c& 0x00FF));
    I2C_WaitAck();
     I2C_Start();
    I2C_SendByte(0xAB & 0xFFFF); //這是重點
    I2C_WaitAck();
    while(length)
    {
      *pBuffer = I2C_ReceiveByte();
      if(length == 1)I2C_NoAck();
      else I2C_Ack();
      pBuffer++;
      length--;
    }
    I2C_Stop();
    return TRUE;
}

留言

這個網誌中的熱門文章

STM32 I2C-EEPROM 的讀寫

如何提高STM32 ADC的精度

ADC的校正方法