Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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();
}
}