#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Encoder.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
Encoder enc(2, 3);
#define BUTTON_PIN 4
#define START_PIN 5
#define OUTPUT_PIN A0
#define BUZZER_PIN 6
#define VOLTAGE_PIN A1
#define PROTECTION_PIN A2
#define CONTACT_PIN A3 // New pin for electrode closure control
#define BACKLIGHT_PIN 9
#define NTC_PIN A6 // NTC 10K thermistor pin
#define FAN_PIN 10 // Fan control pin (PWM capable)
// For mode AUTO
bool autoTriggered = false;
unsigned long contactStartTime = 0;
int selected = 0;
int values[3] = {0, 0, 0};
float sValue = 0.1;
bool lightEnabled = true;
byte brightness = 5;
bool autoMode = true;
long lastPos = 0;
bool editMode = false;
bool buttonHeld = false;
unsigned long buttonPressTime = 0;
bool blinkState = true;
bool startButtonState = false;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 5;
const float voltageMultiplier = 1;
bool dangerDisplayed = false;
unsigned long lastBeepTime = 0;
unsigned long lowVoltageStartTime = 0;
bool lowVoltageProtectionActive = false;
unsigned long protectionVoltageStartTime = 0;
bool protectionActive = false;
// NTC thermistor parameters
const int SERIES_RESISTOR = 10000; // 10K series resistor
const int NTC_NOMINAL = 10000; // Resistance at 25 degrees C
const int TEMPERATURE_NOMINAL = 25; // temp. for nominal resistance
const int B_COEFFICIENT = 3950; // The beta coefficient
const int NUM_SAMPLES = 5; // Number of samples for averaging
// Fan control parameters
float currentTemperature = 0;
bool fanEnabled = false;
unsigned long lastTempCheck = 0;
const unsigned long TEMP_CHECK_INTERVAL = 2000; // Check temp every 2 seconds
const float FAN_ON_TEMP = 40.0; // Turn fan on at 40°C
const float FAN_OFF_TEMP = 35.0; // Turn fan off at 35°C
const float CRITICAL_TEMP = 60.0; // Critical temperature for shutdown
bool overheatProtectionActive = false;
void drawScreen();
void drawVoltage(float voltage, bool lowVoltage);
void generatePulse();
float readTemperature();
void updateFanControl();
void beep() {
digitalWrite(BUZZER_PIN, HIGH);
delay(50);
digitalWrite(BUZZER_PIN, LOW);
}
void testDisplay() {
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Testing Display. ");
delay(500);
lcd.setCursor(1, 0);
lcd.print("Testing Display.. ");
delay(500);
lcd.setCursor(1, 0);
lcd.print("Testing Display...");
delay(1000);
lcd.clear();
for (int row = 0; row < 4; row++) {
lcd.setCursor(0, row);
lcd.print("ABCDEFGHIJKLMNOPQRST");
}
delay(1000);
lcd.clear();
for (int row = 0; row < 4; row++) {
lcd.setCursor(0, row);
lcd.print("01234567890123456789");
}
delay(1000);
lcd.clear();
for (int row = 0; row < 4; row++) {
lcd.setCursor(0, row);
lcd.print("####################");
}
delay(1000);
lcd.clear();
}
void selfTest() {
testDisplay();
lcd.setCursor(1, 0);
lcd.print("SYSTEM TESTING!");
delay(500);
lcd.setCursor(2, 1);
lcd.print("EEPROM Check.");
delay(500);
lcd.setCursor(2, 1);
lcd.print("EEPROM Check..");
delay(500);
lcd.setCursor(2, 1);
lcd.print("EEPROM Check...");
delay(500);
lcd.setCursor(2, 1);
lcd.print("EEPROM Check....");
delay(500);
lcd.setCursor(2, 1);
lcd.print("EEPROM Check.....");
for (int i = 0; i < 3; i++) {
values[i] = EEPROM.read(i);
if (values[i] > 50) values[i] = 0;
}
sValue = EEPROM.read(6) / 10.0;
if (sValue < 0.3 || sValue > 2.0) sValue = 0.3;
delay(500);
lcd.setCursor(2, 2);
lcd.print("Backlight Test. ");
lcd.backlight();
delay(500);
lcd.setCursor(2, 2);
lcd.print("Backlight Test.. ");
lcd.backlight();
delay(500);
lcd.setCursor(2, 2);
lcd.print("Backlight Test...");
lcd.backlight();
delay(500);
lcd.noBacklight();
delay(500);
lcd.backlight();
delay(500);
lcd.setCursor(4, 3);
lcd.print("Beep Test. ");
delay(500);
lcd.setCursor(4, 3);
lcd.print("Beep Test.. ");
delay(500);
lcd.setCursor(4, 3);
lcd.print("Beep Test...");
beep();
delay(500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Voltage Test. ");
delay(500);
lcd.setCursor(0, 0);
lcd.print("Voltage Test.. ");
delay(500);
lcd.setCursor(0, 0);
lcd.print("Voltage Test...");
float protectionVoltage = analogRead(PROTECTION_PIN) * (5.0 / 1023.0 * 3.0);
lcd.setCursor(0, 1);
lcd.print("Voltage: ");
lcd.print(protectionVoltage, 2);
lcd.print("V");
delay(500);
if (protectionVoltage < 10.0 || protectionVoltage > 18.0) {
lcd.setCursor(0, 2);
lcd.print("ERROR: OUT OF RANGE");
lcd.setCursor(0, 3);
lcd.print("REQ: 10-18V");
for (int i = 0; i < 3; i++) {
beep();
delay(500);
}
delay(1000);
} else {
lcd.setCursor(0, 2);
lcd.print("Voltage OK");
}
// Temperature sensor test
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp Sensor Test. ");
delay(500);
lcd.setCursor(0, 0);
lcd.print("Temp Sensor Test.. ");
delay(500);
lcd.setCursor(0, 0);
lcd.print("Temp Sensor Test...");
float temp = readTemperature();
lcd.setCursor(0, 1);
lcd.print("Temp: ");
lcd.print(temp, 1);
lcd.print("C");
delay(1000);
// Fan test
lcd.setCursor(0, 2);
lcd.print("Fan Test.");
delay(500);
lcd.setCursor(0, 2);
lcd.print("Fan Test..");
delay(500);
lcd.setCursor(0, 2);
lcd.print("Fan Test...");
delay(500);
lcd.setCursor(0, 2);
lcd.print("Fan Test....");
delay(500);
lcd.setCursor(0, 2);
lcd.print("Fan Test.....");
analogWrite(FAN_PIN, 255); // Full speed
delay(2000);
analogWrite(FAN_PIN, 0); // Turn off
lcd.setCursor(0, 3);
lcd.print("Fan OK");
delay(2000);
lcd.clear();
lcd.setCursor(3, 1);
lcd.print("TEST COMPLETE!");
delay(2000);
lcd.clear();
delay(500);
}
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(START_PIN, INPUT_PULLUP);
pinMode(OUTPUT_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(VOLTAGE_PIN, INPUT);
pinMode(PROTECTION_PIN, INPUT);
pinMode(CONTACT_PIN, INPUT); // New pin as input
pinMode(NTC_PIN, INPUT); // NTC thermistor pin
pinMode(FAN_PIN, OUTPUT); // Fan control pin
digitalWrite(OUTPUT_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(FAN_PIN, LOW);
pinMode(BACKLIGHT_PIN, OUTPUT);
lcd.init();
lcd.backlight();
brightness = EEPROM.read(7);
if (brightness > 5) brightness = 5;
analogWrite(BACKLIGHT_PIN, map(brightness, 0, 5, 0, 255));
lcd.setCursor(3, 0);
lcd.print("MNG proSystems");
lcd.setCursor(2, 1);
lcd.print(">>Spot Welders<<");
lcd.setCursor(3, 2);
lcd.print("Firmware V1.2s");
lcd.setCursor(0, 3);
lcd.print(" ** ");
delay(40);
lcd.setCursor(0, 3);
lcd.print(" **** ");
delay(40);
lcd.setCursor(0, 3);
lcd.print(" ****** ");
delay(40);
lcd.setCursor(0, 3);
lcd.print(" ******** ");
delay(40);
lcd.setCursor(0, 3);
lcd.print(" ********** ");
delay(40);
lcd.setCursor(0, 3);
lcd.print(" ************ ");
delay(40);
lcd.setCursor(0, 3);
lcd.print(" ************** ");
delay(40);
lcd.setCursor(0, 3);
lcd.print(" **************** ");
delay(40);
lcd.setCursor(0, 3);
lcd.print(" ****************** ");
delay(40);
lcd.setCursor(0, 3);
lcd.print("********************");
delay(2000);
beep();
selfTest();
lcd.clear();
drawScreen();
}
void loop() {
float protectionVoltage = analogRead(PROTECTION_PIN) * (5.0 / 1023.0);
bool protectionVoltageOutOfRange = (protectionVoltage > 5.0 || protectionVoltage < 3.0);
if (protectionVoltageOutOfRange) {
if (protectionVoltageStartTime == 0) {
protectionVoltageStartTime = millis();
} else if (millis() - protectionVoltageStartTime >= 1500) {
protectionActive = true;
}
} else {
protectionVoltageStartTime = 0;
protectionActive = false;
dangerDisplayed = false;
}
if (protectionActive) {
if (!dangerDisplayed) {
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("DC 15V PROBLEM!");
lcd.setCursor(6, 1);
lcd.print("DANGER!");
lcd.setCursor(2, 2);
lcd.print("CONTROL VOLTAGE");
lcd.setCursor(2, 3);
lcd.print("ERROR1 <10V >18V");
dangerDisplayed = true;
}
if (millis() - lastBeepTime >= 1000) {
beep();
lastBeepTime = millis();
}
return;
}
// Check temperature periodically
if (millis() - lastTempCheck >= TEMP_CHECK_INTERVAL) {
currentTemperature = readTemperature();
updateFanControl();
lastTempCheck = millis();
// Overheat protection
if (currentTemperature >= CRITICAL_TEMP && !overheatProtectionActive) {
overheatProtectionActive = true;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("OVERHEAT!");
lcd.setCursor(2, 1);
lcd.print("SYSTEM SHUTDOWN");
lcd.setCursor(0, 2);
lcd.print("Temp: ");
lcd.print(currentTemperature, 1);
lcd.print("C");
lcd.setCursor(2, 3);
lcd.print("COOL DOWN REQUIRED");
// Turn on fan at full speed
analogWrite(FAN_PIN, 255);
// Continuous beeping
beep();
delay(500);
beep();
// Disable output
digitalWrite(OUTPUT_PIN, LOW);
}
}
if (overheatProtectionActive) {
if (currentTemperature < FAN_OFF_TEMP) {
overheatProtectionActive = false;
lcd.clear();
drawScreen();
} else {
// Keep fan running at full speed
analogWrite(FAN_PIN, 255);
return; // Skip normal operation while in overheat protection
}
}
// === Mode AUTO: electrode short circuit control ===
float contactVoltage = analogRead(CONTACT_PIN) * (5.0 / 1023.0);
bool contactDetected = contactVoltage > 2.0; // Sensitivity threshold (adjustment by divider)
if (autoMode && !lowVoltageProtectionActive) {
if (contactDetected) {
if (contactStartTime == 0) {
contactStartTime = millis();
beep(); // Closing signal
} else if (!autoTriggered && millis() - contactStartTime >= (unsigned long)(sValue * 1000)) {
generatePulse();
autoTriggered = true;
}
} else {
contactStartTime = 0;
autoTriggered = false;
}
}
if (digitalRead(BUTTON_PIN) == LOW) {
if (!buttonHeld) {
buttonPressTime = millis();
buttonHeld = true;
} else if (millis() - buttonPressTime > 500) {
editMode = !editMode;
beep();
buttonHeld = false;
}
} else {
buttonHeld = false;
}
static unsigned long lastBlinkTime = 0;
if (editMode && millis() - lastBlinkTime > 500) {
blinkState = !blinkState;
lastBlinkTime = millis();
drawScreen();
}
long newPos = enc.read() / 4;
if (newPos != lastPos) {
beep();
if (!editMode) {
if (newPos > lastPos) {
selected = (selected + 1) % (autoMode ? 6 : 5); // В MAN skip S
} else {
selected = (selected + (autoMode ? 5 : 4)) % (autoMode ? 6 : 5);
}
} else {
if (selected < 3) {
if (newPos > lastPos && values[selected] < 50) values[selected]++;
if (newPos < lastPos && values[selected] > 0) values[selected]--;
EEPROM.write(selected, values[selected]);
} else if (selected == 3) {
if (newPos > lastPos && brightness < 5) brightness++;
if (newPos < lastPos && brightness > 0) brightness--;
analogWrite(BACKLIGHT_PIN, map(brightness, 0, 5, 0, 255));
EEPROM.write(7, brightness);
} else if (selected == 4) {
autoMode = !autoMode;
EEPROM.write(5, autoMode);
if (!autoMode && selected == 5) {
selected = 0;
}
} else if (selected == 5 && autoMode) {
if (newPos > lastPos && sValue < 2.0) sValue += 0.1;
if (newPos < lastPos && sValue > 0.3) sValue -= 0.1;
EEPROM.write(6, (int)(sValue * 10));
}
}
lastPos = newPos;
drawScreen();
}
float voltage = analogRead(VOLTAGE_PIN) * (14 / 1023.0) * voltageMultiplier;
bool lowVoltage = (voltage < 4.5);
if (lowVoltage) {
if (lowVoltageStartTime == 0) {
lowVoltageStartTime = millis();
} else if (millis() - lowVoltageStartTime >= 1500) {
lowVoltageProtectionActive = true;
}
} else {
lowVoltageStartTime = 0;
lowVoltageProtectionActive = false;
}
drawVoltage(voltage, lowVoltageProtectionActive);
if (!autoMode && digitalRead(START_PIN) == LOW && !startButtonState && !lowVoltageProtectionActive) {
startButtonState = true;
beep();
generatePulse();
}
if (digitalRead(START_PIN) == HIGH) {
startButtonState = false;
}
}
void drawScreen() {
for (int i = 0; i < 5; i++) {
lcd.setCursor((i % 2) * 10, i / 2);
// Arrow in front of the selected parameter
if (i == selected) {
lcd.print(" >");
} else {
lcd.print(" ");
}
// Blinking selected parameter
if (i == selected && editMode && blinkState) {
lcd.print(" "); // Clear line when blinking
} else {
if (i < 3) {
lcd.print(i == 0 ? "P1=" : i == 1 ? "T=" : "P2=");
if (i == 2 && values[2] == 0) {
lcd.print("OFF ");
} else {
lcd.print(values[i]);
lcd.print("ms ");
}
} else if (i == 3) {
lcd.print("Light:");
lcd.print(brightness);
lcd.print(" "); // Clear remaining text
} else if (i == 4) {
lcd.print("Mode:");
lcd.print(autoMode ? "AUTO " : "MAN ");
}
}
}
// If the mode is AUTO, draw S, otherwise erase the line
lcd.setCursor(11, 2);
if (autoMode) {
if (selected == 5) {
lcd.print(">");
} else {
lcd.print(" ");
}
if (selected == 5 && editMode && blinkState) {
lcd.print(" "); // Flashing S
} else {
lcd.print("S=");
lcd.print(sValue, 1);
lcd.print("s ");
}
} else {
lcd.print(" "); // Clear the line if the mode is MAN
}
// Display temperature and fan status on the bottom right
lcd.setCursor(11, 3);
lcd.print(currentTemperature, 1);
lcd.print("C");
lcd.setCursor(17, 3);
lcd.print(fanEnabled ? "FAN" : " ");
}
void drawVoltage(float voltage, bool lowVoltage) {
lcd.setCursor(0, 3);
lcd.print("Voltage: ");
lcd.print(voltage, 2);
lcd.print("V ");
if (lowVoltage) {
lcd.print("LOW ");
} else {
lcd.print(" "); // ← 5 spaces to ensure "LOW" is erased
}
}
void generatePulse() {
digitalWrite(OUTPUT_PIN, HIGH);
delay(values[0]);
digitalWrite(OUTPUT_PIN, LOW);
delay(10);
delay(values[1]);
digitalWrite(OUTPUT_PIN, HIGH);
delay(values[2]);
digitalWrite(OUTPUT_PIN, LOW);
}
float readTemperature() {
// Read multiple samples and average them
int samples[NUM_SAMPLES];
for (int i = 0; i < NUM_SAMPLES; i++) {
samples[i] = analogRead(NTC_PIN);
delay(10);
}
// Average the samples
float average = 0;
for (int i = 0; i < NUM_SAMPLES; i++) {
average += samples[i];
}
average /= NUM_SAMPLES;
// Convert the value to resistance
float resistance = SERIES_RESISTOR / (1023.0 / average - 1.0);
// Calculate temperature using Steinhart-Hart equation
float steinhart;
steinhart = resistance / NTC_NOMINAL; // (R/Ro)
steinhart = log(steinhart); // ln(R/Ro)
steinhart /= B_COEFFICIENT; // 1/B * ln(R/Ro)
steinhart += 1.0 / (TEMPERATURE_NOMINAL + 273.15); // + (1/To)
steinhart = 1.0 / steinhart; // Invert
steinhart -= 273.15; // Convert to Celsius
return steinhart;
}
void updateFanControl() {
if (currentTemperature >= FAN_ON_TEMP && !fanEnabled) {
fanEnabled = true;
analogWrite(FAN_PIN, 255); // Turn fan on at full speed
} else if (currentTemperature <= FAN_OFF_TEMP && fanEnabled) {
fanEnabled = false;
analogWrite(FAN_PIN, 0); // Turn fan off
}
}