⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pfc.c

📁 单相电机变频驱动原码,采用DISPIC30芯片
💻 C
字号:
/****************************************************************
*
*		Microchip 16-bit Embedded Control Design Contest
*
*		Entry # MT2268
*
*		Spa Pump Controller
*
*****************************************************************
*
*		Power Factor Corrector control routines
*
*****************************************************************/

#include "PumpCtl.h"
#include "PFC.h"
#include "ADC.h"
#include "PWM.h"
#include "Inverter.h"


static SWORD duty_pfc_i;


/*
	Initialize PFC variables
*/
void PFC_init (void)
{
	pfc_state = P_STOPPED;

	pfcp.v_gain_p	= PFC_V_GAIN_P;
	pfcp.v_gain_f	= PFC_V_GAIN_F;
	pfcp.i_gain_p	= PFC_I_GAIN_P;
	pfcp.i_gain_i	= PFC_I_GAIN_I;
	pfcp.i_gain_lim	= PFC_I_GAIN_LIM;
	pfcp.v_nom		= _VBUS_NOM;
	pfcp.v_low_thr	= _VBUS_LOW_THR;
	pfcp.v_high_thr	= _VBUS_HIGH_THR;
	pfcp.max_duty	= _PWM_MAX_DUTY_PFC;
}


/*
	Start up the PFC
*/
void PFC_start (void)
{

	if (pfc_state != P_STOPPED)
		return;

	_ADIE = 0;				// Disable ADC int while we initialize

	duty_pfc_i = 0;

	PWM_REG (FCLCON, PWM_CH_pfc) = 0x004D;	// Set SFLT2 to non-latched fault mode

	SET_PWM_TRIG  (PWM_CH_pfc, _PWM_MIN_DUTY_PFC >> 1);

	pfc_state = P_STARTWAIT;

	_ADIF = 0;				// Clear system
	ADSTAT = 0;				//  and ADC module interrupt flags
	_ADIE = 1;				// Enable interrupt
}


/*
	Stop the PFC
*/
void PFC_stop (void)
{

	PWM_mode (PWM_CH_pfc, PWM_MODE_off);
	pfc_state = P_STOPPED;
}

/*
	PFC task handler, called by the main routine

	Check for fault conditions
*/
void PFC_run (void)
{

/*
	Check for PWM fault
*/
	if (PWM_REG_BITS (PWMCON, bits.FLTSTAT, PWM_CH_pfc)) {
		PWM_mode (PWM_CH_pfc, PWM_MODE_off);
		pfc_state = STOPPED;
		sys_fault |= FAULT_pfc_fault;
	}

/*
	Check temperature limit
*/
	if (meas.v.temp_pfc >= _TEMP_LIMIT)
		sys_fault |= FAULT_pfc_temp;
}


/*
	The ADC interrupt occurs after all of the PFC conversions
	are complete. It reads all the ADC values, computes the
	duty cycle for the next period, and writes it out.

	There are 4 conversions, which start in the middle of the
	PWM period. The worst case latest start would be if the
	duty cycle were near 100%, which would leave 25 usec for
	the conversions and the interrupt routine, in order to
	write out the new duty cycle in time for the next period.

	The ADC is set up to take .75 usec per conversion, which
	leaves us 22 usec for the interrupt. That's plenty of time,
	since this is the highest priority interrupt and takes
	about half that time.
*/
void _ISR _ADCInterrupt (void)
{
	WORD temp;
	SWORD stemp;
	WORD duty_pfc;
	SWORD v_error, i_error;

	_ADIF = 0;		// Clear interrupt flags
	ADSTAT = 0;

/*
	Get ADC values from current PFC cycle
*/

	// Get all PFC vars from ADC, convert to Q.14 notation,
	//  and filter or average them as needed

	temp = ADCBUF_isns_pfc;
	if (temp >= offset.isns_pfc)	// Subtract offset value to compensate
		temp -= offset.isns_pfc;	//  for hardware offset voltage
	else
		temp = 0;					// Don't let it go below zero
	temp >>= 2;
	meas.nv.isns_pfc = temp;

	temp = ADCBUF_vsns_bus >> 2;
	meas.nv.vsns_bus += (SWORD)(temp - meas.nv.vsns_bus) >> 1;	// Fast average
	if (pfc_state == P_RUNNING)
		meas.nv.vsns_bus_avg +=								// Very slow average
			(SLONG)(((LONG) meas.nv.vsns_bus << 16L) - meas.nv.vsns_bus_avg) >> 10;
	else						// If not running, store value without averaging
		meas.nv.vsns_bus_avg = (LONG) meas.nv.vsns_bus << 16L;

	temp  = ADCBUF_vsns_ac >> 2;
	meas.nv.vsns_ac += (SWORD)(temp - meas.nv.vsns_ac) >> 1;
	// Keep track of the AC voltage peak, using a fast attack and slow decay time
	if (meas.nv.vsns_ac >= (WORD) (meas.nv.vsns_ac_pk >> 16))
		meas.nv.vsns_ac_pk +=
			(SLONG)(((LONG) meas.nv.vsns_ac << 16L) - meas.nv.vsns_ac_pk) >> 3;
	else
		meas.nv.vsns_ac_pk +=
			(SLONG)(((LONG) meas.nv.vsns_ac << 16L) - meas.nv.vsns_ac_pk) >> 12;

	temp = ADCBUF_temp_pfc >> 2;			// Slow average for temperature
	meas.nv.temp_pfc += (SWORD)(temp - meas.nv.temp_pfc) >> 10;


	if (pfc_state == P_STOPPED)				// Stop here if we're not running
		return;

/*
	Compute the PWM value for the next cycle
*/

#define V_AC		meas.nv.vsns_ac			// Make formulas easier to read
#define V_AC_PEAK	((WORD) (meas.nv.vsns_ac_pk >> 16))
#define I_PFC		meas.nv.isns_pfc
#define V_BUS		meas.nv.vsns_bus
#define V_BUS_AVG	((WORD) (meas.nv.vsns_bus_avg >> 16))


	v_error = pfcp.v_nom - V_BUS_AVG;		// Get bus voltage error

#ifdef LOAD_COMP
	if (sys_mode.b.load_comp) {				// Apply feedforward term from inverter
		if (inv_state == RAMP_UP)			//  to prepare for increasing
			v_error += pfcp.v_gain_f;
		if (inv_state == RAMP_DOWN)			//  or decreasing load current
			v_error -= pfcp.v_gain_f;
	}
#endif

	if (V_AC >= V_AC_PEAK)
		temp = Q14_ONE;
	else
		temp = DIV_Q14 (V_AC, V_AC_PEAK);	// Scale AC voltage to get fraction of peak

	i_error = MUL_Q14 (temp, v_error);		//  and use that to scale voltage error

	temp = MUL_Q14 (pfcp.v_gain_p, V_AC_PEAK);	// Compensate gain by scaling with peak

	i_error -= MUL_Q14 (temp, I_PFC);		// Now we have input current error term

	duty_pfc_i += MUL_Q14 (i_error, pfcp.i_gain_i);			// Update integral term

	if (duty_pfc_i > (SWORD) pfcp.i_gain_lim)				// Limit it to prevent
		duty_pfc_i = (SWORD) pfcp.i_gain_lim;				//  too much overshoot
	if (duty_pfc_i < (SWORD) - pfcp.i_gain_lim)
		duty_pfc_i = (SWORD) - pfcp.i_gain_lim;

	stemp = MUL_Q14 (i_error, pfcp.i_gain_p) + duty_pfc_i;	// Add on proportional term

	if (stemp > Q14_ONE)									// Limit result to 0.0 - 1.0
		stemp = Q14_ONE;
	if (stemp < 0)
		stemp = 0;

	duty_pfc = MUL_Q14U (stemp, _PWM_PERIOD);				// Scale by PWM period

	if (duty_pfc > pfcp.max_duty)							// Limit to valid range
		duty_pfc = pfcp.max_duty;
	if (duty_pfc < _PWM_MIN_DUTY_PFC)
		duty_pfc = _PWM_MIN_DUTY_PFC;


/*
	Write out the new PFC value
*/

	// Set the duty cycle value
	SET_PWM_DUTY  (PWM_CH_pfc, duty_pfc);

	// Set ADC trigger to occur in the center of the output pulse
	SET_PWM_TRIG  (PWM_CH_pfc, duty_pfc >> 1);

	// Disable output override at startup
	if (pfc_state == P_STARTWAIT) {
		PWM_REG (IOCON, PWM_CH_pfc) &= ~0x0300;
		pfc_state = P_STARTUP;
	}

/*
	Update status
*/

	if (pfc_state == P_STARTUP)							// If just starting up
		if (V_BUS >= pfcp.v_nom - (pfcp.v_nom >> 3))	//  and voltage near nominal
			if (_RA9 == 1) {							//  and fault input is high
				pfc_state = P_RUNNING;					//  then set state to running
				duty_pfc_i >>= 2;
				PWM_REG (PWMCON, PWM_CH_pfc) = 0x0080;	// Clear and
				PWM_REG (PWMCON, PWM_CH_pfc) = 0x1080;	//  re-enable fault latch
				PWM_REG (FCLCON, PWM_CH_pfc) = 0x004C;	//  and set latched fault mode
			}

#ifdef VBUS_HOLD
	vbus_low  = (V_BUS < pfcp.v_low_thr) ? 1 : 0;	// Report status
	vbus_high = (V_BUS > pfcp.v_high_thr) ? 1 : 0;	//  to inverter
#endif
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -