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
相关产品推荐
相关产品推荐

