This is a Reflow Oven Controller ported to the mbed platform Original article: http://www.circuitcellar.com/renesas/winners/Abstracts/H3323%20abstract.pdf
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(); } }