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

📄 main.c

📁 dc servo using dspic30f
💻 C
字号:
//---------------------------------------------------------------------
//	File:		main.c
//
//	Written By:	Lawrence Glaister VE7IT
//
// Purpose: This program is used to control an single axis servo card
//			using a pic 30f2010 and a OPA549 power op am driver stage.// 
// The following files should be included in the MPLAB project:
//
//		main.c		    -- Main source code file
//		capture.c		-- interface to pc quadrature cmd inputs using IC1 and IC2//      timer1.c        -- timer 1 setup for 100us intervals//      serial.c        -- interface to pc serial port for tuning - 9600n81//      encoder.c       -- interface to quadature encoder//		pwm.c			-- pwn ch for motor current control
//		pid.c			-- actual code for pid loop
//		save-res.c		-- routines to read/write configuration
//		p30f4012.gld	-- Linker script file
//		DataEEPROM.s	-- assembler file for read/write eeprom
//---------------------------------------------------------------------
//
// Revision History
//
// July 4 2006 -- first version 
// Aug 13 2006 -- fixed wrap around problem in servo loop
//             -- when servo is reenabled, the target posn is set to the current posn
//             -- if drive faults, it now stays faulted until pwr cycle
//				  or disable/reenable
// Aug 15 2006 -- added pulse multiplier option for high count motor encoders
// Sept 23 2006-  servo loop from 1ms to 500us (2khz rate)
// 
//---------------------------------------------------------------------- 
#include <stdio.h>
#include "dspicservo.h"
#include <math.h>
//--------------------------Device Configuration------------------------       
// pll16 needs a 30mhz part
_FOSC( XT_PLL16 );  // 6mhz * PLL16  / 4 = 24mips
_FWDT(WDT_OFF);                   // wdt off
/* enablebrownout @4.2v, 64ms powerup delay, MCLR pin active */
/* pwm pins in use, both active low to give 64ms delay on powerup */
//_FBORPOR(PBOR_ON & BORV_42 & PWRT_64 & MCLR_EN & RST_PWMPIN & PWMxL_ACT_LO );
_FBORPOR(MCLR_EN);
//----------------------------------------------------------------------
extern void setup_TMR1(void);
extern void setup_encoder(void);
extern void setup_uart(void);

extern volatile unsigned short int timer_test;
extern volatile unsigned short int cmd_posn;			// current posn cmd from PC
extern volatile short int rxrdy;

extern void setup_pwm(void);
extern void set_pwm(float amps);
extern void setup_adc10(void);
extern void setup_capture(void);
extern int restore_setup( void );
extern int calc_cksum(int sizew, int *adr);
extern void print_tuning( void );

extern void test_pc_interface( void );
extern void test_pid_interface( void );
extern void test_pwm_interface( void );
					
extern struct PID _EEDATA(32) pidEE;
extern volatile unsigned short int do_servo;
extern struct PID pid;
extern void calc_pid( void );
extern void init_pid(void);
extern void	process_serial_buffer();



void __attribute__((__interrupt__)) _StackError (void)
{
	PDC1 = (FCY/FPWM) - 1;	// cutoff output
	while (1)
	{
		STATUS_LED = 1;
		STATUS_LED = 0;			
		STATUS_LED = 0;		
		STATUS_LED = 0;			
	}
}

void __attribute__((__interrupt__)) _AddressError (void)
{
	PDC1 = (FCY/FPWM) - 1;	// cutoff output
	while (1)
	{
		STATUS_LED = 1;
		STATUS_LED = 1;			
		STATUS_LED = 0;			
		STATUS_LED = 0;			
	}
}

void __attribute__((__interrupt__)) _MathError (void)
{
	PDC1 = (FCY/FPWM) - 1;	// cutoff output
	while (1)
	{
		STATUS_LED = 1;
		STATUS_LED = 0;			
		STATUS_LED = 1;			
		STATUS_LED = 0;			
	}
}

/*********************************************************************
  Function:        void set-io(void)

  PreCondition:    None.
 
  Input:           None.

  Output:          None.

  Side Effects:    None.

  Overview:        Sets up io ports for in and out

  Note:            Some periperal configs may change them again
********************************************************************/void setup_io(void)
{
	// PORT B
    ADPCFG = 0xffff;        // make sure analog doesnt grab encoder pins (all digital)
    ADPCFGbits.PCFG0 = 0;   // AN0 is analog in - spare
							// 0=output, 1=input
	_TRISB0 = 1;			// used as AN0 above
	_TRISB1 = 0;			// spare
	_TRISB2 = 0;			// spare
	_TRISB3 = 0;			// spare
	_TRISB4 = 1;			// used by quad encoder input ch A
	_TRISB5 = 1;			// used by quad encoder input ch B

	// PORT C				// 0=output, 1=input
	_TRISC13 = 0;			// serial port aux  tx data
	_TRISC14 = 1;			// serial port aux  rx data
	_TRISC15 = 1;			// spare (maybe future xtal)

	// PORT D				// 0=output, 1=input
	_TRISD0 = 1;			// quad signal from pc
	_TRISD1 = 1;			// quad signal from pc

	// PORT E				// 0=output, 1=input
	_TRISE0 = 1;			// used by pwm1L to drive servo(set as i/p for startup)
	_TRISE1 = 0;			// used by on board fault led
	_TRISE2 = 0;			// used to set fwd/rev on motor power stage
	_TRISE3 = 0;			// used to indicate when PID calc is active
	_TRISE4 = 0;			// spare 
	_TRISE5 = 0;			// spare 
	_TRISE8 = 1;			// goes low on amp overtemp/fault (also state of ext sw)

	// PORT F				// 0=output, 1=input
	_TRISF2 = 1;			// PGC used by icsp
	_TRISF3 = 1;			// PGD used by icsp
}
/*********************************************************************
  Function:        int main(void)

  PreCondition:    None.
 
  Input:           None.

  Output:          None.

  Side Effects:    None.

  Overview:        main function of the application. Peripherals are 
                   initialized.

  Note:            None.
********************************************************************/int main(void) {
	int cs;
	// vars used for detection of incremental motion
	unsigned short new_cmd,last_cmd, new_fb,last_fb;

	setup_io();			// make all i/o pins go the right dir
	STATUS_LED = 0;		// led on
	setup_uart();		// setup the serial interface to the PC
    setup_TMR1();       // set up 1ms timer
	IEC0bits.T1IE = 1;  // Enable interrupts for timer 1
   						// needed for delays in following routines

	// 1/2 seconds startup delay 
	timer_test = 5000;		
	while ( timer_test );

	printf("\r\nPowerup..i/o...uart...timer...");	

	setup_pwm();		// start analog output
	set_pwm(0.0); 
	printf("pwm...");

	init_pid();
	printf("pid...");

    setup_encoder();    // 16 bit quadrature encoder module setup
	printf("encoder...");

    setup_capture();    // 2 pins with quadrature cmd from PC
	printf("capture...");

	printf("done\r\n");

	// some junk for the serial channel	printf("%s%s\n\r",CPWRT,VERSION);

	STATUS_LED = 1;		// led off when init finished

	// restore config from eeprom
	// Read array named "setupEE" from DataEEPROM and place 
	// the result into array in RAM named, "setup" 
	restore_setup();
	cs = calc_cksum(sizeof(pid)/sizeof(int),(int*)&pid);
	if ( cs )
	{
		// opps, no valid setup detected
		// assume we are starting from a new box
		printf("No valid setup found in EEPROM\r\n");
		init_pid();
	}
	else
	{
		printf("Using setup from eeprom.. ? for help\r\n");
		print_tuning();
	}
    printf("using %fms servo loop interval\r\n",pid.ticksperservo * 0.1);

//	BLOCK OF TEST ROUTINES FOR HARDWARE DEBUGGING		
//	test_pwm_interface();		// play with opa549 hardware
//	test_pc_interface();		// echo cmded posn to serial port
//  test_pid_interface();		// test pid loop operation

	new_cmd = last_cmd = new_fb = last_fb = 0;

	while (1)
	{
		if ( do_servo )		// check and see if timer 1 has asked for servo calcs to be run
		{
			do_servo = 0;
			if (SVO_ENABLE)
			{
				if ( pid.enable == 0 )	// last loop, servo was off
				{
				    set_pwm( 0.0 );
					printf("servo-enabled\r\n>");
					pid.enable = 1;
					// make sure we dont move on enabling
					cmd_posn = POSCNT;		// make 16bit incr registers match
					pid.command = 0L;		// make 32 bit counter match
					pid.feedback = 0L;
					// make the 1ms loop temps match
					new_cmd = last_cmd = new_fb = last_fb = 0;
					pid.error_i = 0.0;		// reset integrator
				}
                // we can time the servo cycle calcs by scoping the PID_ACTIVE pin
			    PID_ACTIVE = 1;			// seems to take about 140us
			    new_cmd = cmd_posn;		// grab current cmd from pc
			    new_fb = POSCNT;		// grab current posn from encoder

			    pid.command  += (long int)((short)(new_cmd - last_cmd));
			    pid.feedback += (long int)((short)(new_fb  - last_fb ));
			    last_cmd = new_cmd;
			    last_fb = new_fb;

			    calc_pid();

			    // check for a drive fault ( posn error > allowed )
			    if (( pid.maxerror > 0.0 ) && 
				    ( fabs(pid.error) > pid.maxerror ))
			    {
				    short temp = SVO_ENABLE;
				    set_pwm( 0.0 );
				    while (1)	// trap here until svo disabled or pwr cycle
				    {
					    // reset integrator as it may have wound up
					    pid.error_i = 0.0;
					    printf("drive fault... maxerror exceeded\r\n");
					    STATUS_LED = 0;	timer_test = 2500; while ( timer_test );
					    STATUS_LED = 1;	timer_test = 2500; while ( timer_test );
					    STATUS_LED = 0;	timer_test = 2500; while ( timer_test );
					    STATUS_LED = 1;	timer_test = 2500; while ( timer_test );
					    if (temp != SVO_ENABLE) 
						    break;
				    }
			    }
			    else
			    {
				    set_pwm(pid.output);	// update motor drive
			    }
			    PID_ACTIVE = 0;			// i/o pin for timing pid calcs
			}
			else
			{
				if ( pid.enable == 1 )	// last loop servo was active
				{
				    set_pwm( 0.0 );
					pid.enable = 0;
					printf("servo-disabled\r\n>");
					// extra delay keeps us faulted for min 1 sec to let mechanicals settle
					STATUS_LED = 1;	timer_test = 10000; while ( timer_test );
				}
			}
		}

		// look for serial cmds
		// doing this while svo is enabled will cause bumps in servo loop
		// because of serial i/o time ( unless we get smart and move svo loop
		// into an isr )
		if ( rxrdy )
			process_serial_buffer();

		if (pid.limit_state)			// show we are at drive limit(error)
			STATUS_LED = 0;
		else
			STATUS_LED = 1;
	}
	// to keep compiler happy....
	return 0;
}

⌨️ 快捷键说明

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