Laser Electronics: Difference between revisions

From Hacklab.TO Public Wiki
Jump to navigation Jump to search
(Initial Commit)
(No difference)

Revision as of 18:17, 6 January 2015

Laser Cutter Electronics

File:Laser-control board.pdf

File:Laser-motor driver.pdf

Code

/*
 * Laser Engraver Controller - ver. 1.0
 *
 * Written by: Andrew Kilpatrick
 * Copyright: 2009
 *
 * Runs on PIC16F877A
 *
 * Functional Description:
 *  - support for connection to emc2 or similar host-driven CNC software
 *  - parallel port or other type of bit-bang connection to PC
 *  - E-stop and system run control support (amp enable, charge pump, etc.)
 *  - controls 3 stepper motors (X, Y, Z)
 *  - controls laser PWM control
 *
 * Hardware I/O:
 *  - RA0	- laser power bit 0		- input - active high
 *  - RA1	- laser power bit 1		- input - active high
 *  - RA2	- laser power bit 2		- input - active high
 *  - RA3	- laser power bit 3		- input - active high
 *  - RA4	- laser defeat			- input - active high
 *
 *  - RB0	- E stop loop			- input - 0 = run, 1 = stop
 *  - RB1	- Z dir					- input - 0 = back, 1 = forward
 *  - RB2	- Y dir					- input - 0 = back, 1 = forward
 *  - RB3	- X dir					- input - 0 = back, 1 = forward
 *  - RB4	- laser activate		- input - 0 = off, 1 = on
 *  - RB5	- Z step				- input - rising edge - move one step
 *  - RB6	- Y step				- input - rising edge - move one step
 *  - RB7	- X step				- input - rising edge - move one step
 *
 *  - RC0	- amp enable LED		- output - 0 = off, 1 = on
 *  - RC1	- laser LED				- output - 0 = off, 1 = on
 *  - RC2	- laser PWM				- output - 0 = off, 1 = on
 *  - RC4	- Z motor phase A		- output
 *  - RC5	- Z motor phase B		- output
 *	- RC6	- Z motor phase C		- output
 *  - RC7	- Z motor phase D		- output
 *
 *  - RD0	- X motor phase A		- output
 *  - RD1	- X motor phase B		- output
 *  - RD2 	- X motor phase C		- output
 *  - RD3	- X motor phase D		- output
 *  - RD4	- Y motor phase A		- output
 *  - RD5	- Y motor phase B		- output
 *  - RD6	- Y motor phase C		- output
 *  - RD7	- Y motor phase D		- output
 *
 *  - RE0	- E stop output			- output - 0 = stop, 1 = run
 *  - RE1	- amp enable input		- input - 0 = disable, 1 = enable
 *  - RE2	- charge pump input		- input - high pulses to charge
 *
 */
#include <system.h>

#pragma CLOCK_FREQ 20000000

#pragma DATA 0x2007, _CP_OFF & _DEBUG_OFF & _CPD_OFF & _LVP_OFF & _BODEN_ON & _HS_OSC & _WDT_ON & _PWRTE_ON

// inputs
#define LASER_POWER_1_IN porta.0
#define LASER_POWER_2_IN porta.1
#define LASER_POWER_4_IN porta.2
#define LASER_POWER_8_IN porta.3
#define LASER_DEFEAT_IN porta.4
#define E_STOP_IN portb.0
#define X_DIR_IN portb.3
#define Y_DIR_IN portb.2
#define Z_DIR_IN portb.1
#define X_STEP_IN portb.7
#define Y_STEP_IN portb.6
#define Z_STEP_IN portb.5
#define LASER_IN portb.4
#define AMP_ENABLE_IN porte.1
#define CHARGE_PUMP_IN porte.2

// outputs
#define AMP_ENABLE_LED portc.0
#define LASER_ON_LED portc.1
#define E_STOP_OUT porte.0

// laser setting
#define LASER_TICKLE 0x01

// motor step size - 1 = half-step, 2 = full step
#define X_STEP_SIZE 1
#define Y_STEP_SIZE 1
#define Z_STEP_SIZE 1

// run state machine
#define STATE_IDLE 1
#define STATE_RUN 2
#define STATE_E_STOP 3
unsigned char run_state;

// globals
unsigned char x_phase;			// the X motor step phase
unsigned char y_phase;			// the Y motor step phase
unsigned char z_phase;			// the Z motor step phase
unsigned char run;				// 1 = normal, 0 = stopped
unsigned char charge_pump;		// 0 = stopped, >0 = run
unsigned char old_ch_pump;
unsigned char laser_init;		// 1 = laser initialized, 0 = not initialized
unsigned char laser_power;		// laser power level
unsigned char laser_on;			// 1 = laser on, 0 = laser off
unsigned char flash;			// temp flasher variable
unsigned char x_step;			// temp x step state
unsigned char y_step;			// temp y step state
unsigned char z_step;			// temp z step state

// function prototypes
void step_laser(void);

// main loop
void main() {
	// set up IO
	porta = 0x00;
	trisa = 0xff;  // inputs
	adcon1 = 0x06;  // all digital pins
	
	portb = 0x00;
	trisb = 0xff;  // inputs
	option_reg.NOT_RBPU = 0;  // weak pullups
	
	portc = 0x00;
	trisc = 0x00;  // outputs
	AMP_ENABLE_LED = 0;
	LASER_ON_LED = 0;
	ccpr1l = 0x00;
	ccp1con = 0x0c;  // PWM mode
	t2con = 0x05;  // prescaler 4, timer on
	
	portd = 0x00;
	trisd = 0x00;  // outputs
	trise.PSPMODE = 0;  // no data port
	
	porte = 0x00;
	trise &= 0xfe;  // RE0 = output, RE1-2 = input 
	E_STOP_OUT = 1;  // no E stop

	t1con = 0x21;  // 1:4 prescaler, internal clock, timer on

	// reset temp vars
	x_phase = 0;
	y_phase = 0;
	z_phase = 0;
	run = 0;
	laser_init = 0;
	laser_on = 0;
	flash = 0;
	x_step = 0;
	y_step = 0;
	z_step = 0;
	run_state = STATE_IDLE;
	charge_pump = 0;
	old_ch_pump = 0;

	// bootup light dance
	AMP_ENABLE_LED = 0;
	LASER_ON_LED = 1;
	delay_ms(250);
	delay_ms(250);
	AMP_ENABLE_LED = 1;
	LASER_ON_LED = 0;
	delay_ms(250);
	delay_ms(250);
	AMP_ENABLE_LED = 0;

	// loop
	while(1) {
		clear_wdt();
		
		// do stuff every 50ms
		if(pir1.TMR1IF) {
			pir1.TMR1IF = 0;
			
			// charge pump
			if(charge_pump) charge_pump --;
			
			// EMERGENCY STOP!
			if(E_STOP_IN) {			
				run_state = STATE_E_STOP;				
				E_STOP_OUT = 0;
				
				// turn off the laser
				ccpr1l = 0x00;  // power level to 0
				ccp1con &= 0xcf;  // power level to 0
				laser_power = 0;
				laser_on = 0;
				LASER_ON_LED = 0;
			
				// turn off motors
				portd = 0;
				portc &= 0x0f;

				// LED flashing
				flash = (flash + 1) & 0x07;
				if(flash & 0x04) {
					AMP_ENABLE_LED = 1;
				}
				else {
					AMP_ENABLE_LED = 0;
				}
			}
			// E STOP cleared - enter idle state
			if(run_state == STATE_E_STOP && !E_STOP_IN) {
				run_state = STATE_IDLE;
				AMP_ENABLE_LED = 0;
				E_STOP_OUT = 1;
			}
			// amplifier enabled - enter run state
			if(run_state == STATE_IDLE && AMP_ENABLE_IN && charge_pump > 0x7f) {
				run_state = STATE_RUN;
				AMP_ENABLE_LED = 1;
				ccpr1l = LASER_TICKLE;  // make tickle puses for the laser
				ccp1con |= 0x30;  // PWM mode
			}
			// amplifier disabled - enter idle state
			if(run_state == STATE_RUN && (!AMP_ENABLE_IN || charge_pump < 0x80)) {
				run_state = STATE_IDLE;
				AMP_ENABLE_LED = 0;

				// turn off the laser
				ccpr1l = 0x00;  // power level to 0
				ccp1con &= 0xcf;  // power level to 0
				laser_power = 0;
				laser_on = 0;
				LASER_ON_LED = 0;
			
				// turn off motors
				portd = 0;
				portc &= 0x0f;
			}
			
			// handle laser power adjustments in run state
			if(run_state == STATE_RUN) {
				// laser power adjust
				if(LASER_DEFEAT_IN) {
					// force laser into tickle
					ccpr1l = LASER_TICKLE;
					laser_power = 0;
					LASER_ON_LED = 0;
				}
				else {
					laser_power = (porta & 0x0f) << 4;
					// if laser is on, change power immediately
					if(laser_on) {
						ccpr1l = laser_power;
						LASER_ON_LED = 1;
					}
				}
			}			
		}
		
		// handle realtime run stuff
		if(run_state == STATE_RUN) {
			step_laser();
		}
		
		// handle charge pump on rising edge
		if(CHARGE_PUMP_IN && !old_ch_pump) {
			if(charge_pump != 0xff) charge_pump ++;
		}
		old_ch_pump = CHARGE_PUMP_IN;
	}
}

void step_laser(void) {
	// step inputs are low - reset the flags
	if(!X_STEP_IN) {
		x_step = 0;
	}
	if(!Y_STEP_IN) {
		y_step = 0;
	}
	if(!Z_STEP_IN) {
		z_step = 0;
	}	
				
	// x step
	if(!x_step && X_STEP_IN) {
		x_step = 1;
		// forward
		if(X_DIR_IN) {
			x_phase = (x_phase - X_STEP_SIZE) & 0x07;
		}
		// reverse
		else {
			x_phase = (x_phase + X_STEP_SIZE) & 0x07;
		}			
		// phases
		if(x_phase == 0) portd = (portd & 0xf0) | 0x05;
		if(x_phase == 1) portd = (portd & 0xf0) | 0x0d;
		if(x_phase == 2) portd = (portd & 0xf0) | 0x09;
		if(x_phase == 3) portd = (portd & 0xf0) | 0x0b;
		if(x_phase == 4) portd = (portd & 0xf0) | 0x0a;
		if(x_phase == 5) portd = (portd & 0xf0) | 0x02;
		if(x_phase == 6) portd = (portd & 0xf0) | 0x06;
		if(x_phase == 7) portd = (portd & 0xf0) | 0x04;
	}
	// y step
	if(!y_step && Y_STEP_IN) {
		y_step = 1;
		// forward
		if(Y_DIR_IN) {
			y_phase = (y_phase - Y_STEP_SIZE) & 0x07;
		}
		// reverse
		else {
			y_phase = (y_phase + Y_STEP_SIZE) & 0x07;
		}
		// phases
		if(y_phase == 0) portd = (portd & 0x0f) | 0x50;
		if(y_phase == 1) portd = (portd & 0x0f) | 0xd0;
		if(y_phase == 2) portd = (portd & 0x0f) | 0x90;
		if(y_phase == 3) portd = (portd & 0x0f) | 0xb0;
		if(y_phase == 4) portd = (portd & 0x0f) | 0xa0;
		if(y_phase == 5) portd = (portd & 0x0f) | 0x20;
		if(y_phase == 6) portd = (portd & 0x0f) | 0x60;
		if(y_phase == 7) portd = (portd & 0x0f) | 0x40;
	}
	// z step
	if(!z_step && Z_STEP_IN) {
		z_step = 1;
		// forward
		if(Z_DIR_IN) {
			z_phase = (z_phase - Z_STEP_SIZE) & 0x07;
		}
		// reverse
		else {
			z_phase = (z_phase + Z_STEP_SIZE) & 0x07;
		}
		// phases
		if(z_phase == 0) portc = (portc & 0x0f) | 0x50;
		if(z_phase == 1) portc = (portc & 0x0f) | 0xd0;
		if(z_phase == 2) portc = (portc & 0x0f) | 0x90;
		if(z_phase == 3) portc = (portc & 0x0f) | 0xb0;
		if(z_phase == 4) portc = (portc & 0x0f) | 0xa0;
		if(z_phase == 5) portc = (portc & 0x0f) | 0x20;
		if(z_phase == 6) portc = (portc & 0x0f) | 0x60;
		if(z_phase == 7) portc = (portc & 0x0f) | 0x40;
	}
	// laser
	if(LASER_IN) {
		ccpr1l = laser_power;
		LASER_ON_LED = 1;
		laser_on = 1;
	}
	else {
		ccpr1l = LASER_TICKLE;
		LASER_ON_LED = 0;
		laser_on = 0;
	}
}