You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F302 MPPT系统ADC/DMA采样过慢致算法失效求助

STM32 MPPT系统ADC/DMA采样陈旧与算法失效问题修复方案

一、ADC采样数据陈旧的核心问题与修复

1. 缓冲区平均逻辑错误

当前Analog_GetChannel对DMA缓冲区中所有10次历史采样做平均,而循环DMA模式下缓冲区持续被新数据覆盖,导致计算值包含大量旧采样,数据时效性极差。

修复方案:读取最近的N次采样而非全部历史数据,通过DMA计数器定位当前写入位置,逆向获取最新采样:

uint16_t Analog_GetChannel(int channel)
{
    uint32_t adc_sum = 0;
    int i;
    // 获取DMA当前剩余传输次数,计算已写入位置
    uint16_t current_pos = ANALOG_NUMBERS_CHANNEL * NUMBER_ANALOG_CHANNEL_AVERAGE - __HAL_DMA_GET_COUNTER(&hdma_adc1);
    
    // 取最近10次该通道的采样(循环缓冲区索引处理)
    for(i=0; i<NUMBER_ANALOG_CHANNEL_AVERAGE; i++)
    {
        int idx = (current_pos - (i*ANALOG_NUMBERS_CHANNEL) + channel) % (ANALOG_NUMBERS_CHANNEL * NUMBER_ANALOG_CHANNEL_AVERAGE);
        adc_sum += ADC_DMA_BUFF[idx];
    }
    
    return adc_sum / NUMBER_ANALOG_CHANNEL_AVERAGE;
}

2. 采样与数据使用的同步问题

500μs定时器中断负责ADC数据转换,但MPPT算法未直接使用中断更新后的最新值,而是重复读取缓冲区。需在中断中完成采样转换并存储到专用变量:

// 定时器中断回调示例
void TIM2_IRQHandler(void)
{
    if(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET)
    {
        __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);
        
        // 读取最新采样并转换为电压/电流(根据硬件校准系数调整)
        uint16_t raw_vin = Analog_GetChannel(0); // 对应输入电压通道
        uint16_t raw_iin = Analog_GetChannel(1); // 对应输入电流通道
        
        Control_SetRegulatedInputVoltage(raw_vin * 0.00488f); // 假设3.3V参考,12位ADC:3.3/4096≈0.000805,根据分压系数调整
        Control_SetRegulatedInputCurrent(raw_iin * 0.0005f); // 根据电流采样电路校准
    }
}

二、MPPT扰动观察算法逻辑错误修复

原MPPT_PerturbAndObserve函数末尾的best_power = power导致每次判断时当前功率与自身对比,算法完全失效,出现占空比反复增减的情况。

修复方案:移除多余的赋值,保留正确的峰值跟踪逻辑,同时添加占空比范围限制:

static void MPPT_PerturbAndObserve(void)
{
    static float best_power;
    static uint8_t first_run = 1;
    
    float current = Control_GetRegulatedInputCurrent();
    float voltage = Control_GetRegulatedInputVoltage();
    float power = current * voltage;

    // 第一次运行初始化峰值功率
    if(first_run)
    {
        best_power = power;
        first_run = 0;
        return;
    }

    if (power > best_power)
    {
        best_power = power;
        mppt_duty_cycle += 2; // 功率上升,继续当前方向
    }
    else
    {
        mppt_duty_cycle -= 2; // 功率下降,反转方向
    }
    
    // 限制占空比范围,避免超出硬件允许区间
    if(mppt_duty_cycle < 100) mppt_duty_cycle = 100;
    if(mppt_duty_cycle > 900) mppt_duty_cycle = 900;
    
    PWM_SetDuty(mppt_duty_cycle);
}

三、其他优化建议

  • 提升DMA优先级:将DMA优先级从DMA_PRIORITY_LOW改为DMA_PRIORITY_MEDIUM,避免被高优先级中断抢占导致采样延迟:
    hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
    
  • 缩短ADC采样时间:在硬件允许的情况下,将采样时间从ADC_SAMPLETIME_61CYCLES_5改为ADC_SAMPLETIME_13CYCLES_5,提高采样速率。
  • 添加临界区保护:读取ADC缓冲区时禁用DMA中断,防止数据读写冲突:
    uint16_t Analog_GetChannel(int channel)
    {
        uint32_t adc_sum = 0;
        int i;
        uint16_t current_pos;
        
        __HAL_DMA_DISABLE_IT(&hdma_adc1, DMA_IT_TC | DMA_IT_HT); // 禁用DMA中断
        current_pos = ANALOG_NUMBERS_CHANNEL * NUMBER_ANALOG_CHANNEL_AVERAGE - __HAL_DMA_GET_COUNTER(&hdma_adc1);
        
        for(i=0; i<NUMBER_ANALOG_CHANNEL_AVERAGE; i++)
        {
            int idx = (current_pos - (i*ANALOG_NUMBERS_CHANNEL) + channel) % (ANALOG_NUMBERS_CHANNEL * NUMBER_ANALOG_CHANNEL_AVERAGE);
            adc_sum += ADC_DMA_BUFF[idx];
        }
        
        __HAL_DMA_ENABLE_IT(&hdma_adc1, DMA_IT_TC | DMA_IT_HT); // 重新启用中断
        return adc_sum / NUMBER_ANALOG_CHANNEL_AVERAGE;
    }
    

内容的提问来源于stack exchange,提问作者JaspervdGraaf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 13:32:02