MP8861负载电流精准计算方案
2026/6/8 14:10:51 网站建设 项目流程

目录

1. 方法综述:为什么寄存器读数是“假的”,但又可以算出“真的”

2. 理论推导:为什么公式可以忽略 L 和 Fsw?

2.1 场景判断:电路处于哪种工作模式?

2.2 DCM 模式 (断续导通模式, I_load < I_CRIT)

2.3 CCM 模式 (连续导通模式, I_load > I_CRIT)

2.4 统一计算函数:自动判断模式并计算

3. 软件实现:从错误到正确的完整示例

3.1 正确实现:统一计算公式

3.2 集成到监控任务

3.3 校准:消除元件公差,提升精度

4. 单元测试与验证

5. 技术参考

6. 常见问题解答 (FAQ)


利用 MP8861 内部电流寄存器 REG03(ISCURR)来计算真实的负载电流,关键不在于复杂的公式,而在于理解该寄存器的物理含义,并根据芯片的实际工作模式选择正确的转换模型

下面我将从方法原理到软件实现,详细拆解并提供一个完整的工程化方案。

1. 方法综述:为什么寄存器读数是“假的”,但又可以算出“真的”

MP8861 的 REG03 寄存器报告的是电感的峰值电流,而不是我们想测的输出负载电流,这正是你看到“900mA”读数与实测“300mA”不符的根本原因。下表清晰地说明了这一关系:

项目含义关系公式
I_PEAK电感峰值电流(寄存器报告值)>取决于具体工况
ΔI电感纹波电流峰峰值取决于 L, V_in, V_out, F_sw
I_LOAD真实负载电流(我们需要算的值)<平均电流

准确计算负载电流,仅需一个简洁的DCM公式,与电感L和开关频率Fs无关,因此通用性和稳定性很高:

  • 理论值:根据此公式计算的理论电流I_load = I_peak * (V_in - V_out) / (2 * V_in)

  • 测量校准:在给定负载下,可以通过测量修正系数k来校准元件公差、寄生参数和寄存器量化误差带来的偏差,得到更精准的真实电流值I_load_real = I_load * k

2. 理论推导:为什么公式可以忽略 L 和 Fsw?

在具体应用中,你需要了解推导的原理以做决策。

2.1 场景判断:电路处于哪种工作模式?

根据你提供的参数(V_in=12V, V_out=3V, L=2.2µH, I_load≈300mA),电路是否处于DCM模式,需要通过计算最小负载电流验证:

  1. 计算临界连续电流 (I_CRIT)
    根据公式I_CRIT = V_out * (V_in - V_out) / (2 * F_sw * L * V_in),代入你的参数(F_sw = 1MHz),计算结果I_CRIT ≈ 851.5mA

  2. 比较并判断
    由于你的实际负载电流I_load ≈ 300mA小于I_CRIT (851.5mA),因此电路工作在DCM。不同模式下,REG03的读数含义完全不同,选择错误的公式会导致巨大误差。

2.2 DCM 模式 (断续导通模式, I_load < I_CRIT)

你的电路在DCM模式运行,这意味着在每个开关周期结束前,电感电流会完全降为零。这正是REG03报告“峰值电流”(I_PEAK)的原因。

公式推导:

  • 平均电流计算:在DCM模式下,真实的负载电流(I_load)是开关周期内的平均电流,它等于电感电流三角波面积除以周期T。这个面积就等于(1/2) * I_PEAK * T_off。因此,I_load = (1/2) * I_PEAK * (T_off / T)。【8†L63-L70】

  • 伏秒平衡:在稳态下,电感在开关导通期间(Ton)储存的能量必须等于关断期间(Toff)释放的能量。这给出了电压与时间的关系:(V_in - V_out) * T_on = V_out * T_off。【8†L73-L79】

  • 联立求解:结合平均电流计算公式和伏秒平衡公式,你使用的DCM公式中的变量T_off / T可以被消去,得到最终的I_LOAD表达式。【8†L89-L92】

2.3 CCM 模式 (连续导通模式, I_load > I_CRIT)

在重载时,MP8861会自动切换到效率更高的CCM模式。此时,电感电流在每个周期内都不归零,REG03报告的将是电感电流的谷值(I_VALLEY)

在CCM模式下,负载电流的计算方法是:负载电流(I_LOAD) ≈ 谷值电流(I_VALLEY) + 纹波电流(ΔI) / 2。其核心步骤如下:

  1. 计算占空比 (D)D = V_out / V_in

  2. 计算纹波电流 (ΔI)ΔI = (V_in - V_out) * D / (F_sw * L)

  3. 计算负载电流I_LOAD = I_VALLEY + ΔI/2

2.4 统一计算函数:自动判断模式并计算

在实际软件中,可以编写一个统一的计算函数,它能够自动判断电路当前处于哪种工作模式,并选择正确的公式进行计算,使最终结果在全局负载范围内都保持准确,封装了复杂的模式切换逻辑。

3. 软件实现:从错误到正确的完整示例

你原有的MP8861_GetLoadCurrent函数是错误的,因为它混淆了DCM和CCM的算法。下面我们来纠正并提供完整方案。

3.1 正确实现:统一计算公式

代码修正示例 (mp8861.c)

// 请将此函数定义在 mp8861.h 中,并删除之前的错误版本 // uint16_t MP8861_GetLoadCurrent(MP8861_Dev_t *dev, uint16_t vin_mv, uint16_t vout_mv); /** * @brief 计算MP8861真实负载电流(自动适配DCM和CCM模式) * @param dev MP8861设备句柄 * @param vin_mv 输入电压(mV),从ADC读取 * @param vout_mv 输出电压(mV),从ISVOLT寄存器读取 * @return uint16_t 真实负载电流(mA) */ uint16_t MP8861_GetLoadCurrent(MP8861_Dev_t *dev, uint16_t vin_mv, uint16_t vout_mv) { if (!dev->initialized || vin_mv == 0 || vin_mv <= vout_mv) { return 0; } // 1. 读取 ISCURR 寄存器,得到原始电流值(mA) uint8_t reg; if (SoftI2C_ReadReg(&dev->i2c_dev, MP8861_REG_ISCURR, &reg, 1)) { return 0; } uint16_t i_reg_mA = MP8861_CurrTable[reg]; // 在DCM下是Ipeak,CCM下是Ivalley // 2. 计算DCM模式下的平均电流理论值(忽略模式和各项参数) uint32_t numerator = (uint32_t)i_reg_mA * (vin_mv - vout_mv); uint32_t denominator = 2 * (uint32_t)vin_mv; uint16_t i_dcm_theory_mA = (uint16_t)(numerator / denominator); // Ipeak * (Vin-Vout) / (2*Vin) // 3. 判断模式并选择最终电流值 // 参数设定(请根据实际硬件配置) const float L_uH = 2.2f; // 电感值(uH) const float F_sw_MHz = 1.0f; // 开关频率(MHz) const float I_crit_coeff = 0.9f; // 90%的临界系数阈值,用于设置迟滞 float vin_f = vin_mv / 1000.0f; float vout_f = vout_mv / 1000.0f; // 计算理论临界负载电流值,用于判断工作模式 // I_crit = Vout*(Vin-Vout) / (2*Fsw*L*Vin) // 分母: 2 * 1e6 * 2.2e-6 * Vin = 4.4 * Vin float i_crit_A = (vout_f * (vin_f - vout_f)) / (4.4f * vin_f); uint16_t i_crit_mA = (uint16_t)(i_crit_A * 1000.0f); // 采用迟滞比较,避免负载电流在临界点附近时模式判断反复跳变 static uint8_t last_mode_was_dcm = 1; // 默认真实世界为DCM模式 uint8_t current_mode_is_dcm; if (last_mode_was_dcm) { // DCM模式下,使用较低的阈值(90%)进入CCM,避免误入 current_mode_is_dcm = (i_dcm_theory_mA <= (uint16_t)(i_crit_mA * I_crit_coeff)); } else { // CCM模式下,使用较高的阈值(110%)回到DCM current_mode_is_dcm = (i_dcm_theory_mA < (uint16_t)(i_crit_mA / I_crit_coeff)); } last_mode_was_dcm = current_mode_is_dcm; if (current_mode_is_dcm) { // DCM模式:电感电流从零开始,REG03为峰值电流 return i_dcm_theory_mA; } else { // CCM模式:需要更精确的计算 // 纹波电流 ΔI = (Vin - Vout) * D / (Fsw * L) float duty = vout_f / vin_f; float delta_i_A = (vin_f - vout_f) * duty / (F_sw_MHz * L_uH); uint16_t delta_i_mA = (uint16_t)(delta_i_A * 1000.0f); // 真实负载电流 = 谷值电流 + 纹波电流的一半 uint16_t i_load_mA = i_reg_mA + (delta_i_mA / 2); return i_load_mA; } }
3.2 集成到监控任务

代码修正示例 (mp8861.c)

// MP8861_MonitorRead函数修正 void MP8861_MonitorRead(void) { if (!mp8861_dev.initialized) return; // 1. 获取电压 uint16_t vin_mv = adc_data[E_ADC_PORT_POWER].voltage_mv; uint16_t vout_mv = MP8861_GetVout_Read(&mp8861_dev); // 2. 获取真实负载电流(核心修正) uint16_t i_load_mA = MP8861_GetLoadCurrent(&mp8861_dev, vin_mv, vout_mv); // 3. 一阶低通滤波 if (gMp8861Data.vout_mv == 0) { gMp8861Data.vout_mv = vout_mv; gMp8861Data.iout_ma = i_load_mA; } else { gMp8861Data.vout_mv = (gMp8861Data.vout_mv + vout_mv) / 2; gMp8861Data.iout_ma = (gMp8861Data.iout_ma + i_load_mA) / 2; } // 4. 更新状态 gMp8861Data.status = MP8861_ReadStatus(&mp8861_dev); gMp8861Data.pg = MP8861_IsPG(&mp8861_dev); gMp8861Data.ocp = MP8861_IsOCP(&mp8861_dev); gMp8861Data.ot = MP8861_IsOT(&mp8861_dev); gMp8861Data.ote = MP8861_IsOTE(&mp8861_dev); }
3.3 校准:消除元件公差,提升精度

由于电感、电容等元件的实际值与理论值存在公差,导致公式计算仍有误差,可进行校准来修正。

软件校准方法 (mp8861.c)

// 校准参数,存储在片上Flash的特定扇区 typedef struct { uint32_t magic; // 魔数,用于标识校准参数是否有效 uint16_t calib_current_mA; // 校准时使用的已知负载电流值 uint16_t i_peak_raw_mA; // 校准时读取的REG03原始值 float gain; // 根据校准点计算出的系数 int16_t offset; // 根据校准点计算出的偏移量 } MP8861_Calib_t; MP8861_Calib_t g_mp8861_calib = {0}; /** * @brief 执行一次校准流程 * @param known_load_mA 使用外部精密电流表测得的实际负载电流(mA) */ void MP8861_Calibrate(uint16_t known_load_mA) { uint16_t vout_mv = MP8861_GetVout_Read(&mp8861_dev); uint16_t vin_mv = adc_data[E_ADC_PORT_POWER].voltage_mv; // 读取当前的 i_reg uint8_t reg; SoftI2C_ReadReg(&mp8861_dev.i2c_dev, MP8861_REG_ISCURR, &reg, 1); uint16_t i_peak_raw = MP8861_CurrTable[reg]; // 计算未经校准的理论电流值 uint32_t numerator = (uint32_t)i_peak_raw * (vin_mv - vout_mv); uint16_t i_theory = (uint16_t)(numerator / (2 * vin_mv)); // 计算校准系数(一次线性校准,y = k*x) // 真实值 = 理论值 * k float k = (float)known_load_mA / i_theory; // 保存校准参数 g_mp8861_calib.magic = 0x5A5A5A5A; g_mp8861_calib.calib_current_mA = known_load_mA; g_mp8861_calib.i_peak_raw_mA = i_peak_raw; g_mp8861_calib.gain = k; // 将 g_mp8861_calib 写入Flash(需实现具体写入函数) WriteCalibToFlash(&g_mp8861_calib); } // 在 MP8861_GetLoadCurrent 函数的末尾,应用校准系数: uint16_t MP8861_GetLoadCurrent(...) { // ... 前面的模式判断和电流计算代码 ... uint16_t raw_current = ... // 计算出的原始电流值 // 应用校准系数 if (g_mp8861_calib.magic == 0x5A5A5A5A) { float calibrated = (float)raw_current * g_mp8861_calib.gain; if (calibrated > 65535) calibrated = 65535; if (calibrated < 0) calibrated = 0; return (uint16_t)calibrated; } return raw_current; }
  • 运行校准:在激光器处于连续扫描状态时调用MP8861_Calibrate(300);,即可完成一次校准。

  • 校准原理:该方法通过在已知负载下,比较理论值和实测值,计算出用于修正所有后续读数的线性系数,从而消除由元件误差、温度漂移等因素带来的系统偏差。

4. 单元测试与验证

为了确保算法的正确性和鲁棒性,可以在开发环境中编写简单的单元测试。这些测试通过模拟不同的输入条件来验证函数的行为是否符合预期,特别是在模式切换的关键点。

示例测试代码 (test_mp8861_current.c)

#include <assert.h> #include <stdio.h> // 模拟硬件寄存器 uint16_t mock_vin_mv = 12000; uint16_t mock_vout_mv = 3000; uint8_t mock_isc_reg = 0; MP8861_Dev_t mock_dev = { .initialized = 1 }; MP8861_Dev_t *dev = &mock_dev; // 模拟I2C读操作 uint8_t SoftI2C_ReadReg(SoftI2C_Dev_t *i2c, uint8_t reg, uint8_t *data, uint16_t len) { if (reg == MP8861_REG_ISCURR) { *data = mock_isc_reg; } return 0; } void test_load_current_calculation(void) { // 测试1:DCM模式 (轻载) mock_isc_reg = 0x1F; // 假设对应 900mA printf("Test 1 (DCM): "); uint16_t curr = MP8861_GetLoadCurrent(dev, mock_vin_mv, mock_vout_mv); printf("Calculated Load = %dmA (Expected ~337mA)\n", curr); // 这里可以添加强断言 assert(abs(curr - 337) < 20); // 测试2:CCM模式 (重载) mock_isc_reg = 0x80; // 假设对应 1800mA (谷值) mock_vout_mv = 1200; // 1.2V printf("Test 2 (CCM): "); curr = MP8861_GetLoadCurrent(dev, mock_vin_mv, mock_vout_mv); printf("Calculated Load = %dmA\n", curr); }

5. 技术参考

寄存器/宏地址用途关键宏位操作
REG03 (ISCURR)0x03读取电感峰值/谷值电流MP8861_CurrTable[]查表转换
REG04 (ISVOLT)0x04读取输出电压(精确)MP8861_VoltTable[]查表转换
REG01 (SYSCTL1)0x01系统控制1SYSCTL1_MODEbit0: 0=PFM, 1=PWM

核心参数推荐:

  • 电感值 L:2.2µH

  • 开关频率 Fsw:1.0MHz

  • 输入电压 Vin:12V

  • 输出电压 Vout:可配置(通过I2C)

6. 常见问题解答 (FAQ)

  • Q: 为什么我必须判断电路模式?直接用DCM公式不行吗?
    A: 不行。在CCM模式下,REG03报告的是谷值电流,此时电感电流从未降到零,如果继续套用DCM公式,计算结果会严重偏低,导致错误的电流读数。

  • Q: 什么时候应该做一次校准?
    A: 建议在产品量产前的最终测试阶段,或更换关键物料(如电感)后进行校准。校准后,将参数写入芯片的Flash,后续正常运行只需读取并使用校准系数即可。

  • Q: 为什么我的读数偶尔会跳动很大?
    A: 这是正常的物理现象,由纹波电流引起。解决方案有两个:一是使用软件滤波(如代码中提供的一阶滤波),二是通过I2C将MP8861强制设置为FPWM模式(寄存器SYSCTL1的bit0设为1),但这会增加轻载时的功耗。

  • Q: 输入电压Vin必须用ADC实时读取吗?
    A: 是的,MP8861_GetLoadCurrent函数要求输入电压以参数形式传入,这是为了计算的准确性。如果你的应用场景中输入电压Vin是固定的且纹波很小,也可以用一个常数代替,但会影响最终精度。

  • Q: CCM模式计算公式中的电感L和开关频率Fsw参数从哪里来?
    A:L是你电路板上实际使用的电感值(如2.2µH),Fsw是MP8861通过I2C配置的开关频率(如设置为1MHz)。在计算ΔI时,必须使用这些物理参数。

  • Q: 我的编译器不支持浮点运算怎么办?
    A: 可以使用定点数进行优化。例如,将浮点常数1.0f替换为整数1000,将ΔI的计算转换为定点运算,最后再缩小比例。但通常不建议,除非是资源极度受限的MCU。

  • Q: 校准后,g_mp8861_calib.gain的值大约是多少才正常?
    A:gain值应在0.81.2之间。如果超出这个范围,说明硬件可能存在异常(如电感值偏差过大),或校准时提供的known_load_mA不准确。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询