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

📄 isrs.c

📁 关于无传感器BLDC使用DSPIC现实的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
					break;

		case 1: 	OVDCON=SECTOR1_OVERRIDE;
					adc_channel_config=VPH_YELLOW;
					break;

		case 2: 	OVDCON=SECTOR2_OVERRIDE;
					adc_channel_config=VPH_RED;
					break;

		case 3: 	OVDCON=SECTOR3_OVERRIDE;
					adc_channel_config=VPH_BLUE;
					break;

		case 4: 	OVDCON=SECTOR4_OVERRIDE;
					adc_channel_config=VPH_YELLOW;
					break;

		case 5: 	OVDCON=SECTOR5_OVERRIDE;
					adc_channel_config=VPH_RED;
					break;
	}
	// When running sensorless, the zero_crossing
	// routine actually moves on the sector number
	// in response to a zero crossing. Otherwise
	// need to increment sector in the correct direction
	// to ensure that the next time the routine is called
	// the system commutates.
	
	if (control_flags.SENSORLESS==FALSE)
	{
		if (control_flags.ACQUIRE1==FALSE)
		{
			if (control_flags.DIR==FORWARDS)
			{
				if (sector==5) sector=0;
				else 				sector++;
			}
			else
			{
				if (sector==0) sector=5;
				else 				sector--;
			}
		}
	}

	// When running sensorless need to reconfigure ADC to 
	// look at correct vph channel and initialize several 
	// variables in zero_crossing routine. 
	// This is triggered by ADCCONFIG flag being set.
	// Also need to disable T2 interrupt as zero crossing
	// routine to load up next commutation instant.

	else
	{
		control_flags.ADCCONFIG=TRUE;
		IEC0bits.T2IE = 0;
	}
	IFS0bits.T2IF = 0;
	return;
}

// Timer 3 used as to provide simple PWM of
// brake switch while OC module not functioning
// It is used to time the On time and turns 
// brake switch off when interrupt occurs

void __attribute__((__interrupt__)) _T3Interrupt(void)
{
	IFS0bits.T3IF = 0;
	IEC0bits.T3IE = 0;
	return;
}


// check_zero_crossing is used to detect and act upon phase voltage
// zero crossings (when BEMF crosses vdc/2)
// It is called during normal running and when starting using 
// acqusition method1.

void check_zero_crossing(void)
{
	static unsigned int previous_sample;
	static unsigned char level_counter;
	static unsigned char blanking_counter;

	static unsigned int half_vdc=0;
	
	unsigned int new_timestamp;
	
	// If a commutation just occured which reconfigured
	// ADC to look at next vph feedack, need to clear
	// previous sample and level counter as well as
	// returning without checking for crossing and clearing
	// the relevant flags.
	// Also load up blanking counter to ignore first 
	// few samples to reject false crossings due to 
	// diode action at the end of the demag period
	// Finally determine whether looking for RISING or FALLING X

	if (control_flags.ADCCONFIG==TRUE)
	{
		control_flags.ADCCONFIG=FALSE;
		previous_sample=0;
		level_counter=0;
		control_flags.LEVEL=FALSE;
		control_flags.ZERO_CROSS=FALSE;
		blanking_counter=(unsigned char)user_parameters[32];
		// Decide whether rising or falling edge detect
		if (control_flags.DIR==FORWARDS)
		{
			if ((sector % 2) == 0)	control_flags2.FALLING_EDGE=TRUE;
			else							control_flags2.FALLING_EDGE=FALSE;
		}
		else
		{
			if ((sector % 2) == 0)	control_flags2.FALLING_EDGE=FALSE;
			else							control_flags2.FALLING_EDGE=TRUE;
		}
		return;
	}
	
	// Blanking counter used to ignore samples just after
	// commutation so that diode action doesn't cause false
	// zero_crossing.

	if (blanking_counter > 0)
	{
		blanking_counter--;
		return;
	}
	// This locks out the possibility of a second zero crossing 
	// being detected in a particular sector.
	if (control_flags.ZERO_CROSS==TRUE)
		return;

	// Half_vdc is a simple filtered version of vdc/2
	half_vdc = ((half_vdc + (vdc>>1)) >> 1);

	// To add robustness to the zero crossing detection a programmable
	// number of samples of vph must be seen above (falling edge) 
	// or below (rising edge) before the actual crossing detection is enabled
	// The level_counter variable along with the LEVEL flag implement this

	if (level_counter==(unsigned char)user_parameters[33])
	{
		control_flags.LEVEL=TRUE;
	}

	if (control_flags2.FALLING_EDGE)
	{ 
		if ((level_counter < (unsigned char)user_parameters[33]) && (vph > half_vdc))
		{
			level_counter++;
		}
		if ((level_counter > 0) && (vph <= half_vdc))
		{
			level_counter--;
		}
	}
	else
	{
		if ((level_counter < (unsigned char)user_parameters[33]) && (vph < half_vdc))
		{
			level_counter++;
		}
		if ((level_counter > 0) && (vph >= half_vdc))
		{
			level_counter--;
		}
	}

	// Note that saved timestamp and timedelta data is stored in arrays with three
	// elements corresponding to the three phases. The conventions used are as follows:
	// Index 0 = Red
	// Index 1 = Yellow
	// Index 2 = Blue
	// Sector 0,3 = Blue Phase Crossing
	// Sector 1,4 = Yellow Phase Crossing
	// Sector 2,5 = Red Phase Crossing 
	if (control_flags.LEVEL==TRUE) // Only check for the crossings once LEVEL is true
	{
		// If we have seen sufficient valid samples above or below vdc/2 
		// and the current and previous samples are <= vdc/2 or >= vdc/2 (edge dependant)
		// then this is the valid crossing.
		if (((control_flags2.FALLING_EDGE) && (previous_sample <= half_vdc)\
				&& (vph <= half_vdc)) || \
			((control_flags2.FALLING_EDGE==FALSE) && (previous_sample >= half_vdc)\
				&& (vph >= half_vdc)))
		{
			// Grab latest value of QEI counter which is
			// being used in the 16 bit timer mode
			new_timestamp=POSCNT;

			// Calculate time between this zero crossing and the last one
			// The result of this calculation is correct irrespective
			// of counter rollover due to the elegance of 2's comp
			// arithmetic on unsigned variables.
			// Note that to ensure we use the correct previous zero crossing
			// timestamp the calculation is direction dependent
			if (control_flags.DIR == FORWARDS)
			{
				switch (sector)
				{
					case 0:
					case 3:	latest_delta=new_timestamp-previous_timestamps[0];
								break;
					case 1:
					case 4:	latest_delta=new_timestamp-previous_timestamps[2];
								break;
					case 2:
					case 5:	latest_delta=new_timestamp-previous_timestamps[1];
								break;
				}
			}
			else // going BACKWARDS
			{
				switch (sector)
				{
					case 0:
					case 3:	latest_delta=new_timestamp-previous_timestamps[1];
								break;
					case 1:
					case 4:	latest_delta=new_timestamp-previous_timestamps[0];
								break;
					case 2:
					case 5:	latest_delta=new_timestamp-previous_timestamps[2];
								break;
				}
			}

			// Calculate period measurement used for speed feedback
			// rather than just using 60 degree measurement use 180
			// degrees to get better resolution at high speeds
			// Only calculate period once per electrical cycle in sector 0
			// Note if you calculate period more often than once per electrical
			// cycle, you will get faster update rate but more ripple.
			if (sector==0)
			{
				period_measurement=new_timestamp-previous_timestamps[2];

				// Reset stall counter to denote a valid period measurement event has ocurred
				stall_counter=0;
			}

			// Calculate the number of counts of TIMER2 until next commutation
			// Note that TIMER2 and QEI are on same timebase
			// The divison by 2 is because the diffence between the zero
			// crossing of a phase and the previous one from another phase
			// is 60 electrical degrees. The natural offset between zero_crossing 
			// and the correct commutation is 30 electrical degress without any
			// phase advance. 
			commutation_time=((latest_delta)/2) - phase_advance;

			// Now check that phase advance didn't cause too small a value for
			// commutation time. This can occur because phase advance is only
			// calculated in the medium speed event routine based on the period
			// measurement for efficiency. The test is done at 1 because this is
			// the smallest value that can be loaded into PR2 for the TIMER2 interrupt
			// to function correctly as we reset TIMER2 to zero after writing to PR2
			if (commutation_time < 1) commutation_time=1;

			// Now check to see if commutation has failed. This is done
			// by comparing latest_delta with previous_delta and applying a
			// a tolerance check. 			
			check_value=(latest_delta*100)/previous_delta;
			
			if (((check_value > upper_tol) \
				|| (check_value < lower_tol))	\
				&& (check_counter==0))
			{
				// If sensorless failed then enter
				// acquistion mode2 again if auto re-acquire (user param 31) is enabled
				DISABLE_FIRING;
				IEC0bits.T2IE=FALSE;
				control_flags.SENSORLESS=FALSE;
				if (user_parameters[31])
				{
					control_flags.ACQUIRE2=TRUE;
					control_flags.ADCCONFIG=TRUE;
					control_flags2.RETRY_FLAG=FALSE;
				}
				else
				{
					run_state=FAULT;
					trip_state=LOST;
				}
				return;
			}
			else		// Valid zero crossing detected
			{
				// Update sector
				if (control_flags.DIR==FORWARDS)
				{
					if (sector==5) sector=0;
					else 				sector++;
				}
				else
				{
					if (sector==0) sector=5;
					else 				sector--;
				}
				
				// Commutate as sensorless working provided not acquiring
				// using method1
				if (control_flags.ACQUIRE1==FALSE)
				{
					// Load up period register
					PR2 = (unsigned int) commutation_time;
					TMR2=0;
					// Now clear off interrupt flag and enable interrupt
					IFS0bits.T2IF = 0;
					IEC0bits.T2IE = 1;
					
					// Load up guard timer implemented in Timer 1 with
					// double the latest time delta between zero crossings
					PR1=latest_delta<<1;
					TMR1=0;
					
					// Clear interrupt flag just in case writing to timer
					// generated an interrupt.
					IFS0bits.T1IF = 0;
					// Now enable interrupt.
					IEC0bits.T1IE = 1;
				}
				else
				{
					// Incrementing acquire counter indicates a valid zero x
					// event has just occurred.
					// acquire counter is reset to zero by code in T2ISR if
					// a zero X event is missed during acquistion
					acquire_counter++;
					#ifdef DEBUG
						asm("btg        LATD,#15");
					#endif
					if (acquire_counter > 1) 
					{	// i.e. if have had two consequtive zero X events
						// Disable T2 interrupts ready for transition to 
						// closed loop commutation
						IEC0bits.T2IE = 0;

						// Set flags to indicate now running sensorless
						control_flags.ACQUIRE1=FALSE;
						control_flags.SENSORLESS=TRUE;
						run_state=RUNNING;
						// load up check counter to disable zeor X tolerance
						// checks for 1 elec cycle
						check_counter=6;
						// set up T2 to generate interrupt at correct time
						PR2 = (unsigned int) commutation_time;
						TMR2=0;
						// Now clear off interrupt flag and enable interrupt
						IFS0bits.T2IF = 0;
						IEC0bits.T2IE = 1;
						#ifdef DEBUG
							asm("btg        LATG,#1");
						#endif
					}
				}
			}
			// End of else associated with a valid zero crossing
			// Note that if you fail tolerance check code returns before
			// this point.

			// Save off timestamp info ready for next zero crossing

			if (control_flags.DIR==FORWARDS)
			{
				switch (sector)
				{
					case 0:	
					case 3:	previous_timestamps[0] = new_timestamp;

⌨️ 快捷键说明

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