Close

The Software bit...

A project log for DIY Spot Welder for Creating Battery Packs

Building a Spot Welder for 18650 battery packs is an interesting and challenging adventure. How to over-engineer a spot welder.

timo-birnscheinTimo Birnschein 01/06/2018 at 07:450 Comments

This is not a super elaborate code that controls the universe and everything.

Instead it's just a very simple piece of code that allows driving a display, debouncing a switch, reading two potentiometers, and drive a relay. That's it.

I use busy waiting to execute the read potentiometer values and I use very simple line drawing to visualize the pulse pattern.

I divided the welding process into two steps:

  1. Pre-welding the material to heat it up, make it soft and establish excellent conductivity between all materials to be welded
  2. Welding the material together with a potentially longer pulse.

During my initial tests and from what I have read online in several articles, the typical pre weld time is around 50 ms and the typical weld time is around 100 ms. I used this as a base line since most people don't seem to weld with 1750 Watts. I wanted to be able to adjust my welding times between 25 ms and 275 ms by adjusting two potentiometers. I also added a cooldown time in between the two weld actions of 250 ms. That's a pure guess and should have been adjustable with another potentiometer as well but I didn't see the immediate need for it. If you need it, please add a third pot to the code and to your welder. I don't think it's necessary for making battery packs.

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>

// For the breakout, you can use any 2 or 3 pins
// These pins will also work for the 1.8" TFT shield
#define TFT_CS   10
#define TFT_RST  9
#define TFT_DC   8

#define TFT_SCLK 13
#define TFT_MOSI 11

#define MINWELDTIME   25
#define MAXWELDTIME   250
#define COOLDOWNTIME  250
#define ADCRESOLUTION 1023
#define GRAPHDIVIDER  7 // devides the values for displaying the graph to something that can be displayed

// use the hardware SPI pins (for UNO thats sclk = 13 and sid = 11) and pin 10 must be an output.
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);

// constants won't change. They're used here to
// set pin numbers:
const int buttonPin = 5;    // the number of the pushbutton pin
const int ledPin = 12;      // the number of the LED pin
const int relayPin = 2;     // the number of the relay pin
const int preWeldSensorPin = A0;   // the number of the potentiometer ADC pin
const int weldSensorPin = A1;   // the number of the potentiometer ADC pin

// Variables will change:
int ledState = LOW;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
int preWeldSensorValue = 0;         // variable to store the value coming from the potentiometer
int weldSensorValue = 0;         // variable to store the value coming from the potentiometer
bool redrawGraph = true;      // Did we change the times and need to redraw the graphs?

int lastPreWeldTime = 0;  // Storage for the previously set weld times
int lastWeldTime = 0;     // So that we don't run into flickering numbers on the display

// the following variables are unsigned long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(relayPin, OUTPUT);

  // set initial LED state
  digitalWrite(ledPin, ledState);
  digitalWrite(relayPin, HIGH);

  Serial.begin(115200);     // opens serial port, sets data rate to 115200 bps
  Serial.println("Spot Welder Version 0.1 - Timo Birnschein - MicroForge 2018");
  Serial.println("email: timo.birnschein@microforge.de");

  displayInitScreen();
}

void loop() {
  // read the value from the sensor:
  preWeldSensorValue = analogRead(preWeldSensorPin);
  weldSensorValue = analogRead(weldSensorPin);

  // Read analog signal to determine time to weld
  int preWeldTime = (int)((float)MINWELDTIME + (((float)MAXWELDTIME / (float)ADCRESOLUTION) * (float)preWeldSensorValue)); // Scale 10 bit value to something with an offset
  int weldTime = (int)((float)MINWELDTIME + (((float)MAXWELDTIME / (float)ADCRESOLUTION) * (float)weldSensorValue)); // Scale 10 bit value to something with an offset
  
  // Check for errors
  if (preWeldTime <= 0) preWeldTime = (float)MINWELDTIME;
  if (weldTime <= 0) weldTime = (float)MINWELDTIME;

  if ((preWeldTime > (lastPreWeldTime + 1)) || (preWeldTime < (lastPreWeldTime - 1)))
  {
    redrawGraph = true;
  }
  
  if ((weldTime > (lastWeldTime + 1)) || (weldTime < (lastWeldTime - 1)))
  {    
    redrawGraph = true;
  }

  if (redrawGraph == true)
  {
    redrawGraph = false;
    
    String strBuffer = String("               " + String(lastPreWeldTime) + " ms");
    tftPrintText(strBuffer, 0, 50, 1, ST7735_BLACK);
    strBuffer = String("Pre weld time: " + String(preWeldTime) + " ms");
    tftPrintText(strBuffer, 0, 50, 1, ST7735_RED);
    
    strBuffer = String("           " + String(lastWeldTime) + " ms");
    tftPrintText(strBuffer, 0, 60, 1, ST7735_BLACK);
    strBuffer = String("Weld time: " + String(weldTime) + " ms");
    tftPrintText(strBuffer, 0, 60, 1, ST7735_RED);
    
    tft.drawFastHLine(0, 100, 6, ST7735_BLACK);
    tft.drawFastVLine(5, 80, 20, ST7735_BLACK);
    tft.drawFastHLine(5, 80, (lastPreWeldTime / GRAPHDIVIDER), ST7735_BLACK);
    tft.drawFastVLine(5 + (lastPreWeldTime / GRAPHDIVIDER), 80, 20, ST7735_BLACK);
    tft.drawFastHLine(5 + (lastPreWeldTime / GRAPHDIVIDER), 100, (COOLDOWNTIME / GRAPHDIVIDER) + 1, ST7735_BLACK);

    tft.drawFastVLine(5 + (lastPreWeldTime / GRAPHDIVIDER) + (COOLDOWNTIME / GRAPHDIVIDER), 80, 20, ST7735_BLACK);
    tft.drawFastHLine(5 + (lastPreWeldTime / GRAPHDIVIDER) + (COOLDOWNTIME / GRAPHDIVIDER), 80, (lastWeldTime / GRAPHDIVIDER), ST7735_BLACK);
    tft.drawFastVLine(5 + (lastPreWeldTime / GRAPHDIVIDER) + (COOLDOWNTIME / GRAPHDIVIDER) + (lastWeldTime / GRAPHDIVIDER), 80, 20, ST7735_BLACK);
    tft.drawFastHLine(5 + (lastPreWeldTime / GRAPHDIVIDER) + (COOLDOWNTIME / GRAPHDIVIDER) + (lastWeldTime / GRAPHDIVIDER), 100, COOLDOWNTIME, ST7735_BLACK);
    
    tft.drawFastHLine(0, 100, 6, ST7735_WHITE);
    tft.drawFastVLine(5, 80, 20, ST7735_WHITE);
    tft.drawFastHLine(5, 80, (preWeldTime / GRAPHDIVIDER), ST7735_WHITE);
    tft.drawFastVLine(5 + (preWeldTime / GRAPHDIVIDER), 80, 20, ST7735_WHITE);
    tft.drawFastHLine(5 + (preWeldTime / GRAPHDIVIDER), 100, (COOLDOWNTIME / GRAPHDIVIDER) + 1, ST7735_WHITE);
    
    tft.drawFastVLine(5 + (preWeldTime / GRAPHDIVIDER) + (COOLDOWNTIME / GRAPHDIVIDER), 80, 20, ST7735_WHITE);
    tft.drawFastHLine(5 + (preWeldTime / GRAPHDIVIDER) + (COOLDOWNTIME / GRAPHDIVIDER), 80, (weldTime / GRAPHDIVIDER), ST7735_WHITE);
    tft.drawFastVLine(5 + (preWeldTime / GRAPHDIVIDER) + (COOLDOWNTIME / GRAPHDIVIDER) + (weldTime / GRAPHDIVIDER), 80, 20, ST7735_WHITE);
    tft.drawFastHLine(5 + (preWeldTime / GRAPHDIVIDER) + (COOLDOWNTIME / GRAPHDIVIDER) + (weldTime / GRAPHDIVIDER), 100, COOLDOWNTIME, ST7735_WHITE);
    
    lastPreWeldTime = preWeldTime;
    lastWeldTime = weldTime;
  }

  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
//**************************************************************************************************
        Serial.print("Pre weld time set to: ");
        Serial.print(preWeldTime);
        Serial.print(" ms\n\r");
        Serial.print("Weld time set to: ");
        Serial.print(weldTime);
        Serial.print(" ms\n\r");
        
        String strBuffer = String("!WELDING!");
        tftPrintText(strBuffer, 10, 125, 2, ST7735_RED);
        
        // Do pre heating sequence based on predefined fraction of the total welding time
        digitalWrite(relayPin, LOW); // Relay is active low
        digitalWrite(ledPin, HIGH); // LED is active high
        delay(preWeldTime);
        
        digitalWrite(relayPin, HIGH);
        digitalWrite(ledPin, LOW);
        delay(COOLDOWNTIME);
        
        // Do welding
        digitalWrite(relayPin, LOW);
        digitalWrite(ledPin, HIGH);
        delay(weldTime);

        // Reset all ports
        digitalWrite(relayPin, HIGH);
        digitalWrite(ledPin, LOW);
        
        tftPrintText(strBuffer, 10, 125, 2, ST7735_BLACK);
        // Restart loop
//**************************************************************************************************/
      }
    }
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

void displayInitScreen(void)
{
  tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab  
  tft.setRotation(0);
  tft.fillScreen(ST7735_BLACK);
  
  char display_buffer [20];
  memset(display_buffer, 0, 20);
  sprintf(display_buffer, "Spot Welder v0.1");
  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(1);
  tft.setCursor(0, 0);
  tft.print(display_buffer);
  
  memset(display_buffer, 0, 20);
  sprintf(display_buffer, "    MicroForge - 2018");
  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(1);
  tft.setCursor(0, 10);
  tft.print(display_buffer);

  //delay(1000);
        
  //tft.fillScreen(ST7735_BLACK);

  String strBuffer = String("Spot weld timing:");
  tftPrintText(strBuffer, 0, 35, 1, ST7735_YELLOW);
}

void tftPrintText(String textBuffer, int x, int y, int textSize, int color)
{
  if (textSize == 0) textSize = 1;
  tft.setTextColor(color);
  tft.setTextSize(textSize);
  tft.setCursor(x, y);
  tft.print(textBuffer.c_str());
}

Here is the resulting visualization for both peeks as well as the exact times of both weld actions.

Discussions