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.
Dependencies: Adafruit_RTCLib FastPWM TSI mbed
Revision 2:22d9c714b511, committed 2013-08-11
- Comitter:
- jzeeff
- Date:
- Sun Aug 11 20:39:57 2013 +0000
- Parent:
- 1:b5abc8ddd567
- Child:
- 3:eb60e36b03f6
- Commit message:
- PWM during closed loop brew
Changed in this revision
| main.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/main.cpp Fri Aug 09 20:36:28 2013 +0000
+++ b/main.cpp Sun Aug 11 20:39:57 2013 +0000
@@ -1,6 +1,6 @@
// Program to control espresso maker boiler temperatures
-// Similar to PID, but uses a flexible open loop table during brew
+// Similar to multiple PID control, but uses a flexible open or closed loop table during brew
// Used with a Gaggia Classic, FreeScale FRDM-KL25Z computer, PT1000 RTD, SSR
// Jon Zeeff, 2013
// Public Domain
@@ -18,36 +18,38 @@
#define WHITE 4
#define YELLOW 5
-// PT1000 RTD ohms
+// PT1000 RTD ohms (use Google to find a full table)
// 1360 ohms = 94C
// 1000 ohms = too cold (0C)
// 1520 ohms = too hot (136C)
// note: assume a 2.2K divider resistor, a PT1000 RTD and a 16 bit A/D result
-// use this formula: (RTD_OHMS/(RTD_OHMS+2200)) * 65536
+// use this formula: A/D = (RTD_OHMS/(RTD_OHMS+2200)) * 65536
// desired A/D value for boiler temp while idling
// note: there is an offset between boiler wall temp sensors and actual water temp
-#define TARGET_TEMP 25850 // CHANGE THIS
-
-// table of adjustments (degrees C) to TARGET_TEMP vs time (seconds) into brew cycle (including preheat period)
-// the idea is that extra heat is needed as cool water comes into the boiler during brew
-// note: if you alternate very high and negative values here, you get the equivalent of open loop/PWM/temp surfing
+#define TARGET_TEMP 25900 // CHANGE THIS
-const int table[40] = {
+// Table of adjustments (degrees C) to TARGET_TEMP vs time (seconds) into brew cycle (including preheat period)
+// The idea is that extra heat is needed as cool water comes into the boiler during brew.
+// Extra heat is provided by a higher than normal boiler wall temp.
+// NOTE: the decimal portion of the value is used as the PWM value to be applied if more heat is needed.
+// This can prevent overshoot.
+
+const double table[40] = {
// preheat up to 10 seconds
- 0,0,0,0,0,0,18,18,18,18, // CHANGE THIS
+ 0,0,0,0,18.99,18.99,0,0,0,0, // CHANGE THIS
// brewing (pump is on) up to 30 seconds
- 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, // CHANGE THIS
- 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18
+ 18.7,18.7,18.7,18.7,18.7,18.7,18.7,18.7,18.7,18.7,18.7,18.7,18.7,18.7,18.7, // CHANGE THIS
+ 15.7,15.7,15.7,15.7,15.7,15.7,15.7,15.7,15.7,15.7,15.7,0,0,0,0 // CHANGE THIS
};
// these probably don't need to be changed if you are using a Gaggia Classic
-#define CLOSE 30 // how close in A/D value before switching to proportional control
+#define CLOSE 30 // how close in A/D value before switching to learned value control
#define INITIAL_POWER .05 // initial guess for steady state power needed (try .05 = 5%)
#define MIN_TEMP 21000 // below this is an error
-#define MAX_TEMP 218000 // above this is an error
-#define ROOM_TEMP 22000 // A/D at standard ambient room temp
+#define MAX_TEMP 29000 // above this is an error
+#define ROOM_TEMP 22000 // A/D value at standard ambient room temp
#define MAX_ROOM_TEMP 22500 // above this means ambient isn't valid
#define SLEEP_TIME 3600 // turn off heat after this many seconds
#define BREW_TIME 30 // max brew time
@@ -75,11 +77,9 @@
// loop forever, controlling boiler temperature
for (;;) {
- unsigned temp;
-
// read temp from A/D
// note: in A/D counts, not degrees
- temp = read_ad();
+ unsigned temp = read_ad();
// bang/bang when far away, PWM to learned value when close
if (temp > TARGET_TEMP + CLOSE) {
@@ -114,7 +114,8 @@
static time_t wakeup_time = (24 * 60 * 60) - (20 * 60); // 24 hours minus 20 min
ssr = 0; // turn off heater
- set_color(OFF);
+ set_color(OFF);
+ printf("sleep\r\n");
while (time(NULL) < wakeup_time) // wait till tomorrow
wait(1);
set_time(0); // clock runs zero to 24 hours
@@ -146,11 +147,10 @@
void brew(void)
{
unsigned start_time = time(NULL);
- #define brew_time (time(NULL) - start_time)
double adjust = 1; // default is no adjustment
- // adjust for tank temp (assumed to be equal to ambient at startup)
+ // adjust for higher or lower tank temp (assumed to be equal to ambient at startup)
if (ambient_temp < MAX_ROOM_TEMP) // sanity check
adjust = (double)(ROOM_TEMP - TARGET_TEMP) / (double)(ambient_temp - TARGET_TEMP);
@@ -158,22 +158,29 @@
set_color(WHITE);
for (;;) {
- unsigned prev_brew_time = 0;
+ unsigned brew_time;
+ static unsigned prev_brew_time;
+ brew_time = time(NULL) - start_time;
+
if (brew_time >= BREW_PREHEAT + BREW_TIME)
break;
if (brew_time == BREW_PREHEAT)
set_color(BLUE); // set LED color to blue for start brew/pump now
-
- // bang/bang temp to the table value
- if (read_ad() < (TARGET_TEMP + (table[brew_time] * AD_PER_DEGREE)) * adjust)
- ssr = 1; // heater on
- else
- ssr = 0; // heater off
+
+ double pwm = table[brew_time] - (int)table[brew_time]; // decimal part only
+
+ // if too cold, apply the PWM value, if too hot, do nothing
+ if (read_ad() < (TARGET_TEMP + (table[brew_time] * AD_PER_DEGREE)) * adjust) {
+ ssr = 1;
+ wait(pwm / 2);
+ ssr = 0;
+ wait((1 - pwm) / 2);
+ } // if PWM
- if (brew_time != prev_brew_time)
- debug("target temp %u = %u, temp = %u\r\n",brew_time,table[brew_time],read_ad());
+ if (brew_time != prev_brew_time) // print status every second
+ debug("target temp %u = %F, temp = %u\r\n",brew_time,table[brew_time],read_ad());
prev_brew_time = brew_time;
} // for