一、核心代码执行流程
c
// 1. 执行当前状态的动作函数(句柄函数),返回下一个状态 emState = pSTBatt_Rough->singleBattData[n].pCurrState->pfnAction(pSTBatt_Rough, n);
// 2. 保存上一个状态
pSTBatt_Rough->singleBattData[n].pLastState = pSTBatt_Rough->singleBattData[n].pCurrState;
// 3. 根据返回的状态枚举值,从状态机数组中获取新状态
pSTBatt_Rough->singleBattData[n].pCurrState = &pSTBatt_Rough->stateMachs[emState];
// 4. 如果状态发生变化,记录进入新状态的时间戳
if(pSTBatt_Rough->singleBattData[n].pCurrState != pSTBatt_Rough->singleBattData[n].pLastState)
{
pSTBatt_Rough->singleBattData[n].pCurrState->tm_Enter[n] = GetCurrentTime();
}
二、状态机结构定义
状态机数组 stateMachs[] 的结构:
c
typedef struct {
STBATT_STATEMACHINE_STATE (*pfnAction)(STBATT_SAMPLER_ROUGH*, int); // 函数指针
double tm_Enter[MAX_SINGLE_STBATT_NUM]; // 进入该状态的时间戳
} STATE_MACHINE_NODE;
// 状态机数组初始化(推测)
pSTBatt_Rough->stateMachs[STBATT_STATE_IDLE] = {OnIdle, ...};
pSTBatt_Rough->stateMachs[STBATT_STATE_WAIT_CHARGE] = {OnWaitCharge, ...};
pSTBatt_Rough->stateMachs[STBATT_STATE_IN_CHARGING] = {OnCharging, ...};
pSTBatt_Rough->stateMachs[STBATT_STATE_IN_DISCHARGING] = {OnDischarging, ...};
pSTBatt_Rough->stateMachs[STBATT_STATE_FAULTED] = {OnFaulted, ...};
pSTBatt_Rough->stateMachs[STBATT_STATE_OFFGRID] = {OnOffGrid, ...};
三、状态转换图
┌─────────────────┐
│ STBATT_STATE │
│ IDLE │◄────────┐
└────────┬────────┘ │
│ │
┌────────────────────┼──────────────────┤
│ │ │
│ 充电条件满足 │ 放电条件满足 │ 故障/异常
▼ ▼ │
┌───────────────┐ ┌──────────────────┐ │
│ WAIT_CHARGE │ │ IN_DISCHARGING │ │
│ (等待充电) │ │ (放电中) │ │
└───────┬───────┘ └────────┬─────────┘ │
│ │ │
│ 充电启动成功 │ 停止条件满足 │
▼ │ │
┌───────────────┐ │ │
│ IN_CHARGING │ │ │
│ (充电中) │ │ │
└───────┬───────┘ │ │
│ │ │
└─────────────────────┴────────────────┘
│
▼
┌─────────────────┐
│ FAULTED │
│ (故障状态) │
└─────────────────┘
│
│ 故障恢复
▼
┌─────────────────┐
│ OFFGRID │
│ (离网状态) │
└─────────────────┘
四、各状态句柄函数的执行条件
4.1 OnIdle(空闲状态)
执行时机:系统初始状态或充放电结束后
主要逻辑:
c
STBATT_STATEMACHINE_STATE OnIdle(STBATT_SAMPLER_ROUGH* pSTBatt_Rough, int nBattIdx)
{
// 1. 检查故障条件
if (电池通信故障 || 电池告警 || CCU非空闲)
return STBATT_STATE_FAULTED;
// 2. 检查是否需要进入离网模式
if (JudgeIfNeedEnterOffGrid())
return STBATT_STATE_OFFGRID;
// 3. 判断是否需要启动充电
emReason_ChgStart = Judge_IfNeedChg_Start();
if (emReason_ChgStart == REASON_CHG_ALLOW_START)
{
Send_Ctrl_CCU(GRP_ACDC_RECTIFY_START); // 发送充电启动命令
return STBATT_STATE_WAIT_CHARGE;
}
// 4. 判断是否需要启动放电
emReason_DisChgON = Judge_IfNeedDisChg_ON();
if (emReason_DisChgON == REASON_DISCHG_ALLOW_ON)
{
Send_Ctrl_CCU(GRP_ACDC_INVERT_START); // 发送放电启动命令
return STBATT_STATE_IN_DISCHARGING;
}
// 5. 根据电池电流判断实际状态
if (fPackTotalCurr > 2.0)
return STBATT_STATE_IN_CHARGING;
else if (fPackTotalCurr < -2.0)
return STBATT_STATE_IN_DISCHARGING;
return STBATT_STATE_IDLE;
}
关键判断函数:
Judge_IfNeedChg_Start(第252行)- 检查充电禁止标志
- 检查绝缘检测状态
- 检查
fAvg_ChrgLmtPower是否 > 1kW(来自EMS计算) - 检查
fACDC_Distri_4_BattChrg_Pwr是否 > 1kW(来自EMS分配) - 检查
emBatt_WorkMode是否为充电模式(来自EMS) - 检查是否满足管理计划的充电条件
Judge_IfNeedDisChg_ON(第316行)- 检查放电禁止标志
- 检查
fAvg_DisChrgingLmtPower是否 > 1kW(来自EMS计算) - 检查
fBatt_Distri_4_ACDC_Pwr是否 > 1kW(来自EMS分配) - 检查
emBatt_WorkMode是否为放电模式(来自EMS) - 检查是否满足管理计划的放电条件
4.2 OnWaitCharge(等待充电状态)
执行时机:发送充电启动命令后,等待PCS响应
主要逻辑:
c
STBATT_STATEMACHINE_STATE OnWaitCharge(...)
{
// 1. 检查故障
if (故障条件)
return STBATT_STATE_IDLE;
// 2. 检查充电是否真正启动
if (fPackTotalCurr > 2.0 && emACDC_WorkStatu == STATU_ACDC_RECTIFY)
return STBATT_STATE_IN_CHARGING; // 充电成功启动
// 3. 超时判断(90秒)
if (超过90秒未启动)
return STBATT_STATE_IDLE; // 启动失败
// 4. 定期重发启动命令
if (距离上次发送命令 > 3秒)
Send_Ctrl_CCU(GRP_ACDC_RECTIFY_START);
return STBATT_STATE_WAIT_CHARGE;
}
4.3 OnCharging(充电中状态)
执行时机:充电成功启动后
主要逻辑:
c
STBATT_STATEMACHINE_STATE OnCharging(...)
{
// 1. 检查停止充电条件
if (bIsBatt_ChargeForbidden ||
IsBatt_Plan2_StopCharge() || // SOC达到停止值
故障条件 ||
fAllow_MaxChargeCurr < 5.0 ||
emBatt_WorkMode != BATT_WORKMODE_FIRST_CHRGING) // EMS模式变化
{
Send_Ctrl_CCU(GRP_ACDC_STOP);
return STBATT_STATE_IDLE;
}
// 2. 检查是否需要切换到放电(光伏充电时)
if (MPPT正在充电 && Judge_IfNeedDisChg_ON() == ALLOW)
{
Send_Ctrl_CCU(GRP_ACDC_INVERT_START);
return STBATT_STATE_IN_DISCHARGING;
}
// 3. 计算限制电流
fLimitCurrent = (fACDC_Distri_4_BattChrg_Pwr * 1000) / fPackTotalVolt;
// 4. 判断是否需要调整功率
if (bHiSens_Chrg || // 高灵敏度模式(来自EMS)
电压差 > 2V ||
电流差 > 2A ||
输出电流超限 > 3A)
{
Send_Ctrl_CCU(GRP_ACDC_RECTIFY_START); // 调整充电功率
}
return STBATT_STATE_IN_CHARGING;
}
关键参数来源:
fACDC_Distri_4_BattChrg_Pwr:来自Dispatch_ESSLmtBattChrg_PowerbHiSens_Chrg:来自Power_Control_Loop的PID控制emBatt_WorkMode:来自GetCurrentTimeSector
4.4 OnDischarging(放电中状态)
执行时机:放电成功启动后
主要逻辑:
c
STBATT_STATEMACHINE_STATE OnDischarging(...)
{
// 1. 检查停止放电条件
if (bIsBatt_DisChargeForbidden ||
IsBatt_Plan2_CutDischarge() || // SOC达到保护值
故障条件 ||
emBatt_WorkMode != BATT_WORKMODE_FIRST_DISCHRG) // EMS模式变化
{
Send_Ctrl_CCU(GRP_ACDC_STOP);
return STBATT_STATE_IDLE;
}
// 2. 计算限制电流
fLimitCurrent = (fBatt_Distri_4_ACDC_Pwr * 1000) / fPackTotalVolt;
// 3. 判断是否需要调整功率
if (bHiSens_Disc || // 高灵敏度模式(来自EMS)
电流差 > 2A ||
输出电流超限 > 3A)
{
Send_Ctrl_CCU(GRP_ACDC_INVERT_START); // 调整放电功率
}
return STBATT_STATE_IN_DISCHARGING;
}
关键参数来源:
fBatt_Distri_4_ACDC_Pwr:来自DisPatch_ACLoadReq_DisChrg_PowerbHiSens_Disc:来自Power_Control_Loop的PID控制
4.5 OnFaulted(故障状态)
执行时机:检测到故障时
主要逻辑:
c
STBATT_STATEMACHINE_STATE OnFaulted(...)
{
// 1. 如果仍有故障,停止PCS
if (故障条件)
{
Send_Ctrl_CCU(GRP_ACDC_STOP);
return STBATT_STATE_FAULTED;
}
// 2. 故障恢复,返回空闲
if (CCU空闲 && 电池无告警)
return STBATT_STATE_IDLE;
return STBATT_STATE_FAULTED;
}
4.6 OnOffGrid(离网状态)
执行时机:系统进入离网模式时
主要逻辑:
c
STBATT_STATEMACHINE_STATE OnOffGrid(...)
{
// 1. 检查故障
if (故障条件)
Send_Ctrl_CCU(GRP_ACDC_STOP);
// 2. 检查是否退出离网
if (!JudgeIfNeedEnterOffGrid())
return STBATT_STATE_IDLE;
// 3. SOC保护
if (nSOC <= nProtectSOC)
Send_Ctrl_CCU(GRP_ACDC_STOP);
else
OnHandle_PCSHotWaiting(); // 热备待机
return STBATT_STATE_OFFGRID;
}
五、与EMS功率计算函数的关联关系
5.1 数据流向图
EMS功率计算模块 状态机模块
──────────────── ──────────
Refresh_RealTime_MeterValue
│ 读取电表值
▼
Calc_ACLoadPwrByDiffMeterPosition
│ 计算负载功率
▼
JudgeIfEnterAnti_RefluxOrOverload
│ 设置保护标志位
│ - bEnterAnti_Reflux
│ - bEnter_OverLoad
▼
Calc_ESS_ChgLmtPower
│ 计算充电限制
│ - fTotal_PessChgAvaliable ───┐
▼ │
Calc_ESS_DischgLmtPower │
│ 计算放电限制 │
│ - fTotal_PessDischgLmt ──────┤
▼ │
Dispatch_ESSLmtBattChrg_Power │
│ 分配充电功率 │
│ - fACDC_Distri_4_BattChrg_Pwr ─┼──► Judge_IfNeedChg_Start
▼ │ │
DisPatch_ACLoadReq_DisChrg_Power │ ▼
│ 分配放电功率 │ OnIdle 判断是否启动充电
│ - fBatt_Distri_4_ACDC_Pwr ───┼──► Judge_IfNeedDisChg_ON
▼ │ │
Filter_Disttribute_Power │ ▼
│ 滤波处理 │ OnIdle 判断是否启动放电
│ - fAvg_ChrgLmtPower ─────────┤
│ - fAvg_DisChrgingLmtPower ───┤
▼ │
Power_Control_Loop (PID) │
│ PID控制 │
│ - bHiSens_Chrg ──────────────┼──► OnCharging 调整充电功率
│ - bHiSens_Disc ──────────────┼──► OnDischarging 调整放电功率
▼ │
GetCurrentTimeSector │
│ 获取管理计划 │
│ - emBatt_WorkMode ───────────┴──► OnCharging/OnDischarging
判断是否停止
5.2 关键关联点详解
关联点1:启动充电判断
// EMS计算(ems_management.c)
Dispatch_ESSLmtBattChrg_Power(pCCU);
└─> pEMS->calc_Node[n].fACDC_Distri_4_BattChrg_Pwr = 计算值;
Filter_Disttribute_Power(pCCU);
└─> pEMS->calc_Node[n].fAvg_ChrgLmtPower = 滤波后的值;
c
// 状态机判断(st_batt_statemachine.c)
Judge_IfNeedChg_Start()
{
if (pSTBatt_Rough->calcNodeData[nBattIdx].fAvg_ChrgLmtPower < 1)
return REASON_CHG_AVGPWR_BELOWALLOW; // 功率不足,不启动
if (pSTBatt_Rough->calcNodeData[nBattIdx].fACDC_Distri_4_BattChrg_Pwr < 1.0)
return REASON_CHG_CALCPWR_LITTLE; // 分配功率不足,不启动
if (pSTBatt_Rough->calcNodeData[nBattIdx].emBatt_WorkMode != BATT_WORKMODE_FIRST_CHRGING)
return REASON_CHG_NOTCHGMODE; // EMS模式不是充电,不启动
return REASON_CHG_ALLOW_START; // 允许启动
}
关联点2:启动放电判断
// EMS计算
DisPatch_ACLoadReq_DisChrg_Power(pCCU);
└─> pEMS->calc_Node[n].fBatt_Distri_4_ACDC_Pwr = 计算值;
Filter_Disttribute_Power(pCCU);
└─> pEMS->calc_Node[n].fAvg_DisChrgingLmtPower = 滤波后的值;
c
// 状态机判断
Judge_IfNeedDisChg_ON()
{
if (pSTBatt_Rough->calcNodeData[nBattIdx].fAvg_DisChrgingLmtPower < 1)
return REASON_DISCHG_AVGPWR_BELOWALLOW;
if (pSTBatt_Rough->calcNodeData[nBattIdx].fBatt_Distri_4_ACDC_Pwr < 1.0)
return REASON_DISCHG_CALCPWR_LITTLE;
if (pSTBatt_Rough->calcNodeData[nBattIdx].emBatt_WorkMode != BATT_WORKMODE_FIRST_DISCHRG)
return REASON_DISCHG_NOTDISCHGMODE;
return REASON_DISCHG_ALLOW_ON;
}
关联点3:充电中功率调整
// EMS计算
Power_Control_Loop(pCCU);
└─> pEMS->bHiSens_Chrg = TRUE; // PID控制进入高灵敏度模式
c
// 状态机调整
OnCharging()
{
fLimitCurrent = (fACDC_Distri_4_BattChrg_Pwr * 1000) / fPackTotalVolt;
if (pSTBatt_Rough->bHiSens_Chrg || // 高灵敏度模式
电压差 > 2V || 电流差 > 2A)
{
Send_Ctrl_CCU(GRP_ACDC_RECTIFY_START); // 立即调整功率
}
}
关联点4:停止充放电判断
// EMS计算
GetCurrentTimeSector(pCCU);
└─> pEMS->emBatt_WorkModeReq = BATT_WORKMODE_IDLE; // 管理计划变为空闲
c
// 状态机停止
OnCharging()
{
if (emBatt_WorkMode != BATT_WORKMODE_FIRST_CHRGING) // EMS模式变化
{
Send_Ctrl_CCU(GRP_ACDC_STOP); // 停止充电
return STBATT_STATE_IDLE;
}
}
六、完整的执行时序
时间轴:
────────────────────────────────────────────────────────────►
1. EMS周期计算(每秒执行)
├─ Refresh_RealTime_MeterValue()
├─ Calc_ACLoadPwrByDiffMeterPosition()
│ └─ JudgeIfEnterAnti_RefluxOrOverload()
├─ Calc_ESS_ChgLmtPower()
├─ Calc_ESS_DischgLmtPower()
├─ Dispatch_ESSLmtBattChrg_Power()
├─ DisPatch_ACLoadReq_DisChrg_Power()
├─ Filter_Disttribute_Power()
└─ Power_Control_Loop()
2. 状态机执行(每秒执行)
├─ 读取EMS计算结果
│ ├─ fAvg_ChrgLmtPower
│ ├─ fAvg_DisChrgingLmtPower
│ ├─ fACDC_Distri_4_BattChrg_Pwr
│ ├─ fBatt_Distri_4_ACDC_Pwr
│ ├─ emBatt_WorkMode
│ └─ bHiSens_Chrg / bHiSens_Disc
│
├─ 执行当前状态的句柄函数
│ └─ pfnAction(pSTBatt_Rough, nBattIdx)
│
├─ 根据返回值切换状态
│ └─ pCurrState = &stateMachs[emState]
│
└─ 发送控制命令到PCS
├─ GRP_ACDC_RECTIFY_START(启动充电)
├─ GRP_ACDC_INVERT_START(启动放电)
└─ GRP_ACDC_STOP(停止)
七、总结
状态机与EMS的关系:
- EMS是决策层:计算系统应该充电还是放电,以及充放电功率
- 状态机是执行层:根据EMS的决策,控制PCS的实际启停和功率调整
关键数据传递:
fAvg_ChrgLmtPower / fAvg_DisChrgingLmtPower:决定是否启动fACDC_Distri_4_BattChrg_Pwr / fBatt_Distri_4_ACDC_Pwr:决定功率大小emBatt_WorkMode:决定工作模式bHiSens_Chrg / bHiSens_Disc:决定调整频率
执行逻辑:
- EMS每秒计算一次,更新功率限制和工作模式
- 状态机每秒执行一次,读取EMS结果并控制PCS
- 状态机通过函数指针调用对应的句柄函数
- 句柄函数根据EMS数据和实际状态,返回下一个状态
- 状态机根据返回值切换到新状态,循环执行
这种设计实现了决策与执行的分离,EMS专注于功率计算和保护逻辑,状态机专注于设备控制和状态管理。