This is a Reflow Oven Controller ported to the mbed platform Original article: http://www.circuitcellar.com/renesas/winners/Abstracts/H3323%20abstract.pdf
Diff: main.cpp
- Revision:
- 0:9526e71a200f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sun Jan 15 06:13:50 2012 +0000 @@ -0,0 +1,409 @@ +//----------------------------------------------------------------------- +// 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(); + } +}