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

📄 medium_event.c

📁 关于无传感器BLDC使用DSPIC现实的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/**********************************************************************
 *                                                                     *
 *                        Software License Agreement                   *
 *                                                                     *
 *    The software supplied herewith by Microchip Technology           *
 *    Incorporated (the "Company") for its dsPIC controller            *
 *    is intended and supplied to you, the Company's customer,         *
 *    for use solely and exclusively on Microchip dsPIC                *
 *    products. The software is owned by the Company and/or its        *
 *    supplier, and is protected under applicable copyright laws. All  *
 *    rights are reserved. Any use in violation of the foregoing       *
 *    restrictions may subject the user to criminal sanctions under    *
 *    applicable laws, as well as to civil liability for the breach of *
 *    the terms and conditions of this license.                        *
 *                                                                     *
 *    THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION.  NO           *
 *    WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING,    *
 *    BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND    *
 *    FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE     *
 *    COMPANY SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL,  *
 *    INCIDENTAL OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.  *
 *                                                                     *
  **********************************************************************/

 /**********************************************************************
 *                                                                     * 
 *    Author: Smart Power Soutions, LLP                                * 
 *                                                                     *
 *    Filename:       medium_event.c   	                             *
 *    Date:           4/21/04                                        *
 *    File Version:   4.00                                             *
 *    Project:        53                                               *
 *    Drawing:        2                                                *
 *                                                                     *
 *    Tools used:    MPLAB C30 Compiler v 1.20.01                      *
 *                                                                     *
 *    Linker File:    p30f4012.gld                                   *
 *                                                                     *
 *                                                                     *
 ***********************************************************************
 *	Code Description
 *  
 *  This file has the medium event handler and its associated  functions,
 *  which execute every 10 msec.  In particular, the voltage and speed
 *  control loops are executed here.
 *  
 **********************************************************************/


#include "general.h"
#include "hardware.h"
#include "defs.h"
#include "extern_globals.h"




void medium_event_handler(void);
void speed_loop(void);
void voltage_control(void);
void starting_code(void); 

// debounce_switches is within user_interface.c
extern void debounce_switches(void);

void medium_event_handler(void)
{
	long	ltemp;
	int		itemp;
	// MED_EVENT_RATE set to 10ms in defs.h
	if (medium_speed_event_count > MED_EVENT_RATE)
	{

		medium_speed_event_count=0;
		debounce_switches();
			
		// Check to see if in the lockout period after
		// transitioning from acquistion to sensorless. If in the
		// lockout period (check_counter>0) then assume speed is
		// the same as end of ramp. Without this it is possible to
		// get spurious overspeed trips or even overcurrent
		// trips if speed loop active due to initial oscillation
		// giving unreliable speed calculation
		if (check_counter)
			rpm=user_parameters[7];
		else
			// Calculate speed in RPM for display and control purposes
			// Period used for speed measurement is 180 electrical degrees
			// There are therefore 1*poles counter units per rev
			// Thus to get to Revs per sec do 
			// COUNTER RATE / (poles*period_measurement)
			// To get speed in RPM * this by 60
			
			// First Calculate period*number of rotor poles as this is
			// used more than once
			{				// added this brace S. Bowling
			asm("disi  #5");
			ltemp=((unsigned long)user_parameters[25] \
					*(unsigned long)period_measurement);
					
			// Make sure trap a zero period_measurement or any value
			// that would cause an overflow
			if (ltemp < (COUNTER_RATE*60/65535))
				rpm=65535;
				
			else
				rpm = COUNTER_RATE*60/ltemp;
			}				// added this brace S. Bowling
		// Now check that a stall has not ocurred which would mean
		// that period_measurement is not being updated leading to 
		// incorrect calculation of speed. This is done by having a counter
		// which increments every medium speed event and is reset in the 
		// sector 0 zero_crossing code where the period measurement is done
		// If the counter exceeds the user parameter stall time then it is
		// assumed we are in stall.
		// Stall detection is disabled unless actually running
 		if (run_state!=RUNNING) stall_counter=0;

		// Now check for overspeed and stall if not already
		// in a fault condition
		if (!trip_state)
		{
			if ((rpm>user_parameters[14]) && (control_flags.SENSORLESS))
			{
				DISABLE_FIRING;
				run_state=FAULT;
				trip_state=OVER_SPEED;
			}
		
			if (stall_counter>user_parameters[13])
				
			{
				DISABLE_FIRING;
				run_state=FAULT;
				trip_state=STALLED;
			}
			else
				stall_counter++;
		}
		// Now calculate phase advance
		// If before the start of phase advance then just load in the
		// value required to account for the fact that zero crossing is 
		// always always detected at least 1 PWM cycle late
		if (rpm < user_parameters[11])
		{
			phase_advance=TIME_CORRECTION;
		}
		// else within phase advance speed region
		else
		{
			// Calculate the amount of phase advance required in thousandths
			// of an electrical degree
			ltemp=(long)(rpm-user_parameters[11])*user_parameters[12];
			// Then use the current period_measurement (180 electrical degrees)
			// To calculate the appropriate phase advance time
			phase_advance=((ltemp*period_measurement)/180000)+TIME_CORRECTION;
		}
				
		// Call the speed loop if running sensorless
		if (control_flags.SENSORLESS==TRUE) speed_loop();

		voltage_control();

		if (run_state==STARTING)	starting_code();


	}
	return;
}

// This is the speed control loop which can be used in 4 ways
// When the speed control mode is selected to be open loop the PI
// control is bypassed and either the PWM duty is controlled directly
// from the pot (OPEN_VOLTS mode) or the demand for the current
// control loop is taken from the pot(OPEN_CURRENT mode).
// If the (CLOSED_VOLTS mode) is selected, then the output from the
// speed loop directly controls the PWM duty cycle.
// If the (CLOSED_CURRENT mode) is selected, then the output from the 
// speed loop forms the demand for the current control loop
// The control mode is selectable via the user menu
void speed_loop(void)
{

	static long speed_integral;
	int speed_error;
	long proportional_term, pos_wloop_limit, neg_wloop_limit;
	int control_output,scaled_demand;
	long temp;

	#ifdef DEBUG
		asm("bset	LATG,#2");
	#endif
	// If either not RUNNING or during acquistion to sensorless
	// transition then clear off the integral and return
	if ((run_state != RUNNING) || (check_counter))
	{
		speed_integral=0;

		return;
	}
	switch (user_parameters[1])
	{
		case OPEN_VOLTS:	speed_integral=0;
								// Disable updates of PWM duty registers to ensure
								// All 3 values get loaded together
								PWMCON2bits.UDIS=1;
								scaled_demand=filtered_pot/user_parameters[37];
								// Compensate for inverted firing as FULL_DUTY gives
								// zero duty cycle.
								// First make sure we don't underflow calculation of 
								// correct duty
								if (scaled_demand > FULL_DUTY) 	PDC1=0;
								else	PDC1=FULL_DUTY-scaled_demand;
								PDC2=PDC1;
								PDC3=PDC1;
								// Now enable updates
								PWMCON2bits.UDIS=0;
								return;
								break;

		case OPEN_CURRENT:speed_integral=0;
								scaled_demand=filtered_pot/user_parameters[38];
								if (scaled_demand >= (current_trip-ibus_offset))
									current_demand=current_trip-ibus_offset;
								else
									current_demand=scaled_demand;
								return;
								break;

		case CLOSED_VOLTS:// The *32 is because duty limits
								// also used by current loop where
								// scaling is *512, whereas here it is
								// *16384 hence the 32 factor.
								pos_wloop_limit=pos_duty_limit*32;
								neg_wloop_limit=neg_duty_limit*32;
								break;
		case CLOSED_CURRENT:
								pos_wloop_limit=pos_current_limit;
								neg_wloop_limit=neg_current_limit;
								break;
	}
	
	speed_demand=filtered_pot*user_parameters[39];
	control_flags.TORQUE_LIMIT=FALSE;

	// Form the speed error by subtracting the speed in rpm from the
	// speed demand read from VR2.
	speed_error=speed_demand-rpm;
	
	// All calculated quantities will be shifted back down at the 
	// end by 512. P & I gains are effectively scaled up by 512.
	// This is done to allow fractional values of P & I without
	// severe rounding issues which causes quantization noise etc.

	// Now calculate proportional term
	
	proportional_term=((long)speed_error*(long)wloop_p_gain);

	if (proportional_term > pos_wloop_limit)
	{
		control_flags.TORQUE_LIMIT=TRUE;
		control_output=pos_wloop_limit/16384;
		if (user_parameters[1]==CLOSED_VOLTS)
			control_output+=ZERO_DUTY;

		// If in limit due to just P term then clear
		// off I term so that when come out of limit
		// I term can smoothly take over to eliminate 
		// steady state error.
		speed_integral=0;
	}
	else
	{
		if (proportional_term < neg_wloop_limit)
		{
			control_flags.TORQUE_LIMIT=TRUE;
			control_output=neg_wloop_limit/16384;
			if (user_parameters[1]==CLOSED_VOLTS)
				control_output+=ZERO_DUTY;
			// If in limit due to just P term then clear
			// off I term so that when come out of limit
			// I term can smoothly take over to eliminate 
			// steady state error.
			speed_integral=0;
		}
	}
	// Now do integral term if not in torque limit already due to P term
	if (control_flags.TORQUE_LIMIT==FALSE)
	{
		// Update Intergral term here but this will be overwritten if
		// found to be in limit later on in code
		speed_integral+=((long)speed_error * (long)wloop_i_gain);
		temp=speed_integral+proportional_term;

		// If sum of P+I terms pushes you into positive limit
		if (temp > pos_wloop_limit)
		{
			control_flags.TORQUE_LIMIT=TRUE;
			control_output=pos_wloop_limit/16384;
			if (user_parameters[1]==CLOSED_VOLTS)
				control_output+=ZERO_DUTY;
			// Now calculate integrator limit and clamp
			speed_integral = pos_wloop_limit - proportional_term;
		}
		else
		{
			// If sum of P+I terms pushes you into negative limit
			if (temp < neg_wloop_limit)
			{
				control_flags.TORQUE_LIMIT=TRUE;
				control_output=(neg_wloop_limit/16384);
				if (user_parameters[1]==CLOSED_VOLTS)
					control_output+=ZERO_DUTY;
				// Now calculate integrator limit and clamp
				speed_integral=neg_wloop_limit - proportional_term;
			}
			else
			// Calculate control output based on both unclamped P and I terms
			{
				// Temp still contains unclamped P+I term so no need to recalculate
				control_output=(temp/16384);
				if (user_parameters[1]==CLOSED_VOLTS)
					control_output+=ZERO_DUTY;
			}
		}
	}
	if (user_parameters[1]==CLOSED_VOLTS)
	{
		// Do final check to ensure control_output is not < 0
		// as this would cause large positive value to be loaded
		// into duty cycle registers!
		if (control_output < 0) control_output=0;

		// Disable updates of PWM duty registers to ensure
		// All 3 values get loaded together
		PWMCON2bits.UDIS=1;
		// Now load calculated value into duty cycle registers
		// Compensate for inverted firing as FULL_DUTY gives
		// zero duty cycle.
		control_output=FULL_DUTY-control_output;		
		PDC1=(unsigned int)control_output;
		PDC2=(unsigned int)control_output;
		PDC3=(unsigned int)control_output;
		// Now enable updates
		PWMCON2bits.UDIS=0;
	}
	else
	{
		current_demand=control_output;
	}

	return;
}

// This routine does the voltage control of the DC bus
// As there is an issue with using OC modules, TIMER3
// is used to provide the PWM.
// This is done by directly setting the port pin here
// and loading PR3 with the on time. The TIMER3 ISR 
// sets the port pin low.
void voltage_control(void)
{
	static long voltage_integral;
	int voltage_error;
	long proportional_term;
	long temp;

	if ((run_state != RUNNING) && (run_state != STARTING))
	{
		voltage_integral=0;
		return;
	}

	// If previous on pulse still running then disable the 
	// interrupt used to time the on time and turn switch off
	if(IEC0bits.T3IE)	
	{
		IEC0bits.T3IE=0;
//		BRAKE_FIRE=0;
	}

	// Form the voltage error by subtracting the voltage demand 
	// in the user parameters from the filtered vdc feedback
	// Note that error is of the opposite polarity than usual as
	// if the volts are too high you want to fire the switch
	voltage_error=filtered_vdc-voltage_demand;
	
	// All calculated quantities will be shifted back down at the 
	// end by 512. P & I gains are effectively scaled up by 512.
	// This is done to allow fractional values of P & I without
	// severe rounding issues which causes quantization noise etc.

	// Now calculate proportional term
	
	proportional_term=((long)voltage_error*(long)vloop_p_gain);

	if (proportional_term > POS_V_LIMIT)
	{
		voltage_integral=0;
		return;
	}
	else
	{
		// Note that negative saturation is tested by looking at
		// voltage error with -10 or approx 1% of full scale.

⌨️ 快捷键说明

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