This is a Reflow Oven Controller ported to the mbed platform Original article: http://www.circuitcellar.com/renesas/winners/Abstracts/H3323%20abstract.pdf

Dependencies:   mbed

main.cpp

Committer:
jpelletier
Date:
2012-01-15
Revision:
0:9526e71a200f

File content as of revision 0:9526e71a200f:

//-----------------------------------------------------------------------
// reflow oven controller
//
// Version 1.0 - December 2003
//
// ATOM-Pro basic for Renesas '3687
//
// Copyright (name deleted)

// This project is a port from the original basic code for the Basic Micro EVB87 
// Renesas evaluation board to the mbed in C.
//
// We use the same setup as the original project:
// For the thermocouple, a AD595 cnnected to one of the analog input of the mbed.
// For the buttons, 3 push buttons connected to ground and pullups.
// For the heater, any driver configuration.
//
// http://www.circuitcellar.com/renesas/winners/Abstracts/H3323%20abstract.pdf
//-----------------------------------------------------------------------

#include "mbed.h"
#include "TextLCD.h"

//TextLCD lcd(p6, p7, p8, p13, p14, p15, p16); // rs, rw, e, d4, d5, d6, d7
TextLCD lcd(p6, p8, p13, p14, p15, p16); // rs, e, d4, d5, d6, d7

// 0 button pressed, 1 button released
DigitalIn IN8(p30);
DigitalIn IN9(p29);
DigitalIn IN10(p28);

// 0 off, 1 on
DigitalOut HeaterOutput(p27);

// Use the USB link as serial port
Serial pc(USBTX, USBRX); // tx, rx

// The 0.0v to 3.3v range of the AnalogIn is represented in software
// as a normalised floating point number from 0.0 to 1.0.
AnalogIn ain(p15);

// AD595 10mv/'C at 3.3V -> 330'C

//=======================================================================
// variables
//=======================================================================

int PreheatSlope;          // 1 to 255, 1/10° per sec
int DryingTemp;            // 20 to 250, °C
int Hysteresis;            // 1 to 20, °C
int DryingTime;            // 1 to 255, seconds
int HeatingSlope;         // 1 to 255, 1/10° per sec
int ReflowTemp;            // 150 to 255, °C
int ReflowTime;            // 1 to 255, seconds
int CoolingSlope;        // 1 to 255, 1/10° per sec
int Kd;                    // kd muliplier for pid, in 1/10

char status;            // state machine status
int t;                    // current temperature
int tini;                // initial temperature
int tset10;                // set temperature times 10
int tset;                // set temperature
int remaining_time;                // remaining time in s
char heater;            // heater on/off
int tprec;              // previous temperature
int testim;                // estimated future temperature

// Used to toggle between 2 display screens
char dispcycle;            // display cycle (0/1/0/1...)

int alow;
int ahigh;

char *lcd_status[] = {
    "UpDry  ","WtDry  ","Drying ","UpFlow ","WtFlow ","Reflow ","Coolng "
};

#define PREHEAT         1
#define WAIT_DRYING     2
#define DRYING          3
#define HEAT            4
#define WAIT_REFLOW     5
#define REFLOW          6
#define COOLING         7

void heater_off(void) {
    HeaterOutput = 0;
}

void heater_on(void) {
    HeaterOutput = 1;
}

//=======================================================================
// Subroutines
//=======================================================================

// Initialisation
void Init(void) {
    // Welcome screen
    lcd.cls();
    lcd.printf(" REFLOW CONTROL ");
    lcd.locate(0,1);
    lcd.printf("       V1.0     ");

    wait_ms(10);

    // Initialize variables to default values
    PreheatSlope = 10;    // 1 to 255, 1/10° per sec
    DryingTemp = 100;    // 20 to 250, °C
    Hysteresis = 5;        // 1 to 20, °C
    DryingTime = 120;    // 1 to 255, seconds
    HeatingSlope = 40;    // 1 to 255, 1/10° per sec
    ReflowTemp = 250;    // 150 to 255, °C
    ReflowTime = 45;    // 1 to 255, seconds
    CoolingSlope = 20;    // 1 to 255, 1/10° per sec
    Kd = 10;            // 0 to 100, kd multiplier in 1/10
}

void editnum(int *value,int minval,int maxval) {
    int v;

    v = *value;

    do {
        wait_ms(200);
        lcd.locate(10,0);
        lcd.printf("%d  ",v);
        lcd.locate(0,1);
        lcd.printf("[2+][1-] [0:end]");

        if (IN9 == 0) {
            v--;
            if (v < minval) v = minval;
        }

        if (IN10 == 0) {
            v++;
            if (v > maxval) v = maxval;
        }

    } while (IN8 != 0);

    *value = v;
}

void UpdateStateMachine(void) {
    if (status == 0) return;

    switch (status - 1) {
        case PREHEAT:
            tset10 = tset10 + PreheatSlope;
            tset = tset10/10;

            if (tset > DryingTemp) {
                tset10 = DryingTemp * 10;
                status = WAIT_DRYING;
                dispcycle = 1;
            }
            break;

        case WAIT_DRYING:
            if ((t + Hysteresis) > DryingTemp) {
                remaining_time = DryingTime;
                status = DRYING;
                dispcycle = 1;
            }
            break;

        case DRYING:
            if (remaining_time == 0) {
                remaining_time = (10 * (ReflowTemp - DryingTemp))/HeatingSlope;
                status = HEAT;
                dispcycle = 1;
            }
            break;

        case HEAT:
            tset10 = tset10 + HeatingSlope;
            tset = tset10/10;
            if (tset > ReflowTemp) {
                tset10 = 10 * ReflowTemp;
                status = WAIT_REFLOW;
                dispcycle = 1;
            }
            break;

        case WAIT_REFLOW:
            if ((t + Hysteresis) > ReflowTemp) {
                remaining_time = ReflowTime;
                status = REFLOW;
                dispcycle = 1;
            }
            break;

        case REFLOW:
            if (remaining_time == 0) {
                remaining_time = (10 * (ReflowTemp - tini))/CoolingSlope;
                status = COOLING;
                dispcycle = 1;
            }
            break;

        case COOLING:
            tset10 = tset10 - CoolingSlope;
            tset = tset10/10;
            if (tset < tini) {
                tset10 = 10 * tini;
                status = 0;
                dispcycle = 1;
            }
            break;

        default:
            status = 0;
    }
}

// Read current temperature
// return temperature in ahigh (degrees) and alow (tens of a degree)
void readtemperature(void) {
    long int atemp;
    long int a;             // temporary
    int i;

    a = 0;

    /* 1000 readings */
    for (i=1; i <= 1000; i++) {
        atemp = ain * 330;    // 3.3V from an AD595 at 10mV/'C -> 330'C
        a += atemp;
    }
    /* a = 1000 * avg temp */
    // ex: 300.2    a = 300200

    a = a/100;  // a = 3002

    /* ahigh = */
    ahigh = a/10;   // ahigh = 300
    alow = a - ahigh*10;  // alow = 3002 - 3000 = 2
}

void RunMode() {
    // initialise run mode
    status = 1;
    dispcycle = 0;
    t = 0;
    readtemperature();

    t = ahigh;
    tini = t;
    tset10 = 10*t;
    remaining_time = (10*(DryingTemp - t))/PreheatSlope;
    heater = 0;

    // wait for run button released
    while (IN8 == 0);
    wait_ms(10);

    do {
        tprec = t;

        // read new temperature
        readtemperature();
        t = ahigh;

        // estimate future temperature using kd
        testim = ((10*t) + (t-tprec) * Kd)/10;

        tset = tset10/10;

        // display screen
        lcd.cls();
        lcd.printf("Temp:%dC  ", ahigh);
        lcd.locate(10,0);

        if (dispcycle == 1) {
            lcd.printf("%d/7",status);
        } else {
            lcd.puts(lcd_status[status-1]);
        }

        lcd.locate(0,1);
        lcd.printf("Tset:%dC  ", tset);
        lcd.locate(10,1);
        lcd.printf("sec %d", remaining_time);

        // decrement time (in seconds, due to the 1 second pause)
        if (remaining_time != 0) remaining_time--;

        // check if abort requested
        if (IN8 == 0) {
            status = 0;
            heater_off();

            // wait for run button released
            while (IN8 == 0);
            wait_ms(10);
        }

        UpdateStateMachine();

        tset = tset10/10;

        // control heater
        if (heater == 0) {
            if (testim < (tset - Hysteresis)) heater = 1;
        }

        if (heater == 1) {
            if (testim > (tset + Hysteresis)) heater = 0;
        }

        if (heater == 0)
            heater_off();
        else
            heater_on();

        // send current values to uart
        pc.printf("S%d,%d,%d,%d\n",tset, t, status, heater);

        // wait for 1 second
        wait(1);

        // next dispcycle
        dispcycle = 1 - dispcycle;
    } while (status != 0);
}

void ConfigurationMode(void) {
    int i;

    for (i = 1; i <= 9; i++) {
        lcd.cls();
        lcd.locate(0,0);

        switch (i) {
            case 1:
                lcd.printf("DrySlope");
                editnum(&PreheatSlope,1,255);
                break;
            case 2:
                lcd.printf("DryTemp ");
                editnum(&DryingTemp,40,150);
                break;
            case 3:
                lcd.printf("Hysteres");
                editnum(&Hysteresis,1,40);
                break;
            case 4:
                lcd.printf("DryTime ");
                editnum(&DryingTime,1,255);
                break;
            case 5:
                lcd.printf("HeatSlpe");
                editnum(&HeatingSlope,1,255);
                break;
            case 6:
                lcd.printf("FlowTemp");
                editnum(&ReflowTemp,120,255);
                break;
            case 7:
                lcd.printf("Flowtime");
                editnum(&ReflowTime,1,255);
                break;
            case 8:
                lcd.printf("Coolslop");
                editnum(&CoolingSlope,1,255);
                break;
            case 9:
                lcd.printf("Kd      ");
                editnum(&Kd,0,200);
                break;
        }
    }
}

//=======================================================================
// Main program
//=======================================================================

int main(void) {
    // Initialisations
    Init();

    lcd.cls();

    // Main loop
    while (1) {
        // heater off
        heater_off();

        // Display current temperature
        lcd.locate(0,0);
        readtemperature();
        lcd.printf("Temp : %d.%dC    ", ahigh, alow);
        lcd.locate(0,1);

        // Display menu
        lcd.printf("[1:CONF] [0:RUN]");

        wait_ms(10);

        // Run button ?
        if (IN8 == 0)
            RunMode();
        else if (IN9 == 0) ConfigurationMode();
    }
}