From f099318850548f3ec73c6b42674e0e35b3d51c1d Mon Sep 17 00:00:00 2001 From: Mikel564324 <97843562+Mikel564324@users.noreply.github.com> Date: Fri, 28 Jan 2022 17:41:38 -0600 Subject: [PATCH 1/3] 3DsimoKit2_Freemode Updated Kit2 firmware to enable Freemode for the 3D drawing accessory. I updated the Kit2 with changes made to the original Kit by user AnTi-ArT. --- FW/3DsimoKit2_Freemode.ino | 115 +++++++ FW/NanodeUNIO.h | 136 +++++++++ FW/NanodeUNIO_Freemode.c | 302 +++++++++++++++++++ FW/accessories.h | 61 ++++ FW/accessories_Freemode.c | 597 +++++++++++++++++++++++++++++++++++++ FW/config_Freemode.h | 61 ++++ 6 files changed, 1272 insertions(+) create mode 100644 FW/3DsimoKit2_Freemode.ino create mode 100644 FW/NanodeUNIO.h create mode 100644 FW/NanodeUNIO_Freemode.c create mode 100644 FW/accessories.h create mode 100644 FW/accessories_Freemode.c create mode 100644 FW/config_Freemode.h diff --git a/FW/3DsimoKit2_Freemode.ino b/FW/3DsimoKit2_Freemode.ino new file mode 100644 index 0000000..afc190b --- /dev/null +++ b/FW/3DsimoKit2_Freemode.ino @@ -0,0 +1,115 @@ +/* + * ssd1306 128x32 Alexey Dinda Library + */ +#include +#include +#include "config_Freemode.h" +#include "ssd1306.h" +#include "nano_gfx.h" +#include "nanodeUNIO.h" +#include "accessories.h" +#include + +/* + * create timer for main loop + */ +EveryTimer timer; + +bool righthanded = true; +bool pressUPDOWNhandled = true; +extern int materialID; + +/* + * call every 50ms timer for buttons action and heating + * execute buttons function according to heating state + * change material profile + */ +void timerAction(){ + accessories_t acs; + static accessories_t acsLast; + char text[20]; + + acsIdentify(); + acs = getAccessories(); + + if(acsLast.type != acs.type){ + ssd1306_clearScreen(); + } + + if(acs.type == ACS_NONE){ + sprintf(text, "No tip "); + ssd1306_setFixedFont(ssd1306xled_font6x8); + ssd1306_printFixedN(0, 0, text, STYLE_NORMAL, FONT_SIZE_2X); + + sprintf(text, "Connected "); + ssd1306_setFixedFont(ssd1306xled_font6x8); + ssd1306_printFixedN(0, 16, text, STYLE_NORMAL, FONT_SIZE_2X); + } + else { + acs.function(); + } + if(acs.type != acsLast.type){ + acs.startup(); + } + acsLast = acs; +} + + +/* + * GPIO, OLED initialize + * load material profile + * preset timer + */ +void setup() { + + // initialize OLED display + ssd1306_128x32_i2c_init(); + ssd1306_clearScreen(); + ssd1306_flipHorizontal(1); /* oled_ssd1306.h NEW! rotate screen in X */ + ssd1306_flipVertical(1); /* oled_ssd1306.h NEW! rotate screen in Y */ + + + + // initialize outputs + digitalWrite(HEATER_EN, HIGH); + digitalWrite(HIGH_TEMP_EN, LOW); + digitalWrite(LOW_TEMP_EN, HIGH); + + pinMode(LED_R, OUTPUT); + pinMode(LED_L, OUTPUT); + pinMode(MOTOR_DIR, OUTPUT); + pinMode(MOTOR_PWM, OUTPUT); + pinMode(MOTOR_SLEEP, OUTPUT); + pinMode(HEATER_EN, OUTPUT); + pinMode(HIGH_TEMP_EN, OUTPUT); + pinMode(LOW_TEMP_EN, OUTPUT); + + // initialize inputs + pinMode(BTN_UP, INPUT_PULLUP); + pinMode(BTN_DOWN, INPUT_PULLUP); + pinMode(BTN_EXT, INPUT_PULLUP); + pinMode(BTN_REV, INPUT_PULLUP); + + // preset timer period every 50 ms and call timerAction function when time expire + timer.Every(50, timerAction); + + // initialize outputs + digitalWrite(MOTOR_SLEEP, HIGH); + + Serial.begin(9600); +} + +/* + * main loop + */ +void loop() { + // call timer each preset period + timer.Update(); + + if (Serial.available() > 0) { + char incomingByte; + // read the incoming byte: + incomingByte = Serial.read(); + Serial.write(incomingByte); + } +} diff --git a/FW/NanodeUNIO.h b/FW/NanodeUNIO.h new file mode 100644 index 0000000..9f48ee7 --- /dev/null +++ b/FW/NanodeUNIO.h @@ -0,0 +1,136 @@ +/* Copyright (C) 2011 by Stephen Early + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include + +#ifndef _NANODEUNIO_LIB_H +#define _NANODEUNIO_LIB_H + +// #if ARDUINO >= 100 +// #include // Arduino 1.0 +// #else +// #include // Arduino 0022 +// #endif + +/* Class to access Microchip UNI/O devices connected to pin 7 of the + Nanode, such as the 11AA02E48 MAC address chip. Multiple UNI/O + devices may be connected to this pin, provided they have different + addresses. The 11AA161 2048-char EEPROM has address 0xa1, and so + may be connected along with the 11AA02E48 if the application needs + extra non-volatile storage space. */ + +/* The 11AA02E48 has address 0xa0; the MAC address is stored at offset + 0xfa within it. */ +#define NANODE_MAC_DEVICE 0xa0 +#define NANODE_MAC_ADDRESS 0xfa + +/* Microchip indicate that there may be more device types coming for + this bus - temperature sensors, display controllers, I/O port + expanders, A/D converters, and so on. They will have different + addresses and so can all be connected to the same pin. Don't hold + your breath though! */ +void nanode_init(void); + +//class NanodeUNIO { + //private: + //char addr; + //public: + void NanodeUNIO(uint8_t address); + + /* All the following calls return true for success and false for + failure. */ + + /* Read from memory into the buffer, starting at 'address' in the + device, for 'length' chars. Note that on failure the buffer may + still have been overwritten. */ + bool read(char *buffer,int address,int length); + + /* Write data to memory. The write must not overlap a page + boundary; pages are 16 chars long, starting at zero. Will return + false if this condition is not met, or if there is a problem + communicating with the device. If the write enable bit is not + set, this call will appear to succeed but will do nothing. + + This call returns as soon as the data has been sent to the + device. The write proceeds in the background. You must check + the status register to find out when the write has completed, + before setting the write enable bit and writing more data. Call + await_write_complete() if you want to block until the write is + finished. */ + bool start_write(const char *buffer,int address,int length); + + /* Set the write enable bit. This must be done before EVERY write; + the bit is cleared on a successful write. */ + bool enable_write(void); + + /* Clear the write enable bit. */ + bool disable_write(void); + + /* Read the status register into *status. The bits in this register are: + 0x01 - write in progress + 0x02 - write enable + 0x04 - block protect 0 + 0x08 - block protect 1 */ + bool read_status(char *status); + + /* Write to the status register. Bits are as shown above; only bits + BP0 and BP1 may be written. Values that may be written are: + 0x00 - entire device may be written + 0x04 - upper quarter of device is write-protected + 0x08 - upper half of device is write-protected + 0x0c - whole device is write-protected + + The MAC address chip on the Nanode is shipped with the upper quarter + of the device write-protected. If you disable write-protection, + it is possible to overwrite the MAC address pre-programmed into the + device; this is stored in the last 6 chars (at address 0x00fa). + Be careful! + + The write enable bit must be set before a write to the status + register will succeed. The bit will be cleared on a successful + write. You must wait for the write in progress bit to be clear + before continuing (call await_write_complete()). */ + bool write_status(char status); + + /* Wait until there is no write operation in progress. */ + bool await_write_complete(void); + + /* Write to the device, dealing properly with setting the write + enable bit, avoiding writing over page boundaries, and waiting + for the write to complete. Note that this function may take a + long time to complete - approximately 5ms per 16 chars or part + thereof. Will NOT alter the write-protect bits, so will not + write to write-protected parts of the device - although the + return code will not indicate that this has failed. */ + bool simple_write(const char *buffer,int address,int length); + + + void unio_standby_pulse(void); // send standby pulse + + /* + Set device address + */ + void set_addr(char a); + +//}; + +#endif /* _NANODEUNIO_LIB_H */ diff --git a/FW/NanodeUNIO_Freemode.c b/FW/NanodeUNIO_Freemode.c new file mode 100644 index 0000000..a501579 --- /dev/null +++ b/FW/NanodeUNIO_Freemode.c @@ -0,0 +1,302 @@ +/* Copyright (C) 2011 by Stephen Early + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "config_Freemode.h" +#include "NanodeUNIO.h" +#include +#include + + +#define UNIO_STARTHEADER 0x55 +#define UNIO_READ 0x03 +#define UNIO_CRRD 0x06 +#define UNIO_WRITE 0x6c +#define UNIO_WREN 0x96 +#define UNIO_WRDI 0x91 +#define UNIO_RDSR 0x05 +#define UNIO_WRSR 0x6e +#define UNIO_ERAL 0x6d +#define UNIO_SETAL 0x67 + +// The following are defined in the datasheet as _minimum_ times, in +// microseconds. There is no maximum. +#define UNIO_TSTBY 600 // 600 +#define UNIO_TSS 5 // 10 +#define UNIO_THDR 5 // 5 + +#define UNIO_QUARTER_BIT 20 + +// Add this to all the times defined above, to be on the safe side! +#define UNIO_FUDGE_FACTOR 0 + +#define UNIO_OUTPUT() pinMode(ID_PIN, OUTPUT) +#define UNIO_INPUT() pinMode(ID_PIN, INPUT) + +char addr = 0; + +void set_addr(char a) { + addr = a; +} + +void set_bus(bool state) { + digitalWrite(ID_PIN, state); +} + +bool read_bus(void) { + return digitalRead(ID_PIN); +} + +/* If multiple commands are to be issued to a device without a standby + pulse in between, the bus must be held high for at least UNIO_TSS + between the end of one command and the start of the next. */ +void unio_inter_command_gap(void) { + set_bus(1); + delayMicroseconds(UNIO_TSS+UNIO_FUDGE_FACTOR); +} + +/* Send a standby pulse on the bus. After power-on or brown-out + reset, the device requires a low-to-high transition on the bus at + the start of the standby pulse. To be conservative, we take the + bus low for UNIO_TSS, then high for UNIO_TSTBY. */ +void unio_standby_pulse(void) { + set_bus(0); + UNIO_OUTPUT(); + delayMicroseconds(UNIO_TSS+UNIO_FUDGE_FACTOR); + set_bus(1); + //delayMicroseconds(UNIO_TSTBY+UNIO_FUDGE_FACTOR); // replaced by tmr0 overflow + +} + +void wait_int(void){ + delayMicroseconds(UNIO_QUARTER_BIT); +} + +/* While bit-banging, all delays are expressed in terms of quarter + bits. We use the same code path for reading and writing. During a + write, we perform dummy reads at 1/4 and 3/4 of the way through + each bit time. During a read we perform a dummy write at the start + and 1/2 way through each bit time. */ + +static volatile bool rwbit(bool w) { + bool a,b; + set_bus(!w); + wait_int(); + a=read_bus(); + wait_int(); + set_bus(w); + wait_int(); + b=read_bus(); + wait_int(); + return b&&!a; +} + +static bool read_bit(void) { + bool b; + UNIO_INPUT(); + b=rwbit(1); + UNIO_OUTPUT(); + return b; +} + +static bool send_char(char b, bool mak) { + for (int i=0; i<8; i++) { + rwbit(b&0x80); + b<<=1; + } + rwbit(mak); + return read_bit(); +} + +static bool read_char(char *b, bool mak) { + char data=0; + UNIO_INPUT(); + for (int i=0; i<8; i++) { + data = (data << 1) | rwbit(1); + } + UNIO_OUTPUT(); + *b=data; + rwbit(mak); + return read_bit(); +} + +/* Send data on the bus. If end is true, send NoMAK after the last + char; otherwise send MAK. */ +static bool unio_send(const char *data,int length,bool end) { + for (int i=0; i>8); + cmd[3]=(char)(address&0xff); + //unio_standby_pulse(); + //cli(); + unio_start_header(); + if (!unio_send(cmd,4,false)) fail(); + if (!unio_read(buffer,length)) fail(); + //sei(); + return true; +} + +bool start_write(const char *buffer,int address,int length) { + char cmd[4]; + if (((address&0x0f)+length)>16) return false; // would cross page boundary + cmd[0]=addr; + cmd[1]=UNIO_WRITE; + cmd[2]=(char)(address>>8); + cmd[3]=(char)(address&0xff); + //unio_standby_pulse(); + //cli(); + unio_start_header(); + if (!unio_send(cmd,4,false)) fail(); + if (!unio_send(buffer,length,true)) fail(); + //sei(); + return true; +} + +bool enable_write(void) { + char cmd[2]; + cmd[0]=addr; + cmd[1]=UNIO_WREN; + //unio_standby_pulse(); + //cli(); + unio_start_header(); + if (!unio_send(cmd,2,true)) fail(); + //sei(); + return true; +} + +bool disable_write(void) { + char cmd[2]; + cmd[0]=addr; + cmd[1]=UNIO_WRDI; + //unio_standby_pulse(); + //cli(); + unio_start_header(); + if (!unio_send(cmd,2,true)) fail(); + //sei(); + return true; +} + +bool read_status(char *status) { + char cmd[2]; + cmd[0]=addr; + cmd[1]=UNIO_RDSR; + //unio_standby_pulse(); + //cli(); + unio_start_header(); + if (!unio_send(cmd,2,false)) fail(); + if (!unio_read(status,1)) fail(); + //sei(); + return true; +} + +bool write_status(char status) { + char cmd[3]; + cmd[0]=addr; + cmd[1]=UNIO_WRSR; + cmd[2]=status; + //unio_standby_pulse(); + //cli(); + unio_start_header(); + if (!unio_send(cmd,3,true)) fail(); + //sei(); + return true; +} + +bool await_write_complete(void) { + char cmd[2]; + char status; + cmd[0]=addr; + cmd[1]=UNIO_RDSR; + //unio_standby_pulse(); + /* Here we issue RDSR commands back-to-back until the WIP bit in the + status register is cleared. Note that this isn't absolutely the + most efficient way to monitor this bit; after sending the command + we could read as many chars as we like as long as we send MAK + after each char. The unio_read() function isn't set up to do + this, though, and it's not really performance-critical compared + to the eeprom write time! We re-enable interrupts briefly between + each command so that any background tasks like updating millis() + continue to happen.*/ + do { + unio_inter_command_gap(); + //cli(); + unio_start_header(); + if (!unio_send(cmd,2,false)) fail(); + if (!unio_read(&status,1)) fail(); + //sei(); + } while (status&0x01); + return true; +} + +bool simple_write(const char *buffer,int address,int length) { + int wlen; + while (length>0) { + wlen=length; + if (((address&0x0f)+wlen)>16) { + /* Write would cross a page boundary. Truncate the write to the + page boundary. */ + wlen=16-(address&0x0f); + } + if (!enable_write()) return false; + if (!start_write(buffer,address,wlen)) return false; + if (!await_write_complete()) return false; + buffer+=wlen; + address+=wlen; + length-=wlen; + } + return true; +} diff --git a/FW/accessories.h b/FW/accessories.h new file mode 100644 index 0000000..9338f85 --- /dev/null +++ b/FW/accessories.h @@ -0,0 +1,61 @@ +#include + +#ifndef _ACCESSORIES_H +#define _ACCESSORIES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define NO_ITERATIONS 10 // iteration for accessories identification + +// define callBack function for accessories list +typedef void (*callBack)(void); + +// define a structure of accessories list +typedef struct{ + char ID; + char type; + char* name; + callBack function; + callBack startup; +} accessories_t; + + +#define ACCS(i, t, n, f, s) {.ID = i, .type = t, .name = n, .function = f, .startup = s} + +enum ACCESSORIES_TYPE{ + ACS_NONE, + ACS_3D_DRAW = 1, + ACS_BURNING = 2, + ACS_SOLDERING = 3, + ACS_FOAM_CUTTING = 4, +}; + +enum ACCESSORIES_ID{ + ACS_ID_NONE = 0x00, + + ACS_ID_BURNING = 0x64, + ACS_ID_FOAM_CUTTING = 0x24, + ACS_ID_3D_DRAW = 0x35, + ACS_ID_SOLDERING = 0x52, +}; + + +// return identified accessories +void acsIdentify(void); + +accessories_t getAccessories(void); + +void loadMaterial(int id); +void startup3D(void); +void startupBurning(void); +void startupSoldering(void); +void startupFoamCutting(void); +void startupNone(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _NANODEUNIO_LIB_H */ diff --git a/FW/accessories_Freemode.c b/FW/accessories_Freemode.c new file mode 100644 index 0000000..2e80129 --- /dev/null +++ b/FW/accessories_Freemode.c @@ -0,0 +1,597 @@ +#include "config_Freemode.h" +#include "ssd1306.h" +#include "nanodeUNIO.h" +#include "accessories.h" +#include +#include +#include + +accessories_t accessories; + +/* + define material profiles for 3D extension + didn't remove for Freemode but shouldn't affect anything +*/ +const profile_t materials[] PROGMEM = { + // {temperature (deg. C), motorSpeed (%), materialName} + {0, 0, "OFF"}, /* NEW! BEGIN OFF - BUT IF YOU SELECT THIS AFTER PETG, 3DPEN COOLS TO 153º PRIOR TO SHUTDOWN*/ + {230, 60, "PLA"}, + {250, 50, "ABS"}, + {245, 60, "PETG"}, +}; + +#define MAXSPEED 70 // for safety. change this up to 100 (%), if you know what you are doing. +#define MAXTEMP 275 // not sure whats better: define or const, also not sure about the actual max temp... testing with 300 +#define MINTEMP 155 // 153/154 is the lowest measurement possible. actual temperature can be lower. + // We can use this to put heater in off mode (COOLING) if we choose "150°C" aka "LOW". However: hot temperatures will start at 155°C + +int setTemperature = 0; // set heater temperature (we raise this directly to "155" when up button is pressed once. and drop it down to "0" if the user goes below "155") +int setMotorSpeed = 40; // set motor speed in % + // ToDo maybe add icrement step value (hardcoded at 5) +char controlMode = MODE_TEMP; // Control Mode: MODE_TEMP or MODE_SPEED. selects which values the UP-DOWN buttons change + +/* + define number of materials in list and variables +*/ +const int MATERIAL_COUNT = sizeof(materials)/sizeof(profile_t); + +int materialID = 0; // chosen material profile + + +int elapsedTime = 0; +char statusHeating = STATE_HEATING; +char stateMotor = MOTOR_STOP, lastMotorState = MOTOR_STOP; +int timeMotorReverse = 0; +char powerPercent = 50; + +void startup3D(void) { + loadMaterial(materialID); + digitalWrite(MOTOR_DIR, LOW); + analogWrite(MOTOR_PWM, 0); +} + +void startupBurning(void) { + analogWrite(HEATER_EN, 255); + digitalWrite(MOTOR_DIR, LOW); + analogWrite(MOTOR_PWM, 0); + powerPercent = 50; +} + +void startupSoldering(void) { + analogWrite(HEATER_EN, 255); + digitalWrite(MOTOR_DIR, LOW); + analogWrite(MOTOR_PWM, 0); + powerPercent = 50; +} + +void startupFoamCutting(void) { + analogWrite(HEATER_EN, 255); + digitalWrite(MOTOR_DIR, LOW); + analogWrite(MOTOR_PWM, 0); + powerPercent = 50; +} + +void startupNone(void) { + analogWrite(HEATER_EN, 255); + digitalWrite(MOTOR_DIR, LOW); + analogWrite(MOTOR_PWM, 0); + powerPercent = 50; +} + +void percentRoutine(void){ + char text[15]; + // button UP pressed + if (!digitalRead(BTN_UP) && digitalRead(BTN_DOWN)) { + if (powerPercent < 100) { + ++powerPercent; + } + } + + // button DOWN pressed + if (digitalRead(BTN_UP) && !digitalRead(BTN_DOWN)) { + if (powerPercent > 0) { + --powerPercent; + } + } + + // button EXTRUSION pressed + if (!digitalRead(BTN_REV)) { + int output = (255*(100-powerPercent))/100; + analogWrite(HEATER_EN, output); + + // indicate that extension is working + digitalWrite(LED_R, HIGH); // turn the LED on + digitalWrite(LED_L, HIGH); // turn the LED on + } + else{ + analogWrite(HEATER_EN, 255); + + // indicate that extension is not working + digitalWrite(LED_R, LOW); // turn the LED off + digitalWrite(LED_L, LOW); // turn the LED off + } + + sprintf(text, "%s", accessories.name); + ssd1306_setFixedFont(ssd1306xled_font6x8); + ssd1306_printFixedN(0, 0, text, STYLE_NORMAL, FONT_SIZE_2X); + + sprintf(text, "%3d %%", powerPercent); + ssd1306_setFixedFont(ssd1306xled_font6x8); + ssd1306_printFixedN(0, 16, text, STYLE_NORMAL, FONT_SIZE_2X); +} + +/* + * function for measuring temperature of the tip in ranges 40-130 deg.C and 185-350 deg.C + * with automatic autorange function + * + * forbidden range is from 130 C to 185 C, because temperature is inacurate and unstable + */ +int getTemperature() { // get temperature in deg. Celsius from ADU value + long avgTemp = 0; + char text[10]; + + // set reference for ADC to power supply (5V) + analogReference(DEFAULT); + + // enable measuring for high temperatures + digitalWrite(HIGH_TEMP_EN, LOW); + digitalWrite(LOW_TEMP_EN, HIGH); + delayMicroseconds(1000); + + for (int i = 0; i < 16; i++) { + avgTemp += analogRead(TEMP_IN); + } + + // read averaged analog value of temperature + long tempADU; + + // decide if high temperatures are possible to measure, 980 according to ~160 deg. C + if ((avgTemp >> 4) > 980) { + // enable measuring for low temperatures + digitalWrite(HIGH_TEMP_EN, HIGH); + digitalWrite(LOW_TEMP_EN, LOW); + delayMicroseconds(1000); + + avgTemp = 0; + for (int i = 0; i < 16; i++) { + avgTemp += analogRead(TEMP_IN); + } + + // convert ADU into temperature (multiplied by 10 -> 200deg = 2000) + // constants could slightly change for different ceramic tip + // T = -0.1232*ADU + 146.1 + // Low temperatures (approx. 40 - 120 deg.) + tempADU = avgTemp; + tempADU *= -1261; // -1261 = -0.1232*1024 + tempADU >>= 14; + tempADU += 1461; + + } + else { + // convert ADU into temperature + // constants could slightly change for different ceramic tip + // T = -0.2059*ADU + 351.4 + // High temperatures (approx. 180 - 280 deg.) + tempADU = avgTemp; + tempADU *= -2108; // -2108 = -0.2059*1024 + tempADU >>= 14; + tempADU += 3514; + } + + return tempADU; +} + +/* + load actual material profile +*/ +void loadMaterial(int id) { + profile_t profile; + char text[10]; + + // load material profile from PROGMEM and assign variables + memcpy_P(&profile, &materials[id], sizeof(profile_t)); +/* + setTemperature = profile.temperature; + setMotorSpeed = profile.motorSpeed; +*/ + // clear display and show all information +/* sprintf(text, "%d %%", setMotorSpeed); + ssd1306_clearScreen(); + ssd1306_setFixedFont(ssd1306xled_font6x8); + ssd1306_printFixedN(0, 0, profile.materialName, STYLE_NORMAL, FONT_SIZE_2X); + ssd1306_printFixedN(80, 0, text, STYLE_NORMAL, FONT_SIZE_2X);*/ + +} + +/* + PID variables and constants for tuning +*/ +float Kp = 3.2, Ki = 0.33, Kd = 0.14, dT = 0.1, Hz = 10; + +/* + basic PID routine to get output value +*/ +int getPIDoutput(int setPoint, int actualValue, int maxValue, int minValue) { + static float sumE = 0; + static int16_t error, previousError = 0; + float outputValue; + static int pidAvg[4] = {0, 0, 0, 0}; + static int pidAvgIndex = 0; + + // reset sumE when actualValue exceed setPoint by 5 + static int noWaitCycles = 0; + + if (actualValue > setPoint + 50) { + ++noWaitCycles; + if (noWaitCycles >= 30) { + sumE = maxValue; + noWaitCycles = 0; + } + } + else { + noWaitCycles = 0; + } + + // PID implementation + error = setPoint - actualValue; + sumE += (float) error * dT; + outputValue = Kp * error + Ki * sumE + Kd * (error - previousError) / dT; + previousError = error; + + // restrict output PID value into range between minValue and maxValue + if (outputValue > maxValue) + outputValue = maxValue; + else if (outputValue < minValue) + outputValue = minValue; + + // store n output values for averaging + pidAvg[pidAvgIndex] = outputValue; + ++pidAvgIndex; + if (pidAvgIndex >= 4) + pidAvgIndex = 0; + + // average last n output values + int sumPIDavg = 0; + for (int i = 0; i < 4; i++) { + sumPIDavg += pidAvg[i]; + } + sumPIDavg >>= 2; + + return sumPIDavg; +} + +#define NO_AVERAGES_VALUES 64 + +/* + heating function for heater driving by PID regulator +*/ +int heating() { + static int tempAvg[NO_AVERAGES_VALUES]; // temperature array for averaging it + static int tempAvgIter = 0; // current index in temperature array + static char firstTime = 0; // if is 1, this function ran at least one time + char text[30]; // buffer for text + + // variables initialization + if (!firstTime) { + memset(tempAvg, 0, NO_AVERAGES_VALUES*sizeof(int)); + firstTime = 1; + } + + // resolve PID value for heater PWM + int temperature = getTemperature(); + int valuePID = getPIDoutput(setTemperature*10, temperature, 255, 0); + + analogWrite(HEATER_EN, 255 - valuePID); + + // save actual temperature for averaging + tempAvg[tempAvgIter] = temperature; + if (++tempAvgIter >= NO_AVERAGES_VALUES) + tempAvgIter = 0; + + // make temperature average from NO_AVERAGES_VALUES + long sumTemp = 0; + for (int i = 0; i < NO_AVERAGES_VALUES; i++) { + sumTemp += tempAvg[i]; + } + sumTemp /= NO_AVERAGES_VALUES; + + +displayControls(); + // show on display actual and preset temperature + sprintf(text, "%3d", (int)sumTemp/10); + ssd1306_setFixedFont(ssd1306xled_font6x8); + ssd1306_printFixedN(0, 0, text, STYLE_NORMAL, FONT_SIZE_2X); + ssd1306_printFixedN(39, 12, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); + + + return sumTemp; +} + +void acs3Ddrawing() { + // decide temperature state (heating, cooling, ready) and show it on display + if (++elapsedTime == 2) { // 100ms + elapsedTime = 0; + int actualTemperature = heating(); + + // tolerant zone where temperature is ABOVE preset temperature, + // but it is possible to do extrusion/reverse + if (actualTemperature > setTemperature*10 + 100) { + statusHeating = STATE_COOLING; + ssd1306_printFixedN(64, 0, "Cooling", STYLE_NORMAL, FONT_SIZE_NORMAL); + } + + // tolerant zone where temperature is OK for extrusion/reverse + else if (actualTemperature > setTemperature*10 - 100) { + statusHeating = STATE_READY; + ssd1306_printFixedN(64, 0, "Ready ", STYLE_NORMAL, FONT_SIZE_NORMAL); //spaces used instead of clearing space as heating is longer + digitalWrite(LED_R, HIGH); // turn the LED on (HIGH is the voltage level) + digitalWrite(LED_L, HIGH); // turn the LED on (HIGH is the voltage level) + } + + // tolerant zone where temperature is LOW for extrusion/reverse + else { + statusHeating = STATE_HEATING; + ssd1306_printFixedN(64, 0, "Heating", STYLE_NORMAL, FONT_SIZE_NORMAL); + digitalWrite(LED_R, !digitalRead(LED_R)); // turn the LED on (HIGH is the voltage level) + digitalWrite(LED_L, !digitalRead(LED_L)); // turn the LED on (HIGH is the voltage level) + } + } + + // assing functions according to heating state (mainly button function) + switch (statusHeating) { + case STATE_COOLING: + case STATE_READY: { + // button EXTRUSION is pressed, extrude material + if (!digitalRead(BTN_EXT) && digitalRead(BTN_REV)) { + stateMotor = MOTOR_EXTRUSION; + } + + // button REVERSE is pressed, retract material + else if (digitalRead(BTN_EXT) && !digitalRead(BTN_REV)) { + stateMotor = MOTOR_REVERSE; + timeMotorReverse = 400; // reverse time is 50ms * timeMotorReverse (400 = 20s) + } + + // both buttons are pressed, motor stopped + else if (!digitalRead(BTN_EXT) && !digitalRead(BTN_REV)) { + stateMotor = MOTOR_STOP; + } + + // no buttons are pressed + else { + if (lastMotorState == MOTOR_EXTRUSION) { + stateMotor = MOTOR_REVERSE_AFTER_EXTRUSION; + timeMotorReverse = 20; // reverse time is 50ms * timeMotorReverse (20 = 1s) + } + } + break; + } + + case STATE_HEATING: + // if happened that heater has so low temperature, motor stop + digitalWrite(MOTOR_DIR, LOW); + analogWrite(MOTOR_PWM, 0); + stateMotor = MOTOR_STOP; + break; + } + + // resolve motor states (Extrusion, Reverse, Stop, ...) + switch (stateMotor) { + case MOTOR_STOP: + digitalWrite(MOTOR_DIR, LOW); + analogWrite(MOTOR_PWM, 0); + break; + + case MOTOR_EXTRUSION: { + int pwmSpeed = setMotorSpeed * 255; + digitalWrite(MOTOR_DIR, LOW); + analogWrite(MOTOR_PWM, pwmSpeed / 100); + break; + } + + case MOTOR_REVERSE: + --timeMotorReverse; + if (timeMotorReverse > 0) { + digitalWrite(MOTOR_DIR, HIGH); + analogWrite(MOTOR_PWM, 0); + } + else { + stateMotor = MOTOR_STOP; + } + break; + + case MOTOR_REVERSE_AFTER_EXTRUSION: + --timeMotorReverse; + if (timeMotorReverse > 0) { + int pwmSpeed = (100 - setMotorSpeed) * 255; + digitalWrite(MOTOR_DIR, HIGH); + analogWrite(MOTOR_PWM, pwmSpeed / 100); + } + else { + stateMotor = MOTOR_STOP; + } + break; + } + lastMotorState = stateMotor; + + // one time action, mainly for material change + static char buttonsPressed = 0; + + // The Mode Control Buttons + // (note: buttons are LOW/0/false when PRESSED!) + //// UP && DOWN are pressed + if(!digitalRead(BTN_UP) && !digitalRead(BTN_DOWN)) { // Are both Buttons pressed? + + if ((~buttonsPressed & B10000000)) { // was I NOT pressed in the LAST cycle? = on time only + if (controlMode == MODE_TEMP) { + controlMode = MODE_SPEED; + } else { + controlMode = MODE_TEMP; + } + displayControls(); + } + buttonsPressed |= B10000000; // set both buttons to "was pressed", new flag instead of 00000011! + + } else { // else = not BOTH are pressed at the same time -> UP || DOWN || NONE + + //// UP Button on Release Action + if(!digitalRead(BTN_UP)) { // if UP pressed + buttonsPressed |= B00000001; // set UP to pressed + } else { + if (!(buttonsPressed & B10000000) && (buttonsPressed & B00000001) && digitalRead(BTN_DOWN)) { // was I pressed in the LAST cycle? = onRelease + if (controlMode == MODE_TEMP) { + if (setTemperature == 0) { + setTemperature = MINTEMP; + } else if (setTemperature <= MAXTEMP - 5){ + setTemperature += 5; + } + } else { + if (setMotorSpeed <= MAXSPEED - 5) { + setMotorSpeed += 5; + } + } + displayControls(); + } + buttonsPressed &= B11111110; // set UP to released + } + + //// DOWN Button on Release action + if(!digitalRead(BTN_DOWN)) { // if DOWN pressed + buttonsPressed |= B00000010; // set DOWN to pressed + } else { + if (!(buttonsPressed & B10000000) && (buttonsPressed & B00000010) && digitalRead(BTN_UP)) { // was I pressed in the LAST cycle? = onRelease + if (controlMode == MODE_TEMP) { + if (setTemperature == MINTEMP) { + setTemperature = 0; + } else if (setTemperature >= MINTEMP + 5) { + setTemperature -= 5; + } + } else { + if (setMotorSpeed >= 0 +5) { + setMotorSpeed -= 5; + } + } + displayControls(); + } + buttonsPressed &= B11111101; // set DOWN to released + } + + //// NONE + if (digitalRead(BTN_UP) && digitalRead(BTN_DOWN)) { + buttonsPressed &= B01111111; // BOTH release + } + + } // end of if-UP&&DOWN-are-pressed-else... + + +} + +void displayControls() { + + char textSetTemp[5]; // Buffers for formatted control input text + char textSetMotor[5]; + if (setTemperature >= MINTEMP) { + sprintf(textSetTemp,"%3d ", setTemperature); + } else { + sprintf(textSetTemp,"OFF "); + } + + sprintf(textSetMotor,"%3d ",setMotorSpeed); + + // clear display and show all information + /*ssd1306_clearScreen();*/ + ssd1306_setFixedFont(ssd1306xled_font6x8); + + if (controlMode == MODE_TEMP) { + ssd1306_negativeMode(); + ssd1306_printFixedN(0, 16, textSetTemp, STYLE_NORMAL, FONT_SIZE_2X); + ssd1306_printFixedN(36+3, 24, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_positiveMode(); + ssd1306_printFixedN(68, 16, textSetMotor, STYLE_NORMAL, FONT_SIZE_2X); + ssd1306_printFixedN(110, 24, "%", STYLE_NORMAL, FONT_SIZE_NORMAL); + } else { + ssd1306_printFixedN(0, 16, textSetTemp, STYLE_NORMAL, FONT_SIZE_2X); + ssd1306_printFixedN(36+3, 24, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_negativeMode(); + ssd1306_printFixedN(68, 16, textSetMotor, STYLE_NORMAL, FONT_SIZE_2X); + ssd1306_printFixedN(110, 24, "%", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_positiveMode(); + } + + ssd1306_printFixedN(60, 16, "<", STYLE_NORMAL, FONT_SIZE_NORMAL); // icon in the middle + ssd1306_printFixedN(60, 24, ">", STYLE_NORMAL, FONT_SIZE_NORMAL); + +} + + +void acsBurning() { + percentRoutine(); +} + +void acsSoldering() { + percentRoutine(); +} + +void acsFoamCutting() { + percentRoutine(); +} + +void acsNone() { + ; +} + +const accessories_t accessoriesList[] = { + // ID type display name function startup + ACCS(ACS_ID_3D_DRAW, ACS_3D_DRAW, "3D drawing", (callBack)acs3Ddrawing, (callBack)startup3D), + ACCS(ACS_ID_BURNING, ACS_BURNING, "Burning", (callBack)acsBurning, (callBack)startupBurning), + ACCS(ACS_ID_SOLDERING, ACS_SOLDERING, "Soldering", (callBack)acsSoldering, (callBack)startupSoldering), + ACCS(ACS_ID_FOAM_CUTTING, ACS_FOAM_CUTTING, "Foam cutt.", (callBack)acsFoamCutting, (callBack)startupFoamCutting), + ACCS(ACS_ID_NONE, ACS_NONE, "None", (callBack)acsNone, (callBack)startupNone) +}; + +const char noAccs = sizeof(accessoriesList) / sizeof(accessories_t); + +void acsIdentify(void) { + accessories_t input; + static accessories_t lastInput; + char id = 0; + static char idIter = NO_ITERATIONS; + int i; + + NanodeUNIO(0xA0); + if (read(&id, 0x00, 1)) { + for (i = 0; i < noAccs; i++) { + memcpy(&input, &(accessoriesList[i]), sizeof(accessories_t)); + if (input.ID == id) { + idIter = 0; + lastInput = input; + break; + } + } + + if (i == noAccs) { + if (++idIter >= NO_ITERATIONS) { + idIter = 0; + memcpy(&input, &(accessoriesList[noAccs - 1]), sizeof(accessories_t)); + lastInput = input; + } else { + input = lastInput; + } + } + } + else { + if (++idIter >= NO_ITERATIONS) { + idIter = 0; + memcpy(&input, &(accessoriesList[noAccs - 1]), sizeof(accessories_t)); + lastInput = input; + } else { + input = lastInput; + } + } + + accessories = input; +} + +accessories_t getAccessories(void) { + return accessories; +} diff --git a/FW/config_Freemode.h b/FW/config_Freemode.h new file mode 100644 index 0000000..9b82d43 --- /dev/null +++ b/FW/config_Freemode.h @@ -0,0 +1,61 @@ + +#ifndef _CONFIG_H +#define _CONFIG_H + +/* + * define Input/Outputs + */ + +#define LED_L 13 // LED placed on Arduino Nano board +#define LED_R 4 // LED placed on 3Dsimo KIT opposite to LED_NANO + +#define BTN_UP 12 // controlling button UP/PLUS /* NEW! changed for right hand - default 11 */ +#define BTN_DOWN 11 // controlling button DOWN/MINUS /* NEW! changed for right hand - default 12 */ +#define BTN_EXT 7 // button for material extrusion +#define BTN_REV 8 // button for material reverse + +#define MOTOR_DIR 6 // motor direction output +#define MOTOR_PWM 10 // motor PWM output for power driving +#define MOTOR_SLEEP 5 +#define HEATER_EN 9 // heater/power output + +#define TEMP_IN A0 // temperature measure ADC input + +#define LOW_TEMP_EN 3 // enable measurement for low temperatures (~from 40deg. Celsius) +#define HIGH_TEMP_EN 2 // enable measurement for high temperatures (~from 150deg. Celsius) + +#define ID_PIN 16 // Pin for identification of the accessories + +/* + * define heating states + */ +enum { + STATE_HEATING, + STATE_COOLING, + STATE_READY, + STATE_OFF +} STATE_e; + +enum { + MOTOR_STOP, + MOTOR_EXTRUSION, + MOTOR_REVERSE, + MOTOR_CONTINUOUS, + MOTOR_REVERSE_AFTER_EXTRUSION +} MOTOR_STATE_e; + +enum { + MODE_TEMP, + MODE_SPEED +} MODE_CONTROL_e; + +/* + * define structure for the material list + */ +typedef struct { + int temperature; + int motorSpeed; + char* materialName; +} profile_t; + +#endif From 9eb0e22c52f8ca31edf45b814a7f780f5311d493 Mon Sep 17 00:00:00 2001 From: Mikel564324 <97843562+Mikel564324@users.noreply.github.com> Date: Sat, 29 Jan 2022 16:19:32 -0600 Subject: [PATCH 2/3] Update accessories_Freemode.c Removed sections related to materials profile that is not used with freemode. --- FW/accessories_Freemode.c | 80 ++++++++++----------------------------- 1 file changed, 19 insertions(+), 61 deletions(-) diff --git a/FW/accessories_Freemode.c b/FW/accessories_Freemode.c index 2e80129..6eb99a0 100644 --- a/FW/accessories_Freemode.c +++ b/FW/accessories_Freemode.c @@ -8,18 +8,6 @@ accessories_t accessories; -/* - define material profiles for 3D extension - didn't remove for Freemode but shouldn't affect anything -*/ -const profile_t materials[] PROGMEM = { - // {temperature (deg. C), motorSpeed (%), materialName} - {0, 0, "OFF"}, /* NEW! BEGIN OFF - BUT IF YOU SELECT THIS AFTER PETG, 3DPEN COOLS TO 153º PRIOR TO SHUTDOWN*/ - {230, 60, "PLA"}, - {250, 50, "ABS"}, - {245, 60, "PETG"}, -}; - #define MAXSPEED 70 // for safety. change this up to 100 (%), if you know what you are doing. #define MAXTEMP 275 // not sure whats better: define or const, also not sure about the actual max temp... testing with 300 #define MINTEMP 155 // 153/154 is the lowest measurement possible. actual temperature can be lower. @@ -29,23 +17,15 @@ int setTemperature = 0; // set heater temperature (we raise this directl int setMotorSpeed = 40; // set motor speed in % // ToDo maybe add icrement step value (hardcoded at 5) char controlMode = MODE_TEMP; // Control Mode: MODE_TEMP or MODE_SPEED. selects which values the UP-DOWN buttons change - -/* - define number of materials in list and variables -*/ -const int MATERIAL_COUNT = sizeof(materials)/sizeof(profile_t); - -int materialID = 0; // chosen material profile - - + int elapsedTime = 0; char statusHeating = STATE_HEATING; char stateMotor = MOTOR_STOP, lastMotorState = MOTOR_STOP; + int timeMotorReverse = 0; char powerPercent = 50; void startup3D(void) { - loadMaterial(materialID); digitalWrite(MOTOR_DIR, LOW); analogWrite(MOTOR_PWM, 0); } @@ -181,28 +161,6 @@ int getTemperature() { // get temperature in deg. Celsius from ADU value return tempADU; } -/* - load actual material profile -*/ -void loadMaterial(int id) { - profile_t profile; - char text[10]; - - // load material profile from PROGMEM and assign variables - memcpy_P(&profile, &materials[id], sizeof(profile_t)); -/* - setTemperature = profile.temperature; - setMotorSpeed = profile.motorSpeed; -*/ - // clear display and show all information -/* sprintf(text, "%d %%", setMotorSpeed); - ssd1306_clearScreen(); - ssd1306_setFixedFont(ssd1306xled_font6x8); - ssd1306_printFixedN(0, 0, profile.materialName, STYLE_NORMAL, FONT_SIZE_2X); - ssd1306_printFixedN(80, 0, text, STYLE_NORMAL, FONT_SIZE_2X);*/ - -} - /* PID variables and constants for tuning */ @@ -296,12 +254,13 @@ int heating() { sumTemp /= NO_AVERAGES_VALUES; -displayControls(); + displayControls(); + // show on display actual and preset temperature sprintf(text, "%3d", (int)sumTemp/10); ssd1306_setFixedFont(ssd1306xled_font6x8); ssd1306_printFixedN(0, 0, text, STYLE_NORMAL, FONT_SIZE_2X); - ssd1306_printFixedN(39, 12, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_printFixedN(40, 12, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); return sumTemp; @@ -318,12 +277,12 @@ void acs3Ddrawing() { if (actualTemperature > setTemperature*10 + 100) { statusHeating = STATE_COOLING; ssd1306_printFixedN(64, 0, "Cooling", STYLE_NORMAL, FONT_SIZE_NORMAL); - } - + } + // tolerant zone where temperature is OK for extrusion/reverse else if (actualTemperature > setTemperature*10 - 100) { statusHeating = STATE_READY; - ssd1306_printFixedN(64, 0, "Ready ", STYLE_NORMAL, FONT_SIZE_NORMAL); //spaces used instead of clearing space as heating is longer + ssd1306_printFixedN(64, 0, "Ready ", STYLE_NORMAL, FONT_SIZE_NORMAL); //spaces used as extra characters because "heating" is a longer word digitalWrite(LED_R, HIGH); // turn the LED on (HIGH is the voltage level) digitalWrite(LED_L, HIGH); // turn the LED on (HIGH is the voltage level) } @@ -337,10 +296,12 @@ void acs3Ddrawing() { } } - // assing functions according to heating state (mainly button function) + // assessing functions according to heating state (mainly button function) switch (statusHeating) { - case STATE_COOLING: - case STATE_READY: { + case STATE_COOLING: + stateMotor = MOTOR_STOP; + break; + case STATE_READY: { // button EXTRUSION is pressed, extrude material if (!digitalRead(BTN_EXT) && digitalRead(BTN_REV)) { stateMotor = MOTOR_EXTRUSION; @@ -366,13 +327,10 @@ void acs3Ddrawing() { } break; } - case STATE_HEATING: // if happened that heater has so low temperature, motor stop digitalWrite(MOTOR_DIR, LOW); analogWrite(MOTOR_PWM, 0); - stateMotor = MOTOR_STOP; - break; } // resolve motor states (Extrusion, Reverse, Stop, ...) @@ -505,21 +463,21 @@ void displayControls() { if (controlMode == MODE_TEMP) { ssd1306_negativeMode(); ssd1306_printFixedN(0, 16, textSetTemp, STYLE_NORMAL, FONT_SIZE_2X); - ssd1306_printFixedN(36+3, 24, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_printFixedN(40, 28, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); ssd1306_positiveMode(); ssd1306_printFixedN(68, 16, textSetMotor, STYLE_NORMAL, FONT_SIZE_2X); - ssd1306_printFixedN(110, 24, "%", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_printFixedN(108, 24, "%", STYLE_NORMAL, FONT_SIZE_NORMAL); } else { ssd1306_printFixedN(0, 16, textSetTemp, STYLE_NORMAL, FONT_SIZE_2X); - ssd1306_printFixedN(36+3, 24, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_printFixedN(40, 28, "C", STYLE_NORMAL, FONT_SIZE_NORMAL); ssd1306_negativeMode(); ssd1306_printFixedN(68, 16, textSetMotor, STYLE_NORMAL, FONT_SIZE_2X); - ssd1306_printFixedN(110, 24, "%", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_printFixedN(108, 24, "%", STYLE_NORMAL, FONT_SIZE_NORMAL); ssd1306_positiveMode(); } - ssd1306_printFixedN(60, 16, "<", STYLE_NORMAL, FONT_SIZE_NORMAL); // icon in the middle - ssd1306_printFixedN(60, 24, ">", STYLE_NORMAL, FONT_SIZE_NORMAL); + ssd1306_printFixedN(56, 16, "<", STYLE_NORMAL, FONT_SIZE_NORMAL); // icon in the middle + ssd1306_printFixedN(56, 24, ">", STYLE_NORMAL, FONT_SIZE_NORMAL); } From de31bf1d128aba261acf01a6faeacad895628cac Mon Sep 17 00:00:00 2001 From: Mikel564324 <97843562+Mikel564324@users.noreply.github.com> Date: Sat, 29 Jan 2022 16:30:41 -0600 Subject: [PATCH 3/3] Update 3DsimoKit2_Freemode.ino --- FW/3DsimoKit2_Freemode.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FW/3DsimoKit2_Freemode.ino b/FW/3DsimoKit2_Freemode.ino index afc190b..9e25ad7 100644 --- a/FW/3DsimoKit2_Freemode.ino +++ b/FW/3DsimoKit2_Freemode.ino @@ -17,7 +17,7 @@ EveryTimer timer; bool righthanded = true; bool pressUPDOWNhandled = true; -extern int materialID; +//extern int materialID; /* * call every 50ms timer for buttons action and heating