Q: 问题解决了! 经过数周的调试排错,我终于实现了BMS与MCU的通信。因此,我将发布检查清单、待办事项、预防措施和调试步骤 我的设置是: MCU: Arduino Promini(5v版本) BMS: BQ7694003(3.3v版本) 电池组:13-15秒可配置 硬件调试 1. 从原理图开始,请确保遵循与BQ相关的数据表和参考设计。我发现TIDR773和TIDA00792非常有用。TIDR使用P-ch MOSFET进行平衡,而TIDA00792使用N-ch MOSFET进行平衡。您可根据自己的偏好进行选择。这两种设计的其他方面在概念上都很相似。 2. 如需要,确保将电容器靠近ic管脚放置。使负载电路远离敏感的数字电路,以最大限度地减少耦合到数字电路中的噪声。 3. 完整的接地用PCB层将大大降低噪声。 4. 尽管BQ被设计为处理随机的电池连接,但为安全起见,请先让电池接地,然后再插入电池1,插入电池2,再插入电池3,依此类推,直到插入最后一个电池。 5. 保持I2C轨迹短,并确保两者之间没有太多的电容耦合。这种耦合会导致I2C通信过程中的位识别错误 7. 切勿忘记I2C的上拉电阻!否则整个通信将出现故障。通常来讲,上拉使用4.7k-10k电阻。这是有关I2C通信基础知识的优秀指南。 9. 现在最重要的是,请检查数据表并验证以下管脚上的标称电压读数。 TS0, TS1, TS2
CAP1, CAP2, CAP3
V5X, VC10X, BAT
REGSRC
REGOUT CAP1 - GND = 3.3V
CAP2 - VC5X = 3.3V
CAP3 - VC10X = 3.3V
REGOUT = 3.3V 如果所有这些管脚上的电压读数均正确,则您可不必担心!您的硬件没有问题。 10. 也要连接NC管脚!另外,如果未使用热敏电阻,则通过10k电阻器将相应的TSx管脚下拉至GND。 11. TS1管脚上需要启动信号以唤醒BQ76940IC。不要指望IC自行唤醒:) 12. 将BQ的ALERT管脚连接到MCU的中断管脚。这将帮助您快速识别和清除故障 软件 调试 1. 确保所有的管脚声明和ISR均已设置并正常工作。逐个调试整个代码。请勿一次调试1000行代码。 2. 如要测试I2C通信,请首先运行I2C扫描器代码以找到BQ IC。这需要立即完成两件事——您可以验证BQ IC的I2C地址,此外,如果设备响应,则可以确保设备仍在运行! 3. 在MCU识别出BQ后,请测试I2C读写功能。(可选)读取BQ设备的所有寄存器并记录下来。 对于所有Arduino狂热粉丝,请使用Wire()库。读取顺序是- /* READS 1 BYTE */
byte registerRead(byte regAddress)
{
Wire.beginTransmission(bqI2CAddress);
Wire.write(regAddress);
Wire.endTransmission();
Wire.requestFrom(bqI2CAddress, 1); return (Wire.read());
} /* READS 2 BYTES */
int registerDoubleRead(byte regAddress)
{
Wire.beginTransmission(bqI2CAddress);
Wire.write(regAddress);
Wire.endTransmission(); Wire.requestFrom(bqI2CAddress, 2); byte reg1 = Wire.read();
byte reg2 = Wire.read(); int combined = (int)reg1 << 8;
combined |= reg2; return (combined);
} 4. 查找数据表以查找您的BQ IC是否启用了CRC。如果未启用CRC,则可以使用常规I2C通信协议直接写入BQ寄存器。如果启用了CRC,则必须计算CRC并将其发送给BQ,否则它将不接受对其寄存器的任何写入请求。 /* Write without CRC */
void registerWrite(byte regAddress, byte regData) {
Wire.beginTransmission(bqI2CAddress);
Wire.write(regAddress);
Wire.write(regData);
Wire.write(0x7A);
Wire.endTransmission();
}
/*Write with CRC*/
void registerWriteCRC(unsigned char regAddress, unsigned char regData)
{
uint8_t values[3] = { (bqI2CAddress << 1), regAddress, regData };
uint8_t crc = calc_crc(values, 3); Wire.beginTransmission(bqI2CAddress);
Wire.write(regAddress);
Wire.write(regData);
Wire.write(crc);
Wire.endTransmission();
} unsigned char calc_crc(unsigned char *ptr, unsigned char len)
{
unsigned char key = 7;
unsigned char i;
unsigned char crc = 0; while (len-- != 0)
{
for (i = 0x80; i != 0; i /= 2)
{
if ((crc & 0x80) != 0)
{
crc *= 2;
crc ^= key;
}
else
crc *= 2; if ((*ptr & i) != 0)
crc ^= key;
}
ptr++;
}
return (crc);
} 随时了解CRC计算的步骤。另外,使用CRC时的传输序列和CRC计算有些不同,因此请确保查看数据表以了解更多详细信息。 通过发送的字节计算CRC 5. 确保将接收的字节转换为实际值(伏特、安培等)。查找数据表中的公式。正如我之前提到的,你得像喜欢摇滚乐一样!编写软件将涉及很多 位触发和“撞头”情况。您必须让自己适应HEX、DEC和BIN的世界 6. 要检查写入功能是否起作用,只需将一个值写入寄存器并回读该寄存器。如果您的MCU读取的值与您先前写入的值相同,则写入功能起作用,读取功能也起作用! 7. 设置时,请确保清除XREADY位。这样做可以在BQ Ic遇到某些问题(例如过多的系统瞬态)时可帮您识别事件。
|