1.1. Reloj del Sistema y Configuración GPIO
#include "DSP28x_Project.h"
void InicializarSistema(void) {
// Desactivar perro guardián
DINT;
InitSysCtrl();
// Configurar reloj del sistema a 150 MHz
InitPllSys(150, 10, 1, 0);
// Configurar GPIO como función periférica
EALLOW;
GpioCtrlRegs.GPADIR.bit.GPIO0 = 0; // ePWM1A como entrada
GpioCtrlRegs.GPADIR.bit.GPIO1 = 0; // ePWM1B como entrada
GpioCtrlRegs.GPADIR.bit.GPIO2 = 0; // ePWM2A como entrada
GpioCtrlRegs.GPADIR.bit.GPIO3 = 0; // ePWM2B como entrada
EDIS;
}
1.2. Inicialización del Módulo ePWM (ejemplo con ePWM1)
void InicializarEPWM1(uint16_t periodo, float cicloUtil) {
// 1. Configurar divisor de reloj
EPwm1Regs.TBPRD = periodo - 1; // Registro de periodo (10kHz corresponde a 1000)
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Conteo ascendente/descendente
EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0; // Divisor de reloj principal
EPwm1Regs.TBCTL.bit.CLKDIV = 0; // Divisor de reloj del sistema
// 2. Configurar valor de comparación
EPwm1Regs.CMPA.half.CMPA = (uint16_t)(cicloUtil * periodo); // Ciclo de trabajo
EPwm1Regs.CMPB = periodo - EPwm1Regs.CMPA; // Canal complementario
// 3. Configurar acción de límite
EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // Canal A se pone alto en incremento
EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // Canal A se pone bajo en decremento
EPwm1Regs.AQCTLB.bit.CBU = AQ_SET; // Canal B se pone alto en incremento
EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR; // Canal B se pone bajo en decremento
// 4. Control de tiempo muerto (1.5 μs)
EPwm1Regs.DBCTL.bit.DBFED = 150; // Retardo de flanco ascendente
EPwm1Regs.DBCTL.bit.DBRIS = 1; // Habilitar tiempo muerto
// 5. Iniciar contador
EPwm1Regs.TBCTL.bit.ENABLE = 1; // Habilitar contador
}
2. Configuración de Muestreo Sincronizado del ADC
2.1. Inicialización del Módulo ADC
void InicializarADC(void) {
// Apagar alimentación del ADC
EALLOW;
AdcRegs.ADCCTL1.bit.ADCPWDNZ = 0;
DELAY_US(1000); // Esperar estabilización de alimentación
AdcRegs.ADCCTL1.bit.ADCPWDNZ = 1; // Encender
// Configurar reloj del ADC a 12 MHz (SYSCLK/2)
AdcRegs.ADCCTL1.bit.ADCREFSEL = 0; // Referencia interna 1.2V
AdcRegs.ADCCTL1.bit.ADCCLKPS = 0x3; // Factor de división
// Configurar canales para muestreo sincronizado (disparo por ePWM1)
AdcRegs.ADCSOC0CTL.bit.CHSEL = 0; // Canal 0 (muestreo de tensión)
AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // Disparo por ePWM1
AdcRegs.ADCSOC0CTL.bit.ACQPS = 14; // Tiempo de retención de muestreo
AdcRegs.ADCSOC1CTL.bit.CHSEL = 1; // Canal 1 (corriente fase A)
AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 5;
AdcRegs.ADCSOC1CTL.bit.ACQPS = 14;
AdcRegs.ADCSOC2CTL.bit.CHSEL = 2; // Canal 2 (corriente fase B)
AdcRegs.ADCSOC2CTL.bit.TRIGSEL = 5;
AdcRegs.ADCSOC2CTL.bit.ACQPS = 14;
AdcRegs.ADCSOC3CTL.bit.CHSEL = 3; // Canal 3 (corriente fase C)
AdcRegs.ADCSOC3CTL.bit.TRIGSEL = 5;
AdcRegs.ADCSOC3CTL.bit.ACQPS = 14;
// Iniciar ADC
AdcRegs.ADCCTL1.bit.ADCEN = 1;
}
3. Algoritmo de Control de Doble Lazo
3.1. Control PI del Lazo Externo de Tensión
typedef struct {
float Kp;
float Ki;
float integral;
float salidaMax;
} ControladorPI;
float ControlPITension(ControladorPI *pi, float Vref, float Vdc) {
float error = Vref - Vdc;
pi->integral += error;
// Anti-saturación de integral
if (pi->integral > pi->salidaMax) pi->integral = pi->salidaMax;
if (pi->integral < -pi->salidaMax) pi->integral = -pi->salidaMax;
return pi->Kp * error + pi->Ki * pi->integral;
}
3.2. Control PR del Lazo Interno de Corriente
typedef struct {
float Kp;
float Kr;
float alfa;
} ControladorPR;
float ControlPRCorriente(ControladorPR *pr, float Iref, float Ifb, float theta) {
// Transformación de Park
float Id = Iref * cos(theta) + Ifb * sin(theta);
float Iq = -Iref * sin(theta) + Ifb * cos(theta);
// Regulación PR
float Vd = pr->Kp * Id + pr->Kr * (Id - Iq);
float Vq = pr->Kp * Iq + pr->Kr * (Iq - Id);
// Transformación inversa de Park
return Vd * cos(theta) - Vq * sin(theta);
}
4. Rutina de Servicio de Interrupción (disparo por ADC)
interrupt void ISR_ADC(void) {
// Leer resultados del ADC (alineación a la derecha)
float Vdc = (AdcResult.ADCRESULT0 * 3.3f) / 4096.0f;
float Ia = (AdcResult.ADCRESULT1 * 3.3f) / 4096.0f;
float Ib = (AdcResult.ADCRESULT2 * 3.3f) / 4096.0f;
float Ic = (AdcResult.ADCRESULT3 * 3.3f) / 4096.0f;
// Cálculo del ángulo de fase mediante PLL
static float theta = 0.0f;
theta = PLL_SRF(Va, Vb, Vc, theta); // Sincronización de fase basada en SRF-PLL
// Generación de referencia de corriente (seno unitario)
float Iref_a = Iref * cos(theta);
float Iref_b = Iref * cos(theta - 2*M_PI/3);
float Iref_c = Iref * cos(theta + 2*M_PI/3);
// Control del lazo de corriente
float Ciclo_a = ControlPRCorriente(&pr_corriente, Iref_a, Ia, theta);
float Ciclo_b = ControlPRCorriente(&pr_corriente, Iref_b, Ib, theta);
float Ciclo_c = ControlPRCorriente(&pr_corriente, Iref_c, Ic, theta);
// Actualizar ciclo de trabajo del PWM
EPwm1Regs.CMPA.half.CMPA = (uint16_t)(Ciclo_a * EPwm1Regs.TBPRD);
EPwm2Regs.CMPA.half.CMPA = (uint16_t)(Ciclo_b * EPwm2Regs.TBPRD);
EPwm3Regs.CMPA.half.CMPA = (uint16_t)(Ciclo_c * EPwm3Regs.TBPRD);
// Limpiar bandera de interrupción
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
5. Implementación del PLL (SRF-PLL)
float PLL_SRF(float Va, float Vb, float Vc, float theta_prev) {
// Transformación de Clark al marco estacionario
float alfa = Va;
float beta = (Va + 2*Vb) / sqrt(3);
// Transformación de Park al marco rotatorio
float vd = alfa * cos(theta_prev) + beta * sin(theta_prev);
float vq = -alfa * sin(theta_prev) + beta * cos(theta_prev);
// Regulador PI
static float integral = 0.0f;
float error = 0.0f; // Objetivo vq=0
integral += error;
float omega = Kp_pll * error + Ki_pll * integral;
// Actualizar ángulo de fase
float theta = theta_prev + omega * TS_MUESTREO;
// Normalizar ángulo
if (theta > 2*M_PI) theta -= 2*M_PI;
return theta;
}
6. Implementación del Mecanismo de Protección
6.1. Protección contra Sobrecorriente (Zona de Disparo ePWM)
void ConfigurarDisparoEPWM(void) {
// Configurar módulo TZ
EPwm1Regs.TZSEL.bit.CBC = 1; // Disparo por comparador B
EPwm1Regs.TZCTL.bit.TZA = 2; // Forzar canal A a nivel bajo en sobrecorriente
EPwm1Regs.TZCTL.bit.TZB = 2; // Forzar canal B a nivel bajo en sobrecorriente
// Configuración de interrupción
EPwm1Regs.TZINTSEL.bit.TZIF = 1; // Habilitar interrupción TZ
EPwm1Regs.TZINTFLG.bit.TZIF = 0; // Limpiar bandera
}
interrupt void ISR_DisparoEPWM(void) {
// Apagar rápidamente todos los PWM
EPwm1Regs.TZCTL.bit.TZA = 2;
EPwm2Regs.TZCTL.bit.TZA = 2;
EPwm3Regs.TZCTL.bit.TZA = 2;
// Registrar falla
banderaFalla = 1;
// Limpiar bandera de interrupción
EPwm1Regs.TZINTFLG.bit.TZIF = 0;
}
7. Flujo del Programa Principal
void main(void) {
// Inicialización del sistema
InicializarSistema();
InicializarEPWM1(1000, 0.5f); // 10kHz, 50% ciclo de trabajo
InicializarADC();
ConfigurarDisparoEPWM();
// Bucle principal
while(1) {
// Ejecutar tareas en segundo plano (como comunicación, registro de datos)
}
}
// Configuración de la tabla de vectores de interrupción
#pragma CODE_SECTION(ISR_ADC, "ramfuncs");
#pragma INTERRUPT(ISR_ADC, 1);
Código de referencia: Implementación de control digital PFC trifásico www.youwenfan.com/contentcns/73162.html
8. Depuración y Validación
-
Puntos de observación en osciloscopio:
- Simetría de las formas de onda de corriente trifásica (THD < 5%)
- Seguimiento del ciclo de trabajo del PWM con la referencia de corriente
- Rizado de tensión del bus DC (< 2% Vdc)
-
Datos de prueba de rendimiento:
Parámetro Condición de prueba Valor típico Factor de potencia de entrada 220V/50Hz 0.998 THD Carga de 1kW 3.2% Eficiencia Potencia nominal 96.5%
9. Sugerencias de Funicones Adicionales
- Precarga digital: Control de relé mediante GPIO para implementar circuito de precarga.
- Comunicación CAN: Integrar módulo CAN para enviar estado de funcionamiento a la computadora central.
- Parámetros PI adaptativos: Ajustar dinámicamente coeficientes PI según cambios de carga.