/******************************************************************************** Copyright (C), Sinowealth Electronic. Ltd. Author: Sino Version: V0.0 Date: 2020/04/26 History: V2.0 2020/04/26 Preliminary ********************************************************************************/ #include "Main.h" //AFE相关的变量 BOOL bAfeAlarmFlg; BOOL bCADCFlg; BOOL bVADCFlg; BOOL bAfeI2CRWErrFlg; BOOL bAfeErr; U8 data ucCellNum; //当前硬件电芯串数 U8 data ucCellNumOffset; //当前硬件电芯连接方式对应的偏移,用于程序读取AFE对应寄存器 U16 data uiCellVmax; //电芯电压最大值 U16 data uiCellVmin; //电芯电压最小值 U16 xdata uiVadcVmax; //ADC采集最大值 U16 xdata uiVadcVmin; //ADC采集最小值 U8 xdata ucTempeMiddle; U16 xdata uiTempeMin; U16 xdata uiTempeMax; S32 xdata slCadcCurrent; S32 xdata slCadcCurAverage; U8 xdata ucCadcCnt; S32 xdata slCadcCurBuf[16]; U8 xdata ucAfeI2CErrDelayCnt; SYSINFOR xdata Info; //经过计算的值 AFEDATA xdata AFE; //AFE寄存器读取的值 AFEREG xdata REG; //AFE寄存器预设值 /************************************************************************************************* * 函数名: AFETwiCheck * 参 数: 无 * 返回值: 无 * 描 述: 连续5S检测到AFE的I2C通讯错误,则置位bAfeErr=1 *************************************************************************************************/ void AFETwiCheck(void) { if(bAfeI2CRWErrFlg) { if(++ucAfeI2CErrDelayCnt >= TIME_1S_5S) { bAfeErr = 1; ucAfeI2CErrDelayCnt = TIME_1S_5S; } } else { ucAfeI2CErrDelayCnt = 0; } } /************************************************************************************************* * 函数名: AFEWriteReg * 参 数: Reg:寄存器地址 WrBuf:写的数据:1Byte数据+1Byte CRC * 返回值: 1:成功;0:失败 * 描 述: 写AFE寄存器,每次写一个寄存器 *************************************************************************************************/ BOOL AFEWriteReg(U8 Reg, U8 Length, U8 xdata *WrBuf) { BOOL Result = 0; U8 Times = 0; U8 i; if(!bAfeErr) { for(i=0; i= 5) { break; } else { Times = 0; Reg++; WrBuf++; } Delay1ms(1); } } bAfeI2CRWErrFlg = !Result; //标记通讯是否正常 return Result; } /************************************************************************************************* * 函数名: AFEReadReg * 参 数: Reg:寄存器地址 RdBuf:读的数据:2Byte数据+1Byte CRC * 返回值: 1:成功;0:失败 * 描 述: 读AFE寄存器,每次连续读两个寄存器 *************************************************************************************************/ BOOL AFEReadReg(U8 Reg, U8 Length , U8 xdata *RdBuf) { BOOL Result = 0; U8 Times = 0; if(!bAfeErr) { while(Times++ < 5) //如果读数出错,则Try 5次 { #ifdef TWI_Hardware_Module Result = TwiRead(AFE_ID, Reg, TWI_ADDR_1B, Length, TWI_CRC_YES, RdBuf); #else Result = TwiRead(AFE_ID, Reg, Length, RdBuf); #endif if(Result) //如果读数成功且CRC校验正确,则退出循环返回成功标标志 { break; } else //如果TWI读数或CRC校验失败,则延时1mS之后再读取 { TWICON = 0; //Close TWI module Delay1ms(1); TwiInit(); //Reinitial Delay1ms(1); } } } bAfeI2CRWErrFlg = !Result; //标记通讯是否正常 return Result; } /************************************************************************************************* * 函数名: AFEClrFlg * 参 数: * 返回值: 无 * 描 述: 清零AFE标志寄存器 *************************************************************************************************/ void AFEClrFlg(void) { if(AFEReadReg(AFE_FLAG1, 2, ®.AFEFLAG1)) { if((REG.AFEFLAG1!=0) || (REG.AFEFLAG2!=0)) { REG.AFESCONF1 |= 0x80; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); REG.AFESCONF1 &= ~0x80; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); } } } /************************************************************************************************* * 函数名: AFEInitReg * 参 数: 无 * 返回值: 无 * 描 述: 初始化AFE寄存器 *************************************************************************************************/ void AFEInitReg(void) { U16 TempVar; REG.AFEINTEN = 0x00; //采取查询式,故不需要ALARM中断 REG.AFESCONF1 = 0x50; //使能CTLD和WDT功能 REG.AFESCONF2 = 0x00; //AFE引脚配置为复位信号,ALARM输出低电平脉冲,放电MOS与充电MOS都关闭 REG.AFESCONF3 = 0xF8; //默认VADC和CADC都开启,CADC连续采样,10位ADC,VADC只采集电压转换周期50ms REG.AFESCONF4 = 0x00; //默认关闭平衡BAT6-10 REG.AFESCONF5 = 0x00; //默认关闭平衡BAT1-5 REG.AFESCONF6 = 0x70; //CADC采集200mV范围,复位信号宽度1S,硬件短路保护电压100mV,硬件短路保护延时50uS REG.AFESCONF7 = 0x01; //硬件过冲保护延时1个转换周期,充放电状态阈值选择位1.4mV,配置看门狗溢出10S REG.AFESCONF8 = 0x03; //SCONF8 + SCONF9 = 11 1111 1111 = 1023 REG.AFESCONF9 = 0xff; //硬件过冲保护阈值1023*5.86mV = 5994.78 REG.AFESCONF10= 0x00; //低功耗控制位,写入0x33再写PD_EN=1进入低功耗 if(bSC_EN) //配置使能AFE短路功能 { REG.AFESCONF1 |= 0x08; REG.AFESCONF6 |= (E2ucAFEProtectConfig&0x0f);//将FLASH内参数写入AFE寄存器 } if(bOV_EN) //配置使能AFE过压功能 { REG.AFESCONF1 |= 0x04; REG.AFESCONF7 |= (E2ucAFEProtectConfig&0xf0);//将FLASH内参数写入AFE寄存器 TempVar = (U32)E2uiAFEOVvol*50/293; //取出过压保护电压 REG.AFESCONF8 = TempVar>>8; //写高两位 REG.AFESCONF9 = TempVar; //写低八位 } } /************************************************************************************************* * 函数名: AFEInit * 参 数: * 返回值: 1:成功;0:失败 * 描 述: 初始化AFE *************************************************************************************************/ BOOL AFEInit(void) { U8 xdata RdBuf[2]; U8 i; BOOL Result = 1; U8 j = 3; while(j--) { if( AFEWriteReg(AFE_INT_EN, 11, ®.AFEINTEN)) { for(i=3; i<=11; i=i+2) { AFEReadReg(i, 2, RdBuf); if((RdBuf[0]!=*(®.AFEFLAG1+i)) || (RdBuf[1]!=*(®.AFEFLAG1+i+1))) { if(i != 7) //平衡寄存器除外,因为平衡寄存器不置位,持续30s会自动清零 { Result = 0; break; } } } } else { Result = 0; } if(Result) { break; } } return Result; } /************************************************************************************************* * 函数名: AFERdFlg * 参 数: * 返回值: 无 * 描 述: 读取AFE标志寄存器 AFE_SC表示发生短路保护 FLAG2的bit2为1表示发生LVR复位,需要重新初始化AFE *************************************************************************************************/ void AFERdFlg(void) { if(AFEReadReg(AFE_FLAG1, 2, ®.AFEFLAG1)) { if((REG.AFEFLAG2&0x02) != 0) //CADC 电流转换完成 { bCADCFlg = 1; } if((REG.AFEFLAG2&0x01) != 0) //VADC 电压转换完成 { bVADCFlg = 1; } if((REG.AFEFLAG1&0x08) != 0 && (bLoadChkingFlg != 1)) //AFE短路保护 { bAFE_SC = 1; bLoadStartCheckFlg = 1; //开启负载检测 } if((REG.AFEFLAG1&0x04) != 0) //AFE 硬件过压保护 { bAFE_OV= 1; } if((REG.AFEFLAG2&0x04) != 0) //判断FLAG2的bit2是否为1,如为1则表示AFE发生过LVR,需要重新初始化AFE寄存器 { AFEInit(); } } } /************************************************************************************************* * 函数名: AFERdStatus * 参 数: * 返回值: 无 * 描 述: 读取AFE状态寄存器 *************************************************************************************************/ void AFERdStatus(void) { U8 RegTemp[2]; if(AFEReadReg(AFE_BSTATUS, 2, RegTemp))//®.AFEBSTATUS))//AFE固定读2Bytes,只取1Byte { ucAFEStatus = REG.AFEBSTATUS = RegTemp[0]; //更新充电器、负载的检测结果 } } /************************************************************************************************* * 函数名: AFERamCheck * 参 数: * 返回值: 无 * 描 述: 定时检测AFE的寄存器是否被改写,如果是则重新初始化 *************************************************************************************************/ void AFERamCheck(void) { U8 xdata RdBuf[2]; U8 i; for(i=3; i<=11; i=i+2) { AFEReadReg(i, 2, RdBuf); if((RdBuf[0]!=*(®.AFEFLAG1+i)) || (RdBuf[1]!=*(®.AFEFLAG1+i+1))) { if(i != 7) //平衡寄存器除外,因为平衡寄存器不置位,持续30s会自动清零 { if(!AFEInit()) { bPDFlg = 1; } break; } } } } /************************************************************************************************* * 函数名: AFEEnterPD * 参 数: * 返回值: 无 * 描 述: 控制AFE进入PD状态,关闭3.3V输出 *************************************************************************************************/ void AFEEnterPD(void) { REG.AFESCONF10 = 0x33; if(AFEWriteReg(AFE_SCONF10, 1, ®.AFESCONF10)) { REG.AFESCONF1 |= 0x20; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); } } /************************************************************************************************* * 函数名: AFEMosCtl * 参 数: MosStatus:MOS状态。1:开启;0:关闭 * 返回值: 无 * 描 述: 控制充放电MOS的开启和关闭 *************************************************************************************************/ void AFEMosCtl(U8 MosStatus) { REG.AFESCONF2 &= ~0x03; REG.AFESCONF2 |= MosStatus; AFEWriteReg(AFE_SCONF2, 1, ®.AFESCONF2); } /************************************************************************************************* * 函数名: AFEChgerCheckEn、AFEChgerCheckDis、AFELoadCheckEn、AFELoadCheckDis * 参 数: * 返回值: 无 * 描 述: 使能/关闭充电器检测、负载检测 *************************************************************************************************/ void AFEChgerCheckEn(void) { REG.AFESCONF1 |= 0x01; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); } void AFEChgerCheckDis(void) { REG.AFESCONF1 &= ~0x01; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); } void AFELoadCheckEn(void) { REG.AFESCONF1 |= 0x02; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); } void AFELoadCheckDis(void) { REG.AFESCONF1 &= ~0x02; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); } /************************************************************************************************* * 函数名: AfeBalEn * 参 数: BalChTemp:平衡对应的CELL,如果全部为0,则关闭平衡 * 返回值: 无 * 描 述: 开启和关闭平衡 *************************************************************************************************/ void AfeBalCtl(U16 BalChTemp) { REG.AFESCONF4 = BalChTemp>>5; if(AFEWriteReg(AFE_SCONF4, 1, ®.AFESCONF4)) { REG.AFESCONF5 = BalChTemp; AFEWriteReg(AFE_SCONF5, 1, ®.AFESCONF5); } } /************************************************************************************************* * 函数名: AfeWDTEn, AfeWDTDis * 参 数: * 返回值: 无 * 描 述: 开启和关闭看门狗模块 *************************************************************************************************/ void AfeWDTEn(void) { REG.AFESCONF1 |= 0x10; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); } void AfeWDTDis(void) { REG.AFESCONF1 &= ~0x10; AFEWriteReg(AFE_SCONF1, 1, ®.AFESCONF1); } /************************************************************************************************* * 函数名: AfeWDTEn, AfeWDTDis * 参 数: 无 * 返回值: 无 * 描 述: 开启和关闭看门狗模块 *************************************************************************************************/ void AfeADCEn(void) { REG.AFESCONF3 |= 0xf8; AFEWriteReg(AFE_SCONF3, 1, ®.AFESCONF3); } void AfeADCDis(void) { REG.AFESCONF3 &= ~0xf8; AFEWriteReg(AFE_SCONF3, 1, ®.AFESCONF3); } void AfeCADCEn(void) { REG.AFESCONF3 |= 0xe0; AFEWriteReg(AFE_SCONF3, 1, ®.AFESCONF3); } void AfeCADCDis(void) { REG.AFESCONF3 &= ~0xe0; AFEWriteReg(AFE_SCONF3, 1, ®.AFESCONF3); } void AfeTempADCEn(void) { REG.AFESCONF3 |= 0x08; AFEWriteReg(AFE_SCONF3, 1, ®.AFESCONF3); } void AfeTempADCDis(void) { REG.AFESCONF3 &= ~0x08; AFEWriteReg(AFE_SCONF3, 1, ®.AFESCONF3); } /************************************************************************************************* * 函数名: AfeAlarmEn,AfeAlarmDis * 参 数: AlarmFlg:置位对应的ALARM位 * 返回值: 无 * 描 述: 开启和关闭对应的ALARM中断触发 *************************************************************************************************/ void AfeAlarmEn(U8 AlarmFlg) { REG.AFEINTEN |= AlarmFlg; AFEWriteReg(AFE_INT_EN, 1, ®.AFEINTEN); } void AfeAlarmDis(U8 AlarmFlg) { REG.AFEINTEN &= ~AlarmFlg; AFEWriteReg(AFE_INT_EN, 1, ®.AFEINTEN); }