Controls both heat and pump pressure based on a temperature probe and a scale- ie, it does temperature and flow profiling. Should work with any vibratory pump machine.
Dependencies: Adafruit_RTCLib FastPWM TSI mbed
main.cpp
- Committer:
- jzeeff
- Date:
- 2013-08-07
- Revision:
- 0:24cdf76455c4
- Child:
- 1:b5abc8ddd567
File content as of revision 0:24cdf76455c4:
// Program to control espresso maker boiler temperatures // Used with a Gaggia Classic, FreeScale FRDM-KL25Z computer, PT1000 RTD, SSR // Jon Zeeff, 2013 // Public Domain #include "mbed.h" #include "TSISensor.h" DigitalOut ssr(PTA1); AnalogIn adc(PTE20); #define OFF 0 #define RED 1 #define GREEN 2 #define BLUE 3 #define WHITE 4 #define YELLOW 5 // RTD ohms // 1360 ohms = 94C // 1000 ohms = too cold (0C) // 1520 ohms = too hot (136C) // note: assume a 2K divider resistor, a PT1000 RTD and a 16 bit A/D result // use this formula (RTD_OHMS/(RTD_OHMS+2000)) * 65536 // desired A/D value for boiler temp #define TARGET_TEMP 25600 // CHANGE THIS // table of % power level vs time in seconds into brew cycle (including preheat) const int table[40] = { // preheat up to 10 seconds 0,0,100,100,100,100,0,0,0,0, // CHANGE THIS // brewing (pump is on) up to 30 seconds 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, // CHANGE THIS 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65 }; // these probably don't need to be changed #define CLOSE 50 // how close in A/D value before switching to proportional control #define INITIAL_POWER .03 // initial guess for steady state power needed (try .03) #define MIN_TEMP 21000 // below this is an error #define MAX_TEMP 29000 // above this is an error #define SLEEP_TIME 3600 // turn off heat after this many seconds #define BREW_TIME 30 // max brew time #define BREW_PREHEAT 10 // max preheat time #define debug if (1) printf // use if (1) or if (0) void brew(void); void set_color(int color); unsigned read_ad(void); int main() { unsigned ambient_temp = read_ad(); // save temp on startup (future enhancements) time_t prev_time = 0; TSISensor tsi; // used as a start button set_time(0); // start clock at zero debug("starting A/D value/temp = %u\r\n",ambient_temp); // loop forever, controlling boiler temperature for (;;) { unsigned temp; // read temp from A/D // note: in A/D counts, not degrees temp = read_ad(); // bang/bang when far away, PWM to learned value when close if (temp > TARGET_TEMP + CLOSE) { ssr = 0; // turn off heater set_color(GREEN); // set LED to green } else if (temp < TARGET_TEMP - CLOSE) { ssr = 1; // turn on heater set_color(RED); // set LED to red } else { // close to target temp // learning mode - adjust heat, the fraction of time power should be on static double heat = INITIAL_POWER; // initial fractional heat needed while idle if (temp > TARGET_TEMP) // adjust best guess for % heat needed heat *= .99; else heat *= 1.01; debug("learned heat = %F, temp = %u\r\n",heat, temp); ssr = 1; // turn on heater for PWM set_color(RED); wait(heat); ssr = 0; // turn off heater set_color(GREEN); wait(1-heat); } // if // the user must press a button 10 seconds prior to brewing to start preheat if (tsi.readPercentage() > .5) brew(); // check for idle, sleep till tomorrow if it occurs if (time(NULL) > SLEEP_TIME){ // save power static time_t wakeup_time = (24 * 60 * 60) - (20 * 60); // 24 hours minus 20 min ssr = 0; // turn off heater set_color(OFF); while (time(NULL) < wakeup_time) // wait till tomorrow wait(1); set_time(0); // clock runs zero to 24 hours wakeup_time = (24 * 60 * 60); // no 15 min offset needed now } // check for errors (incorrect boiler temp can be dangerous) if (temp > MAX_TEMP || temp < MIN_TEMP) { ssr = 0; // turn off heater set_color(YELLOW); // set LED to indicate error for (;;); // reset needed to exit this } if (time(NULL) > prev_time) debug("A/D value = %u\r\n",temp); prev_time = time(NULL); } // while } // main() //================================================================= // This subroutine is called when the button is pressed, 10 seconds // before the pump is started. It does open loop power/temp control. //================================================================= void brew(void) { time_t start_time = time(NULL); #define brew_time (time(NULL) - start_time) debug("preheat/brew start\r\n"); set_color(WHITE); while (brew_time < BREW_TIME + BREW_PREHEAT) { // loop for 40 seconds if (brew_time >= BREW_PREHEAT) set_color(BLUE); // set LED color to blue for start brew/pump now // PWM power level over .5 second ssr = 1; // turn on heater wait(table[brew_time] / 200.0); ssr = 0; // turn off heater wait((100 - table[brew_time]) / 200.0); debug("power level %u = %u %%, temp = %u\r\n",brew_time,table[brew_time],read_ad()); } // while set_color(OFF); debug("brew done\r\n"); } // brew() // ============================================= // set multi color LED state // ============================================= DigitalOut r (LED_RED); DigitalOut g (LED_GREEN); DigitalOut b (LED_BLUE); void set_color(int color) { // turn off r = g = b = 1; switch (color) { case OFF: break; case GREEN: g = 0; break; case BLUE: b = 0; break; case RED: r = 0; break; case YELLOW: r = g = 0; break; case WHITE: r = g = b = 0; break; } // switch } // set_color() //======================================= // read A/D value from RTD // median for accuracy //======================================= unsigned read_ad(void) { unsigned a, b, c; a = adc.read_u16(); b = adc.read_u16(); c = adc.read_u16(); if ((a >= b && a <= c) || (a >= c && a <= b)) return a; if ((b >= a && b <= c) || (b >= c && b <= a)) return b; return c; } // read_ad()