This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

BQ27441调试时遇到问题,IIC信号没有任何响应……

Other Parts Discussed in Thread: BQSTUDIO, EV2400

我们在使用BQ27441芯片时,电池采用不可插拔的模式,电池接入后,我们使用单片机IIC接口,进行寄存器的读取和设置都没有ACK信号。

请大神帮忙看看,谢谢。

代码如下:

//main.c

#include "sys.h"
#include "delay.h"
#include "myiic.h"
#include "bq27441_driver.h"

u8 Volt;

int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化

bq27441_init();
Volt = getBoxBattery();

while(1)
{
Volt = getBoxBattery();
delay_ms(100);
}
}

//bq27441_driver.c

#include "bq27441_driver.h"
#include "common.h"
#include "myiic.h"
#include "delay.h"

const uint16_t terminatevoltage ={0x0C80}; //terminate voltage=3000mV,system shutdown voltage , 系统的正常工作电压
//
const uint16_t loadselect ={0x81}; //load select/load loadselectmode; 0x81 power-mode 0x01 current mode, normally use 0x81 ,if design capacity > 8500mAh change to 0x01
#define BATTERY_3200MAH
uint32_t Frack_Num;
u8 FlagBuf[2];
/**************************************************************************************
**************************************************************************************/


#ifdef BATTERY_3200MAH
//3200mAH
unsigned short const Designcapacity={0x0C80}; //Design capacity=2500mAh 这个值随着电池的使用会变化
unsigned short const DesignEnergy={0x2E40}; //Design Energy=2500*3.8mWh; Design Energy=Design capacity*3.7 for 4.2V battery,Design Energy=Design capacity*3.8 for 4.35V battery,
#define FCC_SIZE 950

//220 充电
//Taperrate 是一个充电截止判定的量
const uint16_t Taperrate ={0x0140}; //Taper rate=250,taper rate=Design Capacity*10/taper current mA;(2500*10/220 = 125) a little higher than charger taper current(~>20mA)


//subclass 81
//放电电流 大于62mA 2500*10 / 62.5ma = 400
const uint16_t Dsgcurrentthreshold ={0x190}; // 50000/167=299mA, Dsg current threshold(num)=500, Dsg current threshold(mAh)=Design capacity*10/Dsg current threshold(num)=80mA


//充电电流一定大于这个电流 100mA 2500*10/100 = 250
const uint16_t Chgcurrentthreshold ={0xfa}; //Chg current threshold(num)=500, Chg current threshold(mAh)=Design capacity*10/Chg current threshold(num)=80mA,must smaller than charger taper current


//进入低功耗电流 2500 * 10 / 50ma = 500
const uint16_t Quitcurrent ={0x01f4}; //{0x03E8}; //Quit current threshold(num)=1000,Quit current threshold(mAh)=Design capacity*10/Quit current threshold(num)=40mA

#endif

/**************************************************************************************
**************************************************************************************/


#ifdef BATTERY_3200MAH
const uint16_t Qmax ={0x4000};
const uint16_t Ra[] ={0x66, 0x66, 0x63, 0x6b, 0x48, 0x3b, 0x3e, 0x3f, 0x35, 0x2f, 0x3c, 0x46, 0x8c, 0x171, 0x24c};
//const uint16_t Ra[] ={0x34, 0x34, 0x32, 0x36, 0x2d, 0x32, 0x47, 0x52, 0x50, 0x4b, 0x57, 0x52, 0x72, 0x108, 0x1a4};
#endif

#ifdef BATTERY_2000MAH
uint16_t volt,soc,fcc ;
int16_t avgCur;
#endif
/**************************************************************************************
**************************************************************************************/

static uint32_t bq_MemoryWrite(uint8_t subaddr, uint16_t data );
static uint8_t GetCheckSum(uint8_t addr);
static void bq_Read_Ta_and_Qmax(void);
static void bq_fullReset(void);
static void bq_CONFIG_subclass82(void);
static void bq_CONFIG_subclass81(void);
static void bq_CONFIG_subclass89(void);
static uint32_t bq_ConfigRead(void);
static uint32_t bq_Rdarg(uint16_t *volt, int16_t *avgCur, uint16_t *soc, uint16_t *fcc);
uint16_t bq_ITPOR(void);
/**************************************************************************************
**************************************************************************************/

/**************************************************************************************
**************************************************************************************/


/********************************************************
向subaddr 这个地址写入cmd这个指令(写单个指令)
********************************************************/
uint32_t bq_cmdWrite(uint8_t subaddr, uint8_t cmd)
{
return Hal_IIC_Write_Byte(BQ2744_ADDRESS, subaddr, cmd);
}
/*************************************
*************************************/
uint32_t bq_read(uint8_t *pBuf, uint8_t addr, uint8_t len)
{
return Hal_IIC_Read_Len(BQ2744_ADDRESS, addr, len, pBuf);
}

/********************************************************
*********************************************************/
uint32_t bq_MemoryWrite(uint8_t subaddr, uint16_t data )
{
uint8_t Mdata=(data>>8);
uint8_t Ldata=(data&0xFF);
Hal_IIC_Write_Byte(BQ2744_ADDRESS, subaddr, Mdata);
return Hal_IIC_Write_Byte(BQ2744_ADDRESS, subaddr+1, Mdata);
}
/********************************************************
*********************************************************/
uint8_t GetCheckSum(uint8_t addr)
{
uint8_t checksum = 0, i;
uint8_t rtBuf[2];

for (i = 0; i < 32; i++)
{
rtBuf[0] = 0;
bq_read(rtBuf, addr, 1);
checksum = checksum + rtBuf[0];
addr++;
}

checksum = 0xFF - checksum;
return checksum;
}
/********************************************************
*********************************************************/
void bq_Read_Ta_and_Qmax(void)
{

unsigned short qmax=0x00;
uint8_t Ra_table[32]= {0x0A};
unsigned short cap=0x00;

uint8_t buf[2];
uint8_t tbuf[2];

uint8_t i;
tbuf[0]=0;
tbuf[1]=0;
Ra_table[31]='\r';
Ra_table[30]='\n';
bq_cmdWrite(0x00,0x00); //Places the device in UNSEALED access mode.
bq_cmdWrite(0x01,0x80);

bq_cmdWrite(0x00,0x00);
bq_cmdWrite(0x01,0x80);


bq_cmdWrite(0x61,0x00); // enables BlockData() to access to RAM.

bq_cmdWrite(0x3e,0x52); //选择0x52区域 //access the state subclass (decimal 82, 0x52 hex)

bq_cmdWrite(0x3f,0x00); //use offset 0x00 for offsets 0 to 31


bq_read(buf, 0x40, 2);
qmax = (buf[0] << 8) | buf[1]; //高低位交换

bq_read(buf, 0x4A, 2);
cap = (buf[0] << 8) | buf[1]; //高低位交换


bq_cmdWrite(0x3e,0x59);//选择0x59区域
bq_cmdWrite(0x3f,0x00);

for(i=0; i<30; i++)
{
bq_read(buf, 0x40+i, 1);
Ra_table[i] = buf[0]; //高低位交换
}
// HAL_UART_Transmit(&huart2,Ra_table,32,0xff);
//
//
// Frack_Num++;
// tbuf[0]=Frack_Num>>24;
// HAL_UART_Transmit(&huart2,tbuf,1,0xff);
// tbuf[0]=((Frack_Num>>16)&0xFF);
// HAL_UART_Transmit(&huart2,tbuf,1,0xff);
// tbuf[0]=((Frack_Num>>8)&0xFF);
// HAL_UART_Transmit(&huart2,tbuf,1,0xff);
// tbuf[0]=(Frack_Num&0xFF);
// HAL_UART_Transmit(&huart2,tbuf,1,0xff);
// bq_cmdWrite(0x3e,0x40);//选择0x59区域
// bq_cmdWrite(0x3f,0x00);
//
//
// bq_read(buf, 0x40, 1);
// HAL_UART_Transmit(&huart2,buf,1,0xff);
// bq_read(tbuf, 0x41, 1);
// HAL_UART_Transmit(&huart2,tbuf,1,0xff);

}

/********************************************************
*********************************************************/
void bq_fullReset(void)
{
if (bq_cmdWrite(0x00,0x00) || bq_cmdWrite(0x01,0x80)) return ; //Places the device in UNSEALED access mode.
if (bq_cmdWrite(0x00,0x00) || bq_cmdWrite(0x01,0x80)) return ;
if (bq_cmdWrite(0x00,0x41) || bq_cmdWrite(0x01,0x00)) return;//Performs a full device reset.
}

/********************************************************
*********************************************************/

void bq_CONFIG_subclass82(void)
{
uint8_t checksum = 0;
bq_cmdWrite(0x3e, 0x52); //选择0x52区域 //access the state subclass (decimal 82, 0x52 hex)
bq_cmdWrite(0x3f, 0x00); //use offset 0x00 for offsets 0 to 31
bq_MemoryWrite(0x40, Qmax);
bq_MemoryWrite(0x50, terminatevoltage); //terminatevoltage 截止电压(系统能够正常运行的最低电压)
bq_cmdWrite(0x45, loadselect);
bq_MemoryWrite(0x4A, Designcapacity); //电池容量 mAh
bq_MemoryWrite(0x4C, DesignEnergy); //mWh
bq_MemoryWrite(0x5B, Taperrate);
checksum = GetCheckSum(0x40);
bq_cmdWrite(0x60, checksum); //0xba checksum
}
void bq_CONFIG_subclass81(void) //充放电阈值设置
{
uint8_t checksum = 0;
bq_cmdWrite(0x3e, 0x51); //选择0x51区域
bq_cmdWrite(0x3f, 0x00);
bq_MemoryWrite(0x40, Dsgcurrentthreshold); //放电电流
bq_MemoryWrite(0x42, Chgcurrentthreshold); //充电电流,充电电流的判断标准
bq_MemoryWrite(0x44, Quitcurrent); //静态电源
checksum = GetCheckSum(0x40);
bq_cmdWrite(0x60, checksum); //0x5e
}

void bq_CONFIG_subclass89(void)//内阻表设置
{
uint8_t checksum = 0, i = 0;
bq_cmdWrite(0x3e, 0x59); //选择0x59区域
bq_cmdWrite(0x3f, 0x00);
for (i = 0; i < 15; i++) {
bq_MemoryWrite(0x40 + i * 2, Ra[i]);
}
checksum = GetCheckSum(0x40);
bq_cmdWrite(0x60, checksum);
}

/********************************************************
返回0, 进入配置模式并退出成功, 返回1, 进入配置失败, 返回0xFE, 超时
*********************************************************/
uint8_t bq_Config(void)
{
uint16_t value;
uint32_t result;
u8 state;

static uint32_t m_tryCnt = 0;

if (m_tryCnt++ > 10)
{
m_tryCnt = 0;
return 0xFE;
}

if (bq_cmdWrite(0x00, 0x00) || bq_cmdWrite(0x01, 0x80)) return 1;//Places the device in UNSEALED access mode.
if (bq_cmdWrite(0x00, 0x00) || bq_cmdWrite(0x01, 0x80)) return 2;
if (bq_cmdWrite(0x00, 0x13) || bq_cmdWrite(0x01, 0x00)) return 3;

delay_ms(1);

result = bq_read(FlagBuf, bq27421CMD_FLAG_LSB, 2);
if (result == 0)
{
value = (FlagBuf[1] << 8) | FlagBuf[0];

if (!(value & 0x10))
{
bq_cmdWrite(0x61,0x00); // enables BlockData() to access to RAM.
bq_CONFIG_subclass82();

bq_cmdWrite(0x00,0x42); //软复位 退出配置模式
bq_cmdWrite(0x01,0x00);

bq_cmdWrite(0x00,0x00);
bq_cmdWrite(0x01,0x00);

m_tryCnt = 0;
}
else
{
bq_cmdWrite(0x61,0x00); // enables BlockData() to access to RAM.
bq_CONFIG_subclass82();

bq_cmdWrite(0x00,0x42); //软复位 退出配置模式
bq_cmdWrite(0x01,0x00);

bq_cmdWrite(0x00,0x00);
bq_cmdWrite(0x01,0x00);
result = 4;
}
}
else
result = 5;
return result;
}

/********************************************************
返回0, 配置成功, 返回1, 配置失败 返回其他, 配置超时
*********************************************************/
uint32_t bq_ConfigRead(void)
{
uint16_t value;
uint32_t result;

result = bq_read(FlagBuf, bq27421CMD_FLAG_LSB, 2);
if (result != 0) return 0xFF;
if (result == 0)
{
value = (FlagBuf[1] << 8) | FlagBuf[0];
if (value & 0x10) result = 1;
else
{
bq_cmdWrite(0x00,0x20);
bq_cmdWrite(0x01,0x00);
}
}

return result;
}


/********************************************************
读参数
********************************************************/
uint32_t bq_Rdarg(uint16_t *volt, int16_t *avgCur, uint16_t *soc, uint16_t *fcc)
{
uint8_t lrtBuf[1];
uint8_t mrtBuf[1];

uint16_t value;
uint16_t ret1;
uint16_t ret2;

ret1 = bq_read(lrtBuf, bq27421CMD_VOLT_LSB, 1);
ret2 = bq_read(mrtBuf, bq27421CMD_VOLT_MSB, 1);
if(0 == ret1 && ret2 == 0)
{
value = (mrtBuf[0] << 8) |lrtBuf[0];
*volt = value;
}
else
{
return 0xF1;
}


bq_read(lrtBuf, bq27421CMD_AI_LSB, 1);
bq_read(mrtBuf, bq27421CMD_AI_MSB, 1);
if(0 == ret1 && ret2 == 0)
{
value = (mrtBuf[0] << 8) |lrtBuf[0];
*avgCur = value;
}
else
{
return 0xF1;
}


bq_read(lrtBuf, bq27421CMD_SOC_LSB, 1);
bq_read(mrtBuf, bq27421CMD_SOC_MSB, 1);
if(0 == ret1 && ret2 == 0)
{
value = (mrtBuf[0] << 8) |lrtBuf[0];
*soc = value;
}
else
{
return 0xF1;
}

bq_read(lrtBuf, bq27421CMD_FCC_LSB, 1);
bq_read(mrtBuf, bq27421CMD_FCC_MSB, 1);
if(0 == ret1 && ret2 == 0)
{
value = (mrtBuf[0] << 8) |lrtBuf[0];
*fcc = value;
}
else
{
return 0xF1;
}
return ret1;
}


/********************************************************
返回1 出错; 返回AA 需要配置 返回BB 已配置过
********************************************************/
uint16_t bq_ITPOR(void)
{
uint32_t ret;

ret = bq_read(FlagBuf, bq27421CMD_FLAG_LSB, 2);
if (ret != 0)return 1;
if (FlagBuf[0] & 0x20)return 0xAA;
return 0xBB;
}


uint8_t getBoxBattery(void)
{
uint16_t volt,soc,fcc ;
int16_t avgCur;
u32 s;

s = bq_Rdarg(&volt, &avgCur, &soc, &fcc);
return volt&0xFF;
}

uint8_t Batter_Gauge_Test()
{
uint8_t data;
uint16_t volt,soc,fcc ;
int16_t avgCur;
volt=bq_ITPOR();


if(volt == 1 )
{
bq_Config();
if(bq_ConfigRead() != 0)
return 2;
}

bq_Read_Ta_and_Qmax();
bq_Rdarg(&volt, &avgCur, &soc, &fcc);

return 1;
}

/********************************************************
返回0, 进入配置模式并退出成功, 返回1, 进入配置失败, 返回0xFE, 超时
*********************************************************/
uint32_t bq_Config_nww(void)
{
uint16_t value;
uint32_t result;

static uint8_t m_tryCnt = 0;

if (m_tryCnt++ > 10)
{
m_tryCnt = 0;
return 0xFE;
}

if (bq_cmdWrite(0x00, 0x00) || bq_cmdWrite(0x01, 0x80)) return 1;//Places the device in UNSEALED access mode.
if (bq_cmdWrite(0x00, 0x00) || bq_cmdWrite(0x01, 0x80)) return 2;
if (bq_cmdWrite(0x00, 0x13) || bq_cmdWrite(0x01, 0x00)) return 3;

delay_ms(1);
result=1;
while(result)
{
result = bq_read(FlagBuf, bq27421CMD_FLAG_LSB, 2);
if (result == 0)
{
value = (FlagBuf[1] << 8) | FlagBuf[0];
result=(value & 0x10);
}
}
bq_cmdWrite(0x61,0x00); // enables BlockData() to access to RAM.
bq_CONFIG_subclass82();
return result;
}

void bq27441_init(void)
{
u8 state;
IIC_Init();//初始化IIC总线
state = bq_ITPOR();
if(state == 0xAA)
{
delay_ms(1100);
state = bq_Config();
delay_ms(10);
state = bq_ConfigRead();
}
}

//myiic.c

#include "myiic.h"
#include "delay.h"


//初始化IIC
void IIC_Init(void)
{
RCC->APB2ENR|=1<<3; //先使能外设IO PORTB时钟
GPIOB->CRL&=0X00FFFFFF; //PB6/7 推挽输出
GPIOB->CRL|=0X33000000;
GPIOB->ODR|=3<<6; //PB6,7 输出高
}
//产生IIC起始信号
void IIC_Start(void)//START:when CLK is high,DATA change form high to low
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)//STOP:when CLK is high DATA change form low to high
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(8);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u32 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>450)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}

//IIC连续写
//addr:器件地址
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
// 其他,错误代码
u8 Hal_IIC_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
u8 i;
IIC_Start();
IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令
if(IIC_Wait_Ack()) //等待应答
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(reg); //写寄存器地址
IIC_Wait_Ack(); //等待应答
for(i=0;i<len;i++)
{
IIC_Send_Byte(buf[i]); //发送数据
if(IIC_Wait_Ack()) //等待ACK
{
IIC_Stop();
return 1;
}
}
IIC_Stop();
return 0;
}
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
// 其他,错误代码
u8 Hal_IIC_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
IIC_Start();
IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令
if(IIC_Wait_Ack()) //等待应答
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(reg); //写寄存器地址
IIC_Wait_Ack(); //等待应答
IIC_Start();
IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令
IIC_Wait_Ack(); //等待应答
while(len)
{
if(len==1)*buf=IIC_Read_Byte(0);//读数据,发送nACK
else *buf=IIC_Read_Byte(1); //读数据,发送ACK
len--;
buf++;
}
IIC_Stop(); //产生一个停止条件
return 0;
}

//IIC写一个字节
//reg:寄存器地址
//data:数据
//返回值:0,正常
// 其他,错误代码
u8 Hal_IIC_Write_Byte(u8 Addr, u8 reg,u8 data)
{
IIC_Start();
IIC_Send_Byte((Addr<<1)|0);//发送器件地址+写命令
if(IIC_Wait_Ack()) //等待应答
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(reg); //写寄存器地址
IIC_Wait_Ack(); //等待应答
IIC_Send_Byte(data);//发送数据
if(IIC_Wait_Ack()) //等待ACK
{
IIC_Stop();
return 1;
}
IIC_Stop();
return 0;
}
//IIC读一个字节
//reg:寄存器地址
//返回值:读到的数据
u8 Hal_IIC_Read_Byte(u8 Addr, u8 reg)
{
u8 res;
IIC_Start();
IIC_Send_Byte((Addr<<1)|0);//发送器件地址+写命令
IIC_Wait_Ack(); //等待应答
IIC_Send_Byte(reg); //写寄存器地址
IIC_Wait_Ack(); //等待应答
IIC_Start();
IIC_Send_Byte((Addr<<1)|1);//发送器件地址+读命令
IIC_Wait_Ack(); //等待应答
res=IIC_Read_Byte(0);//读取数据,发送nACK
IIC_Stop(); //产生一个停止条件
return res;
}