1. 数字电源控制基础

任务目标

本案例面向数字电源DSP控制的基础环节:完成ADC模块初始化与配置,对电源输出电压、输出电流两路模拟信号进行连续采样,并通过标定转换将ADC原始数字量换算为真实的电压(V)与电流(A)数值,为后续电压环/电流环控制算法提供准确的反馈量。

环境与依赖

  • 硬件平台:TI TMS320F280049C(或任意C2000系列DSP,需调整头文件与引脚映射)
  • 开发环境:Code Composer Studio (CCS) 12.x + C2000Ware SDK
  • 使用片内ADC模块(12位,双采样保持器),EPWM1作为ADC触发源,连续采样模式

关键完整代码

// adc_sample_calib.c - 数字电源ADC采样与标定(最小可复现实现)
#include "F28x_Project.h"
#include "math.h"

// 标定参数(由硬件分压/采样电阻网络决定,需根据实际电路修改)
#define V_SCALE      0.003225f   // 电压通道:LSB对应电压(V),例如 3.3V/1023
#define I_SCALE      0.001612f   // 电流通道:LSB对应电流(A),例如 1.65V/1023/1A
#define V_OFFSET     0.0f        // 电压零点偏移
#define I_OFFSET     0.0f        // 电流零点偏移

// 全局采样结果(供控制算法调用)
volatile float gVout = 0.0f;     // 输出电压标定值 (V)
volatile float gIout = 0.0f;     // 输出电流标定值 (A)

// 内部原始ADC结果寄存器
static volatile Uint16 adcRawV, adcRawI;

// 中断标志
volatile Uint16 adcConvFlag = 0;

// 初始化ADC:双通道采样,EPWM1SOC触发
void initADC(void)
{
    EALLOW;
    // 配置ADC-A:两个采样保持器,分别采样电压与电流
    AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);
    AdcSetMode(ADC_ADCB, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);

    // 电压通道:ADCINA0 (A0),电流通道:ADCINB0 (B0)
    AdcSetSOC(ADC_ADCA, 0, ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN0, 7);  // A0
    AdcSetSOC(ADC_ADCB, 0, ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN0, 7);  // B0

    // 使能ADC中断(ADC-A INT1触发CPU中断)
    AdcEnableInterrupt(ADC_ADCA, 0, ADC_INT1);
    PieCtrlRegs.PIEIER1.bit.INTx10 = 1;   // ADC-A INT1 -> PIE通道1.10
    EDIS;
}

// EPWM1初始化:产生ADC触发信号,频率100kHz
void initEPWM_ADCTrigger(void)
{
    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;  // 暂停时基同步

    EPwm1Regs.TBPRD = 800;                 // 100MHz/800 = 125kHz
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0;
    EPwm1Regs.TBCTL.bit.CLKDIV = 0;
    EPwm1Regs.TBCTL.bit.CTRMODE = 0;       // 递增计数
    EPwm1Regs.TBCTL.bit.SYNCOSEL = 1;      // 禁用同步输出
    EPwm1Regs.ETSEL.bit.SOCASEL = 2;       // 周期匹配触发SOCA
    EPwm1Regs.ETSEL.bit.SOCAEN = 1;        // 使能SOCA
    EPwm1Regs.ETPS.bit.SOCAPRD = 1;        // 每个周期触发一次

    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;  // 恢复时基
    EDIS;
}

// ADC中断服务函数:读取结果并执行标定转换
__interrupt void adcA1ISR(void)
{
    // 读取原始ADC值(12位右对齐)
    adcRawV = AdcResult.ADCA_RESULT0;
    adcRawI = AdcResult.ADCB_RESULT0;

    // 标定转换:数字量 -> 物理量
    gVout = (float)adcRawV * V_SCALE + V_OFFSET;
    gIout = (float)adcRawI * I_SCALE + I_OFFSET;

    // 清除中断标志
    AdcClearInterrupt(ADC_ADCA, 0, ADC_INT1);
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    adcConvFlag = 1;   // 置位采样完成标志
}

// 主函数:初始化并等待采样
void main(void)
{
    InitSysCtrl();
    InitGpio();
    DINT;
    InitPieCtrl();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();

    // 注册ISR
    EALLOW;
    PieVectTable.ADCINT1_ISR = &adcA1ISR;
    EDIS;

    // 初始化外设
    initADC();
    initEPWM_ADCTrigger();

    // 使能ADC中断
    IER |= M_INT1;
    EINT;

    // 主循环:等待采样完成,读取标定后的电压/电流值
    for(;;)
    {
        if(adcConvFlag)
        {
            adcConvFlag = 0;
            // 在此处可调用后续控制算法,使用 gVout 和 gIout
            // 例如:voltageLoop(gVout, gIout);
        }
    }
}

运行与验证方法

编译与烧录:在CCS中新建工程,将上述代码保存为adc_sample_calib.c并添加至工程。需包含C2000Ware的器件支持头文件,并在工程属性中链接F28004x对应的CMD文件。编译无误后通过XDS110仿真器烧录至目标板。

硬件连接:将电源输出电压经分压电阻(使ADC输入范围0~3.3V)连接至ADCINA0引脚;电流采样使用霍尔传感器或采样电阻+运放电路,输出0~3.3V模拟信号连接至ADCINB0引脚。

验证步骤:

  1. 在CCS的Variables窗口中添加全局变量gVout和gIout,运行程序并暂停。
  2. 使用数字万用表测量实际电压/电流值,与gVout/gIout显示值对比。
  3. 调整输入电压(如从5V升至12V),观察gVout是否线性跟随变化。

通过判定标准:标定后的电压/电流显示值与万用表实测值误差在±2%以内,且采样值稳定无跳变,即判定ADC采样与标定功能正常。

标定参数调整说明

代码中的V_SCALE和I_SCALE需根据实际硬件电路计算:若电压通道分压比为10:1,则ADC满量程3.3V对应实际电压33V,V_SCALE = 33.0f / 4095.0f(12位ADC满量程4095)。电流通道若使用1V/A的传感器,则I_SCALE = 1.0f / 4095.0f * 3.3f。零点偏移V_OFFSET/I_OFFSET用于消除运放偏置电压,可在无输入信号时测量ADC读数并填入。

常见问题

  • 采样值始终为0:检查EPWM1是否已正确产生SOC触发信号,以及ADC引脚配置是否正确(GPIO复用为模拟功能)。
  • 采样值跳变剧烈:在ADC输入引脚对地并联100nF滤波电容,或在代码中对连续多次采样结果取平均值。
  • 标定值偏差大:确认分压电阻精度,使用高精度万用表校准V_SCALE值。