#include "parameters.h" #include "pins.h" #include "extruder.h" //init our variables long max_delta; long x_counter; long y_counter; long z_counter; bool x_can_step; bool y_can_step; bool z_can_step; int milli_delay; void init_steppers() { //init our points. current_units.x = 0.0; current_units.y = 0.0; current_units.z = 0.0; target_units.x = 0.0; target_units.y = 0.0; target_units.z = 0.0; pinMode(X_STEP_PIN, OUTPUT); pinMode(X_DIR_PIN, OUTPUT); pinMode(Y_STEP_PIN, OUTPUT); pinMode(Y_DIR_PIN, OUTPUT); pinMode(Z_STEP_PIN, OUTPUT); pinMode(Z_DIR_PIN, OUTPUT); #ifdef SANGUINO pinMode(X_ENABLE_PIN, OUTPUT); pinMode(Y_ENABLE_PIN, OUTPUT); pinMode(Z_ENABLE_PIN, OUTPUT); #endif //turn them off to start. disable_steppers(); #if ENDSTOPS_MIN_ENABLED == 1 pinMode(X_MIN_PIN, INPUT); pinMode(Y_MIN_PIN, INPUT); pinMode(Z_MIN_PIN, INPUT); #endif #if ENDSTOPS_MAX_ENABLED == 1 pinMode(X_MAX_PIN, INPUT); pinMode(Y_MAX_PIN, INPUT); pinMode(Z_MAX_PIN, INPUT); #endif //figure our stuff. calculate_deltas(); } void dda_move(long micro_delay) { //turn on steppers to start moving =) enable_steppers(); //figure out our deltas max_delta = max(delta_steps.x, delta_steps.y); max_delta = max(delta_steps.z, max_delta); //init stuff. long x_counter = -max_delta/2; long y_counter = -max_delta/2; long z_counter = -max_delta/2; //our step flags bool x_can_step = 0; bool y_can_step = 0; bool z_can_step = 0; //how long do we delay for? if (micro_delay >= 16383) milli_delay = micro_delay / 1000; else milli_delay = 0; //do our DDA line! do { x_can_step = can_step(X_MIN_PIN, X_MAX_PIN, current_steps.x, target_steps.x, x_direction); y_can_step = can_step(Y_MIN_PIN, Y_MAX_PIN, current_steps.y, target_steps.y, y_direction); z_can_step = can_step(Z_MIN_PIN, Z_MAX_PIN, current_steps.z, target_steps.z, z_direction); if (x_can_step) { x_counter += delta_steps.x; if (x_counter > 0) { do_step(X_STEP_PIN); x_counter -= max_delta; if (x_direction) current_steps.x++; else current_steps.x--; } } if (y_can_step) { y_counter += delta_steps.y; if (y_counter > 0) { do_step(Y_STEP_PIN); y_counter -= max_delta; if (y_direction) current_steps.y++; else current_steps.y--; } } if (z_can_step) { z_counter += delta_steps.z; if (z_counter > 0) { do_step(Z_STEP_PIN); z_counter -= max_delta; if (z_direction) current_steps.z++; else current_steps.z--; } } //keep it hot =) manage_all_extruders(); //wait for next step. if (milli_delay > 0) delay(milli_delay); else delayMicrosecondsInterruptible(micro_delay); } while (x_can_step || y_can_step || z_can_step); //set our points to be the same current_units.x = target_units.x; current_units.y = target_units.y; current_units.z = target_units.z; calculate_deltas(); disable_steppers(); } bool can_step(byte min_pin, byte max_pin, long current, long target, byte dir) { //stop us if we're on target if (target == current) return false; #if ENDSTOPS_MIN_ENABLED == 1 //stop us if we're home and still going else if (read_switch(min_pin) && !dir) return false; #endif #if ENDSTOPS_MAX_ENABLED == 1 //stop us if we're at max and still going else if (read_switch(max_pin) && dir) return false; #endif //default to being able to step return true; } void do_step(byte step_pin) { digitalWrite(step_pin, HIGH); delayMicroseconds(5); digitalWrite(step_pin, LOW); } bool read_switch(byte pin) { //dual read as crude debounce #if ENDSTOPS_INVERTING == 1 return !digitalRead(pin) && !digitalRead(pin); #else return digitalRead(pin) && digitalRead(pin); #endif } long to_steps(float steps_per_unit, float units) { return steps_per_unit * units; } void set_target(float x, float y, float z) { target_units.x = x; target_units.y = y; target_units.z = z; calculate_deltas(); } void set_position(float x, float y, float z) { current_units.x = x; current_units.y = y; current_units.z = z; calculate_deltas(); } void calculate_deltas() { //figure our deltas. delta_units.x = abs(target_units.x - current_units.x); delta_units.y = abs(target_units.y - current_units.y); delta_units.z = abs(target_units.z - current_units.z); //set our steps current, target, and delta current_steps.x = to_steps(x_units, current_units.x); current_steps.y = to_steps(y_units, current_units.y); current_steps.z = to_steps(z_units, current_units.z); target_steps.x = to_steps(x_units, target_units.x); target_steps.y = to_steps(y_units, target_units.y); target_steps.z = to_steps(z_units, target_units.z); delta_steps.x = abs(target_steps.x - current_steps.x); delta_steps.y = abs(target_steps.y - current_steps.y); delta_steps.z = abs(target_steps.z - current_steps.z); //what is our direction x_direction = (target_units.x >= current_units.x); y_direction = (target_units.y >= current_units.y); z_direction = (target_units.z >= current_units.z); //set our direction pins as well #if INVERT_X_DIR == 1 digitalWrite(X_DIR_PIN, !x_direction); #else digitalWrite(X_DIR_PIN, x_direction); #endif #if INVERT_Y_DIR == 1 digitalWrite(Y_DIR_PIN, !y_direction); #else digitalWrite(Y_DIR_PIN, y_direction); #endif #if INVERT_Z_DIR == 1 digitalWrite(Z_DIR_PIN, !z_direction); #else digitalWrite(Z_DIR_PIN, z_direction); #endif } long calculate_feedrate_delay(float feedrate) { //how long is our line length? float distance = sqrt(delta_units.x*delta_units.x + delta_units.y*delta_units.y + delta_units.z*delta_units.z); long master_steps = 0; //find the dominant axis. if (delta_steps.x > delta_steps.y) { if (delta_steps.z > delta_steps.x) master_steps = delta_steps.z; else master_steps = delta_steps.x; } else { if (delta_steps.z > delta_steps.y) master_steps = delta_steps.z; else master_steps = delta_steps.y; } //calculate delay between steps in microseconds. this is sort of tricky, but not too bad. //the formula has been condensed to save space. here it is in english: // (feedrate is in mm/minute) // distance / feedrate * 60000000.0 = move duration in microseconds // move duration / master_steps = time between steps for master axis. return ((distance * 60000000.0) / feedrate) / master_steps; } long getMaxSpeed() { if (delta_steps.z > 0) return calculate_feedrate_delay(FAST_Z_FEEDRATE); else return calculate_feedrate_delay(FAST_XY_FEEDRATE); } void enable_steppers() { #ifdef SANGUINO if(target_units.x != current_units.x) digitalWrite(X_ENABLE_PIN, ENABLE_ON); if(target_units.y != current_units.y) digitalWrite(Y_ENABLE_PIN, ENABLE_ON); if(target_units.z != current_units.z) digitalWrite(Z_ENABLE_PIN, ENABLE_ON); #endif } #if 0 void enable_steppers() { // Enable steppers only for axes which are moving // taking account of the fact that some or all axes // may share an enable line (check using macros at // compile time to avoid needless code) // Not enough pins for enable on Arduino #ifdef SANGUINO if ( target_units.x == current_units.x #if X_ENABLE_PIN == Y_ENABLE_PIN && target_units.y == current_units.y #endif #if X_ENABLE_PIN == Z_ENABLE_PIN && target_units.z == current_units.z #endif ) digitalWrite(X_ENABLE_PIN, !ENABLE_ON); else digitalWrite(X_ENABLE_PIN, ENABLE_ON); if ( target_units.y == current_units.y #if Y_ENABLE_PIN == X_ENABLE_PIN && target_units.x == current_units.x #endif #if Y_ENABLE_PIN == Z_ENABLE_PIN && target_units.z == current_units.z #endif ) digitalWrite(Y_ENABLE_PIN, !ENABLE_ON); else digitalWrite(Y_ENABLE_PIN, ENABLE_ON); if ( target_units.z == current_units.z #if Z_ENABLE_PIN == X_ENABLE_PIN && target_units.x == current_units.x #endif #if Z_ENABLE_PIN == Y_ENABLE_PIN && target_units.y == current_units.y #endif ) digitalWrite(Z_ENABLE_PIN, !ENABLE_ON); else digitalWrite(Z_ENABLE_PIN, ENABLE_ON); #endif } #endif void disable_steppers() { #ifdef SANGUINO //disable our steppers digitalWrite(X_ENABLE_PIN, !ENABLE_ON); digitalWrite(Y_ENABLE_PIN, !ENABLE_ON); digitalWrite(Z_ENABLE_PIN, !ENABLE_ON); #endif } void delayMicrosecondsInterruptible(unsigned int us) { #if F_CPU >= 16000000L // for the 16 MHz clock on most Arduino boards // for a one-microsecond delay, simply return. the overhead // of the function call yields a delay of approximately 1 1/8 us. if (--us == 0) return; // the following loop takes a quarter of a microsecond (4 cycles) // per iteration, so execute it four times for each microsecond of // delay requested. us <<= 2; // account for the time taken in the preceeding commands. us -= 2; #else // for the 8 MHz internal clock on the ATmega168 // for a one- or two-microsecond delay, simply return. the overhead of // the function calls takes more than two microseconds. can't just // subtract two, since us is unsigned; we'd overflow. if (--us == 0) return; if (--us == 0) return; // the following loop takes half of a microsecond (4 cycles) // per iteration, so execute it twice for each microsecond of // delay requested. us <<= 1; // partially compensate for the time taken by the preceeding commands. // we can't subtract any more than this or we'd overflow w/ small delays. us--; #endif // busy wait __asm__ __volatile__ ( "1: sbiw %0,1" "\n\t" // 2 cycles "brne 1b" : "=w" (us) : "0" (us) // 2 cycles ); } #ifdef TEST_MACHINE void X_motor_test() { Serial.println("Moving X forward by 100 mm at half maximum speed."); set_target(100, 0, 0); enable_steppers(); dda_move(calculate_feedrate_delay(FAST_XY_FEEDRATE/2)); Serial.println("Pause for 2 seconds."); delay(2000); Serial.println("Moving X back to the start."); set_target(0, 0, 0); enable_steppers(); dda_move(calculate_feedrate_delay(FAST_XY_FEEDRATE/2)); Serial.println("Pause for 2 seconds."); delay(2000); } void Y_motor_test() { Serial.println("Moving Y forward by 100 mm at half maximum speed."); set_target(0, 100, 0); enable_steppers(); dda_move(calculate_feedrate_delay(FAST_XY_FEEDRATE/2)); Serial.println("Pause for 2 seconds."); delay(2000); Serial.println("Moving Y back to the start."); set_target(0, 0, 0); enable_steppers(); dda_move(calculate_feedrate_delay(FAST_XY_FEEDRATE/2)); Serial.println("Pause for 2 seconds."); delay(2000); } void Z_motor_test() { Serial.println("Moving Z down by 5 mm at half maximum speed."); set_target(0, 0, 5); enable_steppers(); dda_move(calculate_feedrate_delay(FAST_Z_FEEDRATE/2)); Serial.println("Pause for 2 seconds."); delay(2000); Serial.println("Moving Z back to the start."); set_target(0, 0, 0); enable_steppers(); dda_move(calculate_feedrate_delay(FAST_Z_FEEDRATE/2)); Serial.println("Pause for 2 seconds."); delay(2000); } #endif