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

📄 inverter.c

📁 单相电机变频驱动原码,采用DISPIC30芯片
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************
*
*		Microchip 16-bit Embedded Control Design Contest
*
*		Entry # MT2268
*
*		Spa Pump Controller
*
*****************************************************************
*
*		Motor drive inverter routines
*
*****************************************************************/

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


static BYTE inv_freq;		// Inverter output frequency (Hz * 4)
static BYTE target_freq;	// Requested inverter output frequency (Hz * 4)

static WORD ampl_scale;		// Overall amplitude scaling factor (Q.14)
static WORD ampl_freq;		// Amplitude scaling from output frequency
static WORD ampl_ph;		// Amplitude scaling from output phase offset


static WORD phase_accum;	// Phase accumulator (0 - 65535)
static WORD phase_step;		// Phase step increment value
static SWORD phase_offset;	// Phase offset between com and aux/run channels
static WORD phase_delta;	// Phase difference between aux and run channels

static WORD ampl_com, ampl_aux, ampl_run;		// Individual amplitude values (Q.14)

static WORD duty_com, duty_aux, duty_run;		// PWM duty cycle values


struct IPHASE_S {			// Data for computing motor current phase delta

	SWORD	min;			// Min motor current value for this cycle
	SWORD	max;			// Max motor current value for this cycle
	SWORD	last_min;		// Min motor current value for last cycle
	SWORD	last_max;		// Max motor current value for last cycle
	LONG	time;			// Average time of zero crossing
	BYTE	sign;			// Sign of motor current
	BYTE	flag;			// Data valid flag
};

#define SIGN_INIT	0
#define SIGN_POS	1
#define SIGN_NEG	2

static volatile struct IPHASE_S iphase_aux, iphase_run;
static volatile WORD iphase_delta;

static volatile BYTE inv_period_flag;		// PWM interrupt occurred flag
static volatile WORD inv_period_count;		// PWM period counter
static volatile WORD inv_cycle_flag;		// Output waveform cycle completed flag


	// First two quadrants of cos(x) in Q.15 format
	// This is equivalent to Q.14 format * 2

const SWORD cos_tbl[129] = {
		32767, 32757, 32728, 32678, 32609, 32521, 32412, 32285,
		32137, 31971, 31785, 31580, 31356, 31113, 30852, 30571,
		30273, 29956, 29621, 29268, 28898, 28510, 28105, 27683,
		27245, 26790, 26319, 25832, 25329, 24811, 24279, 23731,
		23170, 22594, 22005, 21403, 20787, 20159, 19519, 18868,
		18204, 17530, 16846, 16151, 15446, 14732, 14010, 13279,
		12539, 11793, 11039, 10278, 9512,  8739,  7962,  7179,
		6393,  5602,  4808,  4011,  3212,  2410,  1608,  804,
		0,      -804,   -1608,  -2410,  -3212,  -4011,  -4808,  -5602,
		-6393,  -7179,  -7962,  -8739,  -9512,  -10278, -11039, -11793,
		-12539, -13279, -14010, -14732, -15446, -16151, -16846, -17530,
		-18204, -18868, -19519, -20159, -20787, -21403, -22005, -22594,
		-23170, -23731, -24279, -24811, -25329, -25832, -26319, -26790,
		-27245, -27683, -28105, -28510, -28898, -29268, -29621, -29956,
		-30273, -30571, -30852, -31113, -31356, -31580, -31785, -31971,
		-32137, -32285, -32412, -32521, -32609, -32678, -32728, -32757,
		-32767
};

	// Compute cos(x) over all 4 quadrants, for x = 0 to 255,
	// by accessing the table in reverse for x >= 128

#define COS_Q15(x)	(((x) & 0x80) ? cos_tbl[256 - (x)] : cos_tbl[(x)])


/*
	Initialize inverter variables
*/
void Inv_init (void)
{
	inv_state = STOPPED;

	invp.ramp.up	= RAMP_RATE_UP;
	invp.ramp.down	= RAMP_RATE_DOWN;
	invp.ampl_var	= AMPL_VBUS_VAR;
	invp.delta_nom	= DELTA_NOM;
	invp.delta_thr	= DELTA_THRESH;
	invp.offset_nom	= OFFSET_NOM;
	invp.offset_thr	= OFFSET_THRESH;
}


/*
	Get inverter frequency, or 0 if stopped
*/
BYTE Inv_get_freq (void)
{
	if (inv_state == STOPPED)
		return (0);
	else
		return (inv_freq);
}


/*
	Set inverter frequency, after checking against valid limits
*/
void Inv_set_freq (BYTE freq)
{
	if (freq < INV_FREQ_MIN)
		freq = INV_FREQ_MIN;

	if (freq > INV_FREQ_MAX)
		freq = INV_FREQ_MAX;

	target_freq = freq;
}


/*
	Stop inverter
*/
void Inv_stop (void)
{
	target_freq = 0;
}


/*
	Start inverter (does nothing if already running)
*/
void Inv_start (void)
{

	if (inv_state != STOPPED)
		return;

	_PSEMIE = 0;					// Disable PWM int while we initialize

	Inv_set_freq (target_freq);		// Make sure target freq is valid

	phase_accum  = 0x0000;			// Init phase accumulator
	phase_offset = invp.offset_nom;	//  and phase offset
	phase_delta  = invp.delta_nom;	//  and phase delta

	duty_com = _PWM_PERIOD / 2;		// Init duty cycles
	duty_aux = _PWM_PERIOD / 2;
	duty_run = _PWM_PERIOD / 2;

	iphase_aux.sign = SIGN_INIT;	// Init motor current sense phase vars
	iphase_aux.min = 32767;
	iphase_aux.max = -32768;
	iphase_aux.last_min = 0;
	iphase_aux.last_max = 0;
	iphase_run.sign = SIGN_INIT;
	iphase_run.min = 32767;
	iphase_run.max = -32768;
	iphase_run.last_min = 0;
	iphase_run.last_max = 0;

	ampl_ph = Q14_ONE;				// Init amplitude

	inv_period_count = 0;			// Init interrupt flags
	inv_cycle_flag = 0;
	inv_update_timer = INV_UPDATE_RATE - 2;

	inv_freq = INV_FREQ_INIT;		// Init starting freq
	inv_state = STARTINIT;			//  and startup state
	inv_update_flag = 1;			// Force a freq update
	inv_period_flag = 1;			//  and a PWM update
	Inv_run ();						// Do first freq update

	_SESTAT = 0;					// Clear PWM module
	_PSEMIF = 0;					//  and system interrupt flags
	_PSEMIE = 1;					// Enable PWM interrupt
}


/*
	Inverter task handler, called by the main routine

	This executes the inverter state machine, and handles
	all foreground tasks for inverter operation.

	Its main tasks are to deal with startup and shutdown
	sequencing, frequency change requests, automatic motor
	waveform phase and amplitude tuning, and checking for
	fault conditions.
*/
void Inv_run (void)
{
	static WORD new_step;
	WORD new_delta;
	SWORD new_offset;
#ifdef PHASE_ADJ
	SWORD stemp;
#endif
	SBYTE inv_freq_adj;

/*
	Check for PWM fault
*/
	if (PWM_REG_BITS (PWMCON, bits.FLTSTAT, PWM_CH_inv)) {
		PWM_mode (PWM_CH_inv, PWM_MODE_off);
		target_freq = 0;
		inv_state = STOPPED;
		sys_fault |= FAULT_inv_fault;
	}

/*
	Check temperature limit
*/
	if (meas.v.temp_inv >= _TEMP_LIMIT) 
		sys_fault |= FAULT_inv_temp;

/*
		Check inverter state and frequency, and adjust if necessary

		This section of code runs at regular intervals, set by INV_UPDATE_RATE
*/
	if (inv_update_flag) {

		inv_update_flag = 0;

		inv_freq_adj = 0;

		switch (inv_state) {

			case STOPPED:				// Nothing to do here
				break;

			case STARTINIT:				// Prepare for startup by forcing a frequency update
				inv_freq --;
				inv_freq_adj = 1;
				inv_state = STARTWAIT1;
				break;

			case STARTWAIT1:			// Wait for vars to settle
				inv_state = STARTWAIT2;
				break;

			case STARTWAIT2:			// Wait for interrupt to occur
				break;

			case STARTUP:				// Now we're ramping up to starting frequency
				if (inv_freq < INV_FREQ_START)
					inv_freq_adj = invp.ramp.up;	// Bump freq up a step
				else
					inv_state = RAMP_UP;	// Reached minimum, go to normal ramp-up
				break;

			case RUNNING:				// Motor is running
				if (target_freq == 0)
					inv_state = STOPPING;			// Freq set to 0 - go shut down
				else {
					if (inv_freq < target_freq)		// Freq increased - go ramp up
						inv_state = RAMP_UP;
					if (inv_freq > target_freq)		// Freq decreased - go ramp down
						inv_state = RAMP_DOWN;
				}
				break;

			case RAMP_UP:				// Ramp up speed
				if (inv_freq < target_freq) {
#ifdef VBUS_HOLD
					if (!vbus_low || !sys_mode.b.vbus_hold)
#endif
						inv_freq_adj = invp.ramp.up;	// Bump freq up a step
				}
				else if (inv_freq > target_freq)
					inv_state = DELAY;		// Freq decreased - delay before ramping down
				else
					inv_state = RUNNING;			// All done - go back to running
				break;

			case RAMP_DOWN:				// Ramp down speed
				if (target_freq == 0)
					inv_state = STOPPING;			// Freq set to 0 - go shut down
				else {
					if (inv_freq > target_freq) {
#ifdef VBUS_HOLD
						if (!vbus_high || !sys_mode.b.vbus_hold)
#endif
							inv_freq_adj = - invp.ramp.down;	// Bump freq down a step
					}
					else if (inv_freq < target_freq)
						inv_state = DELAY;		// Freq increased - delay before ramping up
					else
						inv_state = RUNNING;			// All done - go back to running
				}
				break;

			case STOPPING:				// Ramp down to stopping frequency
				if (inv_freq > INV_FREQ_STOP) {
#ifdef VBUS_HOLD
					if (!vbus_high || !sys_mode.b.vbus_hold)
#endif
						inv_freq_adj = - invp.ramp.down;	// Bump freq down a step
				}
				else if (inv_freq > 0)
					inv_freq = 0;			// Below minimum, go right down to 0
				else {
					PWM_mode (PWM_CH_inv, PWM_MODE_off);
					inv_state = STOPPED;	//  and then shut down PWM outputs
				}
				break;

			case ABORT:					// Ramp down to 0
				if (inv_freq > 0)
					inv_freq_adj = - invp.ramp.down;	// Bump freq down a step
				else {
					PWM_mode (PWM_CH_inv, PWM_MODE_off);
					target_freq = 0;			// Reached 0, shut down PWM outputs
					inv_state = STOPPED;
				}
				break;

			case DELAY:					// Short delay when changing ramp directions
			case DELAY1:
			case DELAY2:
			case DELAY3:
				inv_state ++;
				break;

			case DELAY4:				// Delay complete - go back to running
				inv_state = RUNNING;
				break;
		}
/*
		If the state machine requested a frequency change,
		compute the new phase accumulator step size and
		frequency-based amplitude
*/
		if (inv_freq_adj != 0) {

			inv_freq += inv_freq_adj;

			new_step = ((LONG) inv_freq	// output frequency (Hz * 4)
				<< (16UL - 2UL))	// * counts per cycle (to get counts per second)
				/ PWM_UPDATE_RATE;	// / PWM periods per second (to get counts per period)

			// Set amplitude proportional to frequency for V/F control
			ampl_freq = AMPL_SLOPE * inv_freq / INV_FREQ_MAX;
		}
	}

	new_delta = phase_delta;		// Init temporary tuning vars
	new_offset = phase_offset;
/*
	This code runs once per cycle of the output waveform.
	It checks the relative phase and amplitude of the motor
	run and aux winding currents. It adjusts the PWM signals
	(which control the motor voltages) if the phase and/or
	amplitude are outside of a tolerance threshold, but not
	so far outside that the measurements might be suspect.
*/
	if (inv_cycle_flag) {

		if (inv_state == RUNNING) {

#ifdef PHASE_ADJ
		  if (sys_mode.b.delta_adj) {
/*
			Check the phase difference between the aux and run motor currents
			and adjust the phase difference of the output drive voltage if needed
			to bring the motor current phase difference close to its nominal value

⌨️ 快捷键说明

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