Reflow Oven Controller

This shows the build for a simple Arduino-based reflow oven controller. This converts a basic toaster oven into a temperature controlled reflow oven for making surface mount circuits. The temperature profile is read from a simple text file on an SD card. This makes changing the temperature profile very easy, without any new code to upload.

I’ve not done much surface mount work, mainly as I like the projects that I build to be easily repeatable with minimal tools. But there are a number of ICs which are only available as a surface mount package.

Also, surface mount boards are smaller, so consume less resources, and do not require drilling all the holes.

Finished unit

Here is the finished unit. It has worked on a couple of test runs, but I will upload photos of the first boards built on it.

The oven is controlled with a solid state relay. It still works as a timed oven (but I will not be cooking my food in it after filling it with lead fumes).

The LCD screen shows the actual temperature (Ta), the setpoint temperature (Ts) the time taken in seconds (T) and the phase of the temperature profile.

This is crammed into the laser cut enclosure. It uses the DataDuino as the basis for project (with SD card and real time clock). A serial interfaces LCD screen (again with an Arudino) is used as the display. Temperature is measured with a thermocouple and a specialist  k-type thermocouple amplifier IC.

Reflow temperature profiles

There is quite a lot of information on the temperature profile required for reflow solder techniques.

Here is one link:

Basically there are four main stages:

  • Warm – Approx 90s getting up to 150C
  • Soak – Stay between 150 and 200C for 60s
  • Reflow/Peak – Ramp up up to 250C and stay there for at least 5seconds. Takes around 60s
  • Cool – The slower cooling the better the connections

Obviously each solder paste and set of components is slightly different. I needed a generic reflow curve which I could easily adapt.

I did this by implementing the reflow curve data within a text file on an SD card. This can be changed easily and the new set points are loaded each time the unit is switched on.

The data is in the format:

Start Temp, Finish Temp, Time, Rate

These are in .csv format and you can enter as many as you like. These data points will be used to create the temperature setpoint. A hysteresis controller is used to control the heater to get to the set point.

The setpoint temperature is calculated from first figuring out if the rate is +ve or -ve. This will then increment or decrement the setpoint. The setpoint temperature will then be the start temperature which is then ramped up to the finish temperature at the ramp rate. If the ramp is set to zero then the ramp is calculated from (finish temp-start temp)/Time.

Toaster Oven conversion

I used a second hand toaster oven, which cost £8 from the car boot sale. It was in almost new condition. It is 700W rated, which is a bit under rated it turns out, and uses infra-red elements at the top and in the base.

A solid-state relay (from a Chinese manufacturer, which I had lying around) is used to control the oven. This can cope with 25A, but I am only putting around 3A through it. The back of the relay is a metal plate for heat-sinking, which I bolted to the metal casing of the toaster. This would not be OK for leaving it on all the time, but for the 4-5mins for a reflow oven, this should be OK.

Testing the unit. The relay is added to the mechanical timer contacts.

The relay is mounted inside the case, onto the back metal plate (which is incredibly thin so probably will not work as an amazing heatsink).

Here I am testing the oven using a 5V input. The heaters are controlled well.

Temperature measurement

I have written about temperature measurment before. This time the temperatures are quite high. We need to be able to measure up to 400C with no problems. The typical technique to do this is to use a thermocouple. This is a set of two junctions of two dissimilar metals. If one junction is kept cool while the other heated up then a very small voltage is generated (by the Seeback effect).

The problem is that this voltage is very small (a few uV per degree C). Also a cold junction is required which must have a known temperature.

To convert the thermocouple value into a more useful voltage I used a thermocouple amplifier IC. This was the AD8495CRMZ from Analog Devices. This was expensive (around £6 from Farnell), but did everything I needed. It has an internal calibrated temperature sensor so that it knows the cold junction temperature, a conversion for K type thermocouples and an amplifier. The output is 5mV per degree C, hence it is much easier to read by the microcontroller, especially at higher temperatures.

I used this thermocouple from Farnell, which is good for up to 1000C.

The IC is only available in a surface mount package, hence I needed to use these adaptors I made. The irony of needing a reflow solder oven to solder these is not lost on me, but I hand soldered these.

The final circuit was taken straight out of the data sheet. Which suggests using input resistors and filtering capacitors (there are two more capacitors on the back of the board). Also an output RC filter is used to remove any 50Hz hum.

Circuit overview

I am not planning on making loads of these, hence I have not produced a full circuit, so you will just have to make do with these photos and explanations. The main brains of the device is an Arduino based ATmega328 with the DataDuino board. I used this board as I have a load of them. It has an SD card holder in it and a real time clock to give accurate timing pulses (not really required, but I used it any way).

There are three main sections: The DataDuino brain, the thermocouple conversion circuit and a serial LCD display (the green board and the green LCD display).

The DataDuino has the main control code on it. it has two inputs for start and stop switches. It also has output LEDs for when the device is running and an output to control the heater solid state relay.

There were not enough pins to run and LCD display, but I really wanted a user interface which shows various data. Hence I used another Arduino board (home brewed on the Nottingham hackspace PCB workshop) and uploaded the basic Serial to LCD example within the Arduino IDE.

This worked great. To output data to the 16 x 2 LCD screen I needed to create an output which was 80 characters long. The first 40 are for the first line, which then rolls over to the second line for the next 40. This took a bit of working out, but is there in the data sheets if you look hard enough. So I updated this display with totally new data every second.

I like this as a way of adding a display – it only uses two pins and you can output error messages etc. I will probably roll a PCB for implementing this, please email if interested in one.

Arduino code

The Arduino code is here. I used the Arduino Uno bootloader and version 1.0.5 of the IDE. It requires a number of libraries to be installed, as listed in the header file. It should be commented to explain what it does. Please get in touch if you would like to know more.

/****** Reflow Oven Controller - Arduino DAQ UNIT ********************
/****** by Matt Little **********************************
/****** Date: 15/10/13 **********************************
/****** ************************
/****** *************************

  See for information and construction details

/*************Details of Code*****************************

  This is a reflow oven controller based upon the DataDuino board
  The DataDuino has an SD card holder and a real time clock on-board
  It interfaces with a modified IR cooking oven using a solid state relay
  The SD card holds the temperature profile for the device
  The RTC ensure correct timing for the stages
  An additional k-type thermocouple and converter IC is required.
  A PCF8563 Realt Time Clock is used to timestamp the data.
  Pin D7 controls the heater
  Pin A0 has a temperature sensor attached
  An LCD interface would be nice.
  Pin D4 is set up to record a DS18B20 1 wire temp sensor (up to 4 sensors can be attached) 
  Pin D3 is set up to cound pulses from a sensor (such as a anemometer or flow sensor)
  Pins D7,D8,D9 are set up to record digital information (0 or 1)
  Pins A0 to A3 are set up to record analogue information (0 to 1024)
  15/10/13  Code Started   Matt Little
  17/10/13  Added output via serial LCD  Matt Little
  17/10/13  Added analog input  Matt Little
  17/10/13  Added AD8495 Thermocouple amplifier and conversion factor  Matt Little

 //*********SD CARD DETAILS***************************	
 The SD card circuit:
 SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 10
 ** Card detect - pin 6
 SD card code details:
 created  24 Nov 2010
 updated 2 Dec 2010
 by Tom Igoe
 //************ Real Time Clock code*******************
 A PCF8563 RTC is attached to pins:
 ** A4 - SDA (serial data)
 ** A5 - SDC (serial clock)
 ** D2 - Clock out - This gives a 1 second pulse to record the data
 RTC PCF8563 code details:
 By Joe Robertson, jmr

/************ External Libraries*****************************/
#include <stdlib.h>
#include <Wire.h>          // Required for RTC
#include <Rtc_Pcf8563.h>   // RTC library
#include <SD.h>            // SD card library
#include <avr/pgmspace.h>  // Library for putting data into program memory
#include <EEPROM.h>        // For writing values to the EEPROM
#include <avr/eeprom.h>

/************User variables and hardware allocation**********************************************/

/******* SD CARD*************/
const int chipSelect = 10; // The SD card Chip Select pin 10
const int cardDetect = 6;  // The SD card detect is on pin 6
// The other SD card pins (D11,D12,D13) are all set within SD.h
int cardDetectOld = LOW;  // This is the flag for the old reading of the card detect

/*************Real Time Clock*******/
Rtc_Pcf8563 rtc;
#define I2C_RTC 0x51 // 7 bit address (without last bit - look at the datasheet)
int RTCinterrupt = 0;  // RTC interrupt - This is pin 2 of ardunio - which is INT0

/********* Output LED *************/
const int LEDred = 5;  // The output led is on pin 5

/********* Output for heater ************/
const int heater = 7;  // HEater control is on pin 7

const int swStart = 9;  // Start button
const int swStop = 8;  // Stop button

/********** Input for temperature sensor *******/
//int temperature = A0;  // Analog input

//********Variables for the Filename*******************

char filename[] = "flow.csv";  // This is a holder for the full file name
//int refnumber;     // The house number here, which is stored in EEPROM
File datafile;   // The logging file
int dataArray[100];    // This is the holder array for the data as a string. Start as blank
int dataInt;    // This holds the integer value of the data
int n = 0;    // An integer for counting how many data points available
int dataPoint = 100;  // This tells us which set of data points the control system is using

int timeFromStart = 0;  // Is a counter to show the time from switch ON
int totalFromStart = 0;  // This counts the full time in seconds from the start
int tempSetpoint = 0;   // This is the temperature to try and reach, with the heater control (hysteresis or PID)
int startTemp = 0;      // These hold the temperature setpoints
int endTemp = 0;
int rateTemp = 0;
int endTime =0;  

int actualTemp = 0;  // This holds the actual temperature data
boolean startFlag=LOW;  // Should the device start or not

// Variables for the Pulse Counter
int pulseinterrupt = 1;  // Pulse Counter Interrupt - This is pin 3 of arduino - which is INT1

volatile int writedataflag = HIGH;  // A flag to tell the code when to write data

int day_int =0;      // To find the day from the Date for the filename
int day_int1 =0;
int day_int2 =0;
int month_int = 0;
int month_int1 = 0;
int month_int2 = 0;
int year_int = 0;  // Year
int hour_int = 0;
int min_int = 0;
int sec_int = 0;

// Varibales for writing to EEPROM
int hiByte;      // These are used to store longer variables into EERPRPROM
int loByte;

unsigned long int calibrationFactor = 0;    // This holds the Vref calibration factor

//**********STRINGS TO USE****************************
String comma = ",";
String date;        // The stored date from filename creation
String newdate;     // The new date, read every time 

// These are Char Strings - they are stored in program memory to save space in data memory
// These are a mixutre of error messages and serial printed information
const char initialisesd[] PROGMEM = "Initialising SD card...";
const char noSD[] PROGMEM = "No SD card      ";
const char start[] PROGMEM = "Reflow Oven                             Controller      ";
const char checkSD[] PROGMEM = "Checking SD.....  ";
const char okSD[] PROGMEM = "SD Data is OK    ";

#define MAX_STRING 80      // Sets the maximum length of string probably could be lower
char stringBuffer[MAX_STRING];  // A buffer to hold the string when pulled from program memory

//****************INITIALISE ROUTINE******************************
void setup()

  //******Real Time Clock Set - up********
  // A4 and A5 are used as I2C interface.
  // D2 is connected to CLK OUT from RTC. This triggers an interrupt to take data
  // We need to enable pull up resistors
  pinMode(A4, INPUT);           // set pin to input
  digitalWrite(A4, HIGH);       // turn on pullup resistors
  pinMode(A5, INPUT);           // set pin to input
  digitalWrite(A5, HIGH);       // turn on pullup resistors
  pinMode(2,INPUT);    // Set D2 to be an input for the RTC CLK-OUT   
  //initialise the real time clock
  Rtc_Pcf8563 rtc; 

  Serial.begin(9600);    // Set up a serial output for data display and changing parameters

  analogReference(DEFAULT);  // This sets the internal ref to be 2.56V (or close to this);

  // Read in the Voltage Set-point
  hiByte =;
  loByte =;
  calibrationFactor = (hiByte << 8)+loByte;  // Get the sensor calibrate value
  initialiseSD();    // Inisitalise the SD card
  // Here we want to read from the SD card and get the correct temperature setpoints:
  datafile =;    // Open the correct file
  if (datafile) 
    //Serial.println("Data is available:");
    // read from the file until there's nothing else in it:
    n = 0;
    while (datafile.available()) 
      // Need to parse the data and record it into a varaibale here
      // Data is in the format Start Temp, Finish Temp, Time, Rate
      dataInt = datafile.parseInt();
      //Serial.println(dataInt);  // For debugging
      dataArray[n] = dataInt;
      // The end result of this is dataArray with all the data as int within an array
      // The value n which is the number of ints within the array (divide by 4 to give number of setpoints)
    // close the file:
    // No SD card - the device will not run
    // Show error message and highlight error LED
    //************TO DO****************
    //When SD card is inserted then re-initialise everything....???
    //************TO DO****************

  attachInterrupt(RTCinterrupt, RTC, FALLING);  // This sets up our Interrupt Service Routine (ISR) for RTC
  pinMode(LEDred,OUTPUT);    // Set D5 to be an output LED
  pinMode(cardDetect,INPUT);  // D6 is the SD card detect on pin 6.
  //Set up digital data lines


//**************The RTC interrupt****************
// I use the CLK_OUT from the RTC to give me exact 1Hz signal
// To do this I changed the initialise the RTC with the CLKOUT at 1Hz
void RTC()
    // We update the temperature setpoint every second
    // This is done here to give accurate timing
  if(writedataflag==LOW)  // This stops us loosing data if a second is missed
    // This gives us a 1 second output pulse for accurate timing
    // This is used to output data onto the serial port
    // Set the writedataflag HIGH

void loop()
  // ************ MEASURE THE TEMPERATURE *********************
  // Temperature is measured using a K-type thermocouple.
  // This is amplified with a AD8495 therocouple amplifier
  // Which converts the signal to 5mV per degree celcius
  // Hence the reading in volts / 0.005 = actual temperature
  actualTemp = ((float)analogRead(A0)/(float)calibrationFactor)/(0.005);   // Read the analogue voltage
  // Check if start button pressed
  // If start button is pressed then reset the dataPoint and timer values
    // Only if the start button is pressed do we start

    // If the stop button is pressed then STOP!
    //*******SWITCH OFF HEATER***********
    // Only run if the data point is within the range available on the SD card
      timeFromStart=0;  // Reset the time for this new datapoint set
      dataPoint++;  // Increase the data points
    // Here we run the program
      //*********** SORT OUT HEATER CONTROL HERE *********************
      // The heater works on Hysteresis control
      // We check the heater every 20ms (approx)
      // This might need adjustment of the hysteresis control for overshoot
      delay(200);  // Gives a very short delay to the on/off control
        startTemp = dataArray[(dataPoint*4)];
        endTemp = dataArray[(dataPoint*4)+1];
        endTime = dataArray[(dataPoint*4)+2];
        rateTemp = dataArray[(dataPoint*4)+3];
        // We also want to update the temperature setpoint (tempSetpoint)
        // This must be caluclated from a mixture of the rate, the start temp and the final temp
        // If the rate is zero then we work out the rate from the start/end tempeeratures
          // The rate will depend upon the difference between the start and end temps
            rateTemp = (endTemp-startTemp)*10/endTime;
          else if(endTemp<startTemp)
            rateTemp = (startTemp-endTemp)*10/endTime;
        // We need to calculate the direction of the temperature change:
          // In this case the direction is INCREASING
          tempSetpoint = (startTemp*10 + (rateTemp*timeFromStart))/10;
        else if (endTemp<startTemp)
          // In this case the direction is DECREASNG
          tempSetpoint = (startTemp*10 - (rateTemp*timeFromStart))/10;
    digitalWrite(heater,LOW); // Ensure heater is OFF when stopped running
    //********* DISPLAY DATA **********
    // Want to display data even when not running
    // Do this 1 per second


//*********** FUNCTION TO INITIALISE THE SD CARD***************
void initialiseSD()
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(chipSelect, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    // don't do anything more:
    // Want to turn on an ERROR LED here

// Converts a decimal to BCD (binary coded decimal)
byte DecToBcd(byte value){
  return (value / 10 * 16 + value % 10);

// This routine pulls the string stored in program memory so we can use it
// It is temporaily stored in the stringBuffer
char* getString(const char* str) {
	strcpy_P(stringBuffer, (char*)str);
	return stringBuffer;

//Initialise the RTC
void initialiseRTC()
  // This section configures the RTC to have a 1Hz output.
  // Its a bit strange as first we read the data from the RTC
  // Then we load it back again but including the correct second flag  
  year_int = rtc.getYear();
  day_int = rtc.getDay();
  month_int = rtc.getMonth();  
  hour_int = rtc.getHour();
  min_int = rtc.getMinute();
  sec_int = rtc.getSecond(); 
  Wire.begin(); // Initiate the Wire library and join the I2C bus as a master
  Wire.beginTransmission(I2C_RTC); // Select RTC
  Wire.write(0);        // Start address
  Wire.write(0);     // Control and status 1
  Wire.write(0);     // Control and status 2
  Wire.write(DecToBcd(sec_int));     // Second
  Wire.write(DecToBcd(min_int));    // Minute
  Wire.write(DecToBcd(hour_int));    // Hour
  Wire.write(DecToBcd(day_int));    // Day
  Wire.write(DecToBcd(2));    // Weekday
  Wire.write(DecToBcd(month_int));     // Month (with century bit = 0)
  Wire.write(DecToBcd(year_int));    // Year
  Wire.write(0b10000000);    // Minute alarm (and alarm disabled)
  Wire.write(0b10000000);    // Hour alarm (and alarm disabled)
  Wire.write(0b10000000);    // Day alarm (and alarm disabled)
  Wire.write(0b10000000);    // Weekday alarm (and alarm disabled)
  Wire.write(0b10000011);     // Output clock frequency enabled (1 Hz) ***THIS IS THE IMPORTANT LINE**
  Wire.write(0);     // Timer (countdown) disabled
  Wire.write(0);     // Timer value

// Display the data for the serial LCD display
void displayData()
      // Here we display the data in the correct format for the LCD serial display
      // Data is displayed on a serial LCD screen (another Arduino)
      // Data is in a grid 40 x 2, but only the first 16 char on each line is shown
      // Data is displayed:
      // Ta:XXXC Ts:XXXC
      // T:XXXXs  MODE
      // We need to know the legth of Ta, Ts and T in order to display this properly 
      // MODE will display which section of the relflow curve we are in
      // It will also say if running or stopped
      //Serial.print(" ");
      for(int t=0;t<(5-String(actualTemp).length());t++)
        Serial.print(" ");
      for(int t=0;t<(29-String(tempSetpoint).length());t++)
        Serial.print(" ");
      for(int t=0;t<(6-String(totalFromStart).length());t++)
        Serial.print(" ");
      // Here we want to display the mode.
      // This is figured out from the dataPoint number
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 100:
      for(int t=0;t<(10);t++)
        Serial.print(" ");
      Serial.println(" ");


Here are some photos from initial testing. It worked OK, but did not get up to warm temperature quick enough. I ran through one cycle and then tried it again and it worked much better. I think I need a slightly longer warm up cycle, but this is adjustable via the SD card.

You can see the temperature probe near the surface of the test piece of board.

The test was just an old copper clad board with some flux and solder paste on it. But it did flow.

Leave a Reply

Your email address will not be published. Required fields are marked *