#include #include #include #include #include "WProgram.h" #include "vectors.h" #include "features.h" #include "configuration.h" #include "hostcom.h" #include "intercom.h" #include "pins.h" #include "Temperature.h" #include "pid.h" #include "bed.h" #include "extruder.h" #include "cartesian_dda.h" /** RepRap GCode interpreter. IMPORTANT Before changing this interpreter, read this page: http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes */ // Sanguino G-code Interpreter // Arduino v1.0 by Mike Ellery - initial software (mellery@gmail.com) // v1.1 by Zach Hoeken - cleaned up and did lots of tweaks (hoeken@gmail.com) // v1.2 by Chris Meighan - cleanup / G2&G3 support (cmeighan@gmail.com) // v1.3 by Zach Hoeken - added thermocouple support and multi-sample temp readings. (hoeken@gmail.com) // Sanguino v1.4 by Adrian Bowyer - added the Sanguino; extensive mods... (a.bowyer@bath.ac.uk) // Sanguino v1.5 by Adrian Bowyer - implemented 4D Bressenham XYZ+ stepper control... (a.bowyer@bath.ac.uk) // Sanguino v1.6 by Adrian Bowyer - implemented RS485 extruders // Arduino Mega v1.7 by Adrian Bowyer // Features code v1.8 by David Bussenschutt July 2010 // Maintain a list of extruders... extruder* ex[EXTRUDER_COUNT]; byte extruder_in_use = 0; // Old Mothers... #if EXTRUDER_CONTROLLER == EXTRUDER_CONTROLLER_DC // TODO: For some reason, if you declare the following two in the order ex0 ex1 then // ex0 won't drive its stepper. They seem fine this way round though. But that's got // to be a bug. #if EXTRUDER_COUNT == 2 static extruder ex1(EXTRUDER_1_MOTOR_DIR_PIN, EXTRUDER_1_MOTOR_SPEED_PIN , EXTRUDER_1_HEATER_PIN, EXTRUDER_1_FAN_PIN, EXTRUDER_1_TEMPERATURE_PIN, EXTRUDER_1_VALVE_DIR_PIN, EXTRUDER_1_VALVE_ENABLE_PIN, EXTRUDER_1_STEP_ENABLE_PIN, E1_STEPS_PER_MM); #endif static extruder ex0(EXTRUDER_0_MOTOR_DIR_PIN, EXTRUDER_0_MOTOR_SPEED_PIN , EXTRUDER_0_HEATER_PIN, EXTRUDER_0_FAN_PIN, EXTRUDER_0_TEMPERATURE_PIN, EXTRUDER_0_VALVE_DIR_PIN, EXTRUDER_0_VALVE_ENABLE_PIN, EXTRUDER_0_STEP_ENABLE_PIN, E0_STEPS_PER_MM); static bed heatedBed(BED_HEATER_PIN, BED_TEMPERATURE_PIN); #endif // extruder controller // Standard Mendel, #if EXTRUDER_CONTROLLER == EXTRUDER_CONTROLLER_RS485 #if EXTRUDER_COUNT == 2 static extruder ex1(E1_NAME, E1_STEPS_PER_MM); #endif static extruder ex0(E0_NAME, E0_STEPS_PER_MM); intercom talker; #endif // extruder controller // Arduino Mega and friends #if EXTRUDER_CONTROLLER == EXTRUDER_CONTROLLER_INTERNAL #if EXTRUDER_COUNT == 2 static extruder ex1(EXTRUDER_1_STEP_PIN, EXTRUDER_1_DIR_PIN, EXTRUDER_1_ENABLE_PIN, EXTRUDER_1_HEATER_PIN, EXTRUDER_1_TEMPERATURE_PIN, E1_STEPS_PER_MM); #endif static extruder ex0(EXTRUDER_0_STEP_PIN, EXTRUDER_0_DIR_PIN, EXTRUDER_0_ENABLE_PIN, EXTRUDER_0_HEATER_PIN, EXTRUDER_0_TEMPERATURE_PIN, E0_STEPS_PER_MM); #if HEATED_BED == HEATED_BED_ON static bed heatedBed(BED_HEATER_PIN, BED_TEMPERATURE_PIN); #endif //heated bed #endif // extruder controller static hostcom talkToHost; // Each entry in the buffer is an instance of cartesian_dda. cartesian_dda* cdda[BUFFER_SIZE]; static cartesian_dda cdda0; static cartesian_dda cdda1; static cartesian_dda cdda2; static cartesian_dda cdda3; volatile byte head; volatile byte tail; bool led; word interruptBlink; // Where the machine is from the point of view of the command stream FloatPoint where_i_am; // Our interrupt function /* This has an internal flag (nonest) to prevent its being interrupted by another timer interrupt. It re-enables interrupts internally (not something that one would normally do with an ISR). This allows USART interrupts to be serviced while this ISR is also live, and so prevents communications errors. */ volatile bool nonest; ISR(TIMER1_COMPA_vect) { if(nonest) return; nonest = true; sei(); interruptBlink++; if(interruptBlink == 0x280) { blink(); interruptBlink = 0; } if(cdda[tail]->active()) cdda[tail]->dda_step(); else dQMove(); nonest = false; } void setup() { nonest = false; disableTimerInterrupt(); setupTimerInterrupt(); interruptBlink = 0; pinMode(DEBUG_PIN, OUTPUT); led = false; setupGcodeProcessor(); ex[0] = &ex0; #if EXTRUDER_COUNT == 2 ex[1] = &ex1; #endif extruder_in_use = 0; head = 0; tail = 0; cdda[0] = &cdda0; cdda[1] = &cdda1; cdda[2] = &cdda2; cdda[3] = &cdda3; for(byte i = 0; i < 4; i++) cdda[i]->set_units(true); //setExtruder(); init_process_string(); talkToHost.start(); // turn on remote powersupply, if it's possible #ifdef PS_ON_PIN pinMode(PS_ON_PIN, OUTPUT); // add to run G3 as built by makerbot digitalWrite(PS_ON_PIN, LOW); // ditto delay(2000); #endif #if EXTRUDER_CONTROLLER == EXTRUDER_CONTROLLER_RS485 rs485Interface.begin(RS485_BAUD); #endif setTimer(DEFAULT_TICK); enableTimerInterrupt(); } // This does a hard stop. It disables interrupts, turns off all the motors // (regardless of DISABLE_X etc), and calls extruder.shutdown() for each // extruder. It then spins in an endless loop, never returning. The only // way out is to press the reset button. void shutdown() { // No more stepping or other interrupts cli(); // Delete everything in the ring buffer cancelAndClearQueue(); // Motors off #if DISABLE_X digitalWrite(X_ENABLE_PIN, !ENABLE_ON); #endif #if DISABLE_Y digitalWrite(Y_ENABLE_PIN, !ENABLE_ON); #endif #if DISABLE_Z digitalWrite(Z_ENABLE_PIN, !ENABLE_ON); #endif // Stop the extruders for(byte i = 0; i < EXTRUDER_COUNT; i++) ex[i]->shutdown(); // If we run the bed, turn it off. #if HEATED_BED == HEATED_BED_ON heatedBed.shutdown(); #endif // int a=50; // while(a--) {blink(); delay(50);} // LED off digitalWrite(DEBUG_PIN, 0); // Till the end of time... for(;;); } // Keep all extruders, bed, up to temperature etc. void manage() { for(byte i = 0; i < EXTRUDER_COUNT; i++) ex[i]->manage(); #if HEATED_BED == HEATED_BED_ON heatedBed.manage(); #endif } //long count = 0; //int ct1 = 0; void loop() { nonest = false; manage(); get_and_do_command(); #if EXTRUDER_CONTROLLER == EXTRUDER_CONTROLLER_RS485 talker.tick(); #endif } //****************************************************************************************** // The move buffer inline void cancelAndClearQueue() { tail = head; // clear buffer for(int i=0;ishutdown(); } inline bool qFull() { if(tail == 0) return head == (BUFFER_SIZE - 1); else return head == (tail - 1); } inline bool qEmpty() { return tail == head && !cdda[tail]->active(); } inline void qMove(const FloatPoint& p) { while(qFull()) delay(WAITING_DELAY); byte h = head; h++; if(h >= BUFFER_SIZE) h = 0; cdda[h]->set_target(p); head = h; } inline void dQMove() { if(qEmpty()) return; byte t = tail; t++; if(t >= BUFFER_SIZE) t = 0; cdda[t]->dda_start(); tail = t; } inline void setUnits(bool u) { for(byte i = 0; i < BUFFER_SIZE; i++) cdda[i]->set_units(u); } inline void setPosition(const FloatPoint& p) { where_i_am = p; } void blink() { led = !led; if(led) digitalWrite(DEBUG_PIN, 1); else digitalWrite(DEBUG_PIN, 0); } //****************************************************************************************** // Interrupt functions void setupTimerInterrupt() { //clear the registers TCCR1A = 0; TCCR1B = 0; TCCR1C = 0; TIMSK1 = 0; //waveform generation = 0100 = CTC TCCR1B &= ~(1<