diff --git a/Classes.h b/Classes.h index 9fe775b..c6fb51e 100644 --- a/Classes.h +++ b/Classes.h @@ -27,16 +27,20 @@ class MenuItem class Menu { public: + void displayStart(); void control(); - void displayAll(); - void displayName(int itemNr, String &name); - void displayValue(int itemNr, int value, bool focus, bool background); void displayDot(bool on); - void drawColorTextLine(int line, int left, String str, uint16_t color=COLOR_WHITE, uint16_t backgroundColor=COLOR_BLACK); - + void TFTinit(); + private: - bool editValue=0; - const int txtLeft = 17; + void displayName(int itemNr, String &name); + void displayValue(int itemNr, int value, bool focus, bool edit); + void drawColorTextLine(int line, int left, String str, uint16_t textColor=TFT_WHITE, uint16_t backgroundColor=TFT_BLACK); // line 0..8 + void displayContinuously(); + + bool editValueMode=0; + const int textLeft = 20, fontSize=4, fontHeight=26; + const int vertOffset=3; // 240-9*26)/2 }; #endif diff --git a/Classes.ino b/Classes.ino index a57ca80..17dcbb1 100644 --- a/Classes.ino +++ b/Classes.ino @@ -1,77 +1,91 @@ #include "Classes.h" #include -void Menu::drawColorTextLine(int line, int left, String str, uint16_t color=COLOR_WHITE, uint16_t backgroundColor) -{ tft.fillRectangle(left, 20*line, 175, 20*line+19, backgroundColor); // line <= 10 - tft.setBackgroundColor(backgroundColor); - tft.drawText(left, 20*line+2, str, color); -} - void Menu::control() -{ if(!editValue) +{ if(!editValueMode) { if(upButton.pushed()) - { menu.displayValue(upDownItemNr, menuItems[upDownItemNr].upDownVal, 0, editValue); // un-focus old item - menu.displayValue(upDownItemNr, menuItems[upDownItemNr.down()].upDownVal, 1, editValue); // focus + { displayValue(WeldItemNr, menuItems[WeldItemNr].upDownVal, 0, editValueMode); // un-focus old item + displayValue(WeldItemNr, menuItems[WeldItemNr.down()].upDownVal, 1, editValueMode); // focus return; } if(downButton.pushed()) - { menu.displayValue(upDownItemNr, menuItems[upDownItemNr].upDownVal, 0, editValue); // un-focus old item - menu.displayValue(upDownItemNr, menuItems[upDownItemNr.up()].upDownVal, 1, editValue); // focus + { displayValue(WeldItemNr, menuItems[WeldItemNr].upDownVal, 0, editValueMode); // un-focus old item + displayValue(WeldItemNr, menuItems[WeldItemNr.up()].upDownVal, 1, editValueMode); // focus return; } if(selectButton.pushed()) - { menu.displayValue(upDownItemNr, menuItems[upDownItemNr].upDownVal, 1, editValue=1); // add backgound + { displayValue(WeldItemNr, menuItems[WeldItemNr].upDownVal, 1, editValueMode=1); // add backgound return; } - } - if(editValue) + } + + if(editValueMode) { if(upButton.pushed()) - { menu.displayValue(upDownItemNr, menuItems[upDownItemNr].upDownVal.up(), 1, editValue); + { displayValue(WeldItemNr, menuItems[WeldItemNr].upDownVal.up(), 1, editValueMode); return; } if(downButton.pushed()) - { menu.displayValue(upDownItemNr, menuItems[upDownItemNr].upDownVal.down(), 1, editValue); + { displayValue(WeldItemNr, menuItems[WeldItemNr].upDownVal.down(), 1, editValueMode); return; } if(selectButton.pushed()) - { menu.displayValue(upDownItemNr, menuItems[upDownItemNr].upDownVal, 1, editValue=0); // delete backgound + { displayValue(WeldItemNr, menuItems[WeldItemNr].upDownVal, 1, editValueMode=0); // delete backgound eeprom.write(); return; } } } -void Menu::displayAll() -{ if(!continuously) +void Menu::displayStart() +{ drawColorTextLine(0, textLeft, version, TFT_YELLOW); + delay(1000); + TFTinit(); + + if(!continuously) { for(int i=0; i<3; i++) - { upDownItemNr.value=i; - displayName(upDownItemNr, menuItems[upDownItemNr].name); - menu.displayValue(upDownItemNr, menuItems[upDownItemNr].upDownVal, 0, 0); - } - upDownItemNr.value=0; - menu.displayValue(upDownItemNr, menuItems[upDownItemNr].upDownVal, 1, 0); // item 0 has focus + { WeldItemNr.value=i; + displayName(WeldItemNr, menuItems[WeldItemNr].name); + displayValue(WeldItemNr, menuItems[WeldItemNr].upDownVal, 0, 0); + } + WeldItemNr.value = 0; + displayValue(WeldItemNr, menuItems[WeldItemNr].upDownVal, 1, 0); // item 0 has focus displayDot(0); - drawColorTextLine(10, 0, "- + sel weld", COLOR_YELLOW, COLOR_BLUEVIOLET); - } - else - { drawColorTextLine(4, 0, " Continuously", COLOR_WHITE, COLOR_RED); - drawColorTextLine(5, 0, " mode", COLOR_WHITE, COLOR_RED); - drawColorTextLine(6, 0, " Take care!", COLOR_WHITE, COLOR_RED); + drawColorTextLine(8, 0, " down up sel ", TFT_YELLOW, TFT_BLUE); // to long text is ok } + else displayContinuously(); +} + +void Menu::displayContinuously() +{ tft.fillScreen(TFT_RED); + drawColorTextLine(2, 0, " Continuously", TFT_WHITE, TFT_RED); + drawColorTextLine(3, 0, " mode", TFT_WHITE, TFT_RED); + drawColorTextLine(4, 0, " Take care!", TFT_WHITE, TFT_RED); + displayDot(0); } void Menu::displayDot(bool on) -{ tft.fillCircle(87, 170, 12, on? COLOR_WHITE : COLOR_DARKBLUE); +{ tft.fillCircle(148, 180, 20, on? TFT_WHITE : 0x64A7/*green*/); // https://ee-programming-notepad.blogspot.nl/2016/10/16-bit-color-generator-picker.html } -void Menu::displayName(int upDownItemNr, String &name) -{ drawColorTextLine(2*upDownItemNr, txtLeft, name, TXT_COLOR); +void Menu::drawColorTextLine(int line, int left, String str, uint16_t textColor, uint16_t backgroundColor) +{ tft.setTextColor(textColor, backgroundColor); + tft.drawString(str.c_str(), left, fontHeight*line+vertOffset, fontSize); } -void Menu::displayValue(int upDownItemNr, int value, bool focus, bool background) -{ menu.drawColorTextLine(2*upDownItemNr+1, txtLeft, String(" ")); // clear line - menu.drawColorTextLine(2*upDownItemNr+1, 0, focus? ">" : " ", TXT_COLOR); - menu.drawColorTextLine(2*upDownItemNr+1, txtLeft, String(value), background? COLOR_BLACK : TXT_COLOR, background? COLOR_CYAN : COLOR_BLACK); +void Menu::displayName(int WeldItemNr, String &name) +{ drawColorTextLine(2*WeldItemNr, textLeft, name, TFT_YELLOW); +} + +void Menu::displayValue(int WeldItemNr, int value, bool focus, bool edit) +{ drawColorTextLine(2*WeldItemNr+1, textLeft, " ", TFT_WHITE); // clear line, can't be BLACK (bug?) + drawColorTextLine(2*WeldItemNr+1, 0, ">", focus? TFT_WHITE : TFT_BLACK); // BLACK on BLACK = BLACK + drawColorTextLine(2*WeldItemNr+1, textLeft, String(value), edit? TFT_BLACK : TFT_WHITE, edit? TFT_CYAN : TFT_BLACK); +} + +void Menu::TFTinit() +{ tft.init(); + tft.setRotation(orientation); + tft.fillScreen(TFT_BLACK); } // --------------------------------------------------------------------------- @@ -80,13 +94,15 @@ UpDownValue::UpDownValue(int value, int step, int minValue, int maxValue): value(value), step(step), minValue(minValue), maxValue(maxValue) { } + int UpDownValue::up() { value += step; - return value = min(max(value, minValue), maxValue); + return value = (value > maxValue) ? minValue : value; } + int UpDownValue::down() { value -= step; - return value = min(max(value, minValue), maxValue); + return value = (value < minValue ) ? maxValue : value; } UpDownValue::operator int() // conversion operator, object returns value @@ -100,4 +116,14 @@ name(name), upDownVal(value) { } +/* + if(downButton.on() && selectButton.on()) + { preferencesControl(); + return; + } + + drawColorTextLine(2, textLeft, "Set preferences:", TFT_YELLOW); + drawColorTextLine(3, textLeft, "press down + sel", TFT_YELLOW); +*/ + diff --git a/Definitions.h b/Definitions.h index 69dc7db..4f79f77 100644 --- a/Definitions.h +++ b/Definitions.h @@ -1,29 +1,20 @@ #ifndef _Definitions_H_ #define _Definitions_H_ -const byte BCDswitch0pin = 8; -const byte BCDswitch1pin = 7; -const byte BCDswitch2pin = 6; -const byte BCDswitch3pin = 5; -const byte weldPin = 2; -const byte weldButtonPin = 4; -const byte upButtonPin = 7; -const byte downButtonPin = 8; -const byte selectButtonPin = 6; -const byte ledPin = 12; -const byte zeroCrossPin = 3; -const byte tftJumperOutPin = A5; -const byte tftJumperInPin = A4; +const byte weldPin = 5; +const byte ledPin = A3; +const byte weldButtonPin = 7; +const byte upButtonPin = 9; +const byte downButtonPin = 8; +const byte selectButtonPin = 10; +const byte foodSwitchPin = A5; +const byte zeroCrossPin = 2; -const byte TFT_RSTpin = 9; -const byte TFT_RSpin = 10; -const byte TFT_CSpin = 5; -//const byte TFT_CLKpin = 13; // for SW SDI, doesn't work -//const byte TFT_SDIpin = 11; // for SW SDI, doesn't work +const byte TFT_RSTpin = A1; // set in user.h, todo: do in TFT_ILI9341 constructor +const byte TFT_DCpin = A0; +const byte TFT_CSpin = A2; const int step_ms = 50; -const int sinusMax_us = 4583; - -#define TXT_COLOR COLOR_YELLOW +const int sinusMax_us = 4583; // average between 0.25/50Hz and 0.25/60Hz #endif diff --git a/Eeprom.h b/Eeprom.h index 9a7e044..11c3eac 100644 --- a/Eeprom.h +++ b/Eeprom.h @@ -6,5 +6,5 @@ class Eeprom: public EEPROMClassEx void write(); bool initialized(); - unsigned storedInitValue, preweld_ms, pause_ms, weld_ms; // EEPROM addresses + unsigned storedInitValue_addr, preweld_ms_addr, pause_ms_addr, weld_ms_addr; // EEPROM addresses }; diff --git a/Eeprom.ino b/Eeprom.ino index a23ddef..0eb8659 100644 --- a/Eeprom.ino +++ b/Eeprom.ino @@ -1,32 +1,33 @@ -const unsigned maxWrites = 100; -const unsigned initValue = 12341; // take another value for new initialization +const unsigned maxWrites = 100; +const unsigned initValue = 4; // take another value for factory default settings void Eeprom::init() { setMemPool(0, EEPROMSizeATmega328); setMaxAllowedWrites(maxWrites); - storedInitValue = getAddress(sizeof(unsigned)); - preweld_ms = getAddress(sizeof(unsigned)); - pause_ms = getAddress(sizeof(unsigned)); - weld_ms = getAddress(sizeof(unsigned)); - orientation = getAddress(sizeof(unsigned)); - if(!initialized()) write(); // fill an empty EEPROM + storedInitValue_addr = getAddress(sizeof(unsigned)); + preweld_ms_addr = getAddress(sizeof(unsigned)); + pause_ms_addr = getAddress(sizeof(unsigned)); + weld_ms_addr = getAddress(sizeof(unsigned)); + orientation_addr = getAddress(sizeof(unsigned)); + if(!initialized()) write(); // fill an empty EEPROM with factory default settings } void Eeprom::read() -{ menuItems[0].upDownVal.value = readInt(preweld_ms); - menuItems[1].upDownVal.value = readInt(pause_ms); - menuItems[2].upDownVal.value = readInt(weld_ms); +{ menuItems[0].upDownVal.value = readInt(preweld_ms_addr); + menuItems[1].upDownVal.value = readInt(pause_ms_addr); + menuItems[2].upDownVal.value = readInt(weld_ms_addr); + orientation = readInt(orientation_addr); } void Eeprom::write() -{ writeInt(storedInitValue, initValue); // todo with update()? - writeInt(preweld_ms, menuItems[0].upDownVal.value); - writeInt(pause_ms, menuItems[1].upDownVal.value); - writeInt(weld_ms, menuItems[2].upDownVal.value); - writeInt(orientation, 0); +{ writeInt(storedInitValue_addr, initValue); + writeInt(preweld_ms_addr, menuItems[0].upDownVal.value); + writeInt(pause_ms_addr, menuItems[1].upDownVal.value); + writeInt(weld_ms_addr, menuItems[2].upDownVal.value); + writeInt(orientation_addr, orientation); } bool Eeprom::initialized() -{ return readInt(storedInitValue) == initValue; +{ return readInt(storedInitValue_addr) == initValue; } diff --git a/Functions.ino b/Functions.ino index 86739ee..a40649b 100644 --- a/Functions.ino +++ b/Functions.ino @@ -1,72 +1,72 @@ -void weldControlNoTFT() -{ if(continuously && BCDswitch()==0) weld(weldButton.on()); // continuous welding - else - if(weldButton.pushed()) weldCyclus(BCDswitch() * step_ms); +void selectTFTorientation() // because LCD orientation is unknown +{ if(upButton.on() && downButton.on()) // change between 1<->3 when up and down are pressed during power up + { if(orientation==1) orientation=3; // orientation can only be either 1 or 3 + else orientation=1; // if 0, 2, 3... + eeprom.write(); + } } -void weldControlTFT() -{ //if(continuously && BCDswitch()==0) weld(weldButton.on()); - if(continuously) weld(weldButton.on()); - else - if(weldButton.pushed()) weldCyclus(menuItems[2].upDownVal); +void selectContinuously() +{ const unsigned long switchStable_ms = 200; // min = 50 + const unsigned long weldButtonPressTime = 500; // push weldButton during 500ms at power up + unsigned long start_ms = millis(); + pollAll(); + delay(switchStable_ms); + + while(weldButton.on()) + { pollAll(); + if(!weldButton.on()) break; + } + if(millis()-start_ms > weldButtonPressTime) continuously = 1; +} + +void weldControl() +{ if(continuously) weldContinuously(); + else if(weldButton.pushed() || foodSwitch.pushed()) weldCyclus(menuItems[2].upDownVal); } void weldCyclus(int weldTime_ms) -{ if(!sinMaxDisabled) sinusMax(); - if(TFTused) menu.displayDot(1); // just once per weld cyclus - pulseWeld(menuItems[0].upDownVal); +{ pulseWeld(menuItems[0].upDownVal); delay(menuItems[1].upDownVal); - if(!sinMaxDisabled) sinusMax(); pulseWeld(weldTime_ms); - if(TFTused) menu.displayDot(0); // just once per weld cyclus } -int BCDswitch() -{ int bcd; - bitWrite(bcd, 0, !digitalRead(BCDswitch0pin)); - bitWrite(bcd, 1, !digitalRead(BCDswitch1pin)); - bitWrite(bcd, 2, !digitalRead(BCDswitch2pin)); - bitWrite(bcd, 3, !digitalRead(BCDswitch3pin)); - return bcd; +void weldContinuously() +{ if(weldButton.pushed()) sinusMax(); // do only once + weld(weldButton.on()); } void pulseWeld(int ms) -{ weld(1); +{ sinusMax(); + if(ms) weld(1); // avoid short displayDot flash delay(ms); weld(0); - if(printValuesToSerial) Serial << ms << endl; + Serial << ms << endl; } void weld(bool b) -{ digitalWrite(weldPin, b); - digitalWrite(ledPin, !b); +{ menu.displayDot(b); + digitalWrite(weldPin, b); + if(b) Serial << "w "; } void sinusMax() -{ while(digitalRead(zeroCrossPin)); +{ Serial << "sinusMax "; + if(sinMaxDisabled) return; + while(digitalRead(zeroCrossPin)); while(!digitalRead(zeroCrossPin)); - delayMicroseconds(sinusMax_us); // to prevent inrush current, turn-on at the sinus max -} - -void blinkLed(int n) -{ pinMode(ledPin, OUTPUT); - for(byte i=0; i weldButtonPressTime) continuously = 1; - if(!TFTused) continuously &= bcdswitch==0; // bcdswitch has to be at position 0 too -} - -void TFTinit() -{ tft.begin(); - tft.setOrientation(eeprom.readInt(orientation)); - tft.setFont(Terminal12x16); -} - -bool TFTusedJumper() -{ pinMode(tftJumperOutPin, OUTPUT); - pinMode(tftJumperInPin, INPUT_PULLUP); // default 1 - digitalWrite(tftJumperOutPin, 0); - return !digitalRead(tftJumperInPin); // no jumper = 1 (compatible with old software) + foodSwitch.poll(); } void printValuesToSerial() { Serial << "\npreweld " << menuItems[0].upDownVal << "ms, pause " << menuItems[1].upDownVal << "ms, weldTime " - << menuItems[2].upDownVal << "ms, continuously " << continuously << endl; + << menuItems[2].upDownVal << "ms, continuously " << continuously << ", Orientation " << orientation << endl; } -void setOrientation() -{ pollAll(); // works without too - if(upButton.on() && downButton.on()) - { if(eeprom.readInt(orientation)==0) eeprom.writeInt(orientation, 2); - else eeprom.writeInt(orientation, 0); - } -} diff --git a/Install these libraries.zip b/Install these libraries.zip deleted file mode 100644 index 4445a5a..0000000 Binary files a/Install these libraries.zip and /dev/null differ diff --git a/Spotwelder-6.1.ino b/Spotwelder-7.1.ino similarity index 52% rename from Spotwelder-6.1.ino rename to Spotwelder-7.1.ino index c735b30..62296af 100644 --- a/Spotwelder-6.1.ino +++ b/Spotwelder-7.1.ino @@ -1,6 +1,10 @@ -bool sinMaxDisabled = 0; // for test without transformer, must be 0 - +bool sinMaxDisabled = 0; // 0 for production firmware, 1 for test without transformer /* +Attention: verify code after upload: ON / OFF + +Todo +Change maximum values, just as selectTFTorientation() + Note: use the latest Arduino software and install the libraries. Arduino spot welder controller @@ -11,9 +15,16 @@ This program is free software: you can redistribute it and/or modify it under th as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at http://www.gnu.org/licenses . + +TFT 240x320 library: +https://www.instructables.com/id/Arduino-TFT-display-and-font-library/ +https://github.com/Bodmer/TFT_ILI9341 m + Version 5.2 1-02-2015 Version 6.0 2-01-2017 added menu with TFT display Version 6.1 22-05-2017 added set display orientation +Version 6.2 26-8-2017 only supports PCB with LCD now, weldContinuously with sinusMax, displayDot improved +Version 7.0 2-10-2017 only for smd board and ILI9341 240x320 TFT display Program with FTDI programmer, Extra > Board > Arduino Uno @@ -22,12 +33,17 @@ Program with FTDI programmer, Extra > Board > Arduino Uno zeroCross __| |_____| |_____| |__ _____________ weld __________________| |____ + +T = 1/(4*50Hz) = 5000us +T = 1/(4*60Hz) = 4167us +Average time: sinusMax_us = (5000us + 4167us)/2 = 4583us, is not critical, use for 50 and 60Hz */ #include #include #include -#include +#include // // https://github.com/Bodmer/TFT_ILI9341 disadvantage: settings in library + #include #include #include @@ -35,45 +51,46 @@ weld __________________| |____ #include "Classes.h" #include "Eeprom.h" +String version = "Version 7.1"; + Switch weldButton(weldButtonPin); Switch upButton(upButtonPin); Switch downButton(downButtonPin); Switch selectButton(selectButtonPin); -TFT_22_ILI9225 tft = TFT_22_ILI9225(TFT_RSTpin, TFT_RSpin, TFT_CSpin, 0); // hardware SPI -MenuItem preweldTimeItem = MenuItem("Preweld time", UpDownValue(50, 50, 0, 1000)); // value, step, minValue, maxValue -MenuItem pauseTimeItem = MenuItem("Pause", UpDownValue(500, 100, 0, 1000)); -MenuItem weldTimeItem = MenuItem("Weld time", UpDownValue(250, 50, 50, 1000)); -MenuItem menuItems[] = {preweldTimeItem, pauseTimeItem, weldTimeItem}; -UpDownValue upDownItemNr = UpDownValue(0, 1, 0, 2); // 3 items 0 1 2 +Switch foodSwitch(foodSwitchPin); + +TFT_ILI9341 tft = TFT_ILI9341(); // pins defined in User_Setup.h +UpDownValue WeldItemNr = UpDownValue(0, 1, 0, 2); // 3 items 0 1 2 + Menu menu; Eeprom eeprom; +// Set the menu item DEFAULT values: value, step, minValue, maxValue +MenuItem preweldTimeItem = MenuItem("Preweld, ms", UpDownValue(50, 50, 0, 1000)); +MenuItem pauseTimeItem = MenuItem("Pause, ms", UpDownValue(500, 50, 0, 1000)); +MenuItem weldTimeItem = MenuItem("Weld time, ms", UpDownValue(250, 50, 0, 1000)); +MenuItem menuItems[] = {preweldTimeItem, pauseTimeItem, weldTimeItem}; -bool TFTused; bool continuously; -unsigned orientation; +unsigned orientation_addr, orientation=3; void setup() { Serial.begin(9600); - eeprom.init(); - eeprom.read(); setpinModes(); - TFTused = TFTusedJumper(); - setOrientation(); // after eeprom.init() - if(TFTused) TFTinit(); - if(!TFTused) blinkLed(4); - digitalWrite(ledPin, 1); // power on indication + pollAll(); + blinkLed(ledPin, 3); // is a delay too + pollAll(); // do after the blinkLed() delay + eeprom.init(); + eeprom.read(); // set the menu with the stored EEPROM values + selectTFTorientation(); // do after eeprom.init and before TFTinit() selectContinuously(); + menu.TFTinit(); printValuesToSerial(); - if(TFTused) menu.displayAll(); + menu.displayStart(); } void loop() { pollAll(); - if(TFTused) - { menu.control(); - weldControlTFT(); - } else - weldControlNoTFT(); -} - - + menu.control(); + weldControl(); + // test(); +} diff --git a/tests.ino b/tests.ino new file mode 100644 index 0000000..04bff81 --- /dev/null +++ b/tests.ino @@ -0,0 +1,7 @@ +#include "avdweb_VirtualDelay.h" +VirtualDelay testDelay; // default = millis + +void test() +{ testDelay.start(10000); // weld every 10s + if(testDelay.elapsed()) weldCyclus(menuItems[2].upDownVal); +}