BMS STM32 V4.0.0.0

This commit is contained in:
2026-08-25 17:30:40 +08:00
commit 3ae7bcb054
313 changed files with 115734 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+246
View File
@@ -0,0 +1,246 @@
/**
******************************************************************************
* @file global.h
* @author Jerry Cai
* @version V2.1
* @date 19-April-2022
* @brief This file contains all the functions prototypes for the GPIO
* firmware library.
******************************************************************************
* @attention
*
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __AFE_SH3673520_H
#define __AFE_SH3673520_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
//#define CALICUR 1000
//#define CALICUR 30700 //16个4m欧电阻并联
//#define CALICUR 28000 //16个5m欧电阻并联
#define REG_ADDR_SCONF1 0x40
#define REG_ADDR_SCONF2 0x41
#define REG_ADDR_SCONF3 0x42
#define REG_ADDR_SCONF4 0x43
#define REG_ADDR_SCONF5 0x44
#define REG_ADDR_SCONF6 0x45
#define REG_ADDR_SCONF7 0x46
#define REG_ADDR_OWV_ALARMH 0x47
#define REG_ADDR_ALARML 0x48
#define REG_ADDR_OVT_OVH 0x49
#define REG_ADDR_OVL 0x4A
#define REG_ADDR_UVT_UVL 0x4B
#define REG_ADDR_UVL 0x4C
#define REG_ADDR_OCD1V_OCD1T 0x4D
#define REG_ADDR_OCD2V_OCD2T 0x4E
#define REG_ADDR_SCV_SCT 0x4F
#define REG_ADDR_OCCV_OCCT 0x50
#define REG_ADDR_OTC 0x51
#define REG_ADDR_OTD 0x52
#define REG_ADDR_UTC 0x53
#define REG_ADDR_UTD 0x54
#define REG_ADDR_BALANCEH 0x55
#define REG_ADDR_BALANCEM 0x56
#define REG_ADDR_BALANCEL 0x57
#define REG_ADDR_FLAG1 0x58
#define REG_ADDR_FLAG2 0x59
#define REG_ADDR_FLAG3 0x5A
#define REG_ADDR_BSTATUS1 0x5B
#define REG_ADDR_BSTATUS2 0x5C
#define REG_ADDR_TEMP1H 0x5D
#define REG_ADDR_TEMP1L 0x5E
#define REG_ADDR_TEMP2H 0x5F
#define REG_ADDR_TEMP2L 0x60
#define REG_ADDR_TEMP3H 0x61
#define REG_ADDR_TEMP3L 0x62
#define REG_ADDR_TEMP4H 0x63
#define REG_ADDR_TEMP4L 0x64
#define REG_ADDR_TEMPIH 0x65
#define REG_ADDR_TEMPIL 0x66
#define REG_ADDR_CURH 0x67
#define REG_ADDR_CURL 0x68
#define REG_ADDR_CELL1H 0x69
#define REG_ADDR_CELL1L 0x6A
#define REG_ADDR_CELL2H 0x6B
#define REG_ADDR_CELL2L 0x6C
#define REG_ADDR_CELL3H 0x6D
#define REG_ADDR_CELL3L 0x6E
#define REG_ADDR_CELL4H 0x6F
#define REG_ADDR_CELL4L 0x70
#define REG_ADDR_CELL5H 0x71
#define REG_ADDR_CELL5L 0x72
#define REG_ADDR_CELL6H 0x73
#define REG_ADDR_CELL6L 0x74
#define REG_ADDR_CELL7H 0x75
#define REG_ADDR_CELL7L 0x76
#define REG_ADDR_CELL8H 0x77
#define REG_ADDR_CELL8L 0x78
#define REG_ADDR_CELL9H 0x79
#define REG_ADDR_CELL9L 0x7A
#define REG_ADDR_CELL10H 0X7B
#define REG_ADDR_CELL10L 0X7C
#define REG_ADDR_CELL11H 0X7D
#define REG_ADDR_CELL11L 0X7E
#define REG_ADDR_CELL12H 0X7F
#define REG_ADDR_CELL12L 0X80
#define REG_ADDR_CELL13H 0X81
#define REG_ADDR_CELL13L 0X82
#define REG_ADDR_CELL14H 0X83
#define REG_ADDR_CELL14L 0X84
#define REG_ADDR_CELL15H 0X85
#define REG_ADDR_CELL15L 0X86
#define REG_ADDR_CELL16H 0X87
#define REG_ADDR_CELL16L 0X88
#define REG_ADDR_CELL17H 0X89
#define REG_ADDR_CELL17L 0X8A
#define REG_ADDR_CELL18H 0X8B
#define REG_ADDR_CELL18L 0X8C
#define REG_ADDR_CELL19H 0X8D
#define REG_ADDR_CELL19L 0X8E
#define REG_ADDR_CELL20H 0X8F
#define REG_ADDR_CELL20L 0X90
#define REG_ADDR_CADCDH 0x91
#define REG_ADDR_CADCDL 0x92
#define REG_ADDR_VTOPH 0x93
#define REG_ADDR_VTOPL 0x94
#define REG_ADDR_VCHGRH 0x95
#define REG_ADDR_VCHGRL 0x96
#define REG_ADDR_OWDH 0x97
#define REG_ADDR_OWDM 0x98
#define REG_ADDR_OWDL 0x99
//AFE RAM Register
typedef struct
{
uint8_t sconf1;
uint8_t sconf2;
uint8_t sconf3;
uint8_t sconf4;
uint8_t sconf5;
uint8_t sconf6;
uint8_t sconf7;
uint8_t owv_alarmh;
uint8_t alarml;
uint8_t ovt_ovh;
uint8_t ovl;
uint8_t uvt_uvh;
uint8_t uvl;
uint8_t ocd1v_ocd1t;
uint8_t ocd2v_ocd2t;
uint8_t scv_sct;
uint8_t occv_occt;
uint8_t otc;
uint8_t otd;
uint8_t utc;
uint8_t utd;
uint8_t balanceh;
uint8_t balancem;
uint8_t balancel;
uint8_t flag1;
uint8_t flag2;
uint8_t flag3;
uint8_t bstatus1;
uint8_t bstatus2;
uint8_t temp1h;
uint8_t temp1l;
uint8_t temp2h;
uint8_t temp2l;
uint8_t temp3h;
uint8_t temp3l;
uint8_t temp4h;
uint8_t temp4l;
uint8_t tempih;
uint8_t tempil;
uint8_t curh;
uint8_t curl;
uint8_t cell1h;
uint8_t cell1l;
uint8_t cell2h;
uint8_t cell2l;
uint8_t cell3h;
uint8_t cell3l;
uint8_t cell4h;
uint8_t cell4l;
uint8_t cell5h;
uint8_t cell5l;
uint8_t cell6h;
uint8_t cell6l;
uint8_t cell7h;
uint8_t cell7l;
uint8_t cell8h;
uint8_t cell8l;
uint8_t cell9h;
uint8_t cell9l;
uint8_t cell10h;
uint8_t cell10l;
uint8_t cell11h;
uint8_t cell11l;
uint8_t cell12h;
uint8_t cell12l;
uint8_t cell13h;
uint8_t cell13l;
uint8_t cell14h;
uint8_t cell14l;
uint8_t cell15h;
uint8_t cell15l;
uint8_t cell16h;
uint8_t cell16l;
uint8_t cell17h;
uint8_t cell17l;
uint8_t cell18h;
uint8_t cell18l;
uint8_t cell19h;
uint8_t cell19l;
uint8_t cell20h;
uint8_t cell20l;
uint8_t cadcdh;
uint8_t cadcdl;
uint8_t vtoph;
uint8_t vtopl;
uint8_t vchgrh;
uint8_t vchgrl;
uint8_t owdh;
uint8_t owdm;
uint8_t owdl;
} AFE_RAM;
//AFE FLG Register
typedef struct
{
uint16_t temp1;
uint16_t temp2;
uint16_t temp3;
uint16_t temp4;
} AFE_FLG;
extern AFE_RAM afeRam;
extern AFE_FLG afeFlg;
extern void AFE_VoltageProcess(void);
extern void AFE_CurrentProcess(void);
extern void AFE_TemperaProcess(void);
extern void AFE_ProtectProcess(void);
extern uint8_t MEMORY_UpdateAFE(void);
extern void InitGasGauge(void);
#ifdef __cplusplus
}
#endif
#endif
+656
View File
@@ -0,0 +1,656 @@
/********************************************************************************
Copyright (C), Sinowealth Electronic. Ltd.
Author: Sino
Version: V0.0
Date: 2014/05/30
History:
V0.0 2014/05/30 Preliminary
********************************************************************************/
#include "stm32f10x.h"
#include "global.h"
#include "string.h"
#include "rtc.h"
uint8_t oldsoc;
uint8_t newsoc;
uint8_t fullToZeroStudyFlag; //满充开始学习标记
uint8_t zeroToFullStudyFlag; //满放开始学习标记
uint32_t packcheck_OV; //单体过压校准SOC的总压判断值
uint32_t packcheck_UV; //单体欠压校准SOC的总压判断值
uint16_t ncc_Ah; //额定容量,用于计算传给逆变器的并机总容量 单位1Ah
uint16_t fcc_Ah; //满充容量,用于在上位机修改容量和SOC后,计算此时的剩余容量 单位1Ah
uint16_t rcc_Ah; //剩余容量,用于计入累计容量,然后计算循环次数
uint16_t oldrcc_Ah; //旧现有容量,用于比较计入累计容量
uint16_t cumuliCapacity; //累积容量,单位0.1Ah
uint8_t FullCharge_count; //满充减容量的延迟计数
uint8_t FullCharge_count2; //满充减容量的延迟计数2
uint8_t Cali_Soc_Flag; //15%校准执行标志
uint16_t CaliSocMoniCount; //15%校准等待时间
uint16_t oldcyc;
uint8_t ClearEE[4] = {0xff,0xff,0xff,0xff};
uint8_t tmpRdFCC[8]; //用于读出总容量值
uint8_t tmpWrFCC[8]; //用于写入总容量值
uint32_t RdFCC;
uint32_t fcc; //满充容量,单位mAS
uint8_t fcc_CaliStartFlag; //当开始充电时,如果此时SOC=0/1%,开始计时
uint8_t fcc_fullFlag; //达到任一满充条件的标志,是最终执行满充容量校准的条件之一
/*******************************************************************************
Function:InitGasGauge()
Description: Calculate the remaining capacity according to pack voltage
Input: NULL
Output: NULL
Others:
*******************************************************************************/
void InitGasGauge(void)
{
uint8_t tmpRd[2],tmpWr[2];
uint16_t capacity,cyctime;
//上电读EEPROM 额定容量值
EEPROM_RdMulByte(EE_NCC,tmpRd);
capacity = tmpRd[0]<<8 | tmpRd[1];
if(capacity>0 && capacity<=1000) //如果之前写过容量值,就按照之前的值显示,范围1~1000,否则显示100Ah
{
bmsMem.ncc = 3600 * 1000 * capacity;
ncc_Ah = capacity;
}
else
{
bmsMem.ncc = 3600 * 1000 * 100; //系统额定容量默认100AH = 100,000mAH = 360,000,000mAS
ncc_Ah = 100;
}
//上电读EEPROM 满充容量值
//前4位是正值,后四位是反值,用来校验数值正确
EEPROM_RdMulByte(EE_FCC,tmpRdFCC);
if( ((tmpRdFCC[0]^0xff) == tmpRdFCC[4]) && ((tmpRdFCC[1]^0xff) == tmpRdFCC[5]) && ((tmpRdFCC[2]^0xff) == tmpRdFCC[6]) && ((tmpRdFCC[3]^0xff) == tmpRdFCC[7]) )
{
RdFCC = tmpRdFCC[0]<<24 | tmpRdFCC[1]<<16 | tmpRdFCC[2]<<8 | tmpRdFCC[3];
if((RdFCC>0) && (RdFCC <= 0xFFE00000)) //不出错的正数范围为1~4,292,870,144,大约1192Ah
{
fcc = RdFCC;
fcc_Ah = RdFCC / 3600000;
}
else
{
fcc = bmsMem.ncc;
fcc_Ah = bmsMem.ncc / 3600000;
}
}
else
{
fcc = bmsMem.ncc;
fcc_Ah = bmsMem.ncc / 3600000;
}
//上电读EEPROM 循环次数
EEPROM_RdMulByte(EE_CYCLE,tmpRd);
cyctime = tmpRd[0]<<8 | tmpRd[1];
if(cyctime > paraMem.sohcali_stopTime+10) //初次读取
{
oldcyc = 0;
bmsMem.cycleCount = 0;
}
else
{
oldcyc = cyctime;
bmsMem.cycleCount = cyctime;
}
//上电读EEPROM 累积容量值 //计算时,使用额定容量而不是满充容量
EEPROM_RdMulByte(EE_CUMULI,tmpRd);
capacity = tmpRd[0]<<8 | tmpRd[1];
if((int)capacity>=0 && capacity<=10*ncc_Ah) //剩余容量范围0~10000*0.1Ah,超出则显示0
{
cumuliCapacity = capacity;
//获得进行循环次数计算的单位容量(此处不可为0)
if(paraMem.sohcali_transCent != 0)
{
capacity = 10*ncc_Ah * paraMem.sohcali_transCent/100;
}
else
{
capacity = 10*ncc_Ah * 90/100; //默认90%
}
//计算循环次数
if(cumuliCapacity >= capacity) //当累积容量超出总容量的90%,增加循环次数
{
bmsMem.cycleCount += cumuliCapacity / capacity;
cumuliCapacity = cumuliCapacity % capacity;
//保存参与过循环次数计算后的累积容量
tmpWr[0] = (cumuliCapacity >> 8) & 0xff;
tmpWr[1] = (cumuliCapacity >> 0) & 0xff;
EEPROM_WrMulByte(EE_CUMULI,tmpWr);
delay_ms(5);
}
}
else
{
cumuliCapacity = 0;
}
//上电读EEPROM soc值
EEPROM_RdMulByte(EE_SOC,&tmpRd[0]);
//正常
if(((int)tmpRd[0]>=0) && (tmpRd[0]<=100)) //在比较操作中使用类型转换不会改变变量本身的类型
{
oldsoc = tmpRd[0];
bmsMem.soc = tmpRd[0];
bmsMem.rcc = fcc/100 * bmsMem.soc;
rcc_Ah = fcc_Ah * bmsMem.soc /100;
oldrcc_Ah = rcc_Ah;
}
//首次上电根据电压校准soc
else
{
OCV_CaliSOC_DataWr();
bmsMem.soc = OCV_CaliSoc_dp();
bmsMem.rcc = fcc/100 * bmsMem.soc;
rcc_Ah = fcc_Ah * bmsMem.soc /100;
oldrcc_Ah = rcc_Ah;
}
}
//Manage the capacity of the pack
//interval 1s
void GaugeManage(void)
{
uint8_t tempWr[2];
uint16_t capacity;
/*参与判断的总压限值*/
//模块过压值
packcheck_OV = cell_OV * bmsMem.ucCellNum -8000;
//模块欠压值
packcheck_UV = cell_UV * bmsMem.ucCellNum +5000;
/*计算剩余容量*/
//电流积分法:微小电流认为是干扰,不参与计算
if( (bmsMem.packCurrent <= (-100)) || (bmsMem.packCurrent >= 100) )
{
bmsMem.rcc += bmsMem.packCurrent;
}
if(bmsMem.rcc > 0xFFE00000)//4.21添加,防止过放数据出错 //因改为无符号,需清零的负数范围设-1~-2,097,151,电流值在2000A范围内皆可接受,不出错的正数范围为0~4,292,870,144,大约1192Ah
{
bmsMem.rcc = 0;
}
if((paraMem.cali_min_disable & 0x8000) != 0) //不允许做满充容量校准
{
//在校准容量判断前,保证参数正确
if(fcc_CaliStartFlag != 0)
{
fcc_CaliStartFlag = 0;
EEPROM_WrMulByte(EE_FCC_TIME,ClearEE);
delay_ms(5);
}
if(fcc != bmsMem.ncc) //校准总容量=额定容量
{
//赋值满充容量=额定容量
fcc = bmsMem.ncc;
fcc_Ah = ncc_Ah;
tmpWrFCC[0] = (fcc>>24) & 0xff;
tmpWrFCC[1] = (fcc>>16) & 0xff;
tmpWrFCC[2] = (fcc>> 8) & 0xff;
tmpWrFCC[3] = (fcc>> 0) & 0xff;
tmpWrFCC[4] = tmpWrFCC[0] ^ 0xff;
tmpWrFCC[5] = tmpWrFCC[1] ^ 0xff;
tmpWrFCC[6] = tmpWrFCC[2] ^ 0xff;
tmpWrFCC[7] = tmpWrFCC[3] ^ 0xff;
EEPROM_WrMulByte(EE_FCC,tmpWrFCC);
delay_ms(20);
//赋值剩余容量=新的满充容量*SOC
bmsMem.rcc = fcc/100 * bmsMem.soc;
rcc_Ah = fcc_Ah * bmsMem.soc / 100;
oldrcc_Ah = rcc_Ah;
}
}
/*计算实时SOC=剩余容量/满充容量*/
if(bmsMem.rcc > fcc/100 * 99) //>99%
{
//若SOC已经是100%,不会下调
if(bmsMem.soc >= 100)
{
bmsMem.soc = 100;
}
//若SOC此前<=99,锁定99%
else
{
bmsMem.soc = 99;
}
}
else //0%~99%
{
//如果剩余容量的小数部分至少有0.1Ah,soc+1
if( (bmsMem.rcc%(fcc/100)) /360000 != 0) //取精度0.1%作为判断标准 360000mAS = 0.1*1000*3600 = 0.1Ah
{
bmsMem.soc = bmsMem.rcc/(fcc/100)+1;
}
else
{
bmsMem.soc = bmsMem.rcc/(fcc/100);
}
}
/*若满足特殊条件,直接改动SOC值,注意剩余容量保持不变*/
//read bSTATUS1 ov bit 满充校准
//满充条件1:单体过压
if( ((paraMem.soc100_methods & 0x01) != 0) && ((bmsMem.bStatus1 & 0x0001) != 0) && (bmsMem.packVoltage > packcheck_OV)) //发生过压保护(会关MOS)//带总压判断(根据串数变化)
{
bmsMem.soc = 100;
fcc_fullFlag = 1;
//如果不在等待校准满充容量,同时更新rcc=fcc
if(fcc_CaliStartFlag == 0)
{
bmsMem.rcc = fcc;
}
}
//满充条件2:总体过压
else if( ((paraMem.soc100_methods & 0x02) != 0) && ((bmsMem.bStatus1 & 0x0100) != 0)) //发生总体过压保护(会关MOS)
{
bmsMem.soc = 100;
fcc_fullFlag = 1;
//如果不在等待校准满充容量,同时更新rcc=fcc
if(fcc_CaliStartFlag == 0)
{
bmsMem.rcc = fcc;
//不计入循环次数
rcc_Ah = bmsMem.rcc/3600/1000;
oldrcc_Ah = rcc_Ah;
}
}
//满充条件3:逆变器限压57.6V+2A小电流
else if( ((paraMem.soc100_methods & 0x04) != 0) && (bmsMem.packVoltage >= bmsMem.inverter_chgVolLimit*100) && (bmsMem.packCurrent >= 100) && (bmsMem.packCurrent <= 2000)) //电压大于逆变器充电限压值,电流小于2A(逆变器会逐渐停止充电,但BMS不关闭MOS)
{
bmsMem.soc = 100;
fcc_fullFlag = 1;
//如果不在等待校准满充容量,同时更新rcc=fcc
if(fcc_CaliStartFlag == 0)
{
bmsMem.rcc = fcc;
//不计入循环次数
rcc_Ah = bmsMem.rcc/3600/1000;
oldrcc_Ah = rcc_Ah;
}
}
//满充条件4:满充电压56V+5A截止电流
else if( ((paraMem.soc100_methods & 0x08) != 0) && ((bmsMem.bStatus1 & 0x0800) != 0)) //发生满充停止充电(会关MOS)
{
bmsMem.soc = 100;
fcc_fullFlag = 1;
//如果不在等待校准满充容量,同时更新rcc=fcc
if(fcc_CaliStartFlag == 0)
{
bmsMem.rcc = fcc;
//不计入循环次数
rcc_Ah = bmsMem.rcc/3600/1000;
oldrcc_Ah = rcc_Ah;
}
}
else
{
fcc_fullFlag = 0;
}
//read bFLAG1 ov bit 满放校准
if((bmsMem.bStatus1 & 0x0002) !=0) //发生单体欠压保护
{
if(bmsMem.packVoltage < packcheck_UV) //总压判断(根据串数变化)
{
bmsMem.soc = 0;
bmsMem.rcc = 0;
}
}
else if((bmsMem.bStatus1 & 0x0200) !=0) //发生总体欠压保护
{
bmsMem.soc = 0;
bmsMem.rcc = 0;
}
else
{
if(bDSGING) //还正在放电但rcc已经为0,会上调一点容量,直到满足满放条件
{
if(bmsMem.soc == 0) //若SOC原是0%,放电不破坏该值
{
bmsMem.rcc = 0;
}
else if((bmsMem.rcc <= 360000) || (bmsMem.rcc > 0xFFE00000)) //因改为无符号,需清零的负数范围设-1~-2,097,151,电流值在2000A范围内皆可接受,不出错的正数范围为0~4,292,870,144,大约1192Ah
{
bmsMem.soc = 1;
bmsMem.rcc = 360000 * 5; //增加0.5Ah用于继续下降 //在0.1Ah~0.5Ah之间维持(soc=1%)
}
}
}
//15%校准:当总电压小于等于50V时,若SOC大于15%则校准到15% //4.28增加电流条件放电15A以下
if((bmsMem.packVoltage <= (50000/16*bmsMem.ucCellNum)) && (bmsMem.soc > 15) && (bmsMem.packCurrent > (-15000)) && (bmsMem.packCurrent < 100))
{
Cali_Soc_Flag = 1;
}
else
{
Cali_Soc_Flag = 0;
}
if((paraMem.cali_min_disable & 0x8000) == 0) //允许做满充容量校准
{
Cali_FCC_Moni(); //电流和SOC满足条件后执行
}
else //不允许
{
//在以上所有执行完后,有问题再纠正下
if(bmsMem.soc == 100) //SOC已经到了100%,此时rcc最高不超过fcc
{
if(bmsMem.rcc > fcc)
{
bmsMem.rcc = fcc;
}
}
else //SOC低于100%,此时rcc最高不超过fcc*99%
{
if(bmsMem.rcc > fcc/100 * 99)
{
if(bCHGING) //正在充电
{
bmsMem.rcc = fcc - (fcc/1000*15);
}
else
{
bmsMem.rcc = fcc/100 * 99;
}
}
}
}
bmsMem.can_soc = bmsMem.soc; //sum of all packs
bmsMem.can_soh = bmsMem.soh; //sum of all packs
/*数据存入EEPROM*/
//SOC write to eeprom
if(bmsMem.soc != oldsoc)
{
oldsoc = bmsMem.soc;
tempWr[0] = bmsMem.soc;
EEPROM_WrMulByte(EE_SOC,&tempWr[0]);
delay_ms(5);
}
//累积容量 write to eeprom
rcc_Ah = bmsMem.rcc/3600/1000;
if(rcc_Ah > oldrcc_Ah) //当容量上涨了1Ah
{
cumuliCapacity += 10*(rcc_Ah - oldrcc_Ah); //将增加部分放入累积容量中
oldrcc_Ah = rcc_Ah;
//获得进行循环次数计算的单位容量(此处不可为0)
if(paraMem.sohcali_transCent != 0)
{
capacity = 10*ncc_Ah * paraMem.sohcali_transCent/100;
}
else
{
capacity = 10*ncc_Ah * 90/100; //默认90%
}
//计算循环次数
if(cumuliCapacity >= capacity) //当累积容量超出总容量的90%,增加循环次数
{
bmsMem.cycleCount += cumuliCapacity / capacity;
cumuliCapacity = cumuliCapacity % capacity;
}
//保存当前(或参与过循环次数计算后的)累积容量
tempWr[0] = (cumuliCapacity >> 8) & 0xff;
tempWr[1] = (cumuliCapacity >> 0) & 0xff;
EEPROM_WrMulByte(EE_CUMULI,tempWr);
delay_ms(5);
}
else
{
oldrcc_Ah = rcc_Ah; //要同步增减
}
//循环次数 write to eeprom
if(bmsMem.cycleCount != oldcyc)
{
oldcyc = bmsMem.cycleCount;
tempWr[0] = (bmsMem.cycleCount >> 8) & 0xff;
tempWr[1] = (bmsMem.cycleCount >> 0) & 0xff;
EEPROM_WrMulByte(EE_CYCLE,tempWr);
delay_ms(5);
if(cumuliCapClear_flag == 1)
{
cumuliCapClear_flag = 0;
//保存累积容量为0
cumuliCapacity = 0;
tempWr[0] = (cumuliCapacity >> 8) & 0xff;
tempWr[1] = (cumuliCapacity >> 0) & 0xff;
EEPROM_WrMulByte(EE_CUMULI,tempWr);
delay_ms(5);
}
}
/*通过循环次数计算SOH*/
if(bmsMem.cycleCount <= paraMem.sohcali_stopTime)
{
if(bmsMem.cycleCount <= paraMem.sohcali_startTime)
{
bmsMem.soh = 100; //维持100%
}
else
{
uint16_t cent = (paraMem.sohcali_stopTime-1 - paraMem.sohcali_startTime) / (99-paraMem.sohcali_minSOH); //每1%对应的大概次数
bmsMem.soh = 99 - (bmsMem.cycleCount - paraMem.sohcali_startTime) / cent; //从99%开始下降
}
}
else //超过就维持最大次数
{
bmsMem.cycleCount = paraMem.sohcali_stopTime;
bmsMem.soh = paraMem.sohcali_minSOH;
}
//Wh版屏幕需要
bmsMem.can_cumuliCap = cumuliCapacity/10; //sum of all packs
bmsMem.can_cycleCnt = bmsMem.cycleCount; //sum of all packs
//过压报警的显示判断:在接近满电时,发生[过压保护],则不会因此亮灯屏幕也不显示过压
#if Key_PressLong
if((ON_confirm_flg != 0) && (RST_confirm_flg != 1) && (OFF_confirm_flg != 1))
#endif
{
if(((bmsMem.bStatus1 & 0x0001) != 0) || ((bmsMem.bStatus1 & 0x0100) != 0)) //单体过压+总体过压
{
if(bmsMem.soc<99) //在正常工作时,发生[过压保护],正常显示
{
bAlarmFlag = 1;
if(sleep_flag == 0) LED_ALARM_On();
else LED_ALARM_Off();
}
else
{
//若出现其他报警,就不恢复原状(-单体过压-总体过压+急停)
if( ((bmsMem.bStatus1 & 0x067e) == 0) && ((bmsMem.bStatus2 & 0x00ff) == 0) && ((bmsMem.bStatus3 & 0x0008) == 0) && ((bmsMem.temperaStatus & 0x0f7f) == 0) )
{
bAlarmFlag = 0;
bAlarmFlagOld = 0;
LED_ALARM_Off();
}
}
}
}
//led指示
#if Key_PressLong
if((ON_confirm_flg != 0) && (RST_confirm_flg != 1) && (OFF_confirm_flg != 1))
#endif
{
if(sleep_flag == 0)
{
if(bmsMem.soc<5)
{
LED1_Off();
LED2_Off();
LED3_Off();
LED4_Off();
}
else if(bmsMem.soc>=5 && bmsMem.soc<30)
{
LED1_On();
LED2_Off();
LED3_Off();
LED4_Off();
}
else if(bmsMem.soc>=30 && bmsMem.soc<60)
{
LED1_On();
LED2_On();
LED3_Off();
LED4_Off();
}
else if(bmsMem.soc>=60 && bmsMem.soc<90)
{
LED1_On();
LED2_On();
LED3_On();
LED4_Off();
}
else
{
LED1_On();
LED2_On();
LED3_On();
LED4_On();
}
}
else //休眠模式下灯全灭
{
LED1_Off();
LED2_Off();
LED3_Off();
LED4_Off();
}
}
}
#define CALI_SOC_CNT 12000 //2*60*100个10ms=2分钟
void Cali_SOC_Moni(void)
{
if(Cali_Soc_Flag == 1)
{
CaliSocMoniCount--;
if(CaliSocMoniCount == 0)
{
CaliSocMoniCount = CALI_SOC_CNT;
if(bmsMem.soc>15)
{
bmsMem.soc = 15;
bmsMem.rcc = fcc/100 * bmsMem.soc;
}
}
}
else
{
CaliSocMoniCount = CALI_SOC_CNT;
}
}
//校准满充容量的执行过程
//若刚开始充电时,SOC=0/1%,则允许校准满充容量,同步计时12h超过则不再校准
//若12h内,满足了满充判定的任一条件而使SOC=100%,在基本停止充电(电流<2A)后执行容量校准:赋值[满充容量]=此时的剩余容量并保存。
//若12h外,满足了满充判定的任一条件而使SOC=100%,不会变动满充容量。
//剩余容量可以一直增长,若超过了原来的满充容量,SOC保持100%不再增长。
void Cali_FCC_Moni(void)
{
//没有在计时
if(fcc_CaliStartFlag == 0)
{
if((bmsMem.packCurrent >= 2000) && (bmsMem.soc <= 1)) //充电(大于2A)时,若此时SOC处于低点,进行校准总容量的倒计时
{
fcc_CaliStartFlag = 1;
//更新起始点,如果晶振正常就把标志和起始点都写入EEPROM
if(LSEErrFlag!=1)
{
uint8_t time[4];
fcc_Calitimecount=RTC_GetCounter();
//写入起始时间
time[0] = fcc_Calitimecount>>24 & 0xff;
time[1] = fcc_Calitimecount>>16 & 0xff;
time[2] = fcc_Calitimecount>>8 & 0xff;
time[3] = fcc_Calitimecount>>0 & 0xff;
EEPROM_WrMulByte(EE_FCC_TIME,time);
delay_ms(5);
}
else
{
fcc_Cali_Moni_Count = FCCCALI_MON_CNT;
}
}
}
//此前已经启动计时
else
{
if((bmsMem.packCurrent < 2000) && (fcc_fullFlag == 1)) //不在充电时,若已满足满充条件,说明此时的剩余容量是当前的满充容量值
{
//赋值满充容量=剩余容量
fcc = bmsMem.rcc;
fcc_Ah = bmsMem.rcc / 3600000;
tmpWrFCC[0] = (fcc>>24) & 0xff;
tmpWrFCC[1] = (fcc>>16) & 0xff;
tmpWrFCC[2] = (fcc>> 8) & 0xff;
tmpWrFCC[3] = (fcc>> 0) & 0xff;
tmpWrFCC[4] = tmpWrFCC[0] ^ 0xff;
tmpWrFCC[5] = tmpWrFCC[1] ^ 0xff;
tmpWrFCC[6] = tmpWrFCC[2] ^ 0xff;
tmpWrFCC[7] = tmpWrFCC[3] ^ 0xff;
EEPROM_WrMulByte(EE_FCC,tmpWrFCC);
delay_ms(20);
fcc_CaliStartFlag = 0; //清零
if(LSEErrFlag == 0)
{
EEPROM_WrMulByte(EE_FCC_TIME,ClearEE);
delay_ms(5);
}
}
}
}
+3646
View File
File diff suppressed because it is too large Load Diff
+120
View File
@@ -0,0 +1,120 @@
/**
******************************************************************************
* @file LBS_Transmit.c
* @author
* @version
* @date
* @brief
******************************************************************************
* @attention
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "global.h"
#include <math.h>
#include <stdint.h>
// PI定义
#define M_PI 3.1415926535897932384626433832795
// 常量定义
#define EARTH_RADIUS 6378245.0 // 地球长半径
#define EE 0.00669342162296594323 // 偏心率平方
/**
* @brief 检查坐标是否在中国大陆以外
* @return 1:境外, 0:境内
*/
static int is_out_of_china(double lon, double lat)
{
if (lon < 72.004 || lon > 137.8347)
{
return 1;
}
if (lat < 0.8293 || lat > 55.8271)
{
return 1;
}
return 0;
}
/**
* @brief 纬度转换辅助函数
*/
static double transform_lat(double x, double y)
{
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x));
ret += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
ret += (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0;
ret += (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0;
return ret;
}
/**
* @brief 经度转换辅助函数
*/
static double transform_lon(double x, double y)
{
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x));
ret += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
ret += (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0;
ret += (150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0;
return ret;
}
/**
* @brief GCJ-02转WGS84坐标系
* @param gcj_lon GCJ-02经度
* @param gcj_lat GCJ-02纬度
* @param wgs_lon WGS84经度输出指针
* @param wgs_lat WGS84纬度输出指针
* @note 迭代7次,精度约0.1-0.5米
*/
void gcj02_to_wgs84(double gcj_lon, double gcj_lat, double *wgs_lon, double *wgs_lat)
{
//如果坐标不在中国大陆,直接返回原坐标
if(is_out_of_china(gcj_lon, gcj_lat))
{
*wgs_lon = gcj_lon;
*wgs_lat = gcj_lat;
return;
}
//使用迭代法进行转换(7次迭代足够精确)
double d_lon = 0.0, d_lat = 0.0;
double tmp_lon = gcj_lon, tmp_lat = gcj_lat;
for(int i = 0; i < 7; i++)
{
//计算当前WGS84坐标转GCJ02的偏移
double delta_lat = transform_lat(tmp_lon - 105.0, tmp_lat - 35.0);
double delta_lon = transform_lon(tmp_lon - 105.0, tmp_lat - 35.0);
double rad_lat = tmp_lat * M_PI / 180.0;
double magic = sin(rad_lat);
magic = 1 - EE * magic * magic;
double sqrt_magic = sqrt(magic);
delta_lat = (delta_lat * 180.0) / ((EARTH_RADIUS * (1 - EE)) / (magic * sqrt_magic) * M_PI);
delta_lon = (delta_lon * 180.0) / (EARTH_RADIUS / sqrt_magic * cos(rad_lat) * M_PI);
// 计算与目标GCJ02坐标的差值
d_lat = gcj_lat - (tmp_lat + delta_lat);
d_lon = gcj_lon - (tmp_lon + delta_lon);
// 更新WGS84坐标估计
tmp_lat += d_lat;
tmp_lon += d_lon;
}
*wgs_lon = tmp_lon;
*wgs_lat = tmp_lat;
}
+1407
View File
File diff suppressed because it is too large Load Diff
+172
View File
@@ -0,0 +1,172 @@
/**
******************************************************************************
* @file tim.c
* @author Jerry
* @version V2.1
* @date 19-April-2022
* @brief tim program body.
******************************************************************************
* @attention
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "global.h"
#define SHORT_CIRCUIT_THRESHOLD 70
#define OPEN_CIRCUIT_THRESHOLD 33000
uint8_t ucTempeMiddle;
/*温度电阻对照表*/
//4根温度线——深圳诺睿斯:MF52D103F3950FCL500XH
//单位10欧
//-55 - +125
uint16_t const NTC_103AT[181]=
{
58354, 55464, 52696, 50048, 47515,
45097, 42789, 40589, 38492, 36496, 34597, 32791, 31075, 29444, 27896,
26427, 25034, 23713, 22460, 21273, 20148, 19083, 18075, 17120, 16216,
15361, 14551, 13785, 13061, 12376, 11728, 11114, 10535, 9986, 9468,
8977, 8513, 8075, 7660, 7267, 6896, 6545, 6212, 5898, 5601,
5319, 5053, 4801, 4562, 4336, 4122, 3920, 3728, 3546, 3374,
3211, 3057, 2910, 2771, 2639, 2515, 2396, 2284, 2177, 2076,
1978, 1889, 1802, 1720, 1642, 1568, 1497, 1430, 1366, 1306,
1248, 1193, 1141, 1092, 1044, 1000, 957, 916, 877, 840,
805, 771, 739, 709, 679, 652, 625, 600, 576, 552,
530, 509, 489, 470, 452, 434, 417, 401, 386, 371,
358, 344, 331, 318, 306, 295, 284, 274, 264, 254,
245, 236, 228, 220, 212, 205, 198, 191, 184, 178,
172, 166, 160, 155, 150, 145, 140, 135, 131, 126,
122, 118, 115, 111, 107, 104, 101, 97, 94, 91,
89, 86, 83, 81, 78, 76, 74, 71, 69, 67,
65, 63, 61, 60, 58, 56, 55, 53, 52, 50,
49, 47, 46, 45, 43, 42, 41, 40, 39, 38,
37, 36, 35, 34, 33, 32
};
//板贴热敏电阻——南京时恒:CMFA 103F3950
//单位10欧
//-40 - +125
uint16_t const NTC_103AT_CMFA[166]=
{
34527, 32279, 30192, 28254, 26454, 24781, 23225, 21777, 20429, 19173,
18003, 16912, 15894, 14944, 14057, 13228, 12452, 11726, 11048, 10413,
9818, 9261, 8740, 8251, 7792, 7362, 6958, 6579, 6223, 5889,
5574, 5278, 5000, 4738, 4491, 4259, 4040, 3833, 3638, 3454,
3281, 3117, 2963, 2817, 2680, 2549, 2426, 2309, 2199, 2094,
1995, 1902, 1813, 1729, 1649, 1574, 1502, 1434, 1369, 1308,
1250, 1195, 1142, 1092, 1045, 1000, 957, 916, 877, 840,
804, 771, 739, 708, 679, 652, 625, 600, 576, 553,
531, 510, 490, 471, 452, 435, 418, 402, 387, 372,
358, 345, 332, 320, 308, 297, 286, 276, 266, 256,
247, 238, 230, 222, 214, 207, 200, 193, 186, 180,
174, 168, 162, 157, 152, 147, 142, 137, 133, 129,
124, 120, 117, 113, 109, 106, 103, 100, 96, 94,
91, 88, 85, 83, 80, 78, 76, 73, 71, 69,
67, 65, 63, 61, 60, 58, 56, 55, 53, 52,
50, 49, 48, 46, 45, 44, 43, 42, 41, 40,
39, 38, 37, 36, 35, 34
};
//根据NTC阻值计算温度值:-55~125
//返回的温度值需要-2731
uint16_t TEMP_Cal(uint16_t ntcR)
{
uint8_t i;
uint16_t tempcalcu, temperature;
tempcalcu = ntcR ;
if(tempcalcu >= NTC_103AT[0])
{
temperature = 2731-550; //温度值小于-55度时 =-55度
}
else if(tempcalcu <= NTC_103AT[180])
{
temperature = 2731+1250; //温度值大于125度时 =125度
}
else
{
i = ucTempeMiddle;
if(tempcalcu > NTC_103AT[i])
{
for(i=ucTempeMiddle - 1; i>0; i--)
{
if(tempcalcu <= NTC_103AT[i]) //NTC103AT[i+1]<resis<NTC103AT[i]
{
break;
}
}
}
else
{
for(i=ucTempeMiddle+1; i<180; i++)
{
if(tempcalcu > NTC_103AT[i]) //NTC103AT[i-1]<resis<NTC103AT[i]
{
break;
}
}
i--;
}
ucTempeMiddle = i;
temperature = (uint16_t)(ucTempeMiddle-55)*10 + (NTC_103AT[i]-tempcalcu)*10 / (NTC_103AT[i]-NTC_103AT[i+1])+2731;
}
return temperature;
}
//根据NTC_CMFA阻值计算温度值-40~125
//返回的温度值需要-2731
uint16_t TEMP_Cal_CMFA(uint16_t ntcR)
{
uint8_t i;
uint16_t tempcalcu, temperature;
tempcalcu = ntcR ;
if(tempcalcu >= NTC_103AT_CMFA[0])
{
temperature = 2731-400; //温度值小于-40度时 =-40度
}
else if(tempcalcu <= NTC_103AT_CMFA[165])
{
temperature = 2731+1250; //温度值大于125度时 =125度
}
else
{
i = ucTempeMiddle;
if(tempcalcu > NTC_103AT_CMFA[i])
{
for(i=ucTempeMiddle - 1; i>0; i--)
{
if(tempcalcu <= NTC_103AT_CMFA[i]) //NTC103AT[i+1]<resis<NTC103AT[i]
{
break;
}
}
}
else
{
for(i=ucTempeMiddle+1; i<165; i++)
{
if(tempcalcu > NTC_103AT_CMFA[i]) //NTC103AT[i-1]<resis<NTC103AT[i]
{
break;
}
}
i--;
}
ucTempeMiddle = i;
temperature = (uint16_t)(ucTempeMiddle-40)*10 + (NTC_103AT_CMFA[i]-tempcalcu)*10 / (NTC_103AT_CMFA[i]-NTC_103AT_CMFA[i+1])+2731;
}
return temperature;
}
+273
View File
@@ -0,0 +1,273 @@
/**
******************************************************************************
* @file OCV.c
* @author
* @version
* @date
* @brief
******************************************************************************
* @attention
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "global.h"
uint8_t OCV_soc; //通过OCV曲线获得的soc值
uint8_t OCV_status; //定时校准的当前状态,0:刚开机要获取存储时间 1:符合条件正在计时 2:不在静置 3:不允许OCV校准
uint8_t OCV_Wait_flag; //允许OCV校准走倒计时的标志
uint8_t OCV_CaliSOC_flag; //允许执行OCV校准获取当前电压对应soc的标志
uint16_t OCV_WrTime_count; //在非待机状态下,每过30min记录一次,防止关机时未回到待机状态导致不可用
OCV_Data ocv_data[15]; //OCV曲线数组
uint16_t ocv_Media_dp[15]; //根据写入数据获得中间值
//根据paraMem值,填充ocv_data[]和ocv_Media_dp[]
void OCV_CaliSOC_DataWr(void)
{
uint8_t i;
//填充SOC,共15个点
ocv_data[0].soc = 0;
ocv_data[1].soc = 5;
ocv_data[2].soc = 10;
ocv_data[3].soc = 15;
ocv_data[4].soc = 20;
ocv_data[5].soc = 30;
ocv_data[6].soc = 40;
ocv_data[7].soc = 50;
ocv_data[8].soc = 60;
ocv_data[9].soc = 70;
ocv_data[10].soc = 80;
ocv_data[11].soc = 85;
ocv_data[12].soc = 90;
ocv_data[13].soc = 95;
ocv_data[14].soc = 100;
//填充电压,共15个点
for(i=0;i<15;i++)
{
//ocv_data[i].ocv_cp = paraMem.ocv_cpBuf[i] * bmsMem.ucCellNum;
ocv_data[i].ocv_dp = paraMem.ocv_dpBuf[i] * bmsMem.ucCellNum;
}
//赋值中间量,共14个点
for(i=0;i<=13;i++)
{
ocv_Media_dp[i] = (ocv_data[i].ocv_dp + ocv_data[i+1].ocv_dp) / 2;
}
//50%-90%之间不考虑
ocv_Media_dp[7] = ocv_data[7].ocv_dp; //低于50%对应基准值,校准50%
ocv_Media_dp[11] = ocv_data[12].ocv_dp; //高于90%对应基准值,校准90%
}
//计算OCV表格的dp里,当前总电压对应的SOC
uint8_t OCV_CaliSoc_dp(void)
{
uint16_t caliSoc = 0;
//对总电压求出对应SOC
if(bmsMem.packVoltage >= ocv_Media_dp[13]) //超过最大值认为是满电
{
caliSoc = 100;
}
else if((bmsMem.packVoltage < ocv_Media_dp[13]) && (bmsMem.packVoltage >= ocv_Media_dp[12]))
{
caliSoc = 95;
}
else if((bmsMem.packVoltage < ocv_Media_dp[12]) && (bmsMem.packVoltage >= ocv_Media_dp[11]))
{
caliSoc = 90;
}
else if((bmsMem.packVoltage < ocv_Media_dp[11]) && (bmsMem.packVoltage > ocv_Media_dp[7]))
{
//当电压在>50%、<90%的电压值内时,若实时SOC不在范围内,则校准到50%/90%,否则不校准
if(bmsMem.soc > 90)
{
caliSoc = 90;
}
else if(bmsMem.soc < 50)
{
caliSoc = 50;
}
else
{
caliSoc = bmsMem.soc; //等于当前值,使不会校准
}
}
else if((bmsMem.packVoltage < ocv_Media_dp[7]) && (bmsMem.packVoltage >= ocv_Media_dp[6]))
{
caliSoc = 50;
}
else if((bmsMem.packVoltage < ocv_Media_dp[6]) && (bmsMem.packVoltage >= ocv_Media_dp[5]))
{
caliSoc = 40;
}
else if((bmsMem.packVoltage < ocv_Media_dp[5]) && (bmsMem.packVoltage >= ocv_Media_dp[4]))
{
caliSoc = 30;
}
else if((bmsMem.packVoltage < ocv_Media_dp[4]) && (bmsMem.packVoltage >= ocv_Media_dp[3]))
{
caliSoc = 20;
}
else if((bmsMem.packVoltage < ocv_Media_dp[3]) && (bmsMem.packVoltage >= ocv_Media_dp[2]))
{
caliSoc = 15;
}
else if((bmsMem.packVoltage < ocv_Media_dp[2]) && (bmsMem.packVoltage >= ocv_Media_dp[1]))
{
caliSoc = 10;
}
else if((bmsMem.packVoltage < ocv_Media_dp[1]) && (bmsMem.packVoltage >= ocv_Media_dp[0]))
{
caliSoc = 5;
}
else if(bmsMem.packVoltage <= ocv_Media_dp[0]) //小于最小值认为是空电
{
caliSoc = 0;
}
return caliSoc;
}
//在RTC有效+允许执行校准倒计时+满足静置时间时,获取开路电压法对应soc
//在电芯温度合适+原SOC不靠谱时,将该soc写入
//执行校准后,刷新计时起点,重新等待30min后再次执行校准
void OCV_CaliSOC(void)
{
uint8_t tempEE[4]; //用于保存计时起点
if((LSEErrFlag == 0) && ((paraMem.ocv_min_disable & 0x8000) == 0)) //RTC有效,且允许开路电压校准SOC
{
//静置状态,对应OCV_status为1
if((bmsMem.packCurrent > (-500)) && (bmsMem.packCurrent < 500))
{
//刚开机,读取存在EEPROM的时间
if(OCV_status == 0)
{
OCV_status = 1;
OCV_Wait_flag = 1; //允许在rtc函数中进行时间判断
EEPROM_RdMulByte(EE_TIME_OCV, tempEE);
ocvtimecount = tempEE[0]<<24 | tempEE[1]<<16 | tempEE[2]<<8 | tempEE[3];
if(ocvtimecount > timecount) //存的数据异常
{
//更新计时起点
ocvtimecount = RTC_GetCounter();
//保存到EEPROM
tempEE[0] = (ocvtimecount >> 24) & 0xff;
tempEE[1] = (ocvtimecount >> 16) & 0xff;
tempEE[2] = (ocvtimecount >> 8) & 0xff;
tempEE[3] = (ocvtimecount >> 0) & 0xff;
EEPROM_WrMulByte(EE_TIME_OCV, tempEE);
delay_ms(10);
}
}
//从其他状态回来/从不允许改为允许,更新当前时间为计时起点
else if(OCV_status != 1)
{
OCV_status = 1;
OCV_Wait_flag = 1; //允许在rtc函数中进行时间判断
//更新计时起点
ocvtimecount = RTC_GetCounter();
//保存到EEPROM
tempEE[0] = (ocvtimecount >> 24) & 0xff;
tempEE[1] = (ocvtimecount >> 16) & 0xff;
tempEE[2] = (ocvtimecount >> 8) & 0xff;
tempEE[3] = (ocvtimecount >> 0) & 0xff;
EEPROM_WrMulByte(EE_TIME_OCV, tempEE);
delay_ms(10);
}
//当倒计时结束,校准SOC并更新计时起点
if((OCV_Wait_flag == 1) && (OCV_CaliSOC_flag == 1))
{
//准备下一次计时
OCV_CaliSOC_flag = 0;
ocvtimecount = RTC_GetCounter();
//保存到EEPROM
tempEE[0] = (ocvtimecount >> 24) & 0xff;
tempEE[1] = (ocvtimecount >> 16) & 0xff;
tempEE[2] = (ocvtimecount >> 8) & 0xff;
tempEE[3] = (ocvtimecount >> 0) & 0xff;
EEPROM_WrMulByte(EE_TIME_OCV, tempEE);
delay_ms(10);
//更新OCV中值表
OCV_CaliSOC_DataWr();
//获取校准SOC
OCV_soc = OCV_CaliSoc_dp();
if((OCV_soc == 0) && ((bmsMem.packVoltage == 0) || (bmsMem.packVoltage > ocv_data[0].ocv_dp))) //电压异常改0% or 电压正常但计算得0% = 不执行
{
return;
}
else if(OCV_soc < bmsMem.soc-paraMem.ocv_soc_Range) //只减不增
{
//若温度和原值差距过大则不替换
if((TemperatureAverage > 250+2731-paraMem.ocv_T_Range*10) && (TemperatureAverage < 250+2731+paraMem.ocv_T_Range*10))
{
bmsMem.soc = OCV_soc;
bmsMem.rcc = fcc/100 * bmsMem.soc;
rcc_Ah = fcc_Ah * bmsMem.soc /100;
oldrcc_Ah = rcc_Ah;
}
}
}
OCV_WrTime_count = 0;
}
//不在静置状态,对应OCV_status为2
else
{
OCV_status = 2;
//清除标志位
OCV_Wait_flag = 0;
OCV_CaliSOC_flag = 0;
//非静置状态,每隔30min记录一次计时起点,防止突然断电,导致倒计时偏差过大
//此值在带电流重启后立刻静置的条件下启用
OCV_WrTime_count++;
if(OCV_WrTime_count > 60*30) //等30min
{
OCV_WrTime_count = 0;
ocvtimecount = RTC_GetCounter();
//保存到EEPROM
tempEE[0] = (ocvtimecount >> 24) & 0xff;
tempEE[1] = (ocvtimecount >> 16) & 0xff;
tempEE[2] = (ocvtimecount >> 8) & 0xff;
tempEE[3] = (ocvtimecount >> 0) & 0xff;
EEPROM_WrMulByte(EE_TIME_OCV, tempEE);
delay_ms(10);
}
}
}
//关闭开路电压法,对应OCV_status为3
else
{
OCV_status = 3;
//清除倒计时和标志位
ocvtimecount = 0;
OCV_Wait_flag = 0;
OCV_CaliSOC_flag = 0;
}
}
+698
View File
@@ -0,0 +1,698 @@
/**
******************************************************************************
* @file OTA.c
* @author
* @version
* @date
* @brief
******************************************************************************
* @attention
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "global.h"
#include "string.h"
#include <stdio.h>
#if LTE_Conn
//【OTA数据范围】
#define DATA_BUF_LEN 256 //每包长度
#define PAGE_LEN 120*(1024/DATA_BUF_LEN) //序号范围
#define SIZE_LEN 120*1024 //总字节长度限制 120K以内
//【Flash存储】
#define INFO_LEN 12 //存储信息限制,信息总长包括反向存储
#define DATA_LEN 2048 //存储数据限制,每扇2K=256Byte*8
#define USER_FW_INFO 0X08020000 //新程序信息地址
#define USER_FW_MIDD 0X08021800 //新程序数据地址
//【云平台通信】
uint8_t LTE_OTA_Flag; //4G升级标志 1:收到升级相关报文
uint8_t LTE_OTA_fineFlag; //4G升级完成上报标志(上线后先上报升级完成) 0xAA:升级成功 0xBB:维持原程序
uint8_t ota_code; //回复标志 0:成功 1:内容有缺 6:升级失败仍运行原程序
uint16_t OTA_ErrCnt; //OTA过程的错误计数
//【流程】
//0xA8.回复OTA升级信息帧
//0xA9.回复OTA升级数据帧
//0xAA.转存完成,设备上线后主动上报OTA升级完成
#define ota_check_sub 0xA7
#define ota_info_pub 0xA8
#define ota_data_pub 0xA9
//【步骤】
//0xA8_201~205[回复OTA升级信息帧] 201:主题长度 202:主题内容 203:属性长度 204:属性内容 205:确认上传
//0xA9_206~210[回复OTA升级数据帧] 206:主题长度 207:主题内容 208:属性长度 209:属性内容 210:确认上传
//0xAA_211~215[主动上报OTA升级成功] 211:主题长度 212:主题内容 213:属性长度 214:属性内容 215:确认上传
#define ota_check_sub_step1 201
#define ota_check_sub_step2 202
#define ota_check_sub_step3 203
#define ota_info_pub_step1 211
#define ota_info_pub_step2 212
#define ota_info_pub_step3 213
#define ota_info_pub_step4 214
#define ota_info_pub_step5 215
#define ota_data_pub_step1 216
#define ota_data_pub_step2 217
#define ota_data_pub_step3 218
#define ota_data_pub_step4 219
#define ota_data_pub_step5 220
uint32_t firmware_size; //总包的大小
uint16_t firmware_crc; //总包的CRC校验码
uint16_t rev_page; //OTA升级一共多少分包
uint16_t rev_index; //当前包序号 0~rev_page-1,用于计算存入的地址
uint16_t rev_crc; //当前包数据的CRC校验码
uint16_t ota_data_crc; //数据帧的CRC校验码
uint8_t ota_wr_info[INFO_LEN]; //存放信息让底层能判断读出
uint8_t ota_wr_data[DATA_LEN]; //保存2K数据后再下载
uint8_t OTAfine_WrFlg; //更新OTA升级成功/失败标志的标志 0xAA:更新到0 0xBB:更新到0xBB
uint8_t otaSub_reply_count;
uint8_t otaInfo_reply_count;
uint8_t otaData_reply_count;
uint8_t ota_rx_Buf[2048];
//下发[OTA升级信息]报文的处理
void LTE_OTA_Info(void)
{
//进入升级模式
LTE_OTA_Flag = 1;
//准备订阅主题和发送回复
LTE_status = ota_check_sub;
LTE_step = ota_check_sub_step1;
//收到并存储信息
//{"page":100,"size":65535,"method":"crc16"}
if(strstr(LTE_Rx_Buf, "\"page\"") && strstr(LTE_Rx_Buf, "\"size\"") && strstr(LTE_Rx_Buf, "\"check\""))
{
char str[6]; //字符串 0~102400
uint8_t len = 0; //字符串长度
uint32_t temp; //过程量
uint8_t tmpWr[12];
ota_code = 0;
//Bin文件最大120KB,对应Page最大PAGE_LEN
len = GetStr("\"page\":", ',', ',', LTE_Rx_Buf, str);
sscanf(str, "%u", &temp);
if((temp > 0) && (temp <= PAGE_LEN) && (len > 0))
{
rev_page = temp;
}
else
{
ota_code = 2; //内容超出范围
return;
}
//Bin文件最大120KB,对应size最大120*1024
len = GetStr("\"size\":", ',', ',', LTE_Rx_Buf, str);
sscanf(str, "%u", &temp);
if((temp > 0) && (temp <= SIZE_LEN) && (len > 0))
{
firmware_size = temp;
}
else
{
ota_code = 2; //内容超出范围
return;
}
//整体CRC码
len = GetStr("\"check\":\"", '\"', '\"', LTE_Rx_Buf, str);
if(len == 4)
{
sscanf(str, "%4hx", &firmware_crc);
}
else
{
ota_code = 2; //内容超出范围
return;
}
//序号清零,等待升级
rev_index = 0;
//赋值
tmpWr[0] = (firmware_size>> 0) & 0xFF;
tmpWr[1] = (firmware_size>> 8) & 0xFF;
tmpWr[2] = (firmware_size>>16) & 0xFF;
tmpWr[3] = (firmware_size>>24) & 0xFF;
tmpWr[4] = (firmware_crc >> 0) & 0xFF;
tmpWr[5] = (firmware_crc >> 8) & 0xFF;
tmpWr[6] = tmpWr[0] ^ 0xff;
tmpWr[7] = tmpWr[1] ^ 0xff;
tmpWr[8] = tmpWr[2] ^ 0xff;
tmpWr[9] = tmpWr[3] ^ 0xff;
tmpWr[10] = tmpWr[4] ^ 0xff;
tmpWr[11] = tmpWr[5] ^ 0xff;
//把OTA信息存储
FLASH_WrData(USER_FW_INFO, (uint16_t *)&tmpWr[0], INFO_LEN/2); //12/2=6
}
else
{
ota_code = 1; //内容有缺
}
}
//下发[OTA升级数据]报文的处理
void LTE_OTA_Data(void)
{
LTE_status = ota_data_pub;
LTE_step = ota_data_pub_step1;
//收到并存储数据
//{"index":0,"sign":"Hex","data":"HEX..."}
if(strstr(LTE_Rx_Buf, "\"index\"") && strstr(LTE_Rx_Buf, "\"data\"") && strstr(LTE_Rx_Buf, "\"check\""))
{
char str[6] = {0}; //字符串 0~102400
uint16_t len = 0; //字符串长度
uint32_t temp = 0; //过程量
char data_str[DATA_BUF_LEN*2+4]; //字符串
uint16_t dataLen = 0; //数据长度需要单独拿出参与最后一包的判断
uint8_t dataIdx; //当前包对应2K数组中的位置 0~7
ota_code = 0;
//Bin文件最大120KB,对应index最大PAGE_LEN
len = GetStr("\"index\":", ',', ',', LTE_Rx_Buf, str);
sscanf(str, "%u", &temp);
if(len > 0)
{
if(temp == 0)
{
rev_index = temp;
}
else if((temp > 0) && (temp <= PAGE_LEN))
{
if(temp == rev_index+1)
{
rev_index = temp;
}
else
{
ota_code = 3; //内容不连续
return;
}
}
else
{
ota_code = 2; //内容超出范围
return;
}
}
else
{
ota_code = 1; //内容有缺
}
//该包的CRC码
len = GetStr("\"check\":\"", '\"', '\"', LTE_Rx_Buf, str);
if(len == 4)
{
sscanf(str, "%4hx", &rev_crc);
}
else if(len > 0)
{
if(rev_index != 0) rev_index--; //该包接收错误,应回退等待下一次发当前包
ota_code = 2; //内容超出范围
return;
}
else
{
ota_code = 1; //内容有缺
}
//该包的数据字符串放入str数组
char* dataStart = strstr(LTE_Rx_Buf, "\"data\":\""); dataStart += strlen("\"data\":\"");
char* dataEnd = strchr(dataStart, '\"');
dataLen = dataEnd - dataStart;
strncpy(data_str, dataStart, dataLen);
data_str[dataLen] = '\0';
dataIdx = rev_index%8; //2K数组中的位置0~7 (dataIdx=7)或(rev_index == rev_page-1)时执行写入Flash
if((rev_index < rev_page-1) && (dataLen == DATA_BUF_LEN*2)) //正常包
{
uint16_t i;
//转换到ota_wr_data数组
for(i=0;i<dataLen/2;i++)
{
//每2个字符转换成1个字节
sscanf(&data_str[i*2], "%2hhx", &ota_wr_data[i+dataIdx*256]); //8*256=2048
}
}
else if((rev_index == rev_page-1) && (dataLen > 0)) //最后一包
{
uint16_t i;
//清空ota_wr_data的该包对应位置及以后的位置
for(i=dataIdx;i<8;i++)
{
memset(&ota_wr_data[i*256], 0, DATA_BUF_LEN);
}
//将最后一包也转换到ota_wr_data数组
for(i=0;i<dataLen/2;i++)
{
//每2个字符转换成1个字节
sscanf(&data_str[i*2], "%2hhx", &ota_wr_data[i+dataIdx*256]); //8*256=2048
}
}
else if(dataLen > 0)
{
if(rev_index != 0) rev_index--; //该包接收错误,应回退等待下一次发当前包
ota_code = 2; //内容超出范围
return;
}
else
{
ota_code = 1; //内容有缺
}
//数据格式都正确,进行校验和写入
//CRC校验码
ota_data_crc = CRC16_FirmtoEE(&ota_wr_data[dataIdx*256], dataLen/2);
if(rev_crc == ota_data_crc)
{
if(rev_index == 0) //对第1包进行合法范围判断
{
if((ota_wr_data[6] > 0x01) || (ota_wr_data[7] != 0x08)) //Flash 128KB 0x08000000~0x0801FFFF
{
if(rev_index != 0) rev_index--; //该包接收错误,应回退等待下一次发当前包
ota_code = 5; //内容不是正规升级文件
return;
}
}
//执行写入Flash
else if((dataIdx == 7) || (rev_index == rev_page-1))
{
FLASH_WrData(rev_index/8 * DATA_LEN + USER_FW_MIDD, (uint16_t *)&ota_wr_data[0], DATA_LEN/2); //2048/2=1024
delay_ms(2);
}
}
else
{
if(rev_index != 0) rev_index--; //该包接收错误,应回退等待下一次发当前包
ota_code = 4; //CRC校验错误
return;
}
}
else
{
ota_code = 1; //内容有缺
}
}
//处理数据,接收报文识别后执行
void LTE_OTA_IT_Update(void)
{
if(LTE_status != 0) //收到后,执行回复,才判断OK,>,ERROR
{
/*收到OK或>或ERROR,认为回复完整,开始分析*/
if((LTE_Rx_BufIndex >= 2) && (strstr(LTE_Rx_Buf, "OK")))
{
//0xA7.检查订阅主题
if(LTE_status == ota_check_sub)
{
//1.检查订阅
if(strstr(LTE_Rx_Buf, "AT+CMQTTSUB?") && (LTE_step == ota_check_sub_step1))
{
if(strstr(LTE_Rx_Buf, "/ota/device/firmware/101") == 0) //缺少了OTA数据帧的主题
{
LTE_status = ota_check_sub;
LTE_step = ota_check_sub_step2; //无订阅,跳转:订阅OTA数据帧的主题
}
else
{
LTE_status = ota_info_pub;
LTE_step = ota_info_pub_step1; //有订阅,跳转:发送回复
}
}
//3.订阅OTA数据帧的主题
else if(LTE_step == ota_check_sub_step3)
{
otaSub_reply_count = 0;
LTE_status = ota_info_pub;
LTE_step = ota_info_pub_step1; //订阅成功,进行信息帧的回复
}
}
//0xA8.回复OTA升级信息帧
if(LTE_status == ota_info_pub)
{
//2.
if(LTE_step == ota_info_pub_step2)
{
LTE_status = ota_info_pub;
LTE_step = ota_info_pub_step3; //主题接收OK,准备下一步
}
//4.
else if(LTE_step == ota_info_pub_step4)
{
LTE_status = ota_info_pub;
LTE_step = ota_info_pub_step5; //内容接收OK,准备下一步
}
//5.
else if(strstr(LTE_Rx_Buf, "AT+CMQTTPUB") && (LTE_step == ota_info_pub_step5))
{
otaInfo_reply_count = 0;
if(ota_code == 0)
{
//等待数据内容,期间不主动发数据
LTE_status = 0;
LTE_step = 0;
return;
}
else
{
//退出升级流程,正常上报
LTE_OTA_Flag = 0;
LTE_status = ask_lbs;
LTE_step = ask_lbs_step1; //跳转:正常流程第一步
}
}
}
//0xA9.回复OTA升级数据帧
else if(LTE_status == ota_data_pub)
{
//2.
if(LTE_step == ota_data_pub_step2)
{
LTE_status = ota_data_pub;
LTE_step = ota_data_pub_step3; //主题接收OK,准备下一步
}
//4.
else if(LTE_step == ota_data_pub_step4)
{
LTE_status = ota_data_pub;
LTE_step = ota_data_pub_step5; //内容接收OK,准备下一步
}
//5.
else if(strstr(LTE_Rx_Buf, "AT+CMQTTPUB") && (LTE_step == ota_data_pub_step5))
{
otaData_reply_count = 0;
//未收到全部数据时
if(rev_index < rev_page-1)
{
//等待数据内容,期间不主动发数据
LTE_status = 0;
LTE_step = 0;
return;
}
else
{
//更新EE_OTA完成标志,先更新失败标志,若底层完成,会改为成功标志
LTE_OTA_fineFlag = 0xBB;
OTAfine_WrFlg = 0xBB;
}
}
}
}
else if((LTE_Rx_BufIndex >= 1) && (strstr(LTE_Rx_Buf, ">")))
{
//0xA7.检查订阅
if(LTE_status == ota_check_sub)
{
//1.订阅OTA数据帧的主题
if(strstr(LTE_Rx_Buf, "AT+CMQTTSUB=0,39,1") && (LTE_step == ota_check_sub_step2))
{
LTE_status = ota_check_sub;
LTE_step = ota_check_sub_step3; //准备下一步
}
}
//0xA8.回复OTA升级数据帧
else if(LTE_status == ota_info_pub)
{
//1.
if(strstr(LTE_Rx_Buf, "AT+CMQTTTOPIC") && (LTE_step == ota_info_pub_step1))
{
LTE_status = ota_info_pub;
LTE_step = ota_info_pub_step2; //准备下一步
}
//3.
else if(strstr(LTE_Rx_Buf, "AT+CMQTTPAYLOAD") && (LTE_step == ota_info_pub_step3))
{
LTE_status = ota_info_pub;
LTE_step = ota_info_pub_step4; //准备下一步
}
}
//0xA9.回复OTA升级信息帧
else if(LTE_status == ota_data_pub)
{
//1.
if(strstr(LTE_Rx_Buf, "AT+CMQTTTOPIC") && (LTE_step == ota_data_pub_step1))
{
LTE_status = ota_data_pub;
LTE_step = ota_data_pub_step2; //准备下一步
}
//3.
else if(strstr(LTE_Rx_Buf, "AT+CMQTTPAYLOAD") && (LTE_step == ota_data_pub_step3))
{
LTE_status = ota_data_pub;
LTE_step = ota_data_pub_step4; //准备下一步
}
}
}
else if((LTE_Rx_BufIndex >= 5) && (strstr(LTE_Rx_Buf, "ERROR")))
{
LTE_ResendDelay = ResendTime;
OTA_ErrCnt++;
if(OTA_ErrCnt > ERR_timeEnd2) //1min
{
OTA_ErrCnt = 0;
//退出升级流程,在正常流程中检查问题
LTE_OTA_Flag = 0;
CRESET_flag = 1; //重启
CRESET_step = 0;
}
}
}
}
//收到下发报文后,在主循环进行处理
void LTE_OTA_IQ_Update(void)
{
if((LTE_status == 0) && (LTE_step == 0)) //OTA升级,重点是接收下发报文
{
/*监控下发报文*/
if(strstr(LTE_Rx_Buf, "+CMQTTRXSTART") && strstr(LTE_Rx_Buf, "+CMQTTRXEND")) //有头有尾
{
//OTA信息帧
if(strstr(LTE_Rx_Buf, "/ota/device/upgrade/101"))
{
LTE_OTA_Info();
}
//OTA数据帧
else if(strstr(LTE_Rx_Buf, "/ota/device/firmware/101"))
{
LTE_OTA_Data();
if(ota_code != 0)
{
uint16_t i;
for(i=0;i<2048;i++)
{
ota_rx_Buf[i] = LTE_Rx_Buf[i];
}
}
}
}
}
//更新升级标志归0
if(OTAfine_WrFlg == 0xAA)
{
EEPROM_WrMulByte(EE_OTA_FINE,&LTE_OTA_fineFlag);
delay_ms(5);
OTAfine_WrFlg = 0;
}
//更新升级标志为0xBB,IAP标志为0xBB (不需要兼容旧IAP,不用考虑擦除跳转标志)
else if(OTAfine_WrFlg == 0xBB)
{
EEPROM_WrMulByte(EE_OTA_FINE,&LTE_OTA_fineFlag);
delay_ms(5);
OTAfine_WrFlg = 0;
IAP_Run = 0xBB; //表示存在下一版程序
EEPROM_WrMulByte(EE_IAP_NEW1,&IAP_Run);
delay_ms(10);
EEPROM_WrMulByte(EE_IAP_NEW2,&IAP_Run);
delay_ms(10);
//执行软件重启
NVIC_SystemReset();
}
}
//该函数用于发送报文
void LTE_OTA_IQ_Transmit(void)
{
if(LTE_status != 0)
{
if((LTE_Rx_BufIndex == 0) && (LTE_WaitRxFlg == 1)) //有发送指令却没有回复 //只执行1次
{
LTE_WaitRxFlg = 0;
LTE_WaitRxDelay = WaitRxTime;
return;
}
LTE_Rx_BufIndex = 0;
memset(LTE_Rx_Buf, 0, LTE_RX_BUF_LEN); //填入前先清空
memset(LTE_Tx_Buf, 0, LTE_TX_BUF_LEN);
}
//定期查询订阅并重新订阅主题
if(LTE_status == ota_check_sub)
{
otaSub_reply_count++;
//尝试1次重新回复
if(otaSub_reply_count == 10)
{
LTE_step = ota_check_sub_step1;
}
//仍然失败退出回复
else if(otaSub_reply_count >= 20)
{
LTE_OTA_Flag = 0;
LTE_status = ask_lbs;
LTE_step = ask_lbs_step1; //回复OTA升级信息一直失败,跳转:正常流程第一步
otaSub_reply_count = 0;
}
switch(LTE_step) //ota_info_pub_step1~ota_info_pub_step5
{
case ota_check_sub_step1:
LTE_Send("AT+CMQTTSUB?\r\n"); //查询订阅
break;
case ota_check_sub_step2:
LTE_Send("AT+CMQTTSUB=0,39,1\r\n"); //订阅主题长度 "/ota/device/firmware/101/030200001/post"=39Byte //订阅OTA升级数据
break;
case ota_check_sub_step3:
LTE_Send("/ota/device/firmware/101/%s/post", BMS_SN); //订阅的主题 (只有这个不用换新行)
break;
default:
break;
}
}
//0xA8.回复OTA升级信息帧
else if(LTE_status == ota_info_pub)
{
otaInfo_reply_count++;
//尝试1次重新回复
if(otaInfo_reply_count == 10)
{
LTE_step = ota_info_pub_step1;
}
//仍然失败退出回复
else if(otaInfo_reply_count >= 20)
{
LTE_OTA_Flag = 0;
LTE_status = ask_lbs;
LTE_step = ask_lbs_step1; //回复OTA升级信息一直失败,跳转:正常流程第一步
otaInfo_reply_count = 0;
}
switch(LTE_step) //ota_info_pub_step1~ota_info_pub_step5
{
case ota_info_pub_step1:
LTE_Send("AT+CMQTTTOPIC=0,39\r\n"); //上报主题长度 24+9+6=39Byte
break;
case ota_info_pub_step2:
LTE_Send("/ota/device/upgrade/101/%s/reply", BMS_SN); //上报的主题 (只有这个不用换新行)
break;
case ota_info_pub_step3:
LTE_Send("AT+CMQTTPAYLOAD=0,%hu\r\n", 11+uint_str_len(ota_code)); //上报内容长度 = 数据长度+固定字符长度+回车
break;
case ota_info_pub_step4:
LTE_Send("{\"code\":%hu}\r\n", ota_code);
break;
case ota_info_pub_step5:
LTE_Send("AT+CMQTTPUB=0,1,30\r\n"); //至少上报1次+30s内等待服务器回复
break;
default:
break;
}
}
//0xA9.回复OTA升级数据帧
else if(LTE_status == ota_data_pub)
{
otaData_reply_count++;
//尝试1次重新回复(数据帧比较特殊,如果后续序号不对就失败了,故增加次数)
if(otaData_reply_count == 20)
{
LTE_step = ota_data_pub_step1;
}
//仍然失败退出回复
else if(otaData_reply_count >= 30)
{
LTE_status = 0;
LTE_step = 0;
otaData_reply_count = 0;
}
switch(LTE_step) //ota_data_pub_step1~ota_data_pub_step5
{
case ota_data_pub_step1:
LTE_Send("AT+CMQTTTOPIC=0,40\r\n"); //上报主题长度 25+9+6=40Byte
break;
case ota_data_pub_step2:
LTE_Send("/ota/device/firmware/101/%s/reply", BMS_SN); //上报的主题 (只有这个不用换新行)
break;
case ota_data_pub_step3:
LTE_Send("AT+CMQTTPAYLOAD=0,%hu\r\n", 11+uint_str_len(ota_code)); //上报内容长度 = 数据长度+固定字符长度+回车
break;
case ota_data_pub_step4:
LTE_Send("{\"code\":%hu}\r\n", ota_code);
break;
case ota_data_pub_step5:
LTE_Send("AT+CMQTTPUB=0,1,30\r\n"); //至少上报1次+30s内等待服务器回复
break;
default:
break;
}
}
}
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+4109
View File
File diff suppressed because it is too large Load Diff
+253
View File
@@ -0,0 +1,253 @@
/**
******************************************************************************
* @file tim.c
* @author Jerry
* @version V2.1
* @date 19-April-2022
* @brief tim program body.
******************************************************************************
* @attention
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "global.h"
#include "string.h"
#include "rtc.h"
#include "soe.h"
_soe_obj soe;
uint8_t rdd[64];
/*******************************************************************************
Function:
Description: SOE事件时EEPROM
Input:
Output:
Others:
*******************************************************************************/
void SOE_BkData(uint8_t type)
{
uint8_t wrBuf[64];
uint8_t extBuf[6];
uint8_t adrh,adrl;
uint16_t ee_vol,ee_fcc,ee_rcc;
int16_t ee_cur;
uint8_t afe_mode;
uint16_t ext_addr;
uint8_t i;
uint16_t ee_cellVol[20]; //用于转换存储单芯电压
ee_vol = (uint16_t)(bmsMem.packVoltage/10); //电压保存 单位0.01V
ee_cur = (int16_t) (bmsMem.packCurrent/100); //电流保存 单位0.1A
ee_fcc = (uint16_t)(fcc/3600/100); //满充容量 单位0.1Ah //5.16增加满充容量自适应逻辑后修改
ee_rcc = (uint16_t)(bmsMem.rcc/3600/100); //剩余容量 单位0.1Ah
/*记录序号,便于上位机排序和查看*/
wrBuf[0] = (soe.index >> 24) & 0xff ;
wrBuf[1] = (soe.index >> 16) & 0xff ;
wrBuf[2] = (soe.index >> 8) & 0xff ;
wrBuf[3] = (soe.index >> 0) & 0xff ;
/*记录时间*/
wrBuf[4] = calendar.w_year ;
wrBuf[5] = calendar.w_month ;
wrBuf[6] = calendar.w_date ;
wrBuf[7] = calendar.hour ;
wrBuf[8] = calendar.min ;
wrBuf[9] = calendar.sec ;
/*记录BMS参数*/
wrBuf[10] = bmsMem.bStatus1 & 0xff;
wrBuf[11] = bmsMem.bStatus2 & 0xff;
wrBuf[12] = bmsMem.bStatus3 & 0xff;
wrBuf[13] = bmsMem.temperaStatus & 0xff;
wrBuf[14] = bmsMem.balanceStatus & 0xff;
//wrBuf[15] = bmsMem.packStatus & 0xff;
wrBuf[15] = ((bmsMem.bStatus1>>4) & 0xf0) | ((bmsMem.temperaStatus>>8) & 0x0f); //占用原packStatus位置,保存新增保护
wrBuf[16] = (ee_vol >> 8) & 0xff;
wrBuf[17] = (ee_vol >> 0) & 0xff;
wrBuf[18] = (ee_cur >> 8) & 0xff;
wrBuf[19] = (ee_cur >> 0) & 0xff;
wrBuf[20] = (ee_fcc >> 8) & 0xff;
wrBuf[21] = (ee_fcc >> 0) & 0xff;
wrBuf[22] = (ee_rcc >> 8) & 0xff;
wrBuf[23] = (ee_rcc >> 0) & 0xff;
wrBuf[24] = (bmsMem.cycleCount >> 8) & 0xff;
wrBuf[25] = (bmsMem.cycleCount >> 0) & 0xff;
wrBuf[26] = bmsMem.soh & 0xff;
//afe_T1~T3
wrBuf[27] = (bmsMem.afe_T1>>8) & 0x0f;
wrBuf[28] = (bmsMem.afe_T1>>0) & 0xff;
wrBuf[29] = (bmsMem.afe_T2>>4) & 0xff;
wrBuf[30] = ((bmsMem.afe_T2<<4) & 0xf0) | ((bmsMem.afe_T3>>8) & 0x0f);
wrBuf[31] = (bmsMem.afe_T3>>0) & 0xff;
//mcu_T1~T4
wrBuf[32] = (bmsMem.mcu_T1>>4) & 0xff;
wrBuf[33] = ((bmsMem.mcu_T1<<4) & 0xf0) | ((bmsMem.mcu_T2>>8) & 0x0f);
wrBuf[34] = (bmsMem.mcu_T2>>0) & 0xff;
wrBuf[35] = (bmsMem.mcu_T3>>4) & 0xff;
wrBuf[36] = ((bmsMem.mcu_T3<<4) & 0xf0) | ((bmsMem.mcu_T4>>8) & 0x0f);
wrBuf[37] = (bmsMem.mcu_T4>>0) & 0xff;
afe_mode = (paraMem.sc_mode >> 8) & 0xFF;
for(i=0;i<20;i++)
{
if(i < 16)
{
if(bmsMem.vCell[i] > 5119)
{
ee_cellVol[i] = 0;
}
else if(bmsMem.vCell[i] > 4095)
{
ee_cellVol[i] = 4095;
}
else
{
ee_cellVol[i] = bmsMem.vCell[i];
}
}
else
{
if(afe_mode == 1)
{
if(bmsMem.vCell2[i-16] > 5119)
{
ee_cellVol[i] = 0;
}
else if(bmsMem.vCell2[i-16] > 4095)
{
ee_cellVol[i] = 4095;
}
else
{
ee_cellVol[i] = bmsMem.vCell2[i-16];
}
}
else
{
ee_cellVol[i] = 0;
}
}
}
wrBuf[38] = (ee_cellVol[0]>>4) & 0xff;
wrBuf[39] = ((ee_cellVol[0]<<4) & 0xf0) | ((ee_cellVol[1]>>8) & 0x0f);
wrBuf[40] = (ee_cellVol[1]>>0) & 0xff;
wrBuf[41] = (ee_cellVol[2]>>4) & 0xff;
wrBuf[42] = ((ee_cellVol[2]<<4) & 0xf0) | ((ee_cellVol[3]>>8) & 0x0f);
wrBuf[43] = (ee_cellVol[3]>>0) & 0xff;
wrBuf[44] = (ee_cellVol[4]>>4) & 0xff;
wrBuf[45] = ((ee_cellVol[4]<<4) & 0xf0) | ((ee_cellVol[5]>>8) & 0x0f);
wrBuf[46] = (ee_cellVol[5]>>0) & 0xff;
wrBuf[47] = (ee_cellVol[6]>>4) & 0xff;
wrBuf[48] = ((ee_cellVol[6]<<4) & 0xf0) | ((ee_cellVol[7]>>8) & 0x0f);
wrBuf[49] = (ee_cellVol[7]>>0) & 0xff;
wrBuf[50] = (ee_cellVol[8]>>4) & 0xff;
wrBuf[51] = ((ee_cellVol[8]<<4) & 0xf0) | ((ee_cellVol[9]>>8) & 0x0f);
wrBuf[52] = (ee_cellVol[9]>>0) & 0xff;
wrBuf[53] = (ee_cellVol[10]>>4) & 0xff;
wrBuf[54] = ((ee_cellVol[10]<<4) & 0xf0) | ((ee_cellVol[11]>>8) & 0x0f);
wrBuf[55] = (ee_cellVol[11]>>0) & 0xff;
wrBuf[56] = (ee_cellVol[12]>>4) & 0xff;
wrBuf[57] = ((ee_cellVol[12]<<4) & 0xf0) | ((ee_cellVol[13]>>8) & 0x0f);
wrBuf[58] = (ee_cellVol[13]>>0) & 0xff;
wrBuf[59] = (ee_cellVol[14]>>4) & 0xff;
wrBuf[60] = ((ee_cellVol[14]<<4) & 0xf0) | ((ee_cellVol[15]>>8) & 0x0f);
wrBuf[61] = (ee_cellVol[15]>>0) & 0xff;
wrBuf[62] = type;
if(afe_mode == 1) //SH36735XX, 20 cells
{
wrBuf[63] = 0xA6; //new format flag
//pack cell17~20 into extBuf[0~5]
extBuf[0] = (ee_cellVol[16]>>4) & 0xff;
extBuf[1] = ((ee_cellVol[16]<<4) & 0xf0) | ((ee_cellVol[17]>>8) & 0x0f);
extBuf[2] = (ee_cellVol[17]>>0) & 0xff;
extBuf[3] = (ee_cellVol[18]>>4) & 0xff;
extBuf[4] = ((ee_cellVol[18]<<4) & 0xf0) | ((ee_cellVol[19]>>8) & 0x0f);
extBuf[5] = (ee_cellVol[19]>>0) & 0xff;
}
else
{
wrBuf[63] = 0xA5; //old format flag
}
/*写入前检查是否合法*/
//当前地址=0或0XFFFF或不为64倍数,初始化地址和记录序号
if((soe.pc < 0x1000) || (soe.pc > 0x2940) || (soe.pc == 0xffff) || (soe.pc%64 !=0))
{
soe.pc = RECORD_START_ADDR;
soe.index = 0;
soe.num = 0;
}
/*记录写入EEPROM*/
adrh = (soe.pc>>8) & 0xff;
adrl = soe.pc & 0xff;
EEPROM_WrMulByte(EE_SOE,wrBuf);
delay_ms(10);
EEPROM_RdMulByte(EE_SOE,rdd);
//write extend cell17~20 for SH36735XX
if(afe_mode == 1)
{
ext_addr = 0x2900 + (soe.pc - 0x1000) * 6 / 64;
adrh = (ext_addr>>8) & 0xff;
adrl = ext_addr & 0xff;
EEPROM_WrMulByte(EE_SOE_EXT,extBuf);
delay_ms(10);
EEPROM_RdMulByte(EE_SOE_EXT,rdd);
}
/*清除记录写入标记*/
soe.bkType = 0;
/*暂定400条记录*/
soe.index+=1;
soe.pc +=0x40;
soe.num +=1;
// if(soe.pc == 0x7400) //0x1000-0x7400共400条
// if(soe.pc == 0x1C80) //0x1000-0x1C80共50条
if(soe.pc == 0x2900) //0x1000-0x2900共100条
{
soe.pc = RECORD_START_ADDR;
}
if(soe.num >= 100)
{
soe.num = 100;
}
wrBuf[0] = (soe.index >> 24) & 0xff ;
wrBuf[1] = (soe.index >> 16) & 0xff ;
wrBuf[2] = (soe.index >> 8) & 0xff ;
wrBuf[3] = (soe.index >> 0) & 0xff ;
wrBuf[4] = (soe.pc >>8)&0XFF ;
wrBuf[5] = soe.pc & 0xff ;
wrBuf[6] = (soe.num >>8)&0XFF ;
wrBuf[7] = soe.num & 0xff ;
EEPROM_WrMulByte(EE_SOE_INF,wrBuf);
delay_ms(10);
EEPROM_RdMulByte(EE_SOE_INF,rdd);
scr_RdRecord_Flg = 1;
//SCR_DispProcotol();
}
+3129
View File
File diff suppressed because it is too large Load Diff
+2647
View File
File diff suppressed because it is too large Load Diff
+1004
View File
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
#ifndef __SOE_H
#define __SOE_H
#include "stm32f10x.h"
#define BKTYPE_STARTUP 0X01 //开机
#define BKTYPE_TIME 0X02 //定时
#define BKTYPE_CHARGING 0X03 //充电
#define BKTYPE_DISCHARGING 0X04 //放电
#define BKTYPE_ALARM 0X05 //报警、急停
#define RECORD_START_ADDR 0X1000
//记录结构体
typedef struct
{
uint32_t index; //当前记录序号
uint16_t pc; //待写入地址
uint16_t num; //记录总数
// uint16_t timEn;
// uint16_t tim;
uint8_t bkType; //记录类型,目前只用于报警
uint8_t rsvd[3];
uint8_t bsNew[6]; //对应状态
uint8_t bsOld[6];
uint8_t bk[12];
}_soe_obj;
extern _soe_obj soe;
extern void SOE_BkData(uint8_t type);
#endif