diff --git a/src/ems/loop_readback_service.c b/src/ems/loop_readback_service.c
index 2eb5685f6..8f74bbc35 100644
--- a/src/ems/loop_readback_service.c
+++ b/src/ems/loop_readback_service.c
@@ -68,6 +68,8 @@ typedef struct lrs_tag_node {
     lrs_tag_cb cb;
     double init_val;
     lrs_calc_val_cb calc_cb;
+    int skip_if_no_dev;  // 本轮未遍历到设备时跳过写点位
+    int dev_cnt;         // 本轮遍历到的设备数
 } lrs_tag_node_t;
 
 static lrs_dev_group_t g_lrs_dev_groups[LRS_DEV_TABLE_SIZE];
@@ -130,8 +132,8 @@ static void lrs_read_real_lc_tag(lrs_tag_node_t *tnode)
             if(lc_arr[i].type != eLC_TYPE_VLC) {
                 tmp = dev_get_dev_tag_float(lc_arr[i].no, tnode->ems_tag_name) ;              
                 ems_syslog(LOG_DEBUG, "[LRS]read(%s) tag name : %s->%lf", lc_arr[i].no, tnode->ems_tag_name, tmp);
+                lrs_calc_val(tnode, tmp);
             }
-            lrs_calc_val(tnode, tmp);
         }
     }
 }
@@ -199,15 +201,21 @@ static void lrs_round_read(void)
     lrs_list_for_each_safe(pos, n, &g_lrs_tag_list) {
         lrs_tag_node_t *node = lrs_list_entry(pos, lrs_tag_node_t, list);
         lrs_dev_group_t *grp = lrs_find_group(node->dev_type);
+        node->dev_cnt = 0;
         if (grp) {
             lrs_list_head_t *dpos, *dn;
             lrs_list_for_each_safe(dpos, dn, &grp->head) {
                 lrs_dev_node_t *dev = lrs_list_entry(dpos, lrs_dev_node_t, list);
+                node->dev_cnt++;
                 lrs_read_one(node, dev->dev_no);
             }
         }
 
         lrs_read_real_lc_tag(node);
+        if (node->skip_if_no_dev && node->dev_cnt == 0) {
+            node->cache = node->init_val;   // 未遍历到设备:仅重置缓存,不写点位,避免与同点位规则互相覆盖
+            continue;
+        }
         if (node->cb) {
             node->cb(node->dev_type, node->ems_tag_name, node->cache);
             node->cache = node->init_val;
@@ -415,6 +423,8 @@ int lrs_register_tag(lrs_tag_info_t *info)
     node->init_val = info->init_val;
     node->cache = info->init_val;
     node->calc_cb = info->calc_cb;
+    node->skip_if_no_dev = info->skip_if_no_dev;
+    node->dev_cnt = 0;
 
     pthread_mutex_lock(&g_lrs_mutex);
     lrs_list_add_tail(&node->list, &g_lrs_tag_list);
diff --git a/src/ems/lrs_service.h b/src/ems/lrs_service.h
index 27b621b0b..8c690800b 100644
--- a/src/ems/lrs_service.h
+++ b/src/ems/lrs_service.h
@@ -37,6 +37,7 @@ typedef struct lrs_tag_info {
     lrs_tag_cb cb;
     double init_val;
     lrs_calc_val_cb calc_cb;
+    int skip_if_no_dev;  // 本轮未遍历到设备时跳过写点位(保持点位原值)
 } lrs_tag_info_t;
 int lrs_register_tag(lrs_tag_info_t *info);
 
diff --git a/src/ems/main.c b/src/ems/main.c
index 3db9aad0f..8a1155742 100755
--- a/src/ems/main.c
+++ b/src/ems/main.c
@@ -263,6 +263,7 @@ static void lrs_register_readback_tag()
             .init_val = 0,
             .lc_tag_name = NULL,
             .calc_cb = NULL,
+            .skip_if_no_dev = 1,   // 交流柜只有PV,遍历到PV才写,避免与MPPT规则互相覆盖
         },
         [1] = {
             .dev_type = "BMS",
@@ -294,6 +295,17 @@ static void lrs_register_readback_tag()
             .lc_tag_name = NULL,
             .calc_cb = bms_charge_status_val_calc,
         },
+        [4] = {
+            .dev_type = "MPPT",
+            .pe_func_name = "get_onoff",
+            .ems_tag_name = PV_ONOFF_STATUS,
+            .calc_type = LRS_CT_OR,
+            .cb = NULL,
+            .init_val = 0,
+            .lc_tag_name = NULL,
+            .calc_cb = NULL,
+            .skip_if_no_dev = 1,   // 直流柜只有MPPT,遍历到MPPT才写,避免与PV规则互相覆盖
+        },
     };
 
     for (int i = 0; i < sizeof(tinfo) / sizeof(lrs_tag_info_t); i++) {
diff --git a/src/ems/manual_protect.c b/src/ems/manual_protect.c
index db518160c..ce29c68ad 100644
--- a/src/ems/manual_protect.c
+++ b/src/ems/manual_protect.c
@@ -202,10 +202,33 @@ static void protect_prepare(protect_ctx_t *ctx, cabinet_info_t *cab)
     }
 }
 
-static int mppt_exp_power_set_by_scale(cabinet_inside_t *cab, void *arg)
+static void mppt_exp_power_set_by_count(double pv_final)
 {
-    cab->cab_ctrl.mppt_exp_power = *(double *)arg * cab->cab_cfg.scale;
-    return 0;
+    int cab_num = dev_info_all.cabinet_info.num;
+    int total_mppt = 0;
+
+    for (int i = 0; i < cab_num; i++) {
+        total_mppt += dev_info_all.cabinet_info.cabinet_inside[i]->mppt.num;
+    }
+
+    if (total_mppt <= 0) {
+        ems_syslog(LOG_DEBUG, "[manual_protect] mppt dist: no mppt device, cab_num=%d pv_final=%.2f",
+                   cab_num, pv_final);
+
+        for (int i = 0; i < cab_num; i++) {
+            dev_info_all.cabinet_info.cabinet_inside[i]->cab_ctrl.mppt_exp_power = 0;
+        }
+        return;
+    }
+
+    for (int i = 0; i < cab_num; i++) {
+        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];
+
+        cab->cab_ctrl.mppt_exp_power = pv_final * cab->mppt.num / total_mppt;
+
+        ems_syslog(LOG_DEBUG, "[manual_protect] mppt dist: cab=%s mppt_num=%d total_mppt=%d exp_power=%.2f",
+                   cab->no, cab->mppt.num, total_mppt, cab->cab_ctrl.mppt_exp_power);
+    }
 }
 
 static void ac_manual_set_dev_power(double pv_final)
@@ -214,7 +237,8 @@ static void ac_manual_set_dev_power(double pv_final)
 
     for (int i = 0; i < var->cabinet_info.num; i++) {
         cabinet_inside_t *cab = var->cabinet_info.cabinet_inside[i];
-        double p = atomic_load(&cab->cab_ctrl.pcs_exp_power);
+        double p_exp = atomic_load(&cab->cab_ctrl.pcs_exp_power);
+        double p = p_exp;
 
         if (microgrid_ctrl.en_bms_power_limit) {
             if (p > 0) {
@@ -225,6 +249,9 @@ static void ac_manual_set_dev_power(double pv_final)
         }
 
         dev_set_dev_tag_float(cab->no, SET_ACT_POWER, p);
+
+        ems_syslog(LOG_DEBUG, "[manual_protect] ac pcs: cab=%s pcs_exp=%.2f pcs_set=%.2f bms_limit=%d",
+                   cab->no, p_exp, p, microgrid_ctrl.en_bms_power_limit);
     }
 
     double sum_scale = 0;
@@ -246,16 +273,19 @@ static void ac_manual_set_dev_power(double pv_final)
 
         atomic_store(&pv->info.pv_ctrl.power_set, p);
         pe_set_power(pv->no, p);
+
+        ems_syslog(LOG_DEBUG, "[manual_protect] ac pv: pv=%s scale=%.2f sum_scale=%.2f online=%d power_set=%.2f",
+                   pv->no, scale, sum_scale, pv->info.pv_data.on_line, p);
     }
 }
 
-static void protect_emergency_stop(enum MODE_MICROGRID mode)
+static void protect_system_abnormal(enum MODE_MICROGRID mode)
 {
     if (dev_get_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS) == 0) {
         return;
     }
 
-    ems_syslog(LOG_DEBUG, "[manual_protect] system exception, keep PCS/PV at 0");
+    ems_syslog(LOG_DEBUG, "[manual_protect] system abnormal, keep PCS/PV at 0");
 
     if (is_standard_cabinet(mode)) {
         lc_power_info_t info = {0};
@@ -286,8 +316,7 @@ static void protect_apply(enum MODE_MICROGRID mode, double pcs_final, double pv_
         traverse_cab_dev_func(cabinet_pcs_exp_power_set);
         PCS_set_power(pcs_local, 0);
 
-        double pv_total = pv_final;
-        traverse_cab_dev_func_arg(mppt_exp_power_set_by_scale, &pv_total);
+        mppt_exp_power_set_by_count(pv_final);
         MPPT_set_power(pv_final, 0);
     } else {
         accord_soc_cal_supportpower(microgrid_ctrl.SOC_min_combin, microgrid_ctrl.SOC_max_combin);
@@ -408,7 +437,7 @@ void manual_mode_power_protect(void)
 {
     cabinet_info_t *cab = get_cabinet_info();
 
-    protect_emergency_stop(cab->mode_microgrid);
+    protect_system_abnormal(cab->mode_microgrid);
 
     if (protect_precheck(cab) == PRECHECK_FAIL) {
         ems_syslog(LOG_DEBUG,
diff --git a/src/ems/micro_dev_model.c b/src/ems/micro_dev_model.c
index 3166e2b0c..9737b0ff2 100755
--- a/src/ems/micro_dev_model.c
+++ b/src/ems/micro_dev_model.c
@@ -1384,7 +1384,98 @@ int dev_get_function_int_print(const char* dev_id, const char* function,int* val
     cab->cab_data.mppt_out_power = power;
     return _SUCCESS;
  }
- 
+
+/**
+ * @brief 直流主从模式下从机柜MPPT光伏数据刷新汇总
+ * @param cab 柜子结构
+ * @return _SUCCESS 0:成功 MPPT_ERR:读值失败
+ * @note  与 mppt_flush_data 逻辑一致,仅电压改为取各在线MPPT的最大值,
+ *        避免多柜/多MPPT遍历时 电压被 mppt_BusVol = MAX(0, vol) 覆盖式赋值覆盖
+ */
+int slave_mppt_flush_data(cabinet_inside_t *cab)
+{
+    struct _mppt_t *dev;
+    char *no;
+    double power = 0;
+    cab->cab_ctrl.mppt_power_max = microgrid_ctrl.pvMax * cab->cab_cfg.scale;
+
+    ems_syslog(LOG_NOTICE, "[SLAVE_MPPT] cab[%s] mppt_num=%d 开始汇总",
+               (cab->no != NULL) ? cab->no : "null", cab->mppt.num);
+
+    for(int i = 0; i < cab->mppt.num; i++)
+    {
+        no = cab->mppt.mppt_param[i].no;
+        dev = &(cab->mppt.mppt_param[i]);
+        double vol = 0, cur = 0;
+        int l_ret_vol = 0, l_ret_cur = 0;
+
+        /* 在线状态: 用 with_result 区分"读不到"与"读到0" */
+        int l_ret_online = dev_get_dev_tag_int_with_result(no, STATE_ONLINE, &dev->info.mppt_data.on_line);
+        if (l_ret_online != 0)
+        {
+            dev->info.mppt_data.on_line = 0;
+            ems_syslog(LOG_WARNING, "[SLAVE_MPPT] dev[%s] Online读取失败 ret=%d", no, l_ret_online);
+        }
+
+        /* 开关机状态 */
+        int l_ret_onoff = dev_get_function_int(no, "get_onoff", &dev->info.mppt_data.statu);
+        if (l_ret_onoff != 0)
+        {
+            ems_syslog(LOG_WARNING, "[SLAVE_MPPT] dev[%s] get_onoff读取失败 ret=%d", no, l_ret_onoff);
+        }
+
+        /* 功率: pe_get_power 返回非0表示读取失败 */
+        int l_ret_power = pe_get_power(no, &dev->info.mppt_data.power);
+
+        /* 电压/电流 */
+        l_ret_vol = dev_get_function_double(no, "get_vol", &vol);
+        l_ret_cur = dev_get_function_double(no, "get_cur", &cur);
+
+        if (l_ret_power != 0)
+        {
+            if (l_ret_vol != 0 || l_ret_cur != 0)
+            {
+                ems_syslog(LOG_WARNING, "[SLAVE_MPPT] dev[%s] 功率读失败且电压/电流读失败 power_ret=%d vol_ret=%d cur_ret=%d",
+                           no, l_ret_power, l_ret_vol, l_ret_cur);
+                return MPPT_ERR;
+            }
+            dev->info.mppt_data.power = fabs(vol) * fabs(cur) / 1000;
+            ems_syslog(LOG_NOTICE, "[SLAVE_MPPT] dev[%s] pe功率读失败,改用U*I: vol_ret=%d vol=%.2f cur_ret=%d cur=%.2f power=%.2f",
+                       no, l_ret_vol, vol, l_ret_cur, cur, dev->info.mppt_data.power);
+        }
+        else
+        {
+            ems_syslog(LOG_NOTICE, "[SLAVE_MPPT] dev[%s] pe功率读取成功 power=%.2f vol_ret=%d vol=%.2f cur_ret=%d cur=%.2f",
+                       no, dev->info.mppt_data.power, l_ret_vol, vol, l_ret_cur, cur);
+        }
+
+        if(dev->info.mppt_data.on_line)
+        {
+            if(vol > microgrid_data.mppt_BusVol)
+            {
+                microgrid_data.mppt_BusVol = vol; // 直流母线电压取最大值
+            }
+            microgrid_data.mppt_BusCur += cur;
+            microgrid_data.mppt_BusPow += dev->info.mppt_data.power;
+            microgrid_data.mppt_OnOff |= dev->info.mppt_data.statu;
+            ems_syslog(LOG_NOTICE, "[SLAVE_MPPT] dev[%s] 在线,累加后 bus_vol=%.2f bus_cur=%.2f bus_pow=%.2f bus_onoff=%d",
+                       no, microgrid_data.mppt_BusVol, microgrid_data.mppt_BusCur, microgrid_data.mppt_BusPow, microgrid_data.mppt_OnOff);
+        }
+        else
+        {
+            ems_syslog(LOG_NOTICE, "[SLAVE_MPPT] dev[%s] 离线,不累加 online=%d statu=%d",
+                       no, dev->info.mppt_data.on_line, dev->info.mppt_data.statu);
+        }
+
+        power += dev->info.mppt_data.power;
+    }
+
+    cab->cab_data.mppt_out_power = power;
+    ems_syslog(LOG_NOTICE, "[SLAVE_MPPT] cab[%s] 汇总完成 mppt_out_power=%.2f bus_vol=%.2f bus_cur=%.2f bus_pow=%.2f bus_onoff=%d",
+               (cab->no != NULL) ? cab->no : "null", power, microgrid_data.mppt_BusVol, microgrid_data.mppt_BusCur, microgrid_data.mppt_BusPow, microgrid_data.mppt_OnOff);
+    return _SUCCESS;
+}
+
 /**
  * @description: meter_mppt 设备数据刷新 (单个柜子)
  * @param {cabinet_inside_t} cab
@@ -6862,7 +6953,14 @@ int Relevant_data_refresh()
         traverse_cab_dev_func(bms_flush_data);
         dev_set_dev_tag_int(DEV_NO_EMS, SINGLE_CELL_VOL_THRESHOLD_ALARM, microgrid_ctrl.Single_Cell_Vol_Threshold_Alarm);
 
-        traverse_cab_dev_func(mppt_flush_data);
+        if (cabinet_info.ctrl_mode == EMS_MODE_DD)
+        {
+            traverse_cab_dev_func(mppt_flush_data); // 对等模式
+        }
+        else // EMS_MODE_ZC 直流主从模式
+        {
+            traverse_cab_dev_func(slave_mppt_flush_data); // 从机柜MPPT汇总
+        }
 
         traverse_cab_dev_func(meter_mppt_flush_data);
         traverse_cab_dev_func(meter_pcs_flush_data);
