Paul van der Wielen
/
Reflow_Oven_Controller
based on existing code, added support for max31855 and i2c display
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(); } }