based on existing code, added support for max31855 and i2c display

Dependencies:   MAX31855 mbed

main.cpp

Committer:
pwheels
Date:
2014-01-19
Revision:
2:67c271b56755
Parent:
1:e7ce82863fe9

File content as of revision 2:67c271b56755:

//-----------------------------------------------------------------------
// reflow oven controller, adapted to i2c display
//
// Version 1.0 - December 2003
//
// ATOM-Pro basic for Renesas '3687
//
// Copyright (name deleted) and it's rights are not referenced in the orignal on mbed
//
// 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 Maxim 31855K, the GHI thermocouple board was used
// For the buttons, 3 push buttons connected to ground and pullups.
// For the heater, any driver configuration.
//
// fixed major bug in UpdateStateMachine() switch / case tests on wrong value
//
// http://www.circuitcellar.com/renesas/winners/Abstracts/H3323%20abstract.pdf
// no info could be found on above link but use next link instead.
// http://hobbybotics.com/projects/hobbybotics-reflow-controller-v8-03/ 
//-----------------------------------------------------------------------

#include "mbed.h"
#include "lc_display.h"
#include "max31855.h"

// 0 button pressed, 1 button released
DigitalIn Btn_0(p18);
DigitalIn Btn_1(p19);
DigitalIn Btn_2(p20);

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

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

//SPI Interfaces
SPI testSPI(p11,p12,p13);
//Thermocouples
max31855 max1(testSPI,p26);

//=======================================================================
// 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;
float atemp;

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.write(0);
}

void heater_on(void) {
    HeaterOutput.write(1);
}

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

// Initialisation
void Init(void) {
    // Welcome screen
    _WriteLCD(ClrDisplay);
    _WriteLCD(DisplayON_OFF, 1, 1, 0);
    _WriteLCD(WriteString, "  REFLOW CONTROL  ", 0);
    _WriteLCD(SetCursor, 0x14);
    _WriteLCD(WriteString, "        V2.0a     ", 0);
    wait_ms(1000);

    // 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
    
    //Initialise chip (starts internal timer)
    max1.initialise();
}

void editnum(int *value,int minval,int maxval) {
    int v;
    char tmp[32] = {0};
    v = *value;

    do {
        wait_ms(200);
        _WriteLCD(SetCursor, 0x0a);
        sprintf(tmp, "%3d", v);
        _WriteLCD(WriteString, tmp, 4);
        _WriteLCD(SetCursor, 0x14);
        _WriteLCD(WriteString, "[2+][1-] [0:end]    ", 0);
        
        if (Btn_1.read() == 0) {
            v--;
            if (v < minval) v = minval;
        }

        if (Btn_2.read() == 0) {
            v++;
            if (v > maxval) v = maxval;
        }

    } while (Btn_0.read() != 0);

    *value = v;
}

void UpdateStateMachine(void) {
    if (status == 0) return;
    // original had (status - 1) but this fail to work
    switch (status) {        
        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;
            break;
    }
}

// Read current temperature from thermo couple
// return temperature in ahigh (degrees) and alow (tens of a degree)
void readthermo(void) {
        
    if (max1.ready()==1){
        //Get the reading (average value may be needed 100 ?)
        atemp = max1.read_temp();
            
        if (atemp > 2000){
            if(atemp == 2001){
                printf("No TC");
            }else if(atemp == 2002){
                printf("Short to Ground");
            }else if(atemp == 2004){
                printf("Short to VCC");
            }
        }else{
            ahigh = (int) atemp;
            alow = (int) ((atemp - ahigh) * 100);
        }
    }
}

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

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

    // wait for run button released
    while (Btn_0.read() == 0);
    
    wait_ms(10);

    char tmp[32] = {0};
    do {

        tprec = t;

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

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

        tset = tset10/10;
        
        _WriteLCD(ClrDisplay);
        sprintf(tmp, "Temp: %3d C ", ahigh);
        _WriteLCD(WriteString, tmp, 0);
        
        _WriteLCD(SetCursor, 0x0c);

        if (dispcycle == 1) {
            sprintf(tmp, "%d/7",status);
            _WriteLCD(WriteString, tmp, 0);
        } else {
             sprintf(tmp, lcd_status[status-1]);
            _WriteLCD(WriteString, tmp, 0);
        }
        _WriteLCD(SetCursor, 0x14);
        sprintf(tmp, "Tset: %3d C ", tset);
        _WriteLCD(WriteString, tmp, 0);
        _WriteLCD(SetCursor, 0x20);
        sprintf(tmp, "Sec: %3d ", remaining_time);
        _WriteLCD(WriteString, tmp, 0);
        

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

        // check if abort requested
        if (Btn_0.read() == 0) {

            status = 0;
            heater_off();

            // wait for run button released
            while (Btn_0.read() == 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++) {
        _WriteLCD(ClrDisplay);
        _WriteLCD(SetCursor, 0x00);

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

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

int main(void) {
    // Initialisations
    
    pc.baud(9600);
    pc.printf("\r\nReflow Oven Controller for mbed v1.0\r\n");

    // define some user characters for LCD display
    char MySymbol[2][9]= {{0x01,0x04,0x0e,0x1f,0x04,0x04,0x04,0x00,0x00},
                          {0x02,0x00,0x00,0x04,0x04,0x04,0x1f,0x0e,0x04}};
    // use the internal pull-ups
    Btn_0.mode(PullUp);
    Btn_1.mode(PullUp);    
    Btn_2.mode(PullUp);
    
    _InitLCD();
    _WriteLCD(LCDType,0x01);
    _WriteLCD(WriteUserDefChar,MySymbol[0],9);
    _WriteLCD(WriteUserDefChar,MySymbol[1],9);
    
    Init();
    
    // Main loop
    while (1) {
        // heater off
        heater_off();
        
        // position cursor 
        _WriteLCD(SetCursor, 0x00);
        
        // read thermo couple
        readthermo();
        char msg[32] = {0};
        sprintf(msg, "Temp: %3.2f C        ", atemp);
        
        // Display current temperature
        _WriteLCD(WriteString, msg, 0);
        
        // Display menu
        _WriteLCD(SetCursor, 0x14);
        _WriteLCD(WriteString, "[1:CONF] [0:RUN]    ", 0);

        wait_ms(10);

        // Run button ?
        if (Btn_0.read() == 0)
                RunMode();
        else if (Btn_1.read() == 0) 
            ConfigurationMode();
    }
}