打印
[电池电源管理]

中颖SH367309制作1-17串锂电池保护板(BMS)原理图、源码分享

[复制链接]
351|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Puchou|  楼主 | 2025-6-9 15:55 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一、BMS介绍
1. 定义
BMS 是电池管理系统(Battery Management System)的缩写。
主要功能是监控和管理电池组的状态,确保其安全、高效地运行。
2. 主要功能
状态监测
电压、电流、温度等参数的实时监测。
均衡管理
确保每个电池单元的电压和容量保持一致。
保护机制
过充、过放、短路、高温等异常情况的检测与保护。
通信接口
与外部设备(如充电器、车辆控制系统)进行数据交换。
3. 应用领域
电动汽车
电动汽车中的动力电池管理。
储能系统
大型储能系统的电池管理。
便携式电子设备
手机、笔记本电脑等便携设备的电池管理。
4. 技术特点
高精度传感器
实现对电池参数的精确测量。
智能算法
利用先进的算法进行电池状态预测和优化。
模块化设计
方便维护和扩展。
5. 优势
延长电池寿命
通过有效管理和保护,延长电池使用寿命。
提高安全性
防止电池过热、过充等问题,提升整体安全性。
优化性能
提高电池的使用效率和可靠性。
二、原理介绍



三、原理图分享
1、原理图



2、介绍
a、电流采集电路



b、充放电控制电路



c、AFE烧写电路



四、端口介绍
B-:接电池负极 。
GND_EXE:接负载地。
NTC接热敏电阻。
J5:接电池电源。
JP23:接电池均衡口。
下面四个口接MCU



五、源码分享
iic.c

/*************************************************
* @copyright:
* @author:Xupeng
* @date:2022-11-03
* @description:
**************************************************/  
#include "afe_i2c.h"



/**
* @brief       初始化IIC
* @param       无
* @retval      无
*/
void afe_iic_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    IIC_SCL_GPIO_CLK_ENABLE();                           /* SCL引脚时钟使能 */
    IIC_SDA_GPIO_CLK_ENABLE();                           /* SDA引脚时钟使能 */

    gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;         /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                 /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;  /* 快速 */
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct); /* SCL */

    gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;         /* 开漏输出 */
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct); /* SDA */
    /* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */

    afe_iic_stop();                                          /* 停止总线上所有设备 */
}

/**
* @brief       IIC延时函数,用于控制IIC读写速度
* @param       无
* @retval      无
*/
static void afe_iic_delay(void)
{
    rt_hw_us_delay(4);    /* 2us的延时, 读写速度在250Khz以内 */
}

/**
* @brief       产生IIC起始信号
* @param       无
* @retval      无
*/
void afe_iic_start(void)
{
    IIC_SDA(1);
    IIC_SCL(1);
    afe_iic_delay();
    IIC_SDA(0);     /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
    afe_iic_delay();
    IIC_SCL(0);     /* 钳住I2C总线,准备发送或接收数据 */
    afe_iic_delay();
}

/**
* @brief       产生IIC停止信号
* @param       无
* @retval      无
*/
void afe_iic_stop(void)
{
    IIC_SDA(0);     /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
    afe_iic_delay();
    IIC_SCL(1);
    afe_iic_delay();
    IIC_SDA(1);     /* 发送I2C总线结束信号 */
    afe_iic_delay();
}

/**
* @brief       等待应答信号到来
* @param       无
* @retval      1,接收应答失败
*              0,接收应答成功
*/
uint8_t afe_iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;

    IIC_SDA(1);             /* 主机释放SDA线(此时外部器件可以拉低SDA线) */
    afe_iic_delay();
    IIC_SCL(1);             /* SCL=1, 此时从机可以返回ACK */
    afe_iic_delay();

    while (IIC_READ_SDA)    /* 等待应答 */
    {
        waittime++;

        if (waittime > 250)
        {
            afe_iic_stop();
            rack = 1;
            break;
        }
                afe_iic_delay();
    }

    IIC_SCL(0);             /* SCL=0, 结束ACK检查 */
    afe_iic_delay();
    return rack;
}

/**
* @brief       产生ACK应答
* @param       无
* @retval      无
*/
void afe_iic_ack(void)
{
    IIC_SDA(0);     /* SCL 0 -> 1 时 SDA = 0,表示应答 */
    afe_iic_delay();
    IIC_SCL(1);     /* 产生一个时钟 */
    afe_iic_delay();
    IIC_SCL(0);
    afe_iic_delay();
    IIC_SDA(1);     /* 主机释放SDA线 */
    afe_iic_delay();
}

/**
* @brief       不产生ACK应答
* @param       无
* @retval      无
*/
void afe_iic_nack(void)
{
    IIC_SDA(1);     /* SCL 0 -> 1  时 SDA = 1,表示不应答 */
    afe_iic_delay();
    IIC_SCL(1);     /* 产生一个时钟 */
    afe_iic_delay();
    IIC_SCL(0);
    afe_iic_delay();
}

/**
* @brief       IIC发送一个字节
* @param       data: 要发送的数据
* @retval      无
*/
void afe_iic_send_byte(uint8_t data)
{
    uint8_t t;

    for (t = 0; t < 8; t++)
    {
        IIC_SDA((data & 0x80) >> 7);    /* 高位先发送 */
        afe_iic_delay();
        IIC_SCL(1);
        afe_iic_delay();
        IIC_SCL(0);
                afe_iic_delay();
        data <<= 1;     /* 左移1位,用于下一次发送 */
    }
    IIC_SDA(1);         /* 发送完成, 主机释放SDA线 */
}

/**
* @brief       IIC读取一个字节
* @param       ack:  ack=1时,发送ack; ack=0时,发送nack
* @retval      接收到的数据
*/
uint8_t afe_iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;

    for (i = 0; i < 8; i++ )    /* 接收1个字节数据 */
    {
        receive <<= 1;          /* 高位先输出,所以先收到的数据位要左移 */
        IIC_SCL(1);
        afe_iic_delay();

        if (IIC_READ_SDA)
        {
            receive++;
        }

        IIC_SCL(0);
        afe_iic_delay();
    }

    if (!ack)
    {
        afe_iic_nack();             /* 发送nACK */
    }
    else
    {
        afe_iic_ack();              /* 发送ACK */
    }

    return receive;
}





iic.h


#ifndef __MYIIC_H
#define __MYIIC_H

#include "main_value.h"


/******************************************************************************************/
/* 引脚 定义 */

#define IIC_SCL_GPIO_PORT               GPIOH
#define IIC_SCL_GPIO_PIN                GPIO_PIN_7
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0)   /* PH口时钟使能 */

#define IIC_SDA_GPIO_PORT               GPIOH
#define IIC_SDA_GPIO_PIN                GPIO_PIN_8
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0)   /* PH口时钟使能 */

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

/* IO操作 */
#define IIC_SCL(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SCL */

#define IIC_SDA(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SDA */

#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* 读取SDA */

/******************************************************************************************/
/* IIC所有操作函数 */
void afe_iic_init(void);                /* 初始化IIC的IO口 */
void afe_iic_start(void);               /* 发送IIC开始信号 */
void afe_iic_stop(void);                /* 发送IIC停止信号 */
void afe_iic_ack(void);                 /* IIC发送ACK信号 */
void afe_iic_nack(void);                /* IIC不发送ACK信号 */
uint8_t afe_iic_wait_ack(void);         /* IIC等待ACK信号 */
void afe_iic_send_byte(uint8_t data);   /* IIC发送一个字节 */
uint8_t afe_iic_read_byte(uint8_t ack); /* IIC读取一个字节 */

#endif




bms.c

/*************************************************
* @copyright:
* @author:Xupeng
* @date:2022-11-03
* @description:
**************************************************/  
#include "afe.h"
#include "afe_i2c.h"


#define DBG_TAG    "afe"
#define DBG_LVL    DBG_LOG
#include <rtdbg.h>


#define VPRO_PIN GET_PIN(G,10)
#define CTL_PIN GET_PIN(G,4)


static struct rt_i2c_client afeClient = {.bus = RT_NULL,.client_addr = 0};


const uint8_t CRC8Table[] = {                                                       
        0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F,0x36,0x31,0x24,0x23,0x2A,0x2D,
        0x70,0x77,0x7E,0x79,0x6C,0x6B,0x62,0x65,0x48,0x4F,0x46,0x41,0x54,0x53,0x5A,0x5D,
        0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5,0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD,
        0x90,0x97,0x9E,0x99,0x8C,0x8B,0x82,0x85,0xA8,0xAF,0xA6,0xA1,0xB4,0xB3,0xBA,0xBD,
        0xC7,0xC0,0xC9,0xCE,0xDB,0xDC,0xD5,0xD2,0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA,
        0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2,0x8F,0x88,0x81,0x86,0x93,0x94,0x9D,0x9A,
        0x27,0x20,0x29,0x2E,0x3B,0x3C,0x35,0x32,0x1F,0x18,0x11,0x16,0x03,0x04,0x0D,0x0A,
        0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42,0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A,
        0x89,0x8E,0x87,0x80,0x95,0x92,0x9B,0x9C,0xB1,0xB6,0xBF,0xB8,0xAD,0xAA,0xA3,0xA4,
        0xF9,0xFE,0xF7,0xF0,0xE5,0xE2,0xEB,0xEC,0xC1,0xC6,0xCF,0xC8,0xDD,0xDA,0xD3,0xD4,
        0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C,0x51,0x56,0x5F,0x58,0x4D,0x4A,0x43,0x44,
        0x19,0x1E,0x17,0x10,0x05,0x02,0x0B,0x0C,0x21,0x26,0x2F,0x28,0x3D,0x3A,0x33,0x34,
        0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B,0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63,
        0x3E,0x39,0x30,0x37,0x22,0x25,0x2C,0x2B,0x06,0x01,0x08,0x0F,0x1A,0x1D,0x14,0x13,
        0xAE,0xA9,0xA0,0xA7,0xB2,0xB5,0xBC,0xBB,0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83,
        0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB,0xE6,0xE1,0xE8,0xEF,0xFA,0xFD,0xF4,0xF3
};

/* 温阻特性数据 */
#define TRPOINT_NUM                        21
#define TRK_NUM                                (TRPOINT_NUM-1)
static const struct
{
        float Te;
        int Re;
} TR_PropertyTable[TRPOINT_NUM] =
{
        {5.0, 25456},
        {10.0, 19938},
        {15.0, 15731},
        {20.0, 12500},
        {25.0, 10000},
        {30.0, 8051},
        {35.0, 6522},
        {40.0, 5314},
        {45.0, 4355},
        {50.0, 3588},
        {55.0, 2971},
        {60.0, 2473},
        {65.0, 2068},
        {70.0, 1738},
        {75.0, 1466},
        {80.0, 1243},
        {85.0, 1058},
        {90.0, 904},
        {95.0, 775},
        {100.0, 667},
        {105.0, 576},       
};
static float Ktr[TRK_NUM];
static float Btr[TRK_NUM];

/* AFE内部参考电阻和采样电阻阻值 */
static float afeRref = 0;
#define AfeRsamp                RS_SAMP

__STATIC_INLINE void afe_delay_ms(uint32_t ms)
{
        rt_thread_mdelay(ms);
}
/*************************************************
* @function:static uint8_t crc8_cal(uint8_t *data, uint8_t len)     
* @description:CRC8校验
* @calls:         
* @input:                    
* @return:      
* @others:      
*************************************************/
static uint8_t crc8_cal(uint8_t *data, uint8_t len)                     
{   
    uint8_t crc8 = 0;   

        for( ; len>0; len--)
        {   
        crc8 = CRC8Table[crc8 ^ *data];   
                data++;   
    }
    return(crc8);      
}

/*************************************************
* @function:static void tr_property_init(void)   
* @description:温阻特性初始化
* @calls:         
* @input:计算各段温阻率                    
* @return:      
* @others:Te = Ktr * Re + b;   
*************************************************/
static void tr_property_init(void)
{
        int i;
       
        for(i=0; i<TRK_NUM; i++)
        {
                Ktr = (TR_PropertyTable[i+1].Te - TR_PropertyTable.Te) / (TR_PropertyTable[i+1].Re - TR_PropertyTable.Re);
                Btr = TR_PropertyTable[i+1].Te - Ktr*TR_PropertyTable[i+1].Re;               
                //rt_kprintf("KB%d:K=%f,B=%f\r\n", i, Ktr, Btr);
        }
}
/*************************************************
* @function:float tr_re2te(int Re)   
* @description:电阻转换温度
* @calls:         
* @input:-Re:电阻值(R)                  
* @return:-T:温度(°C)      
* @others:Te = Ktr * Re + b;   
*************************************************/
float tr_re2te(int Re)
{
        int KtrNum;
       
        for(KtrNum=0; KtrNum<TRPOINT_NUM; KtrNum++)
        {
                if(Re > TR_PropertyTable[KtrNum].Re)
                        break;
        }
        if(KtrNum > 0)
                KtrNum--;
        return (Ktr[KtrNum] * Re + Btr[KtrNum]);
}

/*************************************************
* @function:int tr_te2re(float Te)  
* @description:温度转换电阻
* @calls:         
* @input:-Te:温度值(°C)                    
* @return:-R:电阻(R)      
* @others:Re = (Te - b) / Ktr;      
*************************************************/
int tr_te2re(float Te)
{
        int KtrNum;
       
        for(KtrNum=0; KtrNum<TRPOINT_NUM; KtrNum++)
        {
                if(Te < TR_PropertyTable[KtrNum].Te)
                        break;
        }
        if(KtrNum > 0)
                KtrNum--;
        return (Te - Btr[KtrNum]) / Ktr[KtrNum];
}
/*************************************************
* @function:int afe_init(AlArmCb_Type cb)   
* @description:AFE初始化函数
* @calls:         
* @input:-cb:中断回调函数                    
* @return:-res:0成功,-1失败      
* @others:      
*************************************************/
int afe_init(AlArmCb_Type cb)
{
        bConfigType config = 0;
        uint8_t mtpTr;
       
        /* AFE底层接口初始化 */
        //AfePort_Init(cb);
       
        /* AFE的IIC接口初始化 */
        afe_iic_init();
       
        /* 温阻特性初始化 */
        tr_property_init();
       
        /* AFE参考电阻初始化 */
        if(afe_read_buffer(MTP_TR, &mtpTr, 1) != 0)
        {
                LOG_E("AFE_Read_MTP_TR Error!\r\n");
                return -1;
        }
        mtpTr = mtpTr & 0x7F;
        afeRref = 6.8 + 0.05 * mtpTr;
        LOG_I("MtpTr=%d, afeRref=%d.%d.%d\r\n", mtpTr, (int)afeRref,(int)(afeRref*100)%100/10,(int)(afeRref*100)%10);
               
        /* 开启CADC */
        config = CONF_DSGMOS | CONF_CHGMOS | CONF_CADCON;
        if(afe_set_config(config) != 0)
        {
                LOG_E("afe_set_config Error!\r\n");
                return -2;
        }
       
        return 0;
}
/*************************************************
* @function:void afe_programme_open(void)   
* @description:afe烧写EEPROM打开
* @calls:         
* @input:                 
* @return:     
* @others:      
*************************************************/
void afe_programme_open(void)
{
        rt_pin_write(VPRO_PIN,PIN_HIGH);
        rt_thread_mdelay(5);
}
/*************************************************
* @function:void afe_programme_close(void)  
* @description:afe烧写EEPROM关闭
* @calls:         
* @input:                 
* @return:     
* @others:      
*************************************************/
void afe_programme_close(void)
{
        rt_pin_write(VPRO_PIN,PIN_LOW);
}
/*************************************************
* @function:int afe_write_byte(uint8_t addr, uint8_t data)
* @description:afe写寄存器一个字节数据
* @calls:         
* @input:                 
* @return: ret:0为成功,负数为失败   
* @others:      
*************************************************/
int afe_write_byte(uint8_t addr, uint8_t data)
{
        int ret = 0;
        uint8_t write_buff[4] = {0};

        write_buff[0] = MTP_SLAVE_W;
        write_buff[1] = addr;
        write_buff[2] = data;
        write_buff[3] = crc8_cal(write_buff, 3);
        afe_iic_start();
        afe_iic_send_byte(write_buff[0]);
        ret -= afe_iic_wait_ack();
        afe_iic_send_byte(write_buff[1]);
        ret -= afe_iic_wait_ack();
        afe_iic_send_byte(write_buff[2]);
        ret -= afe_iic_wait_ack();
        afe_iic_send_byte(write_buff[3]);
        ret -= afe_iic_wait_ack();
        afe_iic_stop();
        if(addr <= MTP_TR)
                afe_delay_ms(5);
        else
                afe_delay_ms(1);
        return ret;       
}
/*************************************************
* @function:int afe_write_buffer(uint8_t addr, uint8_t *data, uint32_t len)
* @description:afe写寄存器多个字节数据
* @calls:         
* @input:                 
* @return: ret:写入的数据长度   
* @others:      
*************************************************/
int afe_write_buffer(uint8_t addr, uint8_t *data, uint32_t len)
{
        int i, ret = 0, count = 0;

        for(i=0; i<len; i++)
        {
                ret = afe_write_byte(addr, data);
                if(ret >= 0)
                        count++;
                else
                        return count;
                addr++;
        }
        return count;
}
/*************************************************
* @function:int afe_read_buffer(uint8_t addr, uint8_t *data, uint32_t len)
* @description:afe读寄存器多个字节数据
* @calls:         
* @input:                 
* @return: ret:0为成功, 负数为失败,-100为CRC校验错误
* @others:      
*************************************************/
int afe_read_buffer(uint8_t addr, uint8_t *data, uint32_t len)
{
        static uint8_t read_buff[60] = {0};
        uint8_t crc8_ret, i;
        int ret = 0;
       
        read_buff[0] = MTP_SLAVE_W;
        read_buff[1] = addr;
        read_buff[2] = len;
        read_buff[3] = MTP_SLAVE_R;
        afe_iic_start();
        afe_iic_send_byte(read_buff[0]);
        ret -= afe_iic_wait_ack();
        afe_iic_send_byte(read_buff[1]);
        ret -= afe_iic_wait_ack();
        afe_iic_send_byte(read_buff[2]);
        ret -= afe_iic_wait_ack();
        afe_iic_start();
        afe_iic_send_byte(read_buff[3]);
        ret -= afe_iic_wait_ack();
        for(i=0; i<len; i++)
        {
                read_buff[i+4] = afe_iic_read_byte(1);
        }
        read_buff[i+4] = afe_iic_read_byte(0);
        afe_iic_stop();       
        if(ret < 0)
                return ret;
        crc8_ret = crc8_cal(read_buff, len+4);
        if(crc8_ret != read_buff[len+4])
                return -100;
        memcpy(data, &read_buff[4], len);
        return 0;       
}
/*************************************************
* @function:int afe_reset(void)
* @description:afe软件复位
* @calls:         
* @input:                 
* @return: ret:0为成功, 负数为失败
* @others: 如果EEPROM被改写,需执行复位操作才能生效      
*************************************************/
int afe_reset(void)
{
        int ret = 0;
        uint8_t writeBuf[4] = {0};

        writeBuf[0] = MTP_SLAVE_W;
        writeBuf[1] = 0xEA;
        writeBuf[2] = 0xC0;
        writeBuf[3] = crc8_cal(writeBuf, 3);

        afe_iic_start();
        afe_iic_send_byte(writeBuf[0]);
        ret -= afe_iic_wait_ack();
        afe_iic_send_byte(writeBuf[1]);
        ret -= afe_iic_wait_ack();
        afe_iic_send_byte(writeBuf[2]);
        ret -= afe_iic_wait_ack();
        afe_iic_send_byte(writeBuf[3]);
        ret -= afe_iic_wait_ack();
        afe_iic_stop();
       
        rt_thread_mdelay(100);
        return ret;
}
/*************************************************
* @function:int afe_set_sys_config(sysConfigType *data)
* @description:AEF的EEPROM设置系统配置
* @calls:         
* @input:-data:配置数据                 
* @return: ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_set_sys_config(sysConfigType *data)
{
        int ret = 0;
        uint8_t config[2] = {0};

        /* 数据处理 */
        //MTP_SCONF1
        config[0] |= data->ENPCH << 7;
        config[0] |= data->ENMOS << 6;
        config[0] |= data->OCPM << 5;
        config[0] |= data->BAL << 4;
        config[0] |= data->CNX & SCONF1_CNX;
        //MTP_SCONF2
        config[1] |= data->E0VB << 7;
        config[1] |= data->UV_OP << 5;
        config[1] |= data->DIS_PF << 4;
        config[1] |= (data->CTLCX << 2) & SCONF2_CTLCX;
        config[1] |= data->OCRA << 1;
        config[1] |= data->EUVR;

        /* 打开编程电压 */
        afe_programme_open();

        ret = afe_write_buffer(MTP_SCONF1, config, 2);
        if(ret == 2) ret = 0;
       
        /* 关闭编程电压 */
        afe_programme_close();

        return ret;
}
/*************************************************
* @function:int afe_get_sys_config(sysConfigType *data)
* @description:AEF的EEPROM设置系统配置
* @calls:         
* @input:                 
* @return: ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_sys_config(sysConfigType *data)
{
        int ret = 0;
        uint8_t config[2] = {0};

        /* 读寄存器数据 */
        ret = afe_read_buffer(MTP_SCONF1, config, 2);

        /* 数据处理 */
        if(ret == 0)
        {
                //MTP_SCONF1
                data->ENPCH = config[0] & SCONF1_ENPCH ? 1 : 0;
                data->ENMOS = config[0] & SCONF1_ENMOS ? 1 : 0;
                data->OCPM = config[0] & SCONF1_OCPM ? 1 : 0;
                data->BAL = config[0] & SCONF1_BAL ? 1 : 0;
                data->CNX = config[0] & SCONF1_CNX;
                //MTP_SCONF2
                data->E0VB = config[1] & SCONF2_E0VB ? 1 : 0;
                data->UV_OP = config[1] & SCONF2_UV_OP ? 1 : 0;
                data->DIS_PF = config[1] & SCONF2_DIS_PF ? 1 : 0;
                data->CTLCX = (config[1] & SCONF2_CTLCX) >> 2;
                data->OCRA = config[1] & SCONF2_OCRA ? 1 : 0;
                data->EUVR = config[1] & SCONF2_EUVR ? 1 : 0;
        }

        return ret;
}
/*************************************************
* @function:void afe_print_sys_config(sysConfigType *data)
* @description:AEF的EEPROM打印系统配置
* @calls:         
* @input:                 
* @return: ret:0为成功, 负数为失败
* @others:  
*************************************************/
void afe_print_sys_config(sysConfigType *data)
{
        rt_kprintf("ENPCH=%d\r\n", data->ENPCH);
        rt_kprintf("ENMOS=%d\r\n", data->ENMOS);
        rt_kprintf("OCPM=%d\r\n", data->OCPM);
        rt_kprintf("BAL=%d\r\n", data->BAL);
        rt_kprintf("CNX=%d\r\n", data->CNX);
        rt_kprintf("E0VB=%d\r\n", data->E0VB);
        rt_kprintf("UV_OP=%d\r\n", data->UV_OP);
        rt_kprintf("DIS_PF=%d\r\n", data->DIS_PF);
        rt_kprintf("CTLCX=%d\r\n", data->CTLCX);
        rt_kprintf("OCRA=%d\r\n", data->OCRA);
        rt_kprintf("EUVR=%d\r\n\r\n", data->EUVR);
}
/*************************************************
* @function:int afe_set_voltage_protect(VOLTAGE_PROTECT_TYPE *data)
* @description:AEF的EEPROM设置电压保护参数
* @calls:         
* @input:                 
* @return: ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_set_voltage_protect(voltageProtectType *data)
{
        int ret = 0;
        uint8_t config[10] = {0};
        uint16_t temp = 0;

        /* 数据处理 */
        //MTP_OVT_LDRT_OVH、MTP_OVL
        config[0] |= data->OVTX << 4;
        config[0] |= (data->LDRTX << 2) & OVT_LDRT_OVH_LDRTX;
        temp = data->OVX / 5;
        config[0] |= (temp >> 8) & 0x03;
        config[1] = temp & 0xFF;
        //MTP_UVT_OVRH、MTP_OVRL
        config[2] |= data->UVTX << 4;
        temp = data->OVRX / 5;
        config[2] |= (temp >> 8) & 0x03;
        config[3] = temp & 0xFF;
        //MTP_UV、MTP_UVR
        config[4] = data->UVX / 20;
        config[5] = data->UVRX / 20;
        //MTP_BALV
        config[6] = data->BALVX / 20;
        //MTP_PREV
        config[7] = data->PREVX / 20;
        //MTP_L0V
        config[8] = data->L0VX / 20;
        //MTP_PFV
        config[9] = data->PFVX / 20;

        /* 打开编程电压 */
        afe_programme_open();

        ret = afe_write_buffer(MTP_OVT_LDRT_OVH, config, 10);
        if(ret == 10) ret = 0;

        /* 关闭编程电压 */
        afe_programme_close();

        return ret;
}
/*************************************************
* @function:int afe_get_voltage_protect(voltageProtectType *data)
* @description:AEF的EEPROM获取电压保护参数
* @calls:         
* @input:                 
* @return: ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_voltage_protect(voltageProtectType *data)
{
        int ret = 0;
        uint8_t config[10] = {0};
        uint16_t temp = 0;

        /* 读寄存器数据 */
        ret = afe_read_buffer(MTP_OVT_LDRT_OVH, config, 10);

        /* 数据处理 */
        if(ret == 0)
        {
                //MTP_OVT_LDRT_OVH、MTP_OVL
                data->OVTX = config[0] >> 4;
                data->LDRTX = (config[0] & OVT_LDRT_OVH_LDRTX) >> 2;
                temp = ((config[0] & OVT_LDRT_OVH_OV) << 8) | config[1];
                data->OVX = temp * 5;
                //MTP_UVT_OVRH、MTP_OVRL
                data->UVTX = config[2] >> 4;
                temp = ((config[2] & UVT_OVRH_OVR) << 8) | config[3];
                data->OVRX = temp * 5;
                //MTP_UV、MTP_UVR
                data->UVX = config[4] * 20;
                data->UVRX = config[5] * 20;
                //MTP_BALV
                data->BALVX = config[6] * 20;
                //MTP_PREV
                data->PREVX = config[7] * 20;
                //MTP_L0V
                data->L0VX = config[8] * 20;
                //MTP_PFV
                data->PFVX = config[9] * 20;
        }

        return ret;
}
/*************************************************
* @function:void afe_print_voltage_protect(voltageProtectType *data)
* @description:AEF的EEPROM打印电压保护参数
* @calls:         
* @input:                 
* @return:
* @others:  
*************************************************/
void afe_print_voltage_protect(voltageProtectType *data)
{
        rt_kprintf("OVTX=%d\r\n", data->OVTX);
        rt_kprintf("LDRTX=%d\r\n", data->LDRTX);
        rt_kprintf("OVX=%d\r\n", data->OVX);
        rt_kprintf("UVTX=%d\r\n", data->UVTX);       
        rt_kprintf("OVRX=%d\r\n", data->OVRX);
        rt_kprintf("UVX=%d\r\n", data->UVX);
        rt_kprintf("UVRX=%d\r\n", data->UVRX);
        rt_kprintf("BALVX=%d\r\n", data->BALVX);       
        rt_kprintf("PREVX=%d\r\n", data->PREVX);
        rt_kprintf("L0VX=%d\r\n", data->L0VX);
        rt_kprintf("PFVX=%d\r\n\r\n", data->PFVX);
}
/*************************************************
* @function:int afe_set_current_protect(currentProtectType *data)
* @description:AEF的EEPROM设置电流保护参数
* @calls:         
* @input:                 
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_set_current_protect(currentProtectType *data)
{
        int ret = 0;
        uint8_t config[5] = {0};
       
        /* 数据处理 */
        //MTP_OCD1V_OCD1T、MTP_OCD1V_OCD2T
        config[0] |= data->OCD1VX << 4;
        config[0] |= data->OCD1TX & OCD1V_OCD1T_OCD1TX;
        config[1] |= data->OCD2VX << 4;
        config[1] |= data->OCD2TX & OCD2V_OCD2T_OCD2TX;
        //MTP_SCV_SCT
        config[2] |= data->SCVX << 4;
        config[2] |= data->SCTX & SCV_SCT_SCTX;
        //MTP_OCCV_OCCT
        config[3] |= data->OCCVX << 4;
        config[3] |= data->OCCTX & OCCV_OCCT_OCCTX;
        //MTP_MOST_OCRT_PFT
        config[4] |= (data->CHSX << 6) & OCRT_PFT_CHSX;
        config[4] |= (data->MOSTX << 4) & OCRT_PFT_MOSTX;
        config[4] |= (data->OCRTX << 2) & OCRT_PFT_OCRTX;
        config[4] |= (data->PFTX << 0) & OCRT_PFT_PFTX;

        /* 打开编程电压 */
        afe_programme_open();

        ret = afe_write_buffer(MTP_OCD1V_OCD1T, config, 5);
        if(ret == 5) ret = 0;

        /* 关闭编程电压 */
        afe_programme_close();

        return ret;
}
/*************************************************
* @function:int afe_get_current_protect(currentProtectType *data)
* @description:AEF的EEPROM获取电流保护参数
* @calls:         
* @input:                 
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_current_protect(currentProtectType *data)
{
        int ret = 0;
        uint8_t config[5] = {0};

        /* 读寄存器数据 */
        ret = afe_read_buffer(MTP_OCD1V_OCD1T, config, 5);

        /* 数据处理 */
        if(ret == 0)
        {
                //MTP_OCD1V_OCD1T、MTP_OCD1V_OCD2T
                data->OCD1VX = config[0] >> 4;
                data->OCD1TX = config[0] & OCD1V_OCD1T_OCD1TX;
                data->OCD2VX = config[1] >> 4;
                data->OCD2TX = config[1] & OCD2V_OCD2T_OCD2TX;       
                //MTP_SCV_SCT       
                data->SCVX = config[2] >> 4;
                data->SCTX = config[2] & SCV_SCT_SCTX;
                //MTP_OCCV_OCCT
                data->OCCVX = config[3] >> 4;
                data->OCCTX = config[3] & OCCV_OCCT_OCCTX;
                //MTP_MOST_OCRT_PFT
                data->CHSX = (config[4] & OCRT_PFT_CHSX) >> 6;
                data->MOSTX = (config[4] & OCRT_PFT_MOSTX) >> 4;
                data->OCRTX = (config[4] & OCRT_PFT_OCRTX) >> 2;
                data->PFTX = config[4] & OCRT_PFT_PFTX;
        }

        return ret;
}
/*************************************************
* @function:void afe_print_current_protect(currentProtectType *data)
* @description:AEF的EEPROM打印电流保护参数
* @calls:         
* @input:                 
* @return:
* @others:  
*************************************************/
void afe_print_current_protect(currentProtectType *data)
{
        rt_kprintf("OCD1VX=%d\r\n", data->OCD1VX);
        rt_kprintf("OCD1TX=%d\r\n", data->OCD1TX);
        rt_kprintf("OCD2VX=%d\r\n", data->OCD2VX);
        rt_kprintf("OCD2TX=%d\r\n", data->OCD2TX);
        rt_kprintf("SCVX=%d\r\n", data->SCVX);
        rt_kprintf("SCTX=%d\r\n", data->SCTX);
        rt_kprintf("OCCVX=%d\r\n", data->OCCVX);
        rt_kprintf("OCCTX=%d\r\n", data->OCCTX);
        rt_kprintf("CHSX=%d\r\n", data->CHSX);
        rt_kprintf("MOSTX=%d\r\n", data->MOSTX);
        rt_kprintf("OCRTX=%d\r\n", data->OCRTX);
        rt_kprintf("PFTX=%d\r\n\r\n", data->PFTX);
}
/*************************************************
* @function:int afe_set_tempe_protect(tempeProtectType *data)
* @description:AEF的EEPROM设置温度保护参数
* @calls:         
* @input:                 
* @return:
* @others:  
*************************************************/
int afe_set_tempe_protect(tempeProtectType *data)
{
        int ret = 0;
        float Re = 0;
        uint8_t config[8] = {0};
       
        /* 数据处理 */
        //MTP_OTC、MTP_OTCR
        //config[0] = data->OTCX;
        //config[1] = data->OTCRX;
        Re = tr_te2re(data->OTCX)/1000.0;
        config[0] = Re/(afeRref+Re)*512;
        Re = tr_te2re(data->OTCRX)/1000.0;
        config[1] = Re/(afeRref+Re)*512;
       
        //MTP_UTC、MTP_UTCR
        //config[2] = data->UTCX;
        //config[3] = data->UTCRX;
        Re = tr_te2re(data->UTCX)/1000.0;
        config[2] = (Re/(afeRref+Re)-0.5)*512;
        Re = tr_te2re(data->UTCRX)/1000.0;
        config[3] = (Re/(afeRref+Re)-0.5)*512;       
       
        //MTP_OTD、MTP_OTDR
        //config[4] = data->OTDX;
        //config[5] = data->OTDRX;
        Re = tr_te2re(data->OTDX)/1000.0;
        config[4] = Re*1.0/(afeRref+Re)*512;
        Re = tr_te2re(data->OTDRX)/1000.0;
        config[5] = Re*1.0/(afeRref+Re)*512;       
       
        //MTP_UTD、MTP_UTDR
        //config[6] = data->UTDX;
        //config[7] = data->UTDRX;
        Re = tr_te2re(data->UTDX)/1000.0;
        config[6] = (Re/(afeRref+Re)-0.5)*512;
        Re = tr_te2re(data->UTDRX)/1000.0;
        config[7] = (Re/(afeRref+Re)-0.5)*512;

        /* 打开编程电压 */
        afe_programme_open();

        ret = afe_write_buffer(MTP_OTC, config, 8);
        if(ret == 8) ret = 0;
       
        //rt_kprintf("Set_Tempe_Reg=%d,%d,%d,%d,%d,%d,%d,%d\r\n", config[0],config[1],config[2],config[3],config[4],config[5],config[6],config[7]);

        /* 关闭编程电压 */
        afe_programme_close();

        return ret;
}
/*************************************************
* @function:int afe_get_tempe_protect(tempeProtectType *data)
* @description:AEF的EEPROM获取温度保护参数
* @calls:         
* @input:                 
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_tempe_protect(tempeProtectType *data)
{
        int ret = 0, Re = 0;
        uint8_t config[8] = {0};

        /* 读寄存器数据 */
        ret = afe_read_buffer(MTP_OTC, config, 8);
       
        //rt_kprintf("Get_Tempe_Reg=%d,%d,%d,%d,%d,%d,%d,%d\r\n", config[0],config[1],config[2],config[3],config[4],config[5],config[6],config[7]);

        /* 数据处理 */
        if(ret == 0)
        {
                //MTP_OTC、MTP_OTCR
                //data->OTCX = config[0];
                //data->OTCRX = config[1];
                Re = config[0]*afeRref/(512-config[0])*1000;
                data->OTCX = tr_re2te(Re);
                Re = config[1]*afeRref/(512-config[1])*1000;
                data->OTCRX = tr_re2te(Re);
               
                //MTP_UTC、MTP_UTCR
                //data->UTCX = config[2];
                //data->UTCRX = config[3];
                Re = ((config[2]+256)*afeRref)/(256-config[2])*1000;
                data->UTCX = tr_re2te(Re);
                Re = ((config[3]+256)*afeRref)/(256-config[3])*1000;
                data->UTCRX = tr_re2te(Re);
               
                //MTP_OTD、MTP_OTDR
                //data->OTDX = config[4];
                //data->OTDRX = config[5];
                Re = config[4]*afeRref/(512-config[4])*1000;
                data->OTDX = tr_re2te(Re);
                Re = config[5]*afeRref/(512-config[5])*1000;
                data->OTDRX = tr_re2te(Re);
               
                //MTP_UTD、MTP_UTDR
                //data->UTDX = config[6];
                //data->UTDRX = config[7];
                Re = ((config[6]+256)*afeRref)/(256-config[6])*1000;
                data->UTDX = tr_re2te(Re);
                Re = ((config[7]+256)*afeRref)/(256-config[7])*1000;
                data->UTDRX = tr_re2te(Re);
        }
        return ret;
}
/*************************************************
* @function:void afe_print_tempe_protect(tempeProtectType *data)
* @description:AEF的EEPROM打印温度保护参数
* @calls:         
* @input:                 
* @return:
* @others:  
*************************************************/
void afe_print_tempe_protect(tempeProtectType *data)
{
        rt_kprintf("OTCX=%d\r\n", data->OTCX);
        rt_kprintf("OTCRX=%d\r\n", data->OTCRX);
        rt_kprintf("UTCX=%d\r\n", data->UTCX);
        rt_kprintf("UTCRX=%d\r\n", data->UTCRX);
        rt_kprintf("OTDX=%d\r\n", data->OTDX);
        rt_kprintf("OTDRX=%d\r\n", data->OTDRX);
        rt_kprintf("UTDX=%d\r\n", data->UTDX);
        rt_kprintf("UTDRX=%d\r\n", data->UTDRX);
}
/*************************************************
* @function:int afe_set_watchdog_overtime(bWdtType overtime)
* @description:AEF的RAM设置看门狗溢出时间
* @calls:         
* @input:overtime:溢出时间(define)                 
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_set_watchdog_overtime(bWdtType overtime)
{
        int ret = 0;

        ret = afe_write_buffer(MTP_RSTSTAT, &overtime, 1);
        if(ret == 1) ret = 0;               
        return ret;
}
/*************************************************
* @function:int afe_get_watchdog_overtime(bWdtType *overtime)
* @description:AEF的RAM获取看门狗溢出时间
* @calls:         
* @input:overtime:溢出时间(define)                 
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_watchdog_overtime(bWdtType *overtime)
{
        int ret = 0;

        ret = afe_read_buffer(MTP_RSTSTAT, overtime, 1);
        return ret;
}
/*************************************************
* @function:int afe_set_config(bConfigType config)
* @description:AEF的RAM设置系统配置
* @calls:         
* @input:               
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_set_config(bConfigType config)
{
        int ret = 0;

        ret = afe_write_buffer(MTP_CONF, &config, 1);
        if(ret == 1) ret = 0;
        return ret;
}
/*************************************************
* @function:int afe_get_config(bConfigType *config)
* @description:AEF的RAM获取系统配置
* @calls:         
* @input:               
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_config(bConfigType *config)
{
        int ret = 0;

        ret = afe_read_buffer(MTP_CONF, config, 1);
        return ret;
}
/*************************************************
* @function:int afe_get_status(bStatusType *status)
* @description:AEF的RAM获取系统状态
* @calls:         
* @input:status:系统状态(define)               
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_status(bStatusType *status)
{
        int ret = 0;
        uint8_t data[3] = {0};

        ret = afe_read_buffer(MTP_BSTATUS1, data, 3);
        if(ret == 0)
        {
                *status = 0;
                *status |= data[2] << 16;
                *status |= data[1] << 8;
                *status |= data[0];
        }
        return ret;
}
/*************************************************
* @function:int afe_get_flag(bFlagType *flag)
* @description:AEF的RAM获取系统标志
* @calls:         
* @input:flag:系统标志(define)            
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_flag(bFlagType *flag)
{
        int ret = 0;
        uint8_t data[2] = {0};

        ret = afe_read_buffer(MTP_BFLAG1, data, 2);
        if(ret == 0)
        {
                *flag = 0;
                *flag |= data[1] << 8;
                *flag |= data[0];
        }
        return ret;
}
/*************************************************
* @function:int afe_set_flag(bFlagType flag)
* @description:AEF的RAM清除系统标志
* @calls:         
* @input:flag:系统标志(define)         
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_set_flag(bFlagType flag)
{
        int ret = 0;
        uint8_t data[2] = {0};

        data[1] = flag & 0xFF;
        data[0] = flag >> 8;
        ret = afe_write_buffer(MTP_BFLAG1, data, 2);
        if(ret == 2) ret = 0;
        return ret;
}
/*************************************************
* @function:int afe_set_balance(uint16_t balance)
* @description:AEF的RAM设置平衡开关
* @calls:         
* @input:balance:平衡电芯编号(每bit对应一节电芯, 1为开,0为关)      
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_set_balance(uint16_t balance)
{
        int ret = 0;
        uint8_t data[2] = {0};

        data[0] = balance >> 8;
        data[1] = balance & 0xFF;
        ret = afe_write_buffer(MTP_BALANCEH, data, 2);
        if(ret == 2) ret = 0;
        return ret;
}
/*************************************************
* @function:int afe_get_balance(uint16_t *balance)
* @description:AEF的RAM获取平衡开关
* @calls:         
* @input:balance:平衡电芯编号(每bit对应一节电芯, 1为开,0为关)      
* @return:ret:0为成功, 负数为失败
* @others:  
*************************************************/
int afe_get_balance(uint16_t *balance)
{
        int ret = 0;
        uint8_t data[2] = {0};

        ret = afe_read_buffer(MTP_BALANCEH, data, 2);
        if(ret == 0)
        {
                *balance = 0;
                *balance |= data[0] << 8;
                *balance |= data[1];
        }
        return ret;
}
/*************************************************
* @function:int afe_get_tvc_data(int8_t tempe[3], int16_t cellVoltage[16], float *totalVoltage, float *current)
* @description:AEF的RAM获取数据(温度°C、电芯电压mV、总电压V、实时电流A)
* @calls:         
* @input:   
* @return:ret:0为成功, 负数为失败
* @others:tempe、cellVoltage、totalVoltage、current:温度、电芯电压、总电压、电流  
*************************************************/
int afe_get_tvc_data(int8_t tempe[3], int16_t cellVoltage[16], float *totalVoltage, float *current)
{
        int ret = 0, Re = 0;
        uint8_t data[40] = {0};
        int16_t temp = 0;
        uint8_t i = 0, reg_num = 0;
       
        ret = afe_read_buffer(MTP_TEMP1H, data, 40);
        if(ret == 0)
        {
                /* 温度 */
                //温度1
                temp = (data[0] << 8) | data[1];                                        //寄存器值
                Re = temp / (32768.0 - temp) * afeRref * 1000;                //求电阻值(R)
                tempe[0] = tr_re2te(Re);                                                        //电阻转换为温度                                       
                //温度2
                temp = (data[2] << 8) | data[3];                               
                Re = temp / (32768.0 - temp) * afeRref * 1000;       
                tempe[1] = tr_re2te(Re);       
                //温度3
                temp = (data[4] << 8) | data[5];                               
                Re = temp / (32768.0 - temp) * afeRref * 1000;       
                tempe[2] = tr_re2te(Re);

                /* 电流 */
                temp = (data[6] << 8) | data[7];       
                *current = (200.0 * temp) / (26837 * AfeRsamp) / 1000;       

                /* 电芯电压 */
                reg_num = 8;
                *totalVoltage = 0;
                for(i=0; i<16; i++)
                {
                        temp = (data[reg_num] << 8) | data[reg_num+1];
                        reg_num += 2;
                        cellVoltage = temp * (5.0 / 32);
                        *totalVoltage += cellVoltage;
                }
                *totalVoltage = *totalVoltage / 1000;
        }
        return ret;
}
/*************************************************
* @function:int afe_get_integral_data(float *integral)
* @description:AEF的RAM获取积分电流
* @calls:         
* @input:   
* @return:ret:0为成功, 负数为失败
* @others:current:积分电流(A)
*************************************************/
int afe_get_integral_data(float *integral)
{
        int ret = 0;
        uint8_t data[2] = {0};
        int16_t temp = 0;
       
        ret = afe_read_buffer(MTP_CADCDH, data, 2);
        if(ret == 0)
        {
                temp = (data[0] << 8) | data[1];
                *integral = (200.0 * temp) / (21470 * AfeRsamp) / 1000;
        }
        return ret;
}
/*************************************************
* @function:int afe_get_tvci_data(int8_t tempe[3], int16_t cellVoltage[16], float *totalVoltage, float *current, float *integral)
* @description:EF的RAM获取数据(温度°C、电芯电压mV、总电压V、实时电流A、积分电流A)
* @calls:         
* @input:   
* @return:ret:0为成功, 负数为失败
* @others:tempe、cellVoltage、totalVoltage、current:温度、电芯电压、总电压、电流
*************************************************/
int afe_get_tvci_data(int8_t tempe[3], int16_t cellVoltage[16], float *totalVoltage, float *current, float *integral)
{
        int ret = 0, Re = 0;
        uint8_t data[42] = {0};
        int16_t temp = 0;
        uint8_t i = 0, reg_num = 0;
       
        ret = afe_read_buffer(MTP_TEMP1H, data, 42);
        if(ret == 0)
        {
                /* 温度 */
                //温度1
                temp = (data[0] << 8) | data[1];                                        //寄存器值
                Re = temp / (32768.0 - temp) * afeRref * 1000;                //求电阻值(R)
                tempe[0] = tr_re2te(Re);                                                        //电阻转换为温度                                       
                //温度2
                temp = (data[2] << 8) | data[3];                               
                Re = temp / (32768.0 - temp) * afeRref * 1000;       
                tempe[1] = tr_re2te(Re);       
                //温度3
                temp = (data[4] << 8) | data[5];                               
                Re = temp / (32768.0 - temp) * afeRref * 1000;       
                tempe[2] = tr_re2te(Re);

                /* 电流 */
                temp = (data[6] << 8) | data[7];       
                *current = (200.0 * temp) / (26837 * AfeRsamp) / 1000;       

                /* 电芯电压 */
                reg_num = 8;
                *totalVoltage = 0;
                for(i=0; i<16; i++)
                {
                        temp = (data[reg_num] << 8) | data[reg_num+1];
                        reg_num += 2;
                        cellVoltage = temp * (5.0 / 32);
                        *totalVoltage += cellVoltage;
                }
                *totalVoltage = *totalVoltage / 1000;
               
                /* 积分电流 */
                temp = (data[40] << 8) | data[41];
                *integral = (200.0 * temp) / (21470 * AfeRsamp) / 1000;
        }
        return ret;
}



/****************************************************************************************************************
* AFE的SOCE相关
***************************************************************************************************************/
typedef struct
{
        float Capacity;                 //剩余容量(Ah)
        float Percent;                         //剩余容量百分比(Ah)
} socTypeDef;
socTypeDef socData = {0, 0};

/*************************************************
* @function:void afe_soc_set_capacity(float capacity)
* @description:AEF的socData设置容量值
* @calls:         
* @input:capacity:容量值Ah   
* @return:
* @others:
*************************************************/
void afe_soc_set_capacity(float capacity)
{
        if(capacity > SOC_FULL_CAP)
                capacity = SOC_FULL_CAP;
        if(capacity < 0)
                capacity = 0;
        socData.Capacity = capacity;
        socData.Percent = socData.Capacity / SOC_FULL_CAP * 100;
        if(socData.Percent > 100)
                socData.Percent = 100;
}
/*************************************************
* @function:void afe_soc_set_percent(float percent)
* @description:AEF的socData设置百分比
* @calls:         
* @input:
* @return:
* @others:
*************************************************/
void afe_soc_set_percent(float percent)
{
        if(percent > 100)
                percent = 100;
        if(percent < 0)
                percent = 0;
        socData.Percent = percent;
        socData.Capacity = socData.Percent / 100 * SOC_FULL_CAP;
        if(socData.Capacity > SOC_FULL_CAP)
                socData.Capacity = SOC_FULL_CAP;
}
/*************************************************
* @function:float afe_soc_get_capacity(void)
* @description:AEF的socData获取容量值
* @calls:         
* @input:
* @return:capacity:容量值Ah
* @others:
*************************************************/
float afe_soc_get_capacity(void)
{
        return socData.Capacity;
}
/*************************************************
* @function:float afe_soc_get_percent(void)
* @description:AEF的socData获取百分比
* @calls:         
* @input:
* @return:percent:百分比(0%-100%)
* @others:
*************************************************/
float afe_soc_get_percent(void)
{
        return socData.Percent;
}
/*************************************************
* @function:void afe_soc_calc_handler(float integral)
* @description:AEF的socData周期计算处理
* @calls:         
* @input:
* @return:
* @others:必须以SOC_PERIOD周期调用(AFE的VADC中断调用),AFE空闲期间不要调用,以减少累计误差
*************************************************/
void afe_soc_calc_handler(float integral)
{
        socData.Capacity += integral * SOC_PERIOD;
        socData.Percent = socData.Capacity / SOC_FULL_CAP * 100;
}






bms.h

/*************************************************
* @copyright:
* @author:Xupeng
* @date:2022-11-03
* @description:
**************************************************/  
#ifndef _AFE_H_
#define _AFE_H_

#ifdef __cplusplus
extern "C"
{
#endif
       
#include "main_value.h"

/*****************************************************************************
* 器件地址、EEPROM、RAM寄存器定义
****************************************************************************/
/* AFE采样电阻 */
#define RS_SAMP                   0.001      

/* AFE器件地址 */
#define MTP_SLAVE           0x1A      //不含读写位
#define MTP_SLAVE_W         0x34      //含写位
#define MTP_SLAVE_R         0x35      //含读位

/* AFE的EEPROM寄存器列表 */
#define MTP_SCONF1          0x00
#define MTP_SCONF2          0x01
#define MTP_OVT_LDRT_OVH    0x02
#define MTP_OVL             0x03
#define MTP_UVT_OVRH        0x04
#define MTP_OVRL            0x05
#define MTP_UV              0x06
#define MTP_UVR             0x07
#define MTP_BALV            0x08
#define MTP_PREV            0x09
#define MTP_L0V             0x0A
#define MTP_PFV             0x0B
#define MTP_OCD1V_OCD1T     0x0C
#define MTP_OCD2V_OCD2T     0x0D
#define MTP_SCV_SCT         0x0E
#define MTP_OCCV_OCCT       0x0F
#define MTP_MOST_OCRT_PFT   0x10
#define MTP_OTC             0x11
#define MTP_OTCR            0x12
#define MTP_UTC             0x13
#define MTP_UTCR            0x14
#define MTP_OTD             0x15
#define MTP_OTDR            0x16
#define MTP_UTD             0x17
#define MTP_UTDR            0x18
#define MTP_TR              0x19

/* AFE的RAM寄存器列表 */
#define MTP_CONF            0x40
#define MTP_BALANCEH        0x41
#define MTP_BALANCEL        0x42
#define MTP_BSTATUS1        0x43
#define MTP_BSTATUS2        0x44
#define MTP_BSTATUS3        0x45
#define MTP_TEMP1H          0x46
#define MTP_TEMP1L          0x47
#define MTP_TEMP2H          0x48
#define MTP_TEMP2L          0x49
#define MTP_TEMP3H          0x4A
#define MTP_TEMP3L          0x4B
#define MTP_CURH            0x4C
#define MTP_CURL            0x4D
#define MTP_CELL1H          0x4E
#define MTP_CELL1L          0x4F
#define MTP_CELL2H          0x50
#define MTP_CELL2L          0x51
#define MTP_CELL3H          0x52
#define MTP_CELL3L          0x53
#define MTP_CELL4H          0x54
#define MTP_CELL4L          0x55
#define MTP_CELL5H          0x56
#define MTP_CELL5L          0x57
#define MTP_CELL6H          0x58
#define MTP_CELL6L          0x59
#define MTP_CELL7H          0x5A
#define MTP_CELL7L          0x5B
#define MTP_CELL8H          0x5C
#define MTP_CELL8L          0x5D
#define MTP_CELL9H          0x5E
#define MTP_CELL9L          0x5F
#define MTP_CELL10H         0x60
#define MTP_CELL10L         0x61
#define MTP_CELL11H         0x62
#define MTP_CELL11L         0x63
#define MTP_CELL12H         0x64
#define MTP_CELL12L         0x65
#define MTP_CELL13H         0x66
#define MTP_CELL13L         0x67
#define MTP_CELL14H         0x68
#define MTP_CELL14L         0x69
#define MTP_CELL15H         0x6A
#define MTP_CELL15L         0x6B
#define MTP_CELL16H         0x6C
#define MTP_CELL16L         0x6D
#define MTP_CADCDH          0x6E
#define MTP_CADCDL          0x6F
#define MTP_BFLAG1          0x70
#define MTP_BFLAG2          0x71
#define MTP_RSTSTAT         0x72


/*****************************************************************************
* EEPROM寄存器位及参数定义
****************************************************************************/
/* SCONF1寄存器位定义 */
#define SCONF1_ENPCH                  0x80      //预充电模块控制位
#define SCONF1_ENMOS                  0x40      //充电MOS恢复控制位
#define SCONF1_OCPM                   0x20      //充放电过流MOSFET控制位
#define SCONF1_BAL                    0x10      //平衡功能模块使能控制位
#define SCONF1_CNX                    0x0F      //串数配置控制位

/* SCONF2寄存器位定义 */
#define SCONF2_E0VB                   0x80      //禁止低压电芯充电功能设置控制位
#define SCONF2_REV                    0x40      //保留
#define SCONF2_UV_OP                  0x20      //过放电时MOSFET控制位
#define SCONF2_DIS_PF                 0x10      //二次过充电模块使能控制位
#define SCONF2_CTLCX                  0x0C      //CTL管脚功能设置控制位
#define SCONF2_OCRA                   0x02      //电流恢复设置控制位
#define SCONF2_EUVR                   0x01      //过放电恢复设置控制位

/* OVT_LDRT_OVH&OVL寄存器位定义 */
#define OVT_LDRT_OVH_OVTX             0xF0      //过充电保护延时设置控制位
#define OVT_LDRT_OVH_LDRTX            0x0C      //负载释放延时设置控制位
#define OVT_LDRT_OVH_OV               0x03      //过充电保护电压
#define OVT_LDRT_OVL_OV               0xFF      //过充电保护电压
//过充电保护延时值
#define OVT_LDRT_OVH_OVTX_100MS       0
#define OVT_LDRT_OVH_OVTX_200MS       1
#define OVT_LDRT_OVH_OVTX_300MS       2
#define OVT_LDRT_OVH_OVTX_400MS       3
#define OVT_LDRT_OVH_OVTX_600MS       4
#define OVT_LDRT_OVH_OVTX_800MS       5
#define OVT_LDRT_OVH_OVTX_1S          6
#define OVT_LDRT_OVH_OVTX_2S          7
#define OVT_LDRT_OVH_OVTX_3S          8  
#define OVT_LDRT_OVH_OVTX_4S          9
#define OVT_LDRT_OVH_OVTX_6S          10  
#define OVT_LDRT_OVH_OVTX_8S          11   
#define OVT_LDRT_OVH_OVTX_10S         12  
#define OVT_LDRT_OVH_OVTX_20S         13  
#define OVT_LDRT_OVH_OVTX_30S         14  
#define OVT_LDRT_OVH_OVTX_40S         15   
//负载释放延时值  
#define OVT_LDRT_OVH_LDRTX_100MS      0
#define OVT_LDRT_OVH_LDRTX_500MS      1
#define OVT_LDRT_OVH_LDRTX_1000MS     2
#define OVT_LDRT_OVH_LDRTX_2000MS     3

/* UVT_OVRH&OVRL寄存器位定义 */
#define UVT_OVRH_UVTX                 0xF0      //过放电保护延时设置控制位
#define UVT_OVRH_OVR                  0x03      //过充电恢复电压
#define OVRL_OVR                      0xFF      //过充电恢复电压
//过放电保护延时值
#define UVT_OVRH_UVTX_100MS           0
#define UVT_OVRH_UVTX_200MS           1
#define UVT_OVRH_UVTX_300MS           2
#define UVT_OVRH_UVTX_400MS           3
#define UVT_OVRH_UVTX_600MS           4
#define UVT_OVRH_UVTX_800MS           5
#define UVT_OVRH_UVTX_1S              6
#define UVT_OVRH_UVTX_2S              7
#define UVT_OVRH_UVTX_3S              8
#define UVT_OVRH_UVTX_4S              9
#define UVT_OVRH_UVTX_6S              10
#define UVT_OVRH_UVTX_8S              11
#define UVT_OVRH_UVTX_10S             12
#define UVT_OVRH_UVTX_20S             13
#define UVT_OVRH_UVTX_30S             14
#define UVT_OVRH_UVTX_40S             15

/* UV寄存器位定义 */
#define UV_UVX                        0xFF      //过放电保护电压

/* UVR寄存器位定义 */
#define UVR_UVRX                      0xFF      //过放电恢复电压

/* BALV寄存器位定义 */
#define BALV_BALVX                    0xFF      //平衡开启电压

/* PREV寄存器位定义 */
#define PREV_PREVX                    0xFF      //预充电电压

/* L0V寄存器位定义 */
#define L0V_L0VX                      0xFF      //低电压禁止充电电压

/* PFV寄存器位定义 */
#define PFV_PFVX                      0xFF      //二次过充电保护电压

/* OCD1V_OCD1T寄存器位定义 */
#define OCD1V_OCD1T_OCD1VX            0xF0      //放电过流1保护电压设置控制位
#define OCD1V_OCD1T_OCD1TX            0x0F      //放电过流1保护延时设置控制位
//放电过流1保护电压值
#define OCD1V_OCD1T_OCD1VX_20MV       0
#define OCD1V_OCD1T_OCD1VX_30MV       1
#define OCD1V_OCD1T_OCD1VX_40MV       2
#define OCD1V_OCD1T_OCD1VX_50MV       3
#define OCD1V_OCD1T_OCD1VX_60MV       4
#define OCD1V_OCD1T_OCD1VX_70MV       5
#define OCD1V_OCD1T_OCD1VX_80MV       6
#define OCD1V_OCD1T_OCD1VX_90MV       7
#define OCD1V_OCD1T_OCD1VX_100MV      8
#define OCD1V_OCD1T_OCD1VX_110MV      9
#define OCD1V_OCD1T_OCD1VX_120MV      10
#define OCD1V_OCD1T_OCD1VX_130MV      11
#define OCD1V_OCD1T_OCD1VX_140MV      12
#define OCD1V_OCD1T_OCD1VX_160MV      13
#define OCD1V_OCD1T_OCD1VX_180MV      14
#define OCD1V_OCD1T_OCD1VX_200MV      15
//放电过流1保护延时值
#define OCD1V_OCD1T_OCD1TX_50MS       0
#define OCD1V_OCD1T_OCD1TX_100MS      1
#define OCD1V_OCD1T_OCD1TX_200MS      2
#define OCD1V_OCD1T_OCD1TX_400MS      3
#define OCD1V_OCD1T_OCD1TX_600MS      4
#define OCD1V_OCD1T_OCD1TX_800MS      5
#define OCD1V_OCD1T_OCD1TX_1S         6
#define OCD1V_OCD1T_OCD1TX_2S         7
#define OCD1V_OCD1T_OCD1TX_4S         8
#define OCD1V_OCD1T_OCD1TX_6S         9
#define OCD1V_OCD1T_OCD1TX_8S         10
#define OCD1V_OCD1T_OCD1TX_10S        11
#define OCD1V_OCD1T_OCD1TX_15S        12
#define OCD1V_OCD1T_OCD1TX_20S        13
#define OCD1V_OCD1T_OCD1TX_30S        14
#define OCD1V_OCD1T_OCD1TX_40S        15

/* OCD2V_OCD2T寄存器位定义 */
#define OCD2V_OCD2T_OCD2VX            0xF0      //放电过流2保护电压设置控制位
#define OCD2V_OCD2T_OCD2TX            0x0F      //放电过流2保护延时设置控制位
//放电过流2保护电压值
#define OCD2V_OCD2T_OCD2VX_30MV       0
#define OCD2V_OCD2T_OCD2VX_40MV       1
#define OCD2V_OCD2T_OCD2VX_50MV       2
#define OCD2V_OCD2T_OCD2VX_60MV       3
#define OCD2V_OCD2T_OCD2VX_70MV       4
#define OCD2V_OCD2T_OCD2VX_80MV       5
#define OCD2V_OCD2T_OCD2VX_90MV       6
#define OCD2V_OCD2T_OCD2VX_100MV      7
#define OCD2V_OCD2T_OCD2VX_120MV      8
#define OCD2V_OCD2T_OCD2VX_140MV      9
#define OCD2V_OCD2T_OCD2VX_160MV      10
#define OCD2V_OCD2T_OCD2VX_180MV      11
#define OCD2V_OCD2T_OCD2VX_200MV      12
#define OCD2V_OCD2T_OCD2VX_300MV      13
#define OCD2V_OCD2T_OCD2VX_400MV      14
#define OCD2V_OCD2T_OCD2VX_500MV      15
//放电过流2保护延时值
#define OCD2V_OCD2T_OCD2TX_10MS       0
#define OCD2V_OCD2T_OCD2TX_20MS       1
#define OCD2V_OCD2T_OCD2TX_40MS       2
#define OCD2V_OCD2T_OCD2TX_60MS       3
#define OCD2V_OCD2T_OCD2TX_80MS       4
#define OCD2V_OCD2T_OCD2TX_100MS      5
#define OCD2V_OCD2T_OCD2TX_200MS      6
#define OCD2V_OCD2T_OCD2TX_400MS      7
#define OCD2V_OCD2T_OCD2TX_600MS      8
#define OCD2V_OCD2T_OCD2TX_800MS      9
#define OCD2V_OCD2T_OCD2TX_1S         10
#define OCD2V_OCD2T_OCD2TX_2S         11
#define OCD2V_OCD2T_OCD2TX_4S         12
#define OCD2V_OCD2T_OCD2TX_8S         13
#define OCD2V_OCD2T_OCD2TX_10S        14
#define OCD2V_OCD2T_OCD2TX_20S        15

/* SCV_SCT寄存器位定义 */
#define SCV_SCT_SCVX                  0xF0      //短路保护保护电压设置控制位
#define SCV_SCT_SCTX                  0x0F      //短路保护延时设置控制位
//短路保护电压值
#define SCV_SCT_SCVX_50MV             0
#define SCV_SCT_SCVX_80MV             1
#define SCV_SCT_SCVX_110MV            2
#define SCV_SCT_SCVX_140MV            3
#define SCV_SCT_SCVX_170MV            4
#define SCV_SCT_SCVX_200MV            5
#define SCV_SCT_SCVX_230MV            6
#define SCV_SCT_SCVX_260MV            7
#define SCV_SCT_SCVX_290MV            8
#define SCV_SCT_SCVX_320MV            9
#define SCV_SCT_SCVX_350MV            10
#define SCV_SCT_SCVX_400MV            11
#define SCV_SCT_SCVX_500MV            12
#define SCV_SCT_SCVX_600MV            13
#define SCV_SCT_SCVX_800MV            14
#define SCV_SCT_SCVX_1000MV           15
//短路保护延时值
#define SCV_SCT_SCTX_0US              0
#define SCV_SCT_SCTX_64US             1
#define SCV_SCT_SCTX_128US            2
#define SCV_SCT_SCTX_192US            3
#define SCV_SCT_SCTX_256US            4
#define SCV_SCT_SCTX_320US            5
#define SCV_SCT_SCTX_384US            6
#define SCV_SCT_SCTX_448US            7
#define SCV_SCT_SCTX_512US            8
#define SCV_SCT_SCTX_576US            9
#define SCV_SCT_SCTX_640US            10
#define SCV_SCT_SCTX_704US            11
#define SCV_SCT_SCTX_768US            12
#define SCV_SCT_SCTX_832US            13
#define SCV_SCT_SCTX_896US            14
#define SCV_SCT_SCTX_960US            15

/* OCCV_OCCT寄存器位定义 */
#define OCCV_OCCT_OCCVX               0xF0      //充电过流保护电压设置控制位
#define OCCV_OCCT_OCCTX               0x0F      //充电过流保护延时设置控制位
//充电过流保护电压值
#define OCCV_OCCT_OCCVX_20MV          0
#define OCCV_OCCT_OCCVX_30MV          1
#define OCCV_OCCT_OCCVX_40MV          2
#define OCCV_OCCT_OCCVX_50MV          3
#define OCCV_OCCT_OCCVX_60MV          4
#define OCCV_OCCT_OCCVX_70MV          5
#define OCCV_OCCT_OCCVX_80MV          6
#define OCCV_OCCT_OCCVX_90MV          7
#define OCCV_OCCT_OCCVX_100MV         8
#define OCCV_OCCT_OCCVX_110MV         9   
#define OCCV_OCCT_OCCVX_120MV         10
#define OCCV_OCCT_OCCVX_130MV         11
#define OCCV_OCCT_OCCVX_140MV         12
#define OCCV_OCCT_OCCVX_160MV         13
#define OCCV_OCCT_OCCVX_180MV         14
#define OCCV_OCCT_OCCVX_200MV         15
//充电过流保护延时值
#define OCCV_OCCT_OCCTX_10MS          0
#define OCCV_OCCT_OCCTX_20MS          1
#define OCCV_OCCT_OCCTX_40MS          2
#define OCCV_OCCT_OCCTX_60MS          3
#define OCCV_OCCT_OCCTX_80MS          4
#define OCCV_OCCT_OCCTX_100MS         5
#define OCCV_OCCT_OCCTX_200MS         6
#define OCCV_OCCT_OCCTX_400MS         7
#define OCCV_OCCT_OCCTX_600MS         8
#define OCCV_OCCT_OCCTX_800MS         9
#define OCCV_OCCT_OCCTX_1S            10
#define OCCV_OCCT_OCCTX_2S            11  
#define OCCV_OCCT_OCCTX_4S            12
#define OCCV_OCCT_OCCTX_8S            13
#define OCCV_OCCT_OCCTX_10S           14
#define OCCV_OCCT_OCCTX_20S           15

/* OCRT_PFT寄存器位定义 */
#define OCRT_PFT_CHSX                 0xC0      //充放电状态检测电压设置
#define OCRT_PFT_MOSTX                0x30      //充放电MOSFET开启延时设置
#define OCRT_PFT_OCRTX                0x0C      //充放电过流自恢复延时设置
#define OCRT_PFT_PFTX                 0x03      //二次过充电保护延时设置
//充放电状态检测电压值
#define OCRT_PFT_CHSX_200UV           0
#define OCRT_PFT_CHSX_500UV           1
#define OCRT_PFT_CHSX_1000UV          2
#define OCRT_PFT_CHSX_2000UV          3   
//充放电MOSFET开启延时值
#define OCRT_PFT_MOSTX_64US           0  
#define OCRT_PFT_MOSTX_128US          1
#define OCRT_PFT_MOSTX_256US          2  
#define OCRT_PFT_MOSTX_512US          3
//充放电过流自动恢复延时值     
#define OCRT_PFT_OCRTX_8S             0  
#define OCRT_PFT_OCRTX_16S            1  
#define OCRT_PFT_OCRTX_32S            2  
#define OCRT_PFT_OCRTX_64S            3  
//二次过充电保护延时值     
#define OCRT_PFT_PFTX_8S              0  
#define OCRT_PFT_PFTX_16S             1  
#define OCRT_PFT_PFTX_32S             2  
#define OCRT_PFT_PFTX_64S             3  

/* OTC寄存器位定义 */
#define OTC_OTCX                      0xFF      //充电高温保护阈值

/* OTCR寄存器位定义 */
#define OTCR_OTCRX                    0xFF      //充电高温保护释放阈值

/* UTC寄存器位定义 */
#define UTC_UTCX                      0xFF      //充电低温保护阈值

/* UTCR寄存器位定义 */
#define UTCR_UTCRX                    0xFF      //充电低温保护释放阈值

/* OTD寄存器位定义 */
#define OTD_OTDX                      0xFF      //放电高温保护阈值

/* OTDR寄存器位定义 */
#define OTDR_OTDRX                    0xFF      //放电高温保护释放阈值

/* UTD寄存器位定义 */
#define UTD_UTDX                      0xFF      //放电低温保护阈值

/* UTDR寄存器位定义 */
#define UTDR_UTDRX                    0xFF      //放电低温保护释放阈值

/* TR寄存器位定义 */
#define TR_TRX                        0xFF      //温度内部参考电阻系数


/*****************************************************************************
* RAM寄存器位及参数定义
****************************************************************************/
/* CONF寄存器位定义 */
#define CONF_OCRC                     0x80          //过流保护控制位
#define CONF_PCHMOS                   0x40          //预充电MOSFET控制位
#define CONF_DSGMOS                   0x20          //放电MOSFET控制位
#define CONF_CHGMOS                   0x10          //充电MOSFET控制位
#define CONF_CADCON                   0x08          //CADC设置控制位
#define CONF_ENWDT                    0x04          //看门狗设置控制位
#define CONF_SLEEP                    0x02          //SLEEP设置控制位
#define CONF_IDLE                     0x01          //IDLE设置控制位
typedef uint8_t bConfigType;

/* BSTATUS1寄存器位定义 */
#define BSTATUS1_WDT                  0x80          //看门狗状态位
#define BSTATUS1_PF                   0x40          //二次过充电保护状态位
#define BSTATUS1_SC                   0x20          //短路保护状态位
#define BSTATUS1_OCC                  0x10          //充电过流保护状态位
#define BSTATUS1_OCD2                 0x08          //放电过流2保护状态位
#define BSTATUS1_OCD1                 0x04          //放电过流1保护状态位
#define BSTATUS1_UV                   0x02          //欠压保护状态位
#define BSTATUS1_OV                   0x01          //过压保护状态位

/* BSTATUS2寄存器位定义 */
#define BSTATUS2_OTD                  (0x08<<8)      //放电高温保护状态位
#define BSTATUS2_UTD                  (0x04<<8)      //放电低温保护状态位
#define BSTATUS2_OTC                  (0x02<<8)      //充电高温保护状态位
#define BSTATUS2_UTC                  (0x01<<8)      //充电低温保护状态位

/* BSTATUS3寄存器位定义 */
#define BSTATUS3_CHGING               (0x80<<16)      //充电状态位
#define BSTATUS3_DSGING               (0x40<<16)      //放电状态位
#define BSTATUS3_EEPR_WR              (0x10<<16)      //EEPROM写操作状态位
#define BSTATUS3_L0V                  (0x08<<16)      //低电压禁止充电状态位
#define BSTATUS3_PCHG_FET             (0x04<<16)      //预充电MOSFET开关状态位
#define BSTATUS3_CHG_FET              (0x02<<16)      //充电MOSFET开关状态位
#define BSTATUS3_DSG_FET              (0x01<<16)      //放电MOSFET开关状态位
typedef uint32_t bStatusType;

/* BFLAG1寄存器位定义 */
#define BFLAG1_WDT_**                0x80            //看门狗标志位
#define BFLAG1_PF_**                 0x40            //二次过充电保护标志位
#define BFLAG1_SC_**                 0x20            //短路保护标志位
#define BFLAG1_OCC_**                0x10            //充电过流保护标志位
#define BFLAG1_LOAD_**               0x08            //LDO3过流标志位
#define BFLAG1_OCD_**                0x04            //放电过流保护标志位
#define BFLAG1_UV_**                 0x02            //欠压保护标志位
#define BFLAG1_OV_**                 0x01            //过压保护标志位

/* BFLAG2寄存器位定义 */
#define BFLAG2_RST_**                (0x80<<8)       //复位标志位
#define BFLAG2_WAKE_**               (0x40<<8)       //唤醒中断标志位
#define BFLAG2_CADC_**               (0x20<<8)       //CADC中断标志位(读取清零)
#define BFLAG2_VADC_**               (0x10<<8)       //VADC中断标志位(读取清零)
#define BFLAG2_OTD_**                (0x08<<8)       //放电高温保护标志位
#define BFLAG2_UTD_**                (0x04<<8)       //放电低温保护标志位
#define BFLAG2_OTC_**                (0x02<<8)       //充电高温保护标志位
#define BFLAG2_UTC_**                (0x01<<8)       //充电低温保护标志位

/* 保护位定义 */
#define BFLAG_PROTECT_**              0x0F77         //多种保护标志位或值
typedef uint16_t bFlagType;

/* RSTSTAT寄存器位定义 */
#define RSTSTAT_WDTX                  0x03            //看门狗溢出时间控制
//看门狗溢出时间  
#define RSTSTAT_WDTX_32S              0
#define RSTSTAT_WDTX_16S              1
#define RSTSTAT_WDTX_8S               2
#define RSTSTAT_WDTX_4S               3
typedef uint8_t bWdtType;


/*****************************************************************************
* AFE数据类型接口
****************************************************************************/
/* 系统配置 */
#pragma pack(1)
typedef struct
{
  uint8_t ENPCH;         //预充电模块控制(0禁用预充电,1启用预充电)
  uint8_t ENMOS;         //充电MOSFET恢复控制(0禁用,1启用;启用后当过充电/温度保护关闭充电MOSFET后,如果检测到放电过流1或者放电状态,则开启充电MOSFET)
  uint8_t OCPM;          //充放电过流MOSFET控制(0充电过流只关闭充电MOSFET,放电过流只关闭放电MOSFET;1充放电过流关闭充放电MOSFET)
  uint8_t BAL;           //平衡功能模块使能控制(0平衡开启由SH367309内部逻辑控制;1平衡开启由外部MCU控制,平衡时序仍由SH367309内部逻辑控制)
  uint8_t CNX;           //串数配置控制(5~16节电池)
  uint8_t E0VB;          //禁止低压电芯充电功能设置控制(0关闭禁止低压电芯充电功能;1开启禁止低压电芯充电功能)
  uint8_t UV_OP;         //过放电时MOSFET控制(0过放电只关闭放电MOSFET;1过放电关闭充放电MOSFET)
  uint8_t DIS_PF;        //二次过充电模块使能控制(0启用二次过充电保护;1禁止二次过充电保护)
  uint8_t CTLCX;         //CTL管脚功能设置控制(CTL控制效果:0不控制任何MOS;1控制充电和预充电MOS;2控制放电MOSFET; 控制充放电和预充电MOSFET)
  uint8_t OCRA;          //电流恢复设置控制(0不允许电流保护定时恢复;1允许电流保护定时恢复)
  uint8_t EUVR;          //过放电恢复设置控制(0过放电保护状态释放与负载释放无关;1过放电保护状态释放还需负载释放)
} sysConfigType;
#pragma pack()

/* 电压保护 */
#pragma pack(1)
typedef struct
{
  uint8_t OVTX;           //过充电保护延时(define)
  uint8_t LDRTX;          //负载释放延时(define)
  uint16_t OVX;           //过充电保护电压(mV,5x)
  uint8_t UVTX;           //过放电保护延时(define)
  uint16_t OVRX;          //过充电恢复电压(mV,5x)
  uint16_t UVX;           //过放电保护电压(mV,20x)
  uint16_t UVRX;          //过放电恢复电压(mV,20x)
  uint16_t BALVX;         //平衡开启电压(mV,20x)
  uint16_t PREVX;         //预充电电压(mV,20x)
  uint16_t L0VX;          //低电压禁止充电电压(mV,20x)
  uint16_t PFVX;          //二次过充电保护电压(mV,20x)
} voltageProtectType;
#pragma pack()

/* 电流保护 */
#pragma pack(1)
typedef struct
{
  uint8_t OCD1VX;         //放电过流1保护电压(define)
  uint8_t OCD1TX;         //放电过流1保护延时(define)
  uint8_t OCD2VX;         //放电过流2保护电压(define)
  uint8_t OCD2TX;         //放电过流2保护延时(define)
  uint8_t SCVX;           //短路保护电压(define)
  uint8_t SCTX;           //短路保护延时(define)
  uint8_t OCCVX;          //充电过流保护电压(define)
  uint8_t OCCTX;          //充电过流保护延时(define)
  uint8_t CHSX;           //充放电状态检测电压值(define)
  uint8_t MOSTX;          //充放电MOSFET开启延时(define)
  uint8_t OCRTX;          //充放电过流自动恢复延时(define)
  uint8_t PFTX;           //二次过充电保护延时(define)
} currentProtectType;
#pragma pack()

/* 温度保护 */
//计算公式参考《SH367309 BMS User Guide CV1.1》P38
#pragma pack(1)
typedef struct
{
    int8_t OTCX;          //充电高温保护阈值(°C)
    int8_t OTCRX;         //充电高温保护释放阈值(°C)
    int8_t UTCX;          //充电低温保护阈值(°C)
    int8_t UTCRX;         //充电低温保护释放阈值(°C)
    int8_t OTDX;          //放电高温保护阈值(°C)
    int8_t OTDRX;         //放电高温保护释放阈值(°C)
    int8_t UTDX;          //放电低温保护阈值(°C)
    int8_t UTDRX;         //放电低温保护释放阈值(°C)
} tempeProtectType;
#pragma pack()

/* SOC相关 */
#define SOC_FULL_CAP                1.8                                        //SOC满电容量(Ah)
#define SOC_PERIOD                          (250/3600000.0)         //SOC积分时间(采样周期)单位(250ms转换为小时)


/*****************************************************************************
* AFE函数接口
****************************************************************************/
/* ALARM中断回调类型 */
typedef void (*AlArmCb_Type)(void);

/* AFE基础 */
float tr_re2te(int Re);
int tr_te2re(float Te);
int afe_init(AlArmCb_Type cb);
void afe_programme_open(void);
void afe_programme_close(void);
int afe_write_byte(uint8_t addr, uint8_t data);
int afe_write_buffer(uint8_t addr, uint8_t *data, uint32_t len);
int afe_read_buffer(uint8_t addr, uint8_t *data, uint32_t len);
int afe_reset(void);
/* AFE的EEPROM操作接口 */
int afe_set_sys_config(sysConfigType *data);
int afe_get_sys_config(sysConfigType *data);
void afe_print_sys_config(sysConfigType *data);
int afe_set_voltage_protect(voltageProtectType *data);
int afe_get_voltage_protect(voltageProtectType *data);
void afe_print_voltage_protect(voltageProtectType *data);
int afe_set_current_protect(currentProtectType *data);
int afe_get_current_protect(currentProtectType *data);
void afe_print_current_protect(currentProtectType *data);
int afe_set_tempe_protect(tempeProtectType *data);
int afe_get_tempe_protect(tempeProtectType *data);
void afe_print_tempe_protect(tempeProtectType *data);
/* AFE的RAM操作接口 */
int afe_set_watchdog_overtime(bWdtType overtime);
int afe_get_watchdog_overtime(bWdtType *overtime);
int afe_set_config(bConfigType config);
int afe_get_config(bConfigType *config);
int afe_get_status(bStatusType *status);
int afe_get_flag(bFlagType *flag);
int afe_set_flag(bFlagType flag);
int afe_set_balance(uint16_t balance);
int afe_get_balance(uint16_t *balance);
int afe_get_tvc_data(int8_t tempe[3], int16_t cellVoltage[16], float *totalVoltage, float *current);
int afe_get_integral_data(float *integral);
int afe_get_tvci_data(int8_t tempe[3], int16_t cellVoltage[16], float *totalVoltage, float *current, float *integral);
/* SOC接口 */
void afe_soc_set_capacity(float capacity);
void afe_soc_set_percent(float percent);
float afe_soc_get_capacity(void);
float afe_soc_get_percent(void);
void afe_soc_calc_handler(float integral);

#ifdef __cplusplus
}
#endif

#endif



manage.c

/*************************************************
* @copyright:
* @author:Xupeng
* @date:2024-07-18
* @description:
**************************************************/  
#include "bms_manage.hpp"


#define LOG_TAG      "bms_manage"
#define LOG_LVL       ELOG_LVL_VERBOSE
#include <elog.h>

/* 系统配置参数 */
const sysConfigType sysConfigDefault = {
        .ENPCH = 0,
        .ENMOS = 1,
        .OCPM = 1,
        .BAL = 0,
        .CNX = 6,
        .E0VB = 0,
        .UV_OP = 0,
        .DIS_PF = 0,
        .CTLCX = 0,
        .OCRA = 1,
        .EUVR = 1
};

/* 电压保护配置参数 */
const voltageProtectType voltageProtectDefault = {
        .OVTX = OVT_LDRT_OVH_OVTX_1S,
        .LDRTX = OVT_LDRT_OVH_LDRTX_100MS,
        .OVX = 4100,
        .UVTX =        UVT_OVRH_UVTX_1S,
        .OVRX = 4000,
        .UVX = 3200,
        .UVRX = 3300,
        .BALVX = 3900,
        .PREVX = 2500,
        .L0VX = 1500,
        .PFVX = 4500,
};

/* 电流保护配置参数 */
const currentProtectType currentProtectTypeDefault = {
        .OCD1VX = OCD1V_OCD1T_OCD1VX_70MV,
        .OCD1TX = OCD1V_OCD1T_OCD1TX_1S,
        .OCD2VX = OCD2V_OCD2T_OCD2VX_200MV,
        .OCD2TX = OCD2V_OCD2T_OCD2TX_600MS,
        .SCVX = SCV_SCT_SCVX_320MV,
        .SCTX = SCV_SCT_SCTX_256US,
        .OCCVX = OCCV_OCCT_OCCVX_20MV,
        .OCCTX = OCCV_OCCT_OCCTX_20MS,
        .CHSX = OCRT_PFT_CHSX_200UV,
        .MOSTX = OCRT_PFT_MOSTX_64US,
        .OCRTX = OCRT_PFT_OCRTX_32S,
        .PFTX = OCRT_PFT_PFTX_16S
};

/* 温度保护配置参数 */
const tempeProtectType tempeProtectDefault = {
        .OTCX = 55,
        .OTCRX = 50,
        .UTCX = 0,
        .UTCRX = 5,
        .OTDX = 55,
        .OTDRX = 50,
        .UTDX = 0,
        .UTDRX = 5
};

/* 满电总电压 */
#define        FULL_VOLTAGE                                                 25.20f

/* 实时数据 */
bmsDataType bmsData;

static uint16_t timeCnt = 0;


extern "C"
{
    /*************************************************
        * @function:bmsDataType get_bms_data(void)
        * @description:获取bms数据
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/        
        void *get_bms_data(void)
        {
                return &bmsData;
        }
    /*************************************************
        * @function:void bms_balance_enable(bool enable)
        * @description:开启平衡
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/        
        void bms_balance_enable(bool enable)
        {
                uint8_t ret;
                uint16_t balance;
                rt_enter_critical();                                                                //进入调度临界区
                ret = afe_set_balance(enable?0x3F:0x00);
                rt_exit_critical();                                                                        //退出调度临界区
                if(ret < 0)
                        log_v("afe set balance=%d\r\n", ret);
                rt_enter_critical();                                                                //进入调度临界区
                ret = afe_get_balance(&balance);
                rt_exit_critical();                                                                        //退出调度临界区
                log_v("afe get balance=%d, %02X\r\n", ret, balance);
        }
    /*************************************************
        * @function:void afe_sys_config(void)
        * @description:AEF系统配置
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/
        void afe_sys_config(void)
        {
                int ret;
               
                sysConfigType sysConfig;

                ret = afe_set_sys_config((sysConfigType *)&sysConfigDefault);
                if(ret < 0)
                        log_e("AFE_Set_Sys_Config=%d", ret);       

                ret = afe_get_sys_config(&sysConfig);
                if(ret < 0)
                        log_e("AFE_Get_Sys_Config=%d", ret);
                afe_print_sys_config(&sysConfig);
        }
    /*************************************************
        * @function:void afe_voltage_protect_config(void)
        * @description:AEF电压保护配置
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/
        void afe_voltage_protect_config(void)
        {
                int ret;
               
                voltageProtectType voltageProtect;

                ret = afe_set_voltage_protect((voltageProtectType *)&voltageProtectDefault);
                if(ret < 0)
                        log_e("AFE_Set_Voltage_Protect=%d", ret);
                       
                ret = afe_get_voltage_protect(&voltageProtect);
                if(ret < 0)
                        log_e("AFE_Get_Voltage_Protect=%d", ret);
                afe_print_voltage_protect(&voltageProtect);
        }
    /*************************************************
        * @function:void afe_current_protect_config(void)
        * @description:AEF电流保护配置
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/
        void afe_current_protect_config(void)
        {
                int ret;
               
                currentProtectType currentProtect;

                ret = afe_set_current_protect((currentProtectType *)&currentProtectTypeDefault);
                if(ret < 0)
                        log_e("AFE_Set_Current_Protect=%d", ret);       

                ret = afe_get_current_protect(&currentProtect);
                if(ret < 0)
                        log_e("AFE_Get_Current_Protect=%d", ret);
                afe_print_current_protect(&currentProtect);
        }

    /*************************************************
        * @function:void afe_tempe_protect_config(void)
        * @description:AEF温度保护配置
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/        
        void afe_tempe_protect_config(void)
        {
                int ret;
               
                tempeProtectType tempeProtect;

                ret = afe_set_tempe_protect((tempeProtectType *)&tempeProtectDefault);
                if(ret < 0)
                        log_e("AFE_Set_Tempe_Protect=%d", ret);

                ret = afe_get_tempe_protect(&tempeProtect);
                if(ret < 0)
                        log_e("AFE_Get_Tempe_Protect=%d", ret);
                afe_print_tempe_protect(&tempeProtect);
        }

    /*************************************************
        * @function:void system_control_init()
        * @description:BMS管理初始化
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/        
        void bms_manage_init()
        {
                int ret = 0;
                ret = afe_init(NULL);
                if(ret == 0)
                        log_i("afe init ok");
                else
                        log_e("afe_init=%d", ret);       
                if(ret == 0)
                {
                        sysConfigType sysConfig;
                        ret = afe_get_sys_config(&sysConfig);
                        if(ret == 0)
                        {
                                if(sysConfig.ENMOS != sysConfigDefault.ENMOS
                                        ||sysConfig.ENMOS != sysConfigDefault.ENMOS
                                        ||sysConfig.CNX != sysConfigDefault.CNX
                                        ||sysConfig.EUVR != sysConfigDefault.EUVR)
                                {
                                        log_i("first write para!");
                                        /* 系统、电压、电流、温度保护配置(只需配置一次即保存在AFE的EEPROM) */
                                        afe_sys_config();
                                        afe_voltage_protect_config();
                                        afe_current_protect_config();
                                        afe_tempe_protect_config();
                                       
                                        /* 配置后需要复位AFE才能生效 */
                                        int ret1, ret2;
                                        ret1 = afe_reset();
                                        ret2 = afe_set_config((CONF_DSGMOS | CONF_CHGMOS | CONF_CADCON));
                                        log_i("AFE_Reset__Set_Config=%d, %d", ret1, ret2);               
                                       
                                        /* 平衡开关设置 */
//                                        uint16_t balance;
//                                        ret = afe_set_balance(0x3F);
//                                        if(ret < 0)
//                                                log_e("AFE_Set_Balance=%d", ret);
//                                        ret = afe_get_balance(&balance);
//                                        log_i("AFE_Get_Balance=%d, %02X\r\n", ret, balance);
                                }
                        }
                        else
                                log_e("sys config para read error!");
                }
               
               
        }
        /*************************************************
        * @function:void bms_manage_process(uint8_t loopTick)
        * @description:BMS管理周期控制
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/        
        void bms_manage_process(uint8_t loopTick)
        {
                timeCnt += loopTick;
                if(timeCnt <= 500)
                        return ;
                timeCnt = 0;
               
                /* 读状态和中断标志 */
                rt_enter_critical();                                                                //进入调度临界区
                afe_get_status(&bmsData.status);
                afe_get_flag(&bmsData.flag);
                afe_get_balance(&bmsData.balance);
                rt_exit_critical();                                                                        //退出调度临界区       
                log_d("afe get status flag = 0x%06X, 0x%04X", bmsData.status, bmsData.flag);
                log_d("afe get balance = 0x%04x",bmsData.balance);
               
                /* VADC中断 */
                if(bmsData.flag & BFLAG2_VADC_**)
                {
                        /* 读AFE数据 */
                        rt_enter_critical();                                                                //进入调度临界区
                        int ret = afe_get_tvci_data(bmsData.temperature, bmsData.cellVoltage, &bmsData.totalVoltage, &bmsData.current, &bmsData.integral);
                        rt_exit_critical();                                                                        //退出调度临界区       
                        if(ret == 0)
                        {
                                log_d("afe get tvci data = %06X, %04X, %d", bmsData.status, bmsData.flag, bmsData.integral);
                                /* 非空闲时计算SOC */
                                if((bmsData.status & BSTATUS3_CHGING) || (bmsData.status & BSTATUS3_DSGING))
                                {
                                        afe_soc_calc_handler(bmsData.integral);
                                        log_v("soc = %d, %d, %d", (int)(afe_soc_get_capacity()*100),(int)( afe_soc_get_percent()*100), (int)(bmsData.totalVoltage*100));
                                }
                        }
                }
                bmsData.remain = afe_soc_get_percent();
                /* 满电后设置SOC为100% */
                if(bmsData.totalVoltage >= FULL_VOLTAGE)
                {
                        afe_soc_set_percent(100);       
                        //log_v("AFE_SOC_Set_Capacity");
                }                       
//                /* 清除所有中断标志 */
//                int ret = afe_set_flag(bflag);       
        }
        /*************************************************
        * @function:static int bms_cmd()
        * @description:BMS命令
        * @calls:         
        * @input:                    
        * @return:      
        * @others:      
        *************************************************/                
        static int bms_cmd(int argc, char *argv[])
        {
                if(argc == 1)
                {
                        char buf[50];
                        rt_kprintf("status=%06X\r\n", bmsData.status);
                        rt_kprintf("balance=%04X\r\n", bmsData.balance);
                        memset(buf, 0, sizeof(buf));
                        snprintf(buf, sizeof(buf), "voltage=%.3f\r\n", bmsData.totalVoltage);
                        rt_kprintf("%s", buf);
                        memset(buf, 0, sizeof(buf));
                        snprintf(buf, sizeof(buf), "current=%.3f\r\n", bmsData.current);
                        rt_kprintf("%s", buf);
                        memset(buf, 0, sizeof(buf));
                        snprintf(buf, sizeof(buf), "capacity=%.3f\r\n", afe_soc_get_capacity());
                        rt_kprintf("%s", buf);
                        memset(buf, 0, sizeof(buf));
                        snprintf(buf, sizeof(buf), "percent=%.3f\r\n", afe_soc_get_percent());
                        rt_kprintf("%s", buf);       
                        for(uint8_t i = 0; i < 6; i++)
                        {
                                rt_kprintf("cellVoltage[%d]=%d\r\n", i, bmsData.cellVoltage);
                        }               
                        rt_kprintf("temperature1 = %d\r\n",bmsData.temperature[0]);
                        rt_kprintf("temperature2 = %d\r\n",bmsData.temperature[1]);
                        rt_kprintf("temperature3 = %d\r\n",bmsData.temperature[2]);
                    return 0;
                }
                else if(argc == 2)
                {
                        if(strcmp(argv[1], "default") == 0)
                        {
                                /* 系统、电压、电流、温度保护配置(只需配置一次即保存在AFE的EEPROM) */
                                afe_sys_config();
                                afe_voltage_protect_config();
                                afe_current_protect_config();
                                afe_tempe_protect_config();
                               
                                /* 配置后需要复位AFE才能生效 */
                                int ret1, ret2;
                                ret1 = afe_reset();
                                ret2 = afe_set_config((CONF_DSGMOS | CONF_CHGMOS | CONF_CADCON));
                                rt_kprintf("afe set config=%d, %d\r\n", ret1, ret2);                       
                        }
                        else if(strcmp(argv[1], "balance") == 0)
                        {
                                uint8_t ret;
                                uint16_t balance;
                                ret = afe_set_balance(0x3F);
                                if(ret < 0)
                                        rt_kprintf("afe set balance=%d\r\n", ret);
                                ret = afe_get_balance(&balance);
                                rt_kprintf("afe get balance=%d, %02X\r\n", ret, balance);
                        }
                        else
                                rt_kprintf("please input correct cmd!\r\n");
                }
                else
                        rt_kprintf("please input correct cmd!\r\n");               
                return 0;
        }
        MSH_CMD_EXPORT_ALIAS(bms_cmd,bms,bms cmd);
}






————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_15181569/article/details/148402973

使用特权

评论回复
沙发
chenqianqian| | 2025-6-12 08:20 | 只看该作者
这个软硬件有没有经过实测呢?能否正常工作呢?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

53

主题

150

帖子

0

粉丝