储能充放电状态机执行逻辑详解

一、核心代码执行流程

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;
}

关键判断函数:

  1. Judge_IfNeedChg_Start(第252行)
    • 检查充电禁止标志
    • 检查绝缘检测状态
    • 检查 fAvg_ChrgLmtPower 是否 > 1kW(来自EMS计算)
    • 检查 fACDC_Distri_4_BattChrg_Pwr 是否 > 1kW(来自EMS分配)
    • 检查 emBatt_WorkMode 是否为充电模式(来自EMS)
    • 检查是否满足管理计划的充电条件
  2. 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_Power
  • bHiSens_Chrg:来自 Power_Control_LoopPID控制
  • 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_Power
  • bHiSens_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的关系:

  1. EMS是决策层:计算系统应该充电还是放电,以及充放电功率
  2. 状态机是执行层:根据EMS的决策,控制PCS的实际启停和功率调整

关键数据传递:

  • fAvg_ChrgLmtPower / fAvg_DisChrgingLmtPower:决定是否启动
  • fACDC_Distri_4_BattChrg_Pwr / fBatt_Distri_4_ACDC_Pwr:决定功率大小
  • emBatt_WorkMode:决定工作模式
  • bHiSens_Chrg / bHiSens_Disc:决定调整频率

执行逻辑:

  1. EMS每秒计算一次,更新功率限制和工作模式
  2. 状态机每秒执行一次,读取EMS结果并控制PCS
  3. 状态机通过函数指针调用对应的句柄函数
  4. 句柄函数根据EMS数据和实际状态,返回下一个状态
  5. 状态机根据返回值切换到新状态,循环执行

这种设计实现了决策与执行的分离,EMS专注于功率计算和保护逻辑,状态机专注于设备控制和状态管理。

相关推荐
Elastic 中国社区官方博客3 小时前
Elasticsearch percolator 用于电商搜索治理:将模糊查询转换为可控的检索策略
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
zxrhhm3 小时前
PostgreSQL 中的层级查询 Oracle CONNECT BY 替代方案
数据库·postgresql·oracle
嵌入式×边缘AI:打怪升级日志3 小时前
Tina SDK Linux Kernel 基本使用(实战篇:为7寸RGB LCD触摸屏添加驱动支持).md
linux·运维·服务器
万事大吉CC3 小时前
【3】深入剖析 Django 之 MTV:路径引用与资源加载机制
数据库·django·sqlite
Hical_W4 小时前
用 Hical + MySQL 5 分钟搭建 CRUD API(C++20 协程版)
数据库·mysql·c++20
AIMath~4 小时前
agent上下文和模型的上下文区别
数据库
前端之虎陈随易4 小时前
为什么今天还会有新语言?MoonBit 想解决什么问题?
大数据·linux·javascript·人工智能·算法·microsoft·typescript
G.晴天4 小时前
Linux常用命令练习流程
java·linux·运维·服务器·tomcat