基于STM32的数字控制PFC整流器设计

简介: 基于STM32的数字控制PFC整流器设计

一、系统架构设计

1.1 拓扑结构

单相交流输入 → 整流桥 → Boost电感 → MOSFET → 输出电容 → 直流负载
                     ↑
                电流采样电阻
                     ↑
                STM32F103C8T6控制

1.2 控制目标

参数 目标值 说明
输入功率因数 >0.99 接近单位功率因数
输入电流THD <5% 电流正弦化程度
输出电压纹波 <2% 稳定直流输出
效率 >95% 整体转换效率
输入电压范围 85-265V AC 宽电压适应

二、控制策略

2.1 双闭环控制结构

电压外环(慢环):
  输出电压采样 → 与参考电压比较 → 电压PI → 电流参考幅值

电流内环(快环):
  输入电流采样 → 与电流参考比较 → 电流PI → PWM占空比

相位同步:
  输入电压过零检测 → 锁相环(PLL) → 电流参考相位

2.2 数字控制算法

/* 控制参数 */
#define VOUT_REF       400.0f    // 输出电压参考值(V)
#define VIN_FREQ       50.0f     // 输入电压频率(Hz)
#define PWM_FREQ       50000.0f  // PWM开关频率(Hz)
#define SAMPLE_FREQ    20000.0f  // 采样频率(Hz)

/* 控制器结构体 */
typedef struct {
   
    float kp_v;      // 电压环比例系数
    float ki_v;      // 电压环积分系数
    float kp_i;      // 电流环比例系数
    float ki_i;      // 电流环积分系数
    float vout_err;  // 电压误差
    float iout_ref;  // 电流参考幅值
    float iin_err;   // 电流误差
    float duty;      // PWM占空比
} PFC_Controller;

三、STM32F103C8T6实现代码

3.1 主程序(main.c)

/**
  * @file main.c
  * @brief 数字控制PFC整流器主程序
  */
#include "stm32f10x.h"
#include "pfc_control.h"
#include "adc.h"
#include "pwm.h"
#include "pll.h"
#include "protection.h"

/* 全局变量 */
PFC_Controller pfc_ctrl;
System_Status sys_status;
float vin_rms = 0.0f;      // 输入电压有效值
float vin_phase = 0.0f;    // 输入电压相位
float iin_ref = 0.0f;     // 电流参考值

int main(void)
{
   
    /* 系统初始化 */
    System_Init();
    ADC_Init_PFC();        // ADC初始化
    PWM_Init_PFC();        // PWM初始化
    PLL_Init();            // 锁相环初始化
    Protection_Init();     // 保护初始化

    /* 控制器参数初始化 */
    pfc_ctrl.kp_v = 0.5f;
    pfc_ctrl.ki_v = 0.1f;
    pfc_ctrl.kp_i = 0.8f;
    pfc_ctrl.ki_i = 0.2f;
    pfc_ctrl.duty = 0.5f;  // 初始占空比50%

    /* 启动PWM输出 */
    PWM_Start(TIM1, CH1);

    /* 主循环 */
    while(1)
    {
   
        /* 系统状态监测 */
        System_Monitor();

        /* 保护检测 */
        if(Protection_Check() == PROTECT_FAULT)
        {
   
            PWM_Stop(TIM1, CH1);  // 关断PWM
            Fault_Handler();
        }

        /* 延时等待下一个控制周期 */
        Delay_Ms(1);
    }
}

/* TIM2中断服务程序 - 控制周期20kHz */
void TIM2_IRQHandler(void)
{
   
    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
   
        /* 1. 采样 */
        float vin_sample = ADC_GetVoltage(ADC_VIN);   // 输入电压采样
        float vout_sample = ADC_GetVoltage(ADC_VOUT);  // 输出电压采样
        float iin_sample = ADC_GetCurrent(ADC_IIN);    // 输入电流采样

        /* 2. 锁相环计算 */
        PLL_Update(vin_sample);
        vin_phase = PLL_GetPhase();
        vin_rms = PLL_GetRMS();

        /* 3. 电压外环控制 */
        pfc_ctrl.vout_err = VOUT_REF - vout_sample;
        pfc_ctrl.iout_ref += pfc_ctrl.ki_v * pfc_ctrl.vout_err;  // 积分项

        /* 限制电流参考幅值 */
        if(pfc_ctrl.iout_ref > MAX_CURRENT_REF)
            pfc_ctrl.iout_ref = MAX_CURRENT_REF;
        if(pfc_ctrl.iout_ref < 0.0f)
            pfc_ctrl.iout_ref = 0.0f;

        /* 4. 电流内环控制 */
        // 生成正弦电流参考
        iin_ref = pfc_ctrl.iout_ref * sinf(vin_phase);

        // 电流PI控制
        pfc_ctrl.iin_err = iin_ref - iin_sample;
        pfc_ctrl.duty += pfc_ctrl.kp_i * pfc_ctrl.iin_err;  // 比例项
        pfc_ctrl.duty += pfc_ctrl.ki_i * pfc_ctrl.iin_err;  // 积分项

        /* 5. 限制占空比 */
        if(pfc_ctrl.duty > 0.95f) pfc_ctrl.duty = 0.95f;
        if(pfc_ctrl.duty < 0.05f) pfc_ctrl.duty = 0.05f;

        /* 6. 更新PWM占空比 */
        PWM_SetDuty(TIM1, CH1, pfc_ctrl.duty);

        /* 7. 清除中断标志 */
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

3.2 锁相环(pll.c)

/**
  * @file pll.c
  * @brief 软件锁相环实现
  */
#include "pll.h"
#include <math.h>

/* PLL结构体 */
typedef struct {
   
    float phase;           // 当前相位(rad)
    float freq;            // 当前频率(Hz)
    float kp;              // 比例系数
    float ki;              // 积分系数
    float phase_error;     // 相位误差
    float freq_integral;   // 频率积分项
} PLL_TypeDef;

static PLL_TypeDef pll;

/* 初始化PLL */
void PLL_Init(void)
{
   
    pll.phase = 0.0f;
    pll.freq = 50.0f;      // 初始频率50Hz
    pll.kp = 0.1f;         // 比例系数
    pll.ki = 0.01f;        // 积分系数
    pll.phase_error = 0.0f;
    pll.freq_integral = 0.0f;
}

/* 更新PLL */
void PLL_Update(float vin_sample)
{
   
    /* 过零检测 */
    static float last_vin = 0.0f;
    static uint8_t zero_cross_flag = 0;

    if(last_vin < 0 && vin_sample >= 0)
    {
   
        zero_cross_flag = 1;
        // 计算实际频率
        static uint32_t last_zero_time = 0;
        uint32_t now = Get_Tick();
        if(last_zero_time > 0)
        {
   
            float period = (now - last_zero_time) / 1000.0f;  // 转换为秒
            pll.freq = 1.0f / period;
        }
        last_zero_time = now;
    }
    last_vin = vin_sample;

    /* 相位计算 */
    if(zero_cross_flag)
    {
   
        // 使用反正切法计算相位
        pll.phase = atan2f(vin_sample, 1.0f);  // 简化计算

        // 相位误差计算(与电网同步)
        float grid_phase = 2.0f * PI * pll.freq * (Get_Tick() / 1000.0f);
        pll.phase_error = grid_phase - pll.phase;

        // PI调节器
        pll.freq_integral += pll.ki * pll.phase_error;
        pll.freq = 50.0f + pll.freq_integral + pll.kp * pll.phase_error;

        // 限制频率范围
        if(pll.freq > 55.0f) pll.freq = 55.0f;
        if(pll.freq < 45.0f) pll.freq = 45.0f;
    }

    /* 相位累加 */
    pll.phase += 2.0f * PI * pll.freq / SAMPLE_FREQ;
    if(pll.phase > 2.0f * PI) pll.phase -= 2.0f * PI;
}

/* 获取当前相位 */
float PLL_GetPhase(void)
{
   
    return pll.phase;
}

/* 获取输入电压有效值 */
float PLL_GetRMS(void)
{
   
    static float vin_sum = 0.0f;
    static uint32_t sample_count = 0;
    static float vin_square_sum = 0.0f;

    vin_sum += vin_sample;
    vin_square_sum += vin_sample * vin_sample;
    sample_count++;

    if(sample_count >= 1000)  // 每1000个点计算一次
    {
   
        float rms = sqrtf(vin_square_sum / sample_count);
        vin_sum = 0.0f;
        vin_square_sum = 0.0f;
        sample_count = 0;
        return rms;
    }

    return 0.0f;
}

3.3 PWM驱动(pwm.c)

/**
  * @file pwm.c
  * @brief PWM驱动 - 使用TIM1高级定时器
  */
#include "pwm.h"

/* PWM初始化 */
void PWM_Init_PFC(void)
{
   
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 使能时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA, ENABLE);

    /* 配置PA8为TIM1_CH1输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* 时基配置 */
    TIM_TimeBaseStructure.TIM_Period = (SystemCoreClock / PWM_FREQ) - 1;  // 50kHz
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

    /* PWM模式配置 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
    TIM_OCInitStructure.TIM_Pulse = 0;  // 初始占空比0%
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

    /* 使能主输出 */
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
    TIM_Cmd(TIM1, ENABLE);
}

/* 设置PWM占空比 */
void PWM_SetDuty(TIM_TypeDef* TIMx, uint16_t channel, float duty)
{
   
    uint16_t pulse = (uint16_t)((TIMx->ARR + 1) * duty);

    switch(channel)
    {
   
        case CH1:
            TIM_SetCompare1(TIMx, pulse);
            break;
        case CH2:
            TIM_SetCompare2(TIMx, pulse);
            break;
        case CH3:
            TIM_SetCompare3(TIMx, pulse);
            break;
        case CH4:
            TIM_SetCompare4(TIMx, pulse);
            break;
    }
}

/* 启动PWM */
void PWM_Start(TIM_TypeDef* TIMx, uint16_t channel)
{
   
    TIM_Cmd(TIMx, ENABLE);
}

/* 停止PWM */
void PWM_Stop(TIM_TypeDef* TIMx, uint16_t channel)
{
   
    TIM_Cmd(TIMx, DISABLE);
}

3.4 ADC采样(adc.c)

/**
  * @file adc.c
  * @brief ADC采样 - 同时采样电压电流
  */
#include "adc.h"

/* ADC初始化 */
void ADC_Init_PFC(void)
{
   
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 使能时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);

    /* 配置PA0(ADC0)-输入电压,PA1(ADC1)-输出电压,PA2(ADC2)-输入电流 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* ADC配置 */
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;  // 扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  // 连续转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 3;
    ADC_Init(ADC1, &ADC_InitStructure);

    /* 配置ADC通道 */
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);  // VIN
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);  // VOUT
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);  // IIN

    /* 使能ADC */
    ADC_Cmd(ADC1, ENABLE);

    /* ADC校准 */
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));

    /* 启动转换 */
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

/* 获取输入电压采样值 */
float ADC_GetVoltage(uint8_t channel)
{
   
    uint16_t adc_value = 0;
    float voltage = 0.0f;

    if(channel == ADC_VIN)
    {
   
        adc_value = ADC_GetConversionValue(ADC1);
        // 分压比:220k/10k = 22:1,参考电压3.3V
        voltage = (adc_value * 3.3f / 4095.0f) * 22.0f;
    }
    else if(channel == ADC_VOUT)
    {
   
        adc_value = ADC_GetConversionValue(ADC1);
        // 分压比:100k/10k = 10:1
        voltage = (adc_value * 3.3f / 4095.0f) * 10.0f;
    }

    return voltage;
}

/* 获取输入电流采样值 */
float ADC_GetCurrent(uint8_t channel)
{
   
    uint16_t adc_value = 0;
    float current = 0.0f;

    if(channel == ADC_IIN)
    {
   
        adc_value = ADC_GetConversionValue(ADC1);
        // 采样电阻0.01Ω,放大倍数20倍
        // 电压 = 电流 * 0.01 * 20 = 电流 * 0.2
        current = (adc_value * 3.3f / 4095.0f) / 0.2f;
    }

    return current;
}

3.5 保护功能(protection.c)

/**
  * @file protection.c
  * @brief 过压、过流、过温保护
  */
#include "protection.h"

/* 保护阈值 */
#define VOUT_OVERVOLTAGE  450.0f   // 输出过压保护(V)
#define VOUT_UNDERVOLTAGE 350.0f   // 输出欠压保护(V)
#define IIN_OVERCURRENT   15.0f    // 输入过流保护(A)
#define TEMP_OVERTEMP    85.0f     // 过温保护(℃)

/* 保护状态 */
typedef enum {
   
    PROTECT_NORMAL = 0,
    PROTECT_OVERVOLT,
    PROTECT_UNDERVOLT,
    PROTECT_OVERCURR,
    PROTECT_OVERTEMP,
    PROTECT_FAULT
} ProtectState;

static ProtectState protect_state = PROTECT_NORMAL;

/* 初始化保护 */
void Protection_Init(void)
{
   
    protect_state = PROTECT_NORMAL;
}

/* 保护检测 */
ProtectState Protection_Check(void)
{
   
    float vout = ADC_GetVoltage(ADC_VOUT);
    float iin = ADC_GetCurrent(ADC_IIN);
    float temp = Temperature_Get();  // 获取温度

    /* 输出过压保护 */
    if(vout > VOUT_OVERVOLTAGE)
    {
   
        protect_state = PROTECT_OVERVOLT;
        return protect_state;
    }

    /* 输出欠压保护 */
    if(vout < VOUT_UNDERVOLTAGE)
    {
   
        protect_state = PROTECT_UNDERVOLT;
        return protect_state;
    }

    /* 输入过流保护 */
    if(iin > IIN_OVERCURRENT)
    {
   
        protect_state = PROTECT_OVERCURR;
        return protect_state;
    }

    /* 过温保护 */
    if(temp > TEMP_OVERTEMP)
    {
   
        protect_state = PROTECT_OVERTEMP;
        return protect_state;
    }

    protect_state = PROTECT_NORMAL;
    return protect_state;
}

/* 故障处理 */
void Fault_Handler(void)
{
   
    /* 关闭PWM输出 */
    PWM_Stop(TIM1, CH1);

    /* 点亮故障指示灯 */
    GPIO_SetBits(FAULT_LED_PORT, FAULT_LED_PIN);

    /* 记录故障代码 */
    uint8_t fault_code = (uint8_t)protect_state;
    Flash_WriteFaultLog(fault_code);

    /* 进入死循环等待复位 */
    while(1)
    {
   
        /* 闪烁故障灯 */
        GPIO_ToggleBits(FAULT_LED_PORT, FAULT_LED_PIN);
        Delay_Ms(500);
    }
}

参考代码 整流器稳定输出电压 www.youwenfan.com/contentali/56322.html

四、硬件设计要点

4.1 关键元器件选型

元器件 型号/参数 说明
MOSFET IPP65R110CFD 650V/33A,低导通电阻
二极管 IDW30G65C5 碳化硅二极管,低反向恢复
电感 PQ32/20 1mH,铁硅铝磁芯
电容 450V/470μF电解 输出滤波电容
采样电阻 0.01Ω/5W 锰铜合金电阻

4.2 PCB布局要点

  1. 功率回路最小化:减小开关噪声
  2. 模拟地与数字地分离:单点接地
  3. 电流采样走差分线:减小干扰
  4. 驱动信号远离模拟信号:避免串扰
  5. 散热设计:MOSFET和二极管加散热片

五、调试与测试

5.1 调试步骤

  1. 开环测试:不接控制算法,固定占空比测试
  2. 电压环测试:仅启用电压环,验证稳压性能
  3. 电流环测试:加入电流环,验证电流跟踪
  4. 并网测试:连接电网,验证功率因数
  5. 满载测试:验证额定功率下的性能

5.2 性能指标测试

测试项目 测试方法 合格标准
功率因数 功率计测量 >0.99
THD 示波器FFT分析 <5%
效率 输入输出功率比 >95%
稳压精度 负载变化测试 ±1%
动态响应 阶跃负载测试 超调<5%

5.3 示波器观测点

CH1: 输入电压(整流后)
CH2: 输入电流
CH3: 输出电压
CH4: PWM驱动信号

六、优化建议

6.1 软件优化

  1. 数字滤波器:加入低通滤波器滤除高频噪声
  2. 前馈控制:加入输入电压前馈,提高动态响应
  3. 自适应参数:根据负载变化调整PI参数
  4. 软启动:避免启动冲击电流

6.2 硬件优化

  1. EMI滤波:输入端加入LC滤波器
  2. 缓冲电路:MOSFET并联RC吸收电路
  3. 温度传感器:NTC监测散热器温度
  4. 辅助电源:独立的控制电源

七、安全注意事项

高压危险!

  1. 隔离测试:使用隔离变压器进行调试
  2. 绝缘手套:操作时佩戴绝缘防护
  3. 急停按钮:设置紧急断电开关
  4. 接地保护:确保设备良好接地
  5. 逐步加压:从小电压开始测试
目录
相关文章
|
20天前
|
机器学习/深度学习 人工智能 算法
用好 Codex Goal,关键就这三步
Codex 新增 /goal 命令,支持目标驱动的Agent式循环:设定可量化目标(如“运行时间降20%且测试全通过”)、构建短反馈闭环、用PLAN/EXPERIMENTS等Markdown文件持久化记忆。三要素缺一不可,方能真正释放长任务自动化潜力。
580 1
用好 Codex Goal,关键就这三步
|
监控 前端开发
STM32F103标准外设库——RCC时钟(六)
STM32F103标准外设库——RCC时钟(六)
2079 0
STM32F103标准外设库——RCC时钟(六)
|
20天前
|
Kubernetes 数据安全/隐私保护 容器
【架构实战】Helm Chart应用部署最佳实践
Helm是Kubernetes的包管理器: 核心概念: Chart:应用包 Repository:Chart仓库 Release:部署实例
91 2
|
20天前
|
存储 安全 Java
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
本文系统梳理了Java泛型的核心知识体系,主要内容包括: 泛型概述:介绍了泛型的定义、本质和三大优势(类型安全、代码复用、可读性),以及泛型类、接口和方法的三种使用形式。 泛型擦除:深入解析了Java泛型实现的核心机制,包括擦除规则(无界类型擦除为Object,有界类型擦除为第一个边界类型)、擦除带来的问题(如无法使用instanceof、创建泛型数组等)及其解决方案。 泛型通配符:详细讲解了三种通配符类型(无界通配符、上界通配符和下界通配符)的语法、语义和使用场景。
|
20天前
|
存储 安全 Java
【Java基础】String不可变性、String vs StringBuffer vs StringBuilder、常量池、intern()方法(附《思维导图》+《面试考点背诵版》)
本文系统解析Java字符串核心机制:String不可变性(`final char[]`实现)、String/StringBuffer/StringBuilder三者对比(可变性/线程安全/性能)、字符串常量池(JDK7+移至堆)及`intern()`方法(JDK7+直接存堆引用)。
|
20天前
|
人工智能 Rust 运维
qwen3.6-27b批处理掉Token后,​D​М‌X​Α‌РΙ补偿重试
Qwen3.6-27B是270亿参数稠密多模态模型,兼顾强大智能体编程能力与工程落地性:百万上下文、原生多模态、家用显卡可跑,API友好,稳定可控,完美平衡性能、成本与可运维性,成为中文业务场景首选生产级大模型。(239字)
|
20天前
|
人工智能 监控 安全
Gemini API 生产限流治理:从单点调用到企业网关
企业接入 Gemini API,技术难点不是发出请求,而是把模型调用变成可治理的基础设施。网关、限流、审计、成本和供应弹性做好之后,AI 能力才适合长期运行。
108 0
|
20天前
|
人工智能 数据中心
山东制造企业AI落地,从两个场景说起
本文分享JBoltAI在山东制造企业的AI落地实践:一是智能图纸检索,帮企业秒级匹配非标零件,降本增效;二是SOP视频智能剪辑,手机拍摄即可自动生成培训视频。核心路径是“数据接入—语义治理—构建企业级Agent”,小切口、快见效。(239字)
75 0
|
21天前
|
人工智能 JSON 安全
AI智能体的测试
AI Agent测试远超传统软件:需覆盖意图理解、工具调用、记忆一致性、生成质量四大核心能力,并融合自动化黄金数据集评测、LLM-as-a-Judge、链路追踪与安全护栏,构建工程化、可量化的全栈测试体系。(239字)
|
2月前
|
PHP
5个让PHP代码更优雅的小技巧
5个让PHP代码更优雅的小技巧