Want to build a spot welder. Need adjustable pulses and display


I want make a small spot welder to make battery packs

I already have:

  • 1* 3s8p battery pack from high current Lithium-Ion cells (power tool batteries)
  • 1* MCP1407
  • 6* URF1324S Mosfets
  • 1* MCP1407 Mosfet driver
  • 2* 10mm diameter copper electrodes
  • 8mm² wire
  • 12V power supply (also a lab power supply)
  • small Voltmeter with display
  • Arduino Nano
  • Nokia 5110 LCD Breakout 84*48
  • a few different micro and non-micro switches (momentary and normal)

I've spotwelded with a similar setup at a friend's house, so batteries, electrodes, FETs are not the issue. I know for a fact that this works.
But I have zero experience with Arduino and programming in general.

What I would like to do:
First step:

  • Have one button that releases a pulse from the battery through the electrodes
  • Limit that pulse to 50ms

Next step:

  • Display the length of the pusle on the display

Next step:

  • Make the pulse adjustable in 5ms increments between 20ms and 500ms

Next step:

  • Make two pulses with both pulses and the pause inbetween adjustable and displaying all information on the display

It would be excellent, if I could do that for a first project, as it's something I would be using all the time.
Any guidance you guys could offer would be greatly appreciated.

Thank you

I was planning to do the following:

  1. Hook one electrode up to the plus pole using an 8mm wire
  2. Wire the drain of all Mosfets to the other electrode.
  3. Wire the source of the Fets to ground on the battery
  4. Wire the Gate of the Fets to Pin: 6 and/or 7 of the driver
  5. Wire Pin 1 of the driver to +12V on the battery
  6. Wire Pin 4 of the driver to ground on the battery
  7. Wire Pin 2 to a digital Pin on the Arduino

Is that setup correct so far?

The pulse timeing is easy. Take a look at the [u]Blink Example[/u] and the [u]Blink Without Delay Example[/u]. It's generally a good idea to avoid delay(), because the CPU just sits there doing nothing during the delay time, and it can't react to input switches or update the LCD etc. during the delay time.

You'll need to decide what kind of switches/user interface you want, and you'll have to figure-out how to interface to the LCD and how to send data to it.

Since the Arduino has a 10-bit analog-to-digital converter (1024 steps), you might want to consider using a potentiometer to set the pulse time. You can set the increment-size in software if you want.

I already have:

  • 1* 3s8p battery pack from high current Lithium-Ion cells (power tool batteries)

...I've spotwelded with a similar setup at a friend's house, so batteries, electrodes, FETs are not the issue.

I believe it "works", but if you are drawing the welding current directly from the battery, you might want to check the specs on the battery to make sure you re not exceeding the current rating, or that it can be safely shorted. Some batteries can catch fire! Or, it may have an internal thermal fuse that kills the battery if it overheats.

Most spot welder schematics I've seen don't power and switch the electrodes directly from the battery/power source but rather allow a large electrolytic capacitor to charge up to some predetermined voltage level and then separate from the voltage source and let the output switching determine the pulse shape/width determine how strong a weld pulse to deliver. Depending on the material being welded to there is value in being able to control as many variables as possible (voltage, pulse shape and width) to characterize the welding pulse delivered to the work.


Hello you two and thanks for your answers.

This is actually exactly the type of discussion I wanted to avoid.

The battery cells can handle the punishment. I've welded hundreds of cells with a setup that did not consist of 8 parallel cells of this type but only 3.
The cells are completely safe to short. They won't catch fire or anything.
So please, don't mind, whether the Fets, the electrodes or the cells are up to the task. That is the one part of this project I have completely handled.

I have obviously no shortage of pins so I can use one pin for every button. Also, I'm afraid I don't have any potentiometers. I have a bunch of different size resistors and capacitors here though.

I have to say, I have absolutely no idea how to display any kind of information on the display.
I will check out the blink without delay example. I'll quickly wrap up the Fets first. :slight_smile:

I'm well aware of the usual spot welding designs using thyristors or large capacitors. However. These used (broken) cells are dirt cheap and work like a charm. A spot welder like that will run between 50-100 Euros incl. the arduino and the display (depending on the price of the cells) and it'll work perfectly for welding battery packs. Sure, there are more sophisticated designs, but for the purpose, it's enough and it might make an excellent first arduino project for me.

This is the first code I've ever written in my life.
So please be patient.
Would this accomplish phase one?

const int fetPin =  A0;      
const int butttonPin = A1;

int fetState = LOW;    
int buttonState = LOW;
int previousMillis = 0;        

int interval = 50;           

void setup() {

  pinMode(fetPin, OUTPUT);
  pinMode(butttonPin, INPUT);  

void loop()
  if(buttonState = HIGH)
    fetState = HIGH;
      fetState = LOW;
  digitalWrite(fetPin, fetState);
     unsigned int currentMillis = millis();
  if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis;
        fetState = LOW;
  digitalWrite(fetPin, fetState);

This took me like 3 hours of research, thinking, debugging, biting my nails and finally not having any errors show up. I don't understand the "previous" and "current" things yet.

Does " unsigned int currentMillis = millis()" this make the program set some sort of a time stamp that can later be compared?
And in the next line " if(currentMillis - previousMillis > interval) {" will this accomplish that if the difference between the now currentMillis and the currentMillis from the line above have a larger difference than specified in the interval, the action from the next line will be carried out?

I hope I nailed the part about increasing and decreasing the length of the pulse

const int fetPin =  A0;      
const int butttonPin = A1;
const int increasePin = A2;
const int decreasePin =A3;

int fetState = LOW;    
int buttonState = LOW;
int increaseState = LOW;
int decreaseState = LOW;
int previousMillis = 0;        
int interval = 50;           

void setup() {

  pinMode(fetPin, OUTPUT);
  pinMode(butttonPin, INPUT);  

void loop()
  if(buttonState = HIGH)
    fetState = HIGH;
      fetState = LOW;
  digitalWrite(fetPin, fetState);
     unsigned int currentMillis = millis();
  if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis;
        fetState = LOW;
  digitalWrite(fetPin, fetState);
   if(increaseState = HIGH)
   interval + 5;
   if(interval > 500)
   interval = 500;
   if(decreaseState = HIGH)
   interval - 5;
   if(interval < 20)
   interval = 20;

You have made two classic errors in this code:

 if(buttonState = HIGH)

The first is that comparing for equality uses == not =. Everyone does this, usually multiple times. The other is to confuse the pin number with its state. You need to use digitalRead to find out what state the pin is in. Try it this way:

 if(digitalRead(buttonState) == HIGH)

Thank you Wildbill.
I will remember for the future and not make that mistake again :slight_smile: Promise

Can I use this

or this

Display or would that be too hard?

The only display with buttons I found only is a 2 row display, which is not enough.
I would need at least 3, better 4 rows,
plus 4, better 6 or 7 buttons (or a touchscreen)

I’ve managed to display information on the Nokis display. However it is much too small to use for the final device.

I was able to display simple text, however I was not able to display a variable on the display. I always get errors.

#include <HW_ARM_defines.h>
#include <HW_AVR_defines.h>
#include <HW_PIC32_defines.h>
#include <LCD5110_Basic.h>

int p1 = 555;
int d1 = 556;
int p2 = 557;

// The pins to use on the arduino
#define PIN_SCE 12
#define PIN_RESET 11
#define PIN_DC 10
#define PIN_SDIN 9
#define PIN_SCLK 8

// COnfiguration for the LCD
#define LCD_C LOW
#define LCD_D HIGH
#define LCD_CMD 0

// Size of the LCD
#define LCD_X 84
#define LCD_Y 48

int scrollPosition = 0;

static const byte ASCII[5] =
{0x00, 0x00, 0x00, 0x00, 0x00} // 20
,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !
,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 "
,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $
,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %
,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &
,{0x00, 0x05, 0x03, 0x00, 0x00} // 27 ’
,{0x00, 0x1c, 0x22, 0x41, 0x00} // 28 (
,{0x00, 0x41, 0x22, 0x1c, 0x00} // 29 )
,{0x14, 0x08, 0x3e, 0x08, 0x14} // 2a *
,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +
,{0x00, 0x50, 0x30, 0x00, 0x00} // 2c ,
,{0x08, 0x08, 0x08, 0x08, 0x08} // 2d -
,{0x00, 0x60, 0x60, 0x00, 0x00} // 2e .
,{0x20, 0x10, 0x08, 0x04, 0x02} // 2f /
,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 30 0
,{0x00, 0x42, 0x7f, 0x40, 0x00} // 31 1
,{0x42, 0x61, 0x51, 0x49, 0x46} // 32 2
,{0x21, 0x41, 0x45, 0x4b, 0x31} // 33 3
,{0x18, 0x14, 0x12, 0x7f, 0x10} // 34 4
,{0x27, 0x45, 0x45, 0x45, 0x39} // 35 5
,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 36 6
,{0x01, 0x71, 0x09, 0x05, 0x03} // 37 7
,{0x36, 0x49, 0x49, 0x49, 0x36} // 38 8
,{0x06, 0x49, 0x49, 0x29, 0x1e} // 39 9
,{0x00, 0x36, 0x36, 0x00, 0x00} // 3a :
,{0x00, 0x56, 0x36, 0x00, 0x00} // 3b ;
,{0x08, 0x14, 0x22, 0x41, 0x00} // 3c <
,{0x14, 0x14, 0x14, 0x14, 0x14} // 3d =
,{0x00, 0x41, 0x22, 0x14, 0x08} // 3e >
,{0x02, 0x01, 0x51, 0x09, 0x06} // 3f ?
,{0x32, 0x49, 0x79, 0x41, 0x3e} // 40 @
,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 41 A
,{0x7f, 0x49, 0x49, 0x49, 0x36} // 42 B
,{0x3e, 0x41, 0x41, 0x41, 0x22} // 43 C
,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 44 D
,{0x7f, 0x49, 0x49, 0x49, 0x41} // 45 E
,{0x7f, 0x09, 0x09, 0x09, 0x01} // 46 F
,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 47 G
,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 48 H
,{0x00, 0x41, 0x7f, 0x41, 0x00} // 49 I
,{0x20, 0x40, 0x41, 0x3f, 0x01} // 4a J
,{0x7f, 0x08, 0x14, 0x22, 0x41} // 4b K
,{0x7f, 0x40, 0x40, 0x40, 0x40} // 4c L
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 4d M
,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 4e N
,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 4f O
,{0x7f, 0x09, 0x09, 0x09, 0x06} // 50 P
,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 51 Q
,{0x7f, 0x09, 0x19, 0x29, 0x46} // 52 R
,{0x46, 0x49, 0x49, 0x49, 0x31} // 53 S
,{0x01, 0x01, 0x7f, 0x01, 0x01} // 54 T
,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 55 U
,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 56 V
,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 57 W
,{0x63, 0x14, 0x08, 0x14, 0x63} // 58 X
,{0x07, 0x08, 0x70, 0x08, 0x07} // 59 Y
,{0x61, 0x51, 0x49, 0x45, 0x43} // 5a Z
,{0x00, 0x7f, 0x41, 0x41, 0x00} // 5b [
,{0x02, 0x04, 0x08, 0x10, 0x20} // 5c ¥
,{0x00, 0x41, 0x41, 0x7f, 0x00} // 5d ]
,{0x04, 0x02, 0x01, 0x02, 0x04} // 5e ^
,{0x40, 0x40, 0x40, 0x40, 0x40} // 5f _
,{0x00, 0x01, 0x02, 0x04, 0x00} // 60 `
,{0x20, 0x54, 0x54, 0x54, 0x78} // 61 a
,{0x7f, 0x48, 0x44, 0x44, 0x38} // 62 b
,{0x38, 0x44, 0x44, 0x44, 0x20} // 63 c
,{0x38, 0x44, 0x44, 0x48, 0x7f} // 64 d
,{0x38, 0x54, 0x54, 0x54, 0x18} // 65 e
,{0x08, 0x7e, 0x09, 0x01, 0x02} // 66 f
,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 67 g
,{0x7f, 0x08, 0x04, 0x04, 0x78} // 68 h
,{0x00, 0x44, 0x7d, 0x40, 0x00} // 69 i
,{0x20, 0x40, 0x44, 0x3d, 0x00} // 6a j
,{0x7f, 0x10, 0x28, 0x44, 0x00} // 6b k
,{0x00, 0x41, 0x7f, 0x40, 0x00} // 6c l
,{0x7c, 0x04, 0x18, 0x04, 0x78} // 6d m
,{0x7c, 0x08, 0x04, 0x04, 0x78} // 6e n
,{0x38, 0x44, 0x44, 0x44, 0x38} // 6f o
,{0x7c, 0x14, 0x14, 0x14, 0x08} // 70 p
,{0x08, 0x14, 0x14, 0x18, 0x7c} // 71 q
,{0x7c, 0x08, 0x04, 0x04, 0x08} // 72 r
,{0x48, 0x54, 0x54, 0x54, 0x20} // 73 s
,{0x04, 0x3f, 0x44, 0x40, 0x20} // 74 t
,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 75 u
,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 76 v
,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 77 w
,{0x44, 0x28, 0x10, 0x28, 0x44} // 78 x
,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 79 y
,{0x44, 0x64, 0x54, 0x4c, 0x44} // 7a z
,{0x00, 0x08, 0x36, 0x41, 0x00} // 7b {
,{0x00, 0x00, 0x7f, 0x00, 0x00} // 7c |
,{0x00, 0x41, 0x36, 0x08, 0x00} // 7d }
,{0x10, 0x08, 0x08, 0x10, 0x08} // 7e ?
,{0x00, 0x06, 0x09, 0x09, 0x06} // 7f ?

void LcdCharacter(char character)
LcdWrite(LCD_D, 0x00);
for (int index = 0; index < 5; index++)
LcdWrite(LCD_D, ASCII[character - 0x20][index]);
LcdWrite(LCD_D, 0x00);

void LcdClear(void)
for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
LcdWrite(LCD_D, 0x00);

void LcdInitialise(void)
pinMode(PIN_DC, OUTPUT);

digitalWrite(PIN_RESET, LOW);
digitalWrite(PIN_RESET, HIGH);

LcdWrite(LCD_CMD, 0x21); // LCD Extended Commands.
LcdWrite(LCD_CMD, 0xBf); // Set LCD Vop (Contrast). //B1
LcdWrite(LCD_CMD, 0x04); // Set Temp coefficent. //0x04
LcdWrite(LCD_CMD, 0x14); // LCD bias mode 1:48. //0x13
LcdWrite(LCD_CMD, 0x0C); // LCD in normal mode. 0x0d for inverse
LcdWrite(LCD_C, 0x20);
LcdWrite(LCD_C, 0x0C);

void LcdString(char *characters)
while (*characters)

void LcdWrite(byte dc, byte data)
digitalWrite(PIN_DC, dc);
digitalWrite(PIN_SCE, LOW);
digitalWrite(PIN_SCE, HIGH);


  • gotoXY routine to position cursor
  • x - range: 0 to 84
  • y - range: 0 to 5
    void gotoXY(int x, int y)
    LcdWrite( 0, 0x80 | x); // Column.
    LcdWrite( 0, 0x40 | y); // Row.

void setup(void)


void loop(void)
itoa (d1,

LcdString(" ms");



I looked at “char” and “Itoa” commands, also Lcd.Print… but nothing I’ve tried so far worked.
Also notice that in the first line, I moved the “ms” only 57 rows over, while it’s 65 on the others?
That’s the only way I could align them.