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.

[参考译文] BQ78350-R1:通过 SMBus 连接微控制器时、连接所述电池管理系统(BMS)需要什么初始化/配置?

Guru**** 2328790 points
Other Parts Discussed in Thread: BQ78350-R1, BQ78350, BQ76940, MSP430G2553, BQ76940EVM, MSP430FR5994, MSP-EXP430FR5994, MSP430F5338, BQSTUDIO
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/power-management-group/power-management/f/power-management-forum/588042/bq78350-r1-with-a-micro-controller-connected-via-smbus-what-initialization-configuration-is-required-to-interface-with-the-said-battery-management-system-bms

器件型号:BQ78350-R1
主题中讨论的其他器件: BQ78350BQ76940MSP430G2553BQ76940EVMMSP430FR5994MSP430WAREMSP-EXP430FR5994MSP430F5338BQSTUDIO

TRM 负责电池管理的各个方面、包括配置/编程寄存器以启用/禁用某些功能。 但是、由于我只需要从微控制器连接 BMS 即可从 BQ78350-R1的配置值中获取/查询数据、因此是否需要进行一系列初始化或配置才能读取所需的值?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!
    您需要首先根据数据表和 TRM 中的 smbus 协议建立 smbus 通信、
    然后向要读取的寄存器发送读取命令
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您是否想让我转到这样做的部分? 谢谢!

    此外、如果已经有这样做的示例、那将非常有益!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Jan、

    BQ78350无需进行任何特定配置。

    通常、您使用 BQ Studio 配置 BQ78350 (需要 EV2300或 EV23400)、然后所有设置都存储在 BQ 的闪存中。

    然后、使用与微控制器的接口来监控电池、而不是控制电池(如果需要、您仍可以使用微控制器更改设置)。 但在启动时不需要特定的配置。

    我刚才在这个另一个线程中为 MSP430微控制器发布了一些代码、您可以使用这些代码:

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢、Michel! 想知道我在哪里可以找到这些文件的 c#等效文件、否则我需要转换您的 C 代码。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这些是我自己与 MSP430微控制器一起使用的源。 我没有等效的 C#。

    实际上、我从未使用过使用 C#作为其源代码的微控制器。

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢您、Michel 分享了代码。 我认为、查看您在哪里以及如何调用.c 文件中定义的函数可能会很有用。 您是否愿意分享这一信息?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Jan、

    不幸的是、我无法披露整个代码。

    简而言之、我们有一个状态机、它通过 SMBus 定期读取电池状态、然后对这些读数执行操作。

    我可以共享位和段:

    例如、要读取电池电压、您需要执行以下操作:

    // 0x09对应于电池电压的寄存器地址
    //第二个参数(0)对应于我们发送的命令的索引(用于回调)
    // batt_data_buffer 是存储数据的缓冲区
    // battery_rx_done 是 SMBus 接口调用的回调函数,用于指示数据已被读取
    smbus_requestWord (0x09、0、batt_data_buffer、batter_rx_done); 

    和读取操作状态(通过制造商访问命令完成):

    // 0x0054参数对应于制造商访问中的命令 ID
    //第二个参数(1)对应于我们发送的命令的索引(用于回调)
    // batt 数据缓冲区是存储数据的缓冲区
    // battery_rx_done 是 SMBus 接口调用的回调函数,用于指示数据已读取
    smbus_requestMfrAccessReg (0x0054、1、batt 数据缓冲区、battery_rx_done); 

    SMBus 使用 BATTERY_Rx_DONE 回调函数来指示数据已接收。 它包含一个切换用例、然后将数据复制到适当的位置

    void battery_rx_done (unsigned char id){
    switch (id){
    case 0://voltage
    电压= batt 数据缓冲器[0]|(batt 数据缓冲器[1]<< 8);
    中断;
    案例1://操作状态
    operation_status[0]= batt_data_buffer[6];
    operation_status[1]= batt_data_buffer[5];
    operation_status[2]= batt_data_buffer[4];
    operation_status[3]= batt_data_buffer[3];
    
    //检查是否存在永久性故障
    if (operation_status[2]和0x10){
    //检测到永久故障
    Failure_Detected = 1;
    }
    中断;
    …
    
    ...}
    } 

    您需要确定您将需要什么、在哪里以及如何使用您读取的数据。

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Terry。

    TI 是否有建立此通信(通过 SMBus 连接 bq783650<->MCU)的示例代码或指南?
    如果您拥有或能够使用基于 MSP430G2553的 CRC 选项为 bq76940开发 I2C 通信示例代码(www.ti.com/.../slva626b.pdf)、那将是一个非常好的选择。

    此致、
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!
    我手上没有代码。 用户可能需要编辑代码。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Terry 和 Michel。

    我正在尝试使用 MSP430FR5994 (Launch Pad)实施一个非常简单的代码、以便通过 SMBus 读取 bq76940EVM 的电池电压。

    我以电池充电器的 SLAA476A 示例和 Michel 提供的代码为基础。

    不幸的是、我没有取得任何成功。 当我运行代码时、发送的唯一帧是下面显示的帧。


    当我在代码中放置一些断点时,它 总是停留在 SMBus_NotReady()中,或者在中断的情况4中,当我注释它时。

    我出了什么问题? 你有什么建议吗? 我应该在哪里查看?

    代码:

    smbus.h

    #ifndef SMBus_H_
    #define SMBus_H_
    
    //通用定义
    #define SMBus_MASTER_MODE_WRITE 0x00
    #define SMBus_MASTER_MODE_ADDRE 0x01
    #define SMBus_SLAVE_MODE_WRITE 0x02
    #define SMBus_SLAVE_MODE_READ 0x03
    #define SMBus_MODE_ADDR_ADDRE 0x09
    #define PM_PACE_ADDRE #define 0x16
    #define PM_FAIL_T=#define 000#define 000#define
    PM_FAIL #define 000#define SMBus_MODE_FLAG #define 000#define 000#define 000#define SMBus_
    
    
    
    
    
    
    
    CRC8_Poly 0x07
    #define CRC8_INIT_REM 0x0
    
    // SMBus 数据声明
    #define SMBus_DATA_TO_SLAVE 32 //发送表长度
    #define SMBus_DATA_FIT_SLAVE 32 //接收表长度
    
    // SMBus 命令定义
    #define SBS_CMD_TEMP_TEMD_TEMP_VOLTAGE
    0x09 #define
    SBS_CURRENT_0X0CCS_CURRENT #define CCS_CMD_CURRENT#define 0_CMD_CURRENT#define 0x14 #define SBS
    
    
    
    
    0x16
    #define SBS_CMD_Design_VOLTAGE 0x19
    #define SBS_CMD_FTORY_NAME 0x20
    #define SBS_CMD_DEVICE_NAME 0x21
    #define SBS_CMD_CELL_VOLTAGE_4 0x3C
    #define SBS_CMD_CELL_VOLTAGE_3 0x3D
    #define SBS_CMD_COLL_STATEART_BYTCG
    
    
    #define
    电池充电寄存器0x3E #define SBS #define COUNT_STATEARTTER/SBS COUNT_STATEART/ COYTC_BATERTTER1
    
    
    SBS_REG_BATTERYSTATUS_FC BIT5 //完全充电
    
    #define BUS_1 1
    #define BUS_1 2
    
    #define SMBus_MASTER_MODE 0
    #define SMBus_SLAVE_MODE 1
    
    #define SMBus_START_FLAG_SET 1
    #define SMBus_START_FLAG_RESET 0
    
    //外部全局变量声明
    extern SMBus_Data_SLAVE_TXCH_DATA_SLAVE_SET 1 #define SMBus_SLAVE_ST_SLAVE_RT_SLAVE_RT_DATA_SET 1 #define
    
    0 //从 SMBus_SLAVE_TXCH_SLAVE_OBJART/SLAVE_TXQ_SLAVE_RT_DATA_SLAVE_OBJART/无
    符号
    extern unsigned char * pRXData;//指向 RX 数据的指针
    extern unsigned char RXByteCounter;
    extern unsigned char RXFlag;//数据接收标志
    extern unsigned char TXFlag;//数据传输标志
    extern unsigned char RWFlag;//读取/写入标志
    extern unsigned char SMBus_Start_Flag;
    
    extern unsigned char size_bytes;extern unsigned char size_bytes;
    
    
    //函数原型
    unsigned char SMBUS_NotReady();
    静态 unsigned short crc8MakeBitwise (unsigned char CRC、unsigned char Poly、unsigned char *Pmsg、unsigned int Msg_size);
    
    #endif /*SMBus_H_*/ 

    main.c

    #include 
    #include 
    
    //全局变量
    unsigned char SMBus_Data_to_Slave[SMBus_data_to_Slave];
    unsigned char SMBus_Data_fin_Slave[SMBus_data_fin_slave];
    unsigned char * pTXData = 0x0; //指向 TX 数据的指针
    unsigned char TXByteCounter = 0;
    unsigned char * pRXData = 0x0; //指向 RX 数据的指针
    unsigned char RXByteCounter = 0;
    unsigned char RXFlag = flag_FAIL; //数据接收标志
    unsigned char TXFlag = FLAG_FAIL; //数据传输标志
    unsigned char RWFlag = SMBus_master_mode_read; //读取/写入标志
    无符号 char SMBus_Start_Flag = SMBus_start_FLAG;//是否已启动事务?
    
    unsigned char smbus_access_status = 0x0;
    unsigned char crc_msg_size = 0;
    unsigned char crc_master_generated
    = 0;
    unsigned char crc_slave_generated = 0;
    
    unsigned char size_in_bytes;
    unsigned char smbus_command;
    
    static short crc8Makebwise char msg (char char cCRC、Bitg、unsigned pig、unsigned pig
    
    unsigned int i、j、carry;
    unsigned char msg;
    
    CRC =* Pmsg++; //加载到"crc"中的第一个字节
    for (i = 0;i < Msg_size-1;I ++)
    {
    MSG =* Pmsg++; //在"msg"中加载下一个字节
    
    for (j = 0;j < 8;j++)
    {
    进位= CRC 和0x80; //检查 MSB=1
    CRC =(CRC << 1)|(msg >> 7);//将下一个字节的1位移入 CRC
    if (carry) CRC ^= Poly; //如果 MSB=1,执行 XOR
    MSG <<= 1; //左移 msg 字节1
    }
    }
    //前一个循环计算输入位流的 CRC。 为此、
    //填充8个尾随零,结果值的 CRC 为
    //已计算。 这给出了输入位流的最终 CRC。
    for (j = 0;j < 8;j++)
    {
    进位= CRC 和0x80;
    CRC <<= 1;
    if (carry) CRC ^= Poly;
    }
    
    return (CRC);
    }
    
    unsigned char SMBus_NotReady()
    {
    return ((UCB1STATW 和 UCBBUSY)||(UCB1STATW 和 UCSCLLOW));
    }
    
    int main (void)
    {
    WDTCTL = WDTPW | WDTHOLD; //停止 WDT
    
    //禁用 GPIO 上电默认高阻抗模式以激活
    //先前配置的端口设置
    PM5CTL0 &=~LOCKLPM5;
    
    //时钟设置
    CSCTL0_H = CSKKEY_H; //解锁 CS 寄存器
    CSCTL1 = DCOFSEL_0; //将 DCO 设置为 x MHz
    CSCTL2 = SELA_VLOCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 SMCLK = M0CLK = DCO、ACLK = VLOCLK
    CSCTL3 = DIVA__1 | DIVM_1 | DIVM__1;//设置分频器
    CSCTL2 = SELA_VLOCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 SMCLK = M0CLK = DCO、ACLK = VLOCLK
    CSCTL0_H = 0; //锁定 CS 寄存器
    
    //将 UCB 设置为 I2C 模式
    P5SEL0 |= BIT0 | BIT1;
    P5SEL1 &=~(BIT0 | BIT1);
    
    UCB1CTLW0 = UCSWRST; //将 eUSCI_B 置于复位状态
    UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL_SMCLK; // I2C 主控模式、SMCLK
    UCB1BRW = 0x0A; //波特率= SMCLK/UCBxBRW (十六进制)
    UCB1CTLW0 &=~UCSWRST; //清除复位寄存器
    UCB1IFG &= 0xFF; //清除所有标志
    UCB1I2CSA = BQ78350_ADDR; //从机地址是有效载荷的第一个字节
    UCB1CTLW1 &=~UCSWRST; //清除 SW 复位,恢复操作
    UCB1IE |= UCTXIE0 | UCNACKIE | UCRXIE; //发送和 NACK 中断使能
    
    _enable_interrupt ();
    
    while (1)
    {
    
    while (SMBus_NotReady()); //等待 SMBus 变为空闲状态
    
    SMBus_COMMAND = SBS_CMD_VOLTAGE;
    size_in_bytes = 2;
    
    TXByteCounter = 1; //目前 SMBus 命令的 TX 1字节
    pTXData =&(smbus_command);
    
    //根据 SBS 命令规范接收字节数
    //为 PEC 加一个额外的字节
    RXByteCounter = size_in_bytes + 1;
    
    //将 RX 字节存储在全局数组中
    pRXData =(unsigned char*) SMBus_Data_fin_Slave;
    
    //初始化标志以失败,除非成功
    RXFlag = FLAG_FAIL;
    RWFlag = SMBus_MASTER_MODE_READ; //读取模式
    
    while (UCB1CTL1 & UCTXSTP); //是否发送停止条件?
    
    TA1CTL = TASSEL_ACLK + TACLR + MC_UP; //开始计时器 A 测量超时
    SMBus_Start_Flag = SMBus_start_FLAG_set;
    UCB1CTL1 |= UCTR + UCTXSTT; //开始!
    while (UCB1CTL1 & UCTXSTT); //确保发送起始条件
    
    //从设备是否确认了自己的地址? 如果是、则继续
    //使用命令和数据包。
    if ((RXFlag!= FLAG_NACK)&&(RXFlag!= FLAG_FAIL)){
    _bis_SR_register (LPM0_bits + GIE); //输入带中断的 LPM0
    }
    
    // PEC 字节处理
    CRC_msg[0]= SMBus_SLAVE_ADDRESS << 1; // R/W 位为低电平的从器件地址
    crc_msg[1]= smbus_command; //命令字节
    CRC_msg[2]=(SMBus_SLAVE_ADDRESS << 1)+ 1;//从地址、R/W 位为高电平
    CRC_msg[3]= SMBus_Data_From_Slave[0]; //第一个字节 RX
    CRC_msg[4]= SMBus_Data_From_Slave[1]; //第二个字节 RX
    CRC_SLAVE_Generated = SMBus_Data_From_Slave[2];//存储从器件的 PEC 字节
    
    CRC_msg_SIZE = 5; //字节数
    /* CRC 函数调用,生成 CRC 字节与从器件 CRC*/进行比较
    crc_master_generated = crc8MakeBitwise (CRC8_INIT_REM、CRC8_Poly、CRC_msg、CRC_msg_size);
    
    // PEC 字节验证
    if (crc_master_generated = crc_slave_generated)
    {smbus_access_status = SMBus_PEC_Pass; // PEC 字节已验证
    }
    其他
    {smbus_access_status = SMBus_PEC_FAIL; // PEC 测试失败
    }
    }
    
    
    /*
    *函数名称:I2C/SMBus 中断矢量服务例程(USCI B1)
    *
    说明:此 ISR 在
    主从配置中将 MSP430 I2C USCI 模块配置为 RX 和 TX * SMBus 命令和数据。
    *** /
    #pragma vector = USCI_B1_vector
    __interrupt void USCI_B1_ISR (void)
    {
    switch (_even_in_range (UCB1IV、12))
    }{
    情况0:
    中断;
    案例2: // ALIFG
    中断;
    案例4: // NACKIFG
    UCB1CTLW1 |= UCTXSTP; //发送停止
    UCB1IFG &=~UCNACKIFG; //清除 NACK 标志
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
    RXFlag = FLAG_NACK; //数据操作失败
    TXFlag = FLAG_NACK; //数据操作失败
    中断;
    案例6: // STTIFG
    TA1CTL = TASSEL_ACLK + TACLR + MC_UP;
    SMBus_Start_Flag = SMBus_start_FLAG_set;
    中断;
    案例8: // STPIFG
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
    RXFlag = FLAG_SUCCESS; //将接收到的数据 RX 标志设置为成功
    中断;
    案例10: // RXIFG
    
    IF (RWFlag = SMBus_MASTER_MODE_READ)
    {
    RXByteCounter--; //递减 RX 字节计数器
    
    IF (RXByteCounter)
    {
    *pRXData+= UCB1RXBUF; //剩余要接收的多个字节
    TA1CTL = tassel_ACLK + TACLR + MC_UP;
    }
    其他
    {
    *pRXData= UCB1RXBUF; //要接收的最后一个字节
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
    RXFlag = FLAG_SUCCESS; //将接收到的数据 RX 标志设置为成功
    }
    
    
    if (RXByteCounter = 1) //只剩下一个字节?
    UCB1CTLW1 |= UCTXSTP; //生成 I2C 停止条件
    //如果只读取1个字节,则停止条件
    //应该已经发送
    }
    否则、如果(RWFlag = SMBus_SLAVE_MODE_WRITE)
    {
    *pRXData++= UCB1RXBUF; //将每个接收到的字节填充到数组
    中}
    中断;
    情况12: // TXIFG
    //当 UCB1TXBUF 为空时置1
    IF (RWFlag = SMBus_MASTER_MODE_READ)
    {
    IF (TXByteCounter) //如果有要传输的内容
    {
    UCB1TXBUF =*pTXData++; //加载 TX 缓冲区
    TXByteCounter--; //测量 TX 字节计数器
    RXFlag = FLAG_SUCCESS;
    }
    其他 //无需再传输
    {
    UCB1CTLW1 &=~UCTR; //接收器模式
    UCB1IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
    UCB1CTLW1 |= UCTXSTT; // I2C 重新启动(SMBus 协议)
    if (RXByteCounter = 1){ //只接收一个字节?
    //请参阅 USCI - I2C 模式中的 I2C 主接收器模式部分
    // 5xx 系列用户指南的一章(SLAU208G -第607页)
    while (UCB1CTLW1和 UCTXSTT); //已发送开始条件轮询
    UCB1CTLW1 |= UCTXSTP; //生成 I2C 停止条件
    }
    }
    
    否则、如果(RWFlag = SMBus_MASTER_MODE_WRITE)
    {
    IF (TXByteCounter) //如果有要传输的内容
    {
    UCB1TXBUF =*pTXData++; //加载 TX 缓冲区
    TXByteCounter--; //测量 TX 字节计数器
    TXFlag = FLAG_SUCCESS;
    }
    其他
    {
    UCB1CTLW1 |= UCTXSTP; // I2C 停止条件
    UCB1IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
    TXFlag = FLAG_SUCCESS;
    }
    }
    TA1CTL = TASSEL_ACLK + TACLR + MC_UP;
    中断;
    默认值:
    中断;
    }
    



    谢谢、  
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这是发送的第一个字节(0x16)。 我认为它是正确的...  

    我之前发送的打印屏幕就在它之后

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mauro、

    我看到两个可能的问题:

    1. 上升沿看起来非常慢。 (我会先测试此假设)
    2. 我使用的微控制器和您拥有的微控制器之间的外设逻辑可能不同。

    要检查它是否是上升沿问题、请降低波特率。 (您可以使用的最小值为10kHz)

    如果是外设逻辑问题、我建议您查看 Resource Explorer 中的示例代码。
    在 CCS 中、在"View"菜单下或在以下地址在线:

    在 Resource Explorer 中、转到以下路径:
    软件-> MSP430Ware XXXX ->开发工具-> MSP-EXP430FR5994 ->外设示例->寄存器级-> MSP430FR5994

    在该文件夹下、查找以 msp430fr599x_euscib_i2c._xxx 开头的文件
    此外、请在附近查看 MSP430FR599x 的用户指南以进行检查

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    代码如下:

    #include 
    #include 
    
    #define BQ78350_ADDR (0x16>>>1)
    #define MFR_BLK_ACCESS 0x44
    #define MAX_queue 75
    #define MAX_RX_LEN 50
    #define MAX_TX_LEN 10
    #define CRC8_Poly 0x07
    #define CRC8_INIT_REM 0x00
    
    int flag_50ms;
    int flag_100ms;
    int flag_500ms;
    int flag_1000ms;
    int flag_2000ms;
    
    int time = 0;
    
    int count_50ms;
    int count_100ms;
    int count_500ms;
    int count_1000ms;
    int count_2000ms;
    
    unsigned char batt_data_buffer[2]={0x00、0x00};
    unsigned char 电压;
    
    typedef struct message_t{
    无符号字符地址;
    unsigned char mess_dir;
    unsigned char is 块;
    unsigned char TX_DATA[MAX_TX_LEN];
    unsigned int tx_cnt;
    unsigned char * rx_data;
    unsigned int rx_cnt;
    unsigned char nack;
    void (* rx_done 回调)(unsigned char);
    unsigned char id;
    }message;
    
    typedef struct message_queue_t{
    消息 mess_q[MAX_QUE];
    unsigned int mess_q_cnt;
    unsigned int mess_q_in;
    unsigned int Poly_q_out;
    }message_queue;
    
    静态 unsigned char crc8MakeBitwise (unsigned char CRC、unsigned char Poly、unsigned char * Pmsg、unsigned int Msg_size);
    
    smbus_state cur_state = smbus_idle;
    unsigned int error_flag;
    unsigned int TX_don_flag;
    unsigned int mess_delay
    
    
    
    unsigned long nack_cntr;
    
    volatile message * cur_mess;
    message_queue smbus_queue;
    
    volatile unsigned char * ptxData;
    volatile unsigned char
    TXByteCtr;
    volatile unsigned char RXByteCtr;
    
    unsigned char read_mess= 1;
    unsigned char write_mess= 0;
    
    
    unsigned int smbus_Is_running (void){void}
    return (smbus_queue.mess_q_cnt > 0);
    }
    
    unsigned int smbus_get_error (void){
    返回 ERROR_FLAG;
    }
    
    void smbus_read_nack (void){
    __no_operation();
    }
    
    无符号字符 smbus_is_queue_full (void){
    
    if (smbus_queue.mess_q_cnt = MAX_queue)
    返回1;
    
    返回0;
    }
    
    smbus_state smbus_get_state (void){
    返回 cur_state;
    }
    
    void smbus_q_init (void){
    SMBus_queue.mess_q_cnt = 0;
    SMBus_queue.mess_q_in = 0;
    SMBus_queue.mess_q_out = 0;
    }
    
    //此函数假设 SMBus 模块已正确配置。
    void smbus_reset (void){
    
    UCB2CTLW0 |= UCTXSTP;//立即强制停止
    TA1CTL = MC__STOP; //停止超时计数器
    UCB2CTLW0 |= UCSWRST; //重置 SMBus 模块
    
    CUR_ST态= smbus_down;
    }
    
    void smbus_resume (void){
    UCB2CTLW0 &=~UCSWRST;//启用 SMBus 模块
    }
    
    //返回1 (如果有正在处理的消息)。 否则、返回0。
    unsigned char smbus_process (void){
    //unsigned char stream[MAX_RX_LEN + MAX_TX_LEN];
    
    如果(ERROR_FLAG = 1){
    CUR_ST态= smbus_no_resp;
    }
    如果(ERROR_FLAG = 2){
    CUR_ST态= smbus_failure;
    }
    
    CUR_mess=&smbus_queue.mess_q[smbus_queue.mess_q_out];
    
    开关(cur_state){
    案例 smbus_idle:
    
    case smbus_wait:
    if (smbus_queue.mess_q_cnt > 0){
    
    IF (UCB2STAT 和 UCBBUSY){
    CUR_ST态= smbus_wait;
    }
    否则{
    ERROR_FLAG = 0;
    mess_DONE_FLAG = 0;
    TX_DONE_FLAG = 0;
    Timer_delay_over = 1;
    CUR_ST态= smbus_delay;
    }
    }
    否则{
    CUR_ST态= smbus_idle;
    
    返回0;
    }
    中断;
    
    case smbus_delay:
    如果(timer_delay_over = 1){
    PTxData =(unsigned char *)(&cur_mess->TX_DATA[0]);
    PRxData =(unsigned char *)(&cur_mess->rx_data[0]);
    TXByteCtr = cur_mess->TX_cnt;
    RXByteCtr = cur_mess->rx_cnt;
    
    IF (UCB2CTLW0和 UCTXSTP){ //是否发送停止条件?
    中断;
    }
    CUR_ST态= smbus_tx; //更改发送状态
    TA1CTL = tassel_SMCLK | TACLR | MC__Continuous | TAIE;//开始延迟
    
    UCB2CTLW0 |= UCTR | UCTXSTT; // I2C TX,启动条件
    
    }
    中断;
    
    案例 smbus_done:
    /*
    *目前已忽略 PEC
    if (cur_mess->mess_dir = read_mess){
    
    STREAM [0]=(UCB2I2CSA << 1)&~0x01;
    stream[1]= cur_mess->address;
    对于(i = 0;i < cur_mess->TX_cnt;i++){
    stream[i + 1]= cur_mess->TX_DATA[i];
    }
    
    stream[cur_mess->tx_cnt]= cur_mess->address | 0x01;
    对于(i = 0;i < cur_mess->rx_cnt;i++){
    stream[i + cur_mess->TX_cnt + 1]= cur_mess->rx_data[i];
    }
    PEC = crc8MakeBitwise (CRC8_INIT_REM、CRC8_Poly、&(STREAM[0])、
    cucr_mess->tx_cnt + cur_mess->rx_cnt + 2);
    if (PEC =* PRxData){
    //更新状态机的 BQ78350数据
    //P1OUT ^= 0x01;
    }
    //否则{PEC}中的//错误
    }
    *
    //else {我们有一条仅 TX 消息}
    如果(smbus_queue.mess_q_cnt > 0){//删除最后一个消息队列
    
    if (cur_mess->mess_dir = read_mess){
    if (cur_mess->NACK)
    Nack_cntr++;
    //无错误地完成读取,跳转至回调(如果有)。
    否则(cur_mess->rx_done 回调)
    (CUR_mess->Rx_DONE_CALLBACE)(cur_mess->id);
    }
    否则(cur_mess->nack){
    Nack_cntr++;
    }
    
    SMBus_queue.mess_q_out++;
    if (smbus_queue.mess_q_out = MAX_queue) smbus_queue.mess_q_out = 0;
    SMBus_queue.mess_q_cnt--;
    
    }
    CUR_ST态= smbus_wait;
    中断;
    
    案例 smbus_tx:
    如果(TX_DONE_FLAG) cur_state = smbus_Rx;
    //Drop Through
    案例 smbus_Rx:
    如果(mess_done 标志) cur_state = smbus_done;
    中断;
    案例 smbus_down:
    案例 smbus_failure:
    案例 smbus_no_resp:
    //不执行任何操作
    中断;
    默认值:
    CUR_ST态= smbus_wait;
    中断;
    }
    
    返回1;
    }
    
    void battery_rx_done (unsigned char id){
    switch (id){
    case 0://voltage
    电压= batt_data_buffer[0]|(batt_data_buffer[1]<< 8);
    break;
    默认值:break;
    }
    
    
    void smbus_requestWord (unsigned char addr、unsigned char id、unsigned char * return_data、void (* rx_do回 调)(unsigned char))){
    消息*new_mess;
    
    if (smbus_queue.mess_q_cnt < MAX_queue){
    new_mess=&smbus_queue.mess_q[smbus_queue.mess_q_in];
    
    //将数据添加到消息队列
    new_mess->address = BQ78350_ADDR;
    new_mess->mess_dir = read_mess;
    new_mess->is 块= 0;
    new_mess->TX_DATA[0]= addr;
    new_mess->TX_cnt = 1;
    new_mess->Rx_data = return_data;
    new_mess->rx_cnt = 3;
    new_mess->NACK = 0;
    new_mess->Rx_done 回调= Rx_done 回调;
    new_mess->id = id;
    
    //更新队列指针
    SMBus_queue.mess_q_in++;
    如果(smbus_queue.mess_q_in = MAX_queue) smbus_queue.mess_q_in = 0;
    SMBus_queue.mess_q_cnt++;
    }
    }
    
    void smbus_init (void){
    
    TA1CCTL0 = CCIE; //启用 TACCR0中断
    TA1CCTL1 = CCIE; //启用 TACCR1中断
    TA1CCTL2 = CCIE; //启用 TACCR2中断
    TA1CCR0 = 5000;
    TA1CCR1 = 1000;
    TA1CCR2 = 12500;
    TA1CTL = tassel_SMCLK | MC__Continuous; // SMCLK、连续模式
    
    //为 I2C 配置 GPIO
    P7SEL0 |= BIT0 | BIT1;
    P7SEL1 &=~(BIT0 | BIT1);
    
    //将 USCI_B2配置为 I2C 模式
    UCB2CTLW0 = UCSWRST; //将 eUSCI_B 置于复位状态
    UCB2CTLW0 |= UCMODE_3 | UCMST | UCSSEL_SMCLK;// I2C 主控模式、SMCLK
    UCB2BRW = 0x64; //波特率= SMCLK /8
    UCB2CTLW0 &=~UCSWRST; //清除复位寄存器
    UCB2IE |= UCTXIE0 | UCNACKIE; //发送和 NACK 中断使能
    UCB2I2CSA = BQ78350_ADDR; //配置从地址
    
    CUR_ST态= smbus_idle;
    ERROR_FLAG = 0;
    Timer_delay_over = 0;
    TX_DONE_FLAG = 0;
    mess_DONE_FLAG = 0;
    Nack_cntr = 0;
    SMBus_q_init();
    }
    
    int main (void){
    
    WDTCTL = WDTPW | WDTHOLD; //停止 WDT
    
    //配置 GPIO
    P1DIR |= BIT0; // LED 1.0
    P1OUT |= BIT0;
    P1DIR |= BIT1; // LED 1.2
    P1OUT |= BIT1;
    P1DIR |= BIT2; // GPIO 1.2
    P1OUT |= BIT2;
    
    PJSEL0 |= BIT4 | BIT5; // XT1
    
    //禁用 GPIO 上电默认高阻抗模式以激活
    //先前配置的端口设置
    PM5CTL0 &=~LOCKLPM5;
    
    //时钟
    CSCTL0_H = CSKKEY_H; //解锁 CS 寄存器
    CSCTL1 = DCOFSEL_0; //将 DCO 设置为1MHz
    CSCTL2 = SELA_LFXTCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 ACLK = XT1;MCLK = DCO
    CSCTL3 = DIVA__1 | DIVM_1 | DIVM__1;//将所有分频器设置为1
    CSCTL4 &=~LFXTOFF;
    操作
    {
    CSCTL5 &=~LFXTOFFG; //清除 XT1故障标志
    SFRIFG1 &=~OFIFG;
    } while (SFRIFG1和 OFIFG); //测试振荡器故障标志
    CSCTL0_H = 0; //锁定 CS 寄存器
    
    _enable_interrupt ();
    
    SMBus_init();
    SMBus_resume();
    
    while (1){
    
    SMBus_requestWord (0x09、0、batt_data_buffer、battery_rx_done);
    SMBus_process();
    }
    }
    
    #if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)
    #pragma vector = EUSCI_B2_vector
    __interrupt void USCI_B2_ISR (void)
    #Elif defined (__GNU__)
    void __attribute__(interrupt (eUSCI_B2_vector))#USCI_B2_ISR (void Ub2_vector)
    
    )(void UCI_B2_BUF Compiler_B2_b2_b2_b2)(void Ub2编译器#
    #endif
    {
    开关(__evo_in_range (UCB2IV、USCI_I2C_UCBIT9IFG))
    {
    USCI_NONE 案例: 中断; //向量0:无中断
    USCI_I2C_UCALIFG 案例:中断; //向量2:ALIFG
    
    USCI_I2C_UCNACKIFG 案例: //向量4:NACKIFG
    
    UCB2CTLW0 |= UCTXSTP; //发送停止
    UCB2IFG &=~UCNACKIFG; //清除 NACK 标志
    TA1CTL = MC__STOP; //关闭超时计时器
    CUR_mess->NACK = 1; //事务失败。 ISR 处理后无需唤醒。
    mess_DONE_FLAG = 1;
    
    中断;
    
    案例 USCI_I2C_UCSTTIFG:中断; //向量6:STTIFG
    案例 USCI_I2C_UCSTPIFG:中断; //向量8:STPIFG
    USCI_I2C_UCRXIFG3案例:中断; //向量10:RXIFG3
    USCI_I2C_UCTXIFG3案例:中断; //向量12:TXIFG3
    USCI_I2C_UCRXIFG2案例:中断; //向量14:RXIFG2
    USCI_I2C_UCTXIFG2案例:中断; //向量16:TXIFG2
    USCI_I2C_UCRXIFG1案例:中断; //向量18:RXIFG1
    USCI_I2C_UCTXIFG1案例:中断; //向量20:TXIFG1
    USCI_I2C_UCRXIFG0案例: //向量22:RXIFG0
    TA1CTL = MC__STOP; //关闭超时计时器
    RXByteCtr---; //递减 RX 字节计数器
    
    if (RXByteCtr){
    * PRxData = UCB2RXBUF; //剩余要接收的多个字节
    PRxData++;
    
    //if 块访问、第一个字节是块长度
    RXByteCtr =(cur_mess->is 块)? (UCB2RXBUF +1):RXByteCtr;
    //复位是块标志,因此长度只更新一次
    CUR_mess->IS 块= 0;
    
    TA1CTL = tassel_SMCLK | TACLR | MC__Continuous | TAIE;//开始延迟
    }
    否则{
    * PRxData = UCB2RXBUF; //要接收的最后一个字节
    mess_DONE_FLAG = 1; //显示读取完成的标志
    __BIC_SR_REGISTER_ON_EXIT (LPM3_BITS);//退出 LPM3,因为在读取后有一些处理要执行
    }
    
    IF (RXByteCtr = 1) //只剩下一个字节?
    UCB2CTLW0 |= UCTXSTP; //生成 I2C 停止条件
    
    //如果只读取1个字节,则停止条件
    //应该已经发送
    中断;
    
    USCI_I2C_UCTXIFG0案例: //向量24:TXIFG0
    TA1CTL = MC__STOP; //关闭超时计时器
    IF (TXByteCtr) //如果有要传输的内容
    {
    UCB2TXBUF =* PTxData++; //加载 TX 缓冲区
    TXByteCtr --; //测量 TX 字节计数器
    TA1CTL = tassel_SMCLK | TACLR | MC__Continuous | TAIE;//开始延迟
    }
    //无需再传输
    否则、如果(cur_mess->mess_dir = read_mess){//更改为接收模式
    UCB2CTLW0 &=~UCTR; //接收器模式
    UCB2IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
    UCB2CTLW0 |= UCTXSTT; // I2C 重新启动(SMBus 协议)
    TX_DONE_FLAG = 1;
    
    TA1CTL = tassel_SMCLK | TACLR | MC__Continuous | TAIE;//开始延迟
    }
    否则{ //仅发送,停止传输
    UCB2CTLW0 &=~UCTR;
    UCB2IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
    UCB2CTLW0 |= UCTXSTP; //生成 I2C 停止条件
    
    CUR_ST态= smbus_done; //显示读取完成的标志
    mess_Done 标志= 1;
    }
    中断;
    
    案例 USCI_I2C_UCBCNTIFG:break; //向量26:BCNTIFG
    USCI_I2C_UCCLTOIFG 案例:中断; //向量28:时钟低电平超时
    USCI_I2C_UCBIT9IFG 案例:中断; //向量30:第9位
    默认值:break;
    }
    }
    
    #pragma vector = Timer1_A0_vector
    __interrupt void Timer1_A0_ISR (void)
    {
    count_50ms++;
    count_100ms++;
    count_500ms++;
    count_1000ms++;
    count_2000ms++;
    
    如果(count_50ms>=5){count_50ms = 0;flag_50ms = 1;}
    如果(count_100ms>=10){count_100ms = 0;flag_100ms = 1;}
    如果(count_500ms>=50){count_500ms = 0;flag_500ms = 1;}
    如果(count_1000ms>=100){count_1000ms = 0;flag_1000ms = 1;}
    如果(count_2000ms>=200){count_2000ms = 0;flag_2000ms = 1;}
    
    TA1CCR0 += 5000;
    }
    
    #pragma vector = Timer1_A1_vector //针对 CCR1、CCR2
    __interrupt void Timer1_A1_ISR (void)
    {
    switch (TA1IV){
    情况0x02: // CCR1
    TA1CTL = MC__STOP; //关闭超时计时器
    TA1CCTL1 = 0; //禁用此比较点
    Timer_delay_over = 1; //将标志设置为结束延迟
    TA1CCR1 += 1000;
    中断;
    情况0x04: // CCR2
    TA1CTL = MC__STOP; //关闭超时计时器
    UCB2CTLW0 |= UCTXSTP; //在 SDA 线上发送 STOP
    UCB2CTLW0 |= UCSWRST; //启用 SW 复位
    UCB2CTLW0 &=~UCSWRST;
    UCB2IE |= UCTXIE + UCRXIE + UCNACKIE;//启用 TX、RX、NACK 中断
    ERROR_FLAG = 2; //超时标志
    TA1CCR2 += 12500;
    中断;
    }
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mauro、

    参考手册中给出的 BQ78350地址已移位。 即:当您从器件读取时、微控制器应发送0x16作为其第一个字节、并在您写入时发送0x17。 MSP430F5338微控制器需要用户设置从器件地址、以在主模式下设置 I2C。 在有效载荷中、包含地址的第一个字节必须移回才能正确发送。 请确保阅读 UC 用户指南以正确配置 I2C 外设。

    SDA 和 SCL 线路在发送或接收后都应变为高电平、如果情况并非如此、那么您的微控制器会出于某种原因挂起线路。 我假设您在线路上有上拉电阻器。

    根据您提供的信息、可能是 I2C 外设未配置或逻辑不正确。

    遗憾的是、我没有时间检查代码和进行调试、但下面是建议的调试步骤:

    1. 尝试与其他 I2C 器件通信。 我们使用了 Aardvark I2C/SPI 适配器来确保数据的发送和接收正确。
    2. 由于波特率较低的信号看起来是正确的、我建议使用逻辑分析仪记录它发送的数据流。
    3. TI 为 FR5xx 系列器件提供了 SMBus 库。 这可能会简化 SMBus 的编码。 参考资料如下:

    打开 Software -> MSP430Ware xxx -> Libraries -> SMBusLib

    下载内容:

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michel。

    我忘记在初始化期间激活 RX IE、因为我以主器件 TX 代码为例。

    UCB2IE |= UCTXIE0 | UCNACKIE | UCRXIE0;//发送和 NACK 中断使能

    非常感谢您的帮助!

    此致、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    很高兴这个问题得到解决。
    此致、
    米歇尔
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michel。

    每次发送 smbus_requestWord ()/smbus_requestMfrAccessReg ()时,我都必须调用 smbus_process()函数,还是有其他方法可以执行这些任务?

    我问这个、因为我看到有队列逻辑、但我不理解。  

    int main (void){
    
    WDTCTL = WDTPW | WDTHOLD; //停止 WDT
    
    init_gpio();
    init_clock();
    init_timer0();
    
    _enable_interrupt ();
    
    SMBus_init();
    SMBus_resume();
    
    while (1){
    
    SMBus_requestWord (0x0E、0、batt_data_buffer、battery_rx_done);
    SMBus_process();
    SMBus_requestWord (0x09、1、batt_data_buffer、battery_rx_done);
    SMBus_process();
    
    }
    } 

    谢谢、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mauro、

    该过程是一个状态机、用于监控发送/接收的消息。 所有的消息处理都是通过中断(在后台)完成的、并且过程会检查中断的哪个步骤。 因此、每次运行该函数时、它只能"前进"一步。

    简单地说、器件进入该过程、检查状态是否已更改、在必要时执行任何操作并退出。 这使得 SMBus 的工作方式与非阻塞功能相似。 这使您可以在发送 SMBus 消息时执行其他操作。 例如、您可以同时处理 UART 端口上的数据。

    当您有操作系统时、所有这些操作都将在后台处理、而无需注意任何事项。 如果没有操作系统、则需要显式执行此操作。

    话虽如此、您必须尽可能频繁地进入 smbus_process。 如果您有任何类似 SMBus 的其他进程、请确保它们也不会阻止、因为它会阻止 SMBus 执行并导致错误。 这也意味着您不能在代码中使用任何睡眠函数。

    那么、这里有一些应该有所帮助的伪代码

    while (1){
    //更新状态机
    smbus_process ();
    
    
    //出于
    
    此伪代码的目的,我们假设您有一个运行
    //的计时器,并且您正在检查该时间段是否已过去。
    if (一些电池超时){
    //这将排队两条消息。 它们将一个接一个地被处理。
    //您可以将许多消息排队。 您可以检查数据是否已保存
    //通过 SMBus 回调设置一些变量来接收。
    //只需确保队列中的消息数不会超过 smbus 可以处理的消息数。
    //(即确保超时时间足够长,以便在排队新消息之前发送所有消息)
    SMBus_requestWord (0x09、1、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (0x0E、0、batt_data_buffer、battery_Rx_done);
    }
    
    

    我希望这能为您清除问题。

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Michel!

    它对人帮助很大。
    感谢您的关注。 我真的很感激!

    此致、
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michel。

    很抱歉打扰了您、但您的帮助对我的项目非常重要。

    我正在执行一些测试、现在我尝试从 bq76940EVM 读取一些变量并发送一些命令。 例如、我每500ms 读取一次电池的电压、并每2000ms 发送一条命令来打开/关闭 FET。 但是、在我获得读数后、当 FET 环路被执行时、我的 uC 会进入 ISR_TRAP 状态。 命令已发送、但代码在发送后停止。

    ;------------------------------------------------------------------
    ;--如果用户不提供,则缺省 ISR 处理程序
    ;--只需将设备放入 lpm0
    中;---------------------------
    
    .sect".text:_ISR:_TI_ISR_TRAP"
    .align2
    .global__TI_ISR_TRAP
    __TI_ISR_TRAP:
    BIS.W #(0x0010)、SR
    JMP _TI_ISR_TRAP
    
    NOP 


    我的代码结构如下:

    while (1){
    
    SMBus_process();
    
    if (timer&(1<<2)){//此循环每500ms 执行一次
    
    SMBus_requestWord (CellVoltage15、_CellVoltage15、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage14、_CellVoltage14、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage13、_CellVoltage13、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage12、_CellVoltage12、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage11、_CellVoltage11、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage10、_CellVoltage10、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage9、_CellVoltage9、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage8、_CellVoltage8、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage7、_CellVoltage7、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage6、_CellVoltage6、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage5、_CellVoltage5、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage4、_CellVoltage4、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage3、_CellVoltage3、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage2、_CellVoltage2、batt_data_buffer、battery_rx_done);
    SMBus_requestWord (CellVoltage1、_CellVoltage1、batt_data_buffer、battery_rx_done);
    
    定时器&=~BIT2;//flag = 0;
    P1OUT ^= BIT1;//呈绿色闪烁 LED;
    }
    
    if (timer&(1<<4)){//此循环每2000ms 执行一次
    
    SMBus_requestMfrAccessReg (0x22、100、batt_data_buffer、battery_Rx_DONE);//FET 控制
    定时器&=~BIT4;//flag = 0;
    P1OUT ^= BIT1;//闪烁红色 LED;
    } 

    我出了什么问题?

    谢谢、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mauro、

    我不会有太大帮助、因为这是一个微控制器问题、您必须自行对其进行调试。

    但是、您可以查看以下一些内容:

    • 逐个删除 smbus 和计时器的初始化。 如果您缺少其中一个外设的 ISR、则代码将不起作用、但不会最终出现在_TI_ISR_TRAP 中
    • 尝试撤消您所做的更改以查找导致问题的更改。
    • 如果这种情况持续发生、我假设您会发生某种硬故障或存储器错误。 如果您尚未定义错误处理程序 ISR、它将转至_TI_ISR_TRAP 代码。 当代码卡在 ISR 中时、您可能可以检查微控制器的寄存器以尝试找出缺少哪个中断例程。 这些是您的微控制器所特有的、您应该参考用户指南来查看可用的器件。

    很抱歉、我无法提供更多帮助。

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Michel。

    感谢你的帮助。
    这是一个计时器 ISR 问题。

    此致、
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michel。

    我正在尝试了解您提供的用于我的项目的所有代码。 下面是我目前所掌握的流程图。

    我有几个问题:

    -如何处理 smbus_failure? 为此,我将使用 smbus_init()和 smbus_resume()。 是否有更好的方法来重新初始化通信?

    -首次运行后、TIMER_DELAY_OVER 标志永远不会变为零。 为什么? 此代码标志的功能是什么?

    谢谢、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mauro、
    遗憾的是、我没有时间查看您提供的流程图。 我认为状态图更适合表示 SMBus 状态机的逻辑。 这将更易于理解。

    [引用 user="Mauro Basquera"-我应该如何处理 smbus_failure? 为此,我将使用 smbus_init()和 smbus_resume()。 是否有更好的方法来重新初始化通信?

    我复位我的 SMBus。 因此,SMBUS_init()后跟 SMBUS_RESUME 是最好的方法。 我们遇到了一个问题、即25ms 超时并不总是由 BQ78350重新指定、因此我们会经常进入这个条件。 我们通过将延迟增加到26ms 来解决了该问题。

    [引用 user="Mauro Basquera"]-首次运行后 timer_delay_over 标志永远不会变为零。 为什么? 此代码标志的功能是什么?

    我不是最后一个处理代码的人、但你认为它似乎没有被使用是对的。 BQ78350规定了 SMBus 通信之间的最小延迟为2ms。 该标志用于插入该延迟。 我不确定最后一位用于实施延迟的人员是什么。

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Michel。

    感谢您的澄清。
    我知道您一定很忙、我刚才展示了流程图、以简化任何可能的解释。

    您的回答中没有"验证答案"选项、这就是我不这么做的原因。

    总之、再次感谢!

    此致、
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michel。

    我正在尝试使用 smbus_writeWord 函数更新 RemainingCapacity、但该命令不起作用。

    我必须在命令之前或之后发送命令吗? 我已经选中、器件为"完全访问模式"。

    unsigned char * dado;
    unsigned char x1;
    
    x1 = 0;
    dado =&x1;
    smbus_writeWord (0x0F、dado); 

    我有点困惑、因为我能够通过 bqStudio 更新 RemainingCapacity、但在 d/s 中、此命令仅显示为一个读取字。

    同时作为 R/W 字:

    谢谢、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mauro、

    有几件事情看起来是错误的:

    首先、17.17说明说它是一个读取字函数(而不是读取-写入)。 但是、您似乎可以通过 BQ Studio 对其进行配置。 这可能需要 TI 员工澄清。

    是否确定未配置剩余电量警报?
    我会将您转至论坛:看看是否有其他人已经问过这个问题、如果没有、则发布一个新问题。 通过提出新问题、其他论坛用户将查看并可能回答您的问题(IMO、此主题太长、包含的问题和答案太多。 我喜欢有一个主题、一个问题、一个答案)。

    其次、您尝试发送一个字(2个字节)、但将一个无符号字符(1个字节)传递给函数。 我不确定该函数的行为是什么、但很可能是在 SMBus 线路上发送1个额外的字节的垃圾。

    为了使您的代码更紧凑、我建议使用如下所示的代码:

    //根据您的微控制器、这可能是 unsigned int 或 unsigned short。
    //使用 uint16_t (有时是 uint16)更安全、uint16_t
    x1 = 0;
    
    smbus_writeWord (0x0F、&x1); 

    此致、

    米歇尔

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michel。

    好的、我将尝试与 TI 员工进行澄清。

    很抱歉这个长线程、但我在这里问它、因为它与您善意提供的代码相关。 你无法想象它对我有多大帮助。 我对嵌入式编程非常陌生、您可能已经注意到了这一点。

    关于您建议的解决方案、它不起作用。 我将其作为 char 放置、因为该函数的输入被声明为 char。 当我放置 uint16_t 时、我收到警告:"#169-D 参数"类型为 unsigned short *"与"unsigned char *"类型的参数不兼容

    void smbus_writeWord (unsigned char addr、unsigned char *数据){
    消息*new_mess;
    
    if (smbus_queue.mess_q_cnt < MAX_queue){
    new_mess=&smbus_queue.mess_q[smbus_queue.mess_q_in];
    
    new_mess->address = BQ78350_ADDR;
    new_mess->mess_dir = write_mess;
    new_mess->is 块= 0;
    new_mess->TX_DATA[0]= addr;
    new_mess->TX_DATA[1]=*数据;
    new_mess->TX_DATA[2]=*(data + 1);
    
    //更新队列指针
    SMBus_queue.mess_q_in++;
    如果(smbus_queue.mess_q_in = MAX_queue) smbus_queue.mess_q_in = 0;
    SMBus_queue.mess_q_cnt++;
    }
    } 

    我还尝试了其他变体、将数据直接放在 TX_DATA[1]和[2]上、但它不起作用。

    我很确定用于更新 RemainingCapacity 的命令是0x0F、因为我在 bqStudio 中使用它。

    非常感谢你的帮助。 我非常感谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mauro、

    对于剩余的容量问题、请尝试写入另一个寄存器以确保写入字函数正常工作。

    我使用 unsigned char *使函数成为通用函数。

    然后、用户可以将其与 uint16_t (带有 cast)或 uint8_t 的数组一起使用 请参阅以下示例:

    // uint16_t
    uint16_t x = 0x1234;
    smbus_writeWord (0x0F、(unsigned char *)&x);
    
    //使用数组
    uint8_t y[2];
    y[0]= 0x34;
    y[1]= 0x12;
    smbus_writeWord (0x0F、y); 

    最好使用第二种方法、因为您可以控制端字节序(使代码可移植、避免在您更改为其他微控制器时出现意外)。

    此致、

    米歇尔

    编辑:此外、为了确保 BQ Studio 发送的内容、请使用逻辑分析仪。 您将能够准确地查看发送的命令。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michel。

    非常感谢您的帮助。

    它恰好是 smbus_writeWord 函数中缺少的一行。

    new_mess->address = BQ78350_ADDR;
    new_mess->mess_dir = write_mess;
    new_mess->is 块= 0;
    new_mess->TX_cnt = 3;//我添加了此行
    new_mess->TX_DATA[0]= addr;
    new_mess->TX_DATA[1]=*数据;
    new_mess->TX_DATA[2]=*(data+1); 

    我之所以解决这个问题、是因为我使用了示波器、uC 只是发送 bq78350地址、然后将线路拉高以获取任何地址和数据。

    我不知道它是如何处理您的产品的、但我添加了它、它运行得很好。

    感谢您的提示!

    此致、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我对 SMB (或 I2C)没有太多经验、但可能有一些指导。  首先、在 I2C 基础上增加了一些 SMB 限制、因此熟悉 I2C 是一个很好的起点。  如果不仔细检查、我就看不到 I2C 所需的 Start、Ack、Nak 或 Stop 位。  我建议在 TI 网站上查看 slua475.pdf、作为一个良好的起点。  

    此外、我不确定有多少读者会浏览您发布的代码量。  或者更详细地说、我个人不会编写这么多的代码、直到我进行通信。  如果不深入研究、我不知道您是在 SW 中生成每个位、还是使用和 I2C 控制器、但无论采用哪种方法、可能有20行代码允许您生成读取请求并获得应答。  在这种情况下工作之前、其余部分会分散注意力。  更好的方法是执行写请求、因为它更简单、但它必须是导致可观察行为的东西、以便您可以判断它何时起作用。  最简单的写入请求只有四个字节长。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Wilton。

    感谢您的提示。

    此致、