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

Revision:
0:24cdf76455c4
Child:
1:b5abc8ddd567
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Aug 07 16:10:11 2013 +0000
@@ -0,0 +1,219 @@
+
+// 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()
+ 
\ No newline at end of file