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@3:eb60e36b03f6, 2013-08-29 (annotated)
- Committer:
- jzeeff
- Date:
- Thu Aug 29 14:55:52 2013 +0000
- Revision:
- 3:eb60e36b03f6
- Parent:
- 2:22d9c714b511
- Child:
- 4:3d661b485d59
basic pump functions
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jzeeff | 0:24cdf76455c4 | 1 | |
jzeeff | 0:24cdf76455c4 | 2 | // Program to control espresso maker boiler temperatures |
jzeeff | 3:eb60e36b03f6 | 3 | // Similar to multiple PID control (pre-brew, brew and steam), |
jzeeff | 3:eb60e36b03f6 | 4 | // but uses a flexible open and closed loop table during brew |
jzeeff | 3:eb60e36b03f6 | 5 | // Used with a Gaggia Classic, FreeScale FRDM-KL25Z computer, PT1000 RTD, heater |
jzeeff | 3:eb60e36b03f6 | 6 | // See www.coffeegeeks.com for discussion |
jzeeff | 0:24cdf76455c4 | 7 | // Jon Zeeff, 2013 |
jzeeff | 0:24cdf76455c4 | 8 | // Public Domain |
jzeeff | 0:24cdf76455c4 | 9 | |
jzeeff | 2:22d9c714b511 | 10 | // PT1000 RTD ohms (use Google to find a full table) |
jzeeff | 0:24cdf76455c4 | 11 | // 1360 ohms = 94C |
jzeeff | 0:24cdf76455c4 | 12 | // 1000 ohms = too cold (0C) |
jzeeff | 0:24cdf76455c4 | 13 | // 1520 ohms = too hot (136C) |
jzeeff | 0:24cdf76455c4 | 14 | |
jzeeff | 1:b5abc8ddd567 | 15 | // note: assume a 2.2K divider resistor, a PT1000 RTD and a 16 bit A/D result |
jzeeff | 2:22d9c714b511 | 16 | // use this formula: A/D = (RTD_OHMS/(RTD_OHMS+2200)) * 65536 |
jzeeff | 0:24cdf76455c4 | 17 | |
jzeeff | 1:b5abc8ddd567 | 18 | // desired A/D value for boiler temp while idling |
jzeeff | 3:eb60e36b03f6 | 19 | // note: there is usually some offset between boiler wall temp sensors and actual water temp |
jzeeff | 3:eb60e36b03f6 | 20 | #define TARGET_TEMP 25440 // CHANGE THIS |
jzeeff | 1:b5abc8ddd567 | 21 | |
jzeeff | 2:22d9c714b511 | 22 | // Table of adjustments (degrees C) to TARGET_TEMP vs time (seconds) into brew cycle (including preheat period) |
jzeeff | 2:22d9c714b511 | 23 | // The idea is that extra heat is needed as cool water comes into the boiler during brew. |
jzeeff | 2:22d9c714b511 | 24 | // Extra heat is provided by a higher than normal boiler wall temp. |
jzeeff | 3:eb60e36b03f6 | 25 | // NOTE: the fractional portion of the value is used as the PWM value to be applied if more heat is needed. |
jzeeff | 2:22d9c714b511 | 26 | // This can prevent overshoot. |
jzeeff | 3:eb60e36b03f6 | 27 | // Example: 5.3 means that the boiler wall should be 5 degrees C above normal at this time point. If not, apply 30% power. |
jzeeff | 3:eb60e36b03f6 | 28 | // Example: 99.99 means (roughly) that the heater should be completely on for the 1 second period |
jzeeff | 3:eb60e36b03f6 | 29 | // Note: heat takes at least 4 seconds before it is seen by the sensor |
jzeeff | 2:22d9c714b511 | 30 | |
jzeeff | 2:22d9c714b511 | 31 | const double table[40] = { |
jzeeff | 0:24cdf76455c4 | 32 | // preheat up to 10 seconds |
jzeeff | 3:eb60e36b03f6 | 33 | 0.0,0.0,0.0,0.0,0.0,0.0,0.0,99.9,99.9,99.20, // CHANGE THIS |
jzeeff | 0:24cdf76455c4 | 34 | // brewing (pump is on) up to 30 seconds |
jzeeff | 3:eb60e36b03f6 | 35 | 99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20, // CHANGE THIS |
jzeeff | 3:eb60e36b03f6 | 36 | 99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,0,0,0,0 // CHANGE THIS |
jzeeff | 3:eb60e36b03f6 | 37 | }; |
jzeeff | 3:eb60e36b03f6 | 38 | |
jzeeff | 3:eb60e36b03f6 | 39 | const double pump_table[40] = { |
jzeeff | 3:eb60e36b03f6 | 40 | // during pre-brew period |
jzeeff | 3:eb60e36b03f6 | 41 | 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, // CHANGE THIS |
jzeeff | 3:eb60e36b03f6 | 42 | // brewing up to 30 seconds |
jzeeff | 3:eb60e36b03f6 | 43 | 0.0,0.0,99.99,99.99,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20, // CHANGE THIS |
jzeeff | 3:eb60e36b03f6 | 44 | 99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,99.20,0,0,0,0 // CHANGE THIS |
jzeeff | 3:eb60e36b03f6 | 45 | }; |
jzeeff | 0:24cdf76455c4 | 46 | |
jzeeff | 1:b5abc8ddd567 | 47 | // these probably don't need to be changed if you are using a Gaggia Classic |
jzeeff | 3:eb60e36b03f6 | 48 | #define CLOSE 60 // how close in A/D value before switching to learned value control |
jzeeff | 3:eb60e36b03f6 | 49 | #define GAIN .01 // how fast to adjust |
jzeeff | 3:eb60e36b03f6 | 50 | #define INITIAL_POWER .03 // initial guess for steady state heater power needed (try .03 = 3%) |
jzeeff | 0:24cdf76455c4 | 51 | #define MIN_TEMP 21000 // below this is an error |
jzeeff | 3:eb60e36b03f6 | 52 | #define MAX_TEMP 29500 // above this is an error |
jzeeff | 3:eb60e36b03f6 | 53 | #define STEAM_TEMP 28000 // boiler temp while steaming |
jzeeff | 2:22d9c714b511 | 54 | #define ROOM_TEMP 22000 // A/D value at standard ambient room temp |
jzeeff | 1:b5abc8ddd567 | 55 | #define MAX_ROOM_TEMP 22500 // above this means ambient isn't valid |
jzeeff | 3:eb60e36b03f6 | 56 | #define SLEEP_TIME 7200 // turn off heat after this many seconds |
jzeeff | 0:24cdf76455c4 | 57 | #define BREW_TIME 30 // max brew time |
jzeeff | 0:24cdf76455c4 | 58 | #define BREW_PREHEAT 10 // max preheat time |
jzeeff | 1:b5abc8ddd567 | 59 | #define AD_PER_DEGREE 44 // how many A/D counts equal a 1 degree C change |
jzeeff | 0:24cdf76455c4 | 60 | #define debug if (1) printf // use if (1) or if (0) |
jzeeff | 0:24cdf76455c4 | 61 | |
jzeeff | 3:eb60e36b03f6 | 62 | #include "mbed.h" |
jzeeff | 3:eb60e36b03f6 | 63 | #include "TSISensor.h" // touch sensor |
jzeeff | 3:eb60e36b03f6 | 64 | #include "DS1307.h" // real-time clock |
jzeeff | 3:eb60e36b03f6 | 65 | #include "FastPWM.h" // better PWM routine for pump control |
jzeeff | 3:eb60e36b03f6 | 66 | |
jzeeff | 3:eb60e36b03f6 | 67 | #define OFF 0 |
jzeeff | 3:eb60e36b03f6 | 68 | #define RED 1 |
jzeeff | 3:eb60e36b03f6 | 69 | #define GREEN 2 |
jzeeff | 3:eb60e36b03f6 | 70 | #define BLUE 3 |
jzeeff | 3:eb60e36b03f6 | 71 | #define WHITE 4 |
jzeeff | 3:eb60e36b03f6 | 72 | #define YELLOW 5 |
jzeeff | 3:eb60e36b03f6 | 73 | #define AQUA 6 |
jzeeff | 3:eb60e36b03f6 | 74 | #define PINK 7 |
jzeeff | 3:eb60e36b03f6 | 75 | |
jzeeff | 3:eb60e36b03f6 | 76 | #define ON 1 |
jzeeff | 3:eb60e36b03f6 | 77 | #define OFF 0 |
jzeeff | 1:b5abc8ddd567 | 78 | |
jzeeff | 3:eb60e36b03f6 | 79 | DigitalOut heater(PTD7); // Solid State Relay - PTD6&7 have high drive capability |
jzeeff | 3:eb60e36b03f6 | 80 | FastPWM pump(PTD4); // Solid State Relay - PTD4 can do PWM @ 10K hz |
jzeeff | 3:eb60e36b03f6 | 81 | AnalogIn boiler(PTE20); // A/D converter reads temperature on boiler |
jzeeff | 3:eb60e36b03f6 | 82 | AnalogIn group(PTE22); // A/D for group basket temp |
jzeeff | 3:eb60e36b03f6 | 83 | DigitalOut led_green(LED_GREEN); |
jzeeff | 3:eb60e36b03f6 | 84 | I2C gI2c(PTE0, PTE1); // SDA, SCL - use pullups |
jzeeff | 3:eb60e36b03f6 | 85 | RtcDs1307 rtclock(gI2c); // DS1307 is a real time clock chip |
jzeeff | 3:eb60e36b03f6 | 86 | Serial pc(USBTX, USBRX); // Serial to pc connection |
jzeeff | 3:eb60e36b03f6 | 87 | |
jzeeff | 3:eb60e36b03f6 | 88 | void brew(void); |
jzeeff | 3:eb60e36b03f6 | 89 | void led_color(int color); |
jzeeff | 3:eb60e36b03f6 | 90 | unsigned read_temp(AnalogIn adc); |
jzeeff | 3:eb60e36b03f6 | 91 | void steam(int seconds); |
jzeeff | 3:eb60e36b03f6 | 92 | |
jzeeff | 3:eb60e36b03f6 | 93 | unsigned ambient_temp; // room or water tank temp (startup) |
jzeeff | 3:eb60e36b03f6 | 94 | double heat = INITIAL_POWER; // initial fractional heat needed while idle |
jzeeff | 3:eb60e36b03f6 | 95 | unsigned boiler_log[40]; // record boiler temp during brew |
jzeeff | 3:eb60e36b03f6 | 96 | unsigned group_log[40]; // record basket temp during brew |
jzeeff | 3:eb60e36b03f6 | 97 | |
jzeeff | 3:eb60e36b03f6 | 98 | |
jzeeff | 3:eb60e36b03f6 | 99 | int main() // start of program |
jzeeff | 0:24cdf76455c4 | 100 | { |
jzeeff | 0:24cdf76455c4 | 101 | time_t prev_time = 0; |
jzeeff | 3:eb60e36b03f6 | 102 | TSISensor tsi; // used as a brew start button |
jzeeff | 3:eb60e36b03f6 | 103 | ambient_temp = read_temp(boiler); // save temp on startup |
jzeeff | 3:eb60e36b03f6 | 104 | |
jzeeff | 0:24cdf76455c4 | 105 | set_time(0); // start clock at zero |
jzeeff | 3:eb60e36b03f6 | 106 | #if 0 |
jzeeff | 3:eb60e36b03f6 | 107 | DateTime dt = gRtc.now(); |
jzeeff | 3:eb60e36b03f6 | 108 | |
jzeeff | 3:eb60e36b03f6 | 109 | debug("%u/%u/%02u %2u:%02u:%02u\r\n" |
jzeeff | 3:eb60e36b03f6 | 110 | ,dt.month(),dt.day(),dt.year() |
jzeeff | 3:eb60e36b03f6 | 111 | ,dt.hour(),dt.minute(),dt.second()); |
jzeeff | 3:eb60e36b03f6 | 112 | #endif |
jzeeff | 0:24cdf76455c4 | 113 | debug("starting A/D value/temp = %u\r\n",ambient_temp); |
jzeeff | 3:eb60e36b03f6 | 114 | |
jzeeff | 3:eb60e36b03f6 | 115 | pump.period_ms(500); // period of PWM signal |
jzeeff | 3:eb60e36b03f6 | 116 | //pump = 100; // duty cycle. For DC, use 6 msec pulses |
jzeeff | 3:eb60e36b03f6 | 117 | |
jzeeff | 3:eb60e36b03f6 | 118 | if (pc.readable()) // clear any data on serial port |
jzeeff | 3:eb60e36b03f6 | 119 | pc.getc(); |
jzeeff | 3:eb60e36b03f6 | 120 | |
jzeeff | 3:eb60e36b03f6 | 121 | if (ambient_temp < MAX_ROOM_TEMP) |
jzeeff | 3:eb60e36b03f6 | 122 | steam(180); // do accelerated warmup by overheating |
jzeeff | 3:eb60e36b03f6 | 123 | |
jzeeff | 3:eb60e36b03f6 | 124 | // loop forever, controlling boiler temperature |
jzeeff | 0:24cdf76455c4 | 125 | |
jzeeff | 0:24cdf76455c4 | 126 | for (;;) { |
jzeeff | 0:24cdf76455c4 | 127 | // read temp from A/D |
jzeeff | 0:24cdf76455c4 | 128 | // note: in A/D counts, not degrees |
jzeeff | 3:eb60e36b03f6 | 129 | unsigned temp = read_temp(boiler); |
jzeeff | 3:eb60e36b03f6 | 130 | |
jzeeff | 0:24cdf76455c4 | 131 | // bang/bang when far away, PWM to learned value when close |
jzeeff | 0:24cdf76455c4 | 132 | if (temp > TARGET_TEMP + CLOSE) { |
jzeeff | 3:eb60e36b03f6 | 133 | heater = OFF; // turn off heater |
jzeeff | 3:eb60e36b03f6 | 134 | led_color(GREEN); // set LED to green |
jzeeff | 0:24cdf76455c4 | 135 | } else if (temp < TARGET_TEMP - CLOSE) { |
jzeeff | 3:eb60e36b03f6 | 136 | heater = ON; // turn on heater |
jzeeff | 3:eb60e36b03f6 | 137 | led_color(RED); // set LED to red |
jzeeff | 0:24cdf76455c4 | 138 | } else { // close to target temp |
jzeeff | 0:24cdf76455c4 | 139 | // learning mode - adjust heat, the fraction of time power should be on |
jzeeff | 3:eb60e36b03f6 | 140 | |
jzeeff | 3:eb60e36b03f6 | 141 | if (temp > TARGET_TEMP) // adjust best guess for % heat needed |
jzeeff | 3:eb60e36b03f6 | 142 | heat *= (1-GAIN); |
jzeeff | 0:24cdf76455c4 | 143 | else |
jzeeff | 3:eb60e36b03f6 | 144 | heat *= (1+GAIN); |
jzeeff | 3:eb60e36b03f6 | 145 | |
jzeeff | 3:eb60e36b03f6 | 146 | heater = ON; // turn on heater for PWM |
jzeeff | 3:eb60e36b03f6 | 147 | led_color(RED); |
jzeeff | 3:eb60e36b03f6 | 148 | wait(heat * 2.7); // 1.7 to reduce interaction with 50/60Hz power |
jzeeff | 3:eb60e36b03f6 | 149 | heater = OFF; // turn off heater |
jzeeff | 3:eb60e36b03f6 | 150 | led_color(GREEN); |
jzeeff | 3:eb60e36b03f6 | 151 | wait((1-heat) * 2.7); // total time is 2.7 seconds |
jzeeff | 0:24cdf76455c4 | 152 | } // if |
jzeeff | 0:24cdf76455c4 | 153 | |
jzeeff | 0:24cdf76455c4 | 154 | // the user must press a button 10 seconds prior to brewing to start preheat |
jzeeff | 0:24cdf76455c4 | 155 | if (tsi.readPercentage() > .5) |
jzeeff | 0:24cdf76455c4 | 156 | brew(); |
jzeeff | 3:eb60e36b03f6 | 157 | |
jzeeff | 3:eb60e36b03f6 | 158 | // if they signaled for steam |
jzeeff | 3:eb60e36b03f6 | 159 | if (tsi.readPercentage() > .2 && tsi.readPercentage() < .5) |
jzeeff | 3:eb60e36b03f6 | 160 | steam(120); |
jzeeff | 0:24cdf76455c4 | 161 | |
jzeeff | 3:eb60e36b03f6 | 162 | if (pc.readable()){ // Check if data is available on serial port. |
jzeeff | 3:eb60e36b03f6 | 163 | pc.getc(); |
jzeeff | 3:eb60e36b03f6 | 164 | // debug, print out temp log |
jzeeff | 3:eb60e36b03f6 | 165 | int i; |
jzeeff | 3:eb60e36b03f6 | 166 | for (i = 0; i < 40; ++i) |
jzeeff | 3:eb60e36b03f6 | 167 | printf("log %d: %u %u\r\n",i,boiler_log[i],group_log[i]); |
jzeeff | 3:eb60e36b03f6 | 168 | } // if |
jzeeff | 3:eb60e36b03f6 | 169 | |
jzeeff | 3:eb60e36b03f6 | 170 | // check for idle shutdown, sleep till tomorrow if it occurs |
jzeeff | 3:eb60e36b03f6 | 171 | if (time(NULL) > SLEEP_TIME) { // save power |
jzeeff | 3:eb60e36b03f6 | 172 | static time_t wakeup_time = (24 * 60 * 60) - (20 * 60); // 24 hours minus 20 min |
jzeeff | 3:eb60e36b03f6 | 173 | |
jzeeff | 3:eb60e36b03f6 | 174 | heater = OFF; // turn off heater |
jzeeff | 3:eb60e36b03f6 | 175 | led_color(OFF); |
jzeeff | 3:eb60e36b03f6 | 176 | printf("sleep\r\n"); |
jzeeff | 0:24cdf76455c4 | 177 | while (time(NULL) < wakeup_time) // wait till tomorrow |
jzeeff | 3:eb60e36b03f6 | 178 | wait(1); |
jzeeff | 0:24cdf76455c4 | 179 | set_time(0); // clock runs zero to 24 hours |
jzeeff | 1:b5abc8ddd567 | 180 | wakeup_time = (24 * 60 * 60); // no 20 min offset needed now |
jzeeff | 3:eb60e36b03f6 | 181 | ambient_temp = read_temp(boiler); // save temp on startup |
jzeeff | 0:24cdf76455c4 | 182 | } |
jzeeff | 3:eb60e36b03f6 | 183 | |
jzeeff | 0:24cdf76455c4 | 184 | // check for errors (incorrect boiler temp can be dangerous) |
jzeeff | 0:24cdf76455c4 | 185 | if (temp > MAX_TEMP || temp < MIN_TEMP) { |
jzeeff | 3:eb60e36b03f6 | 186 | heater = OFF; // turn off heater |
jzeeff | 3:eb60e36b03f6 | 187 | led_color(YELLOW); // set LED to indicate error |
jzeeff | 1:b5abc8ddd567 | 188 | debug("error A/D = %u\r\n",temp); |
jzeeff | 0:24cdf76455c4 | 189 | for (;;); // reset needed to exit this |
jzeeff | 0:24cdf76455c4 | 190 | } |
jzeeff | 0:24cdf76455c4 | 191 | |
jzeeff | 3:eb60e36b03f6 | 192 | if (time(NULL) > prev_time) debug("A/D value = %u %u, heat = %F\r\n",temp,read_temp(group),heat); // once per second |
jzeeff | 1:b5abc8ddd567 | 193 | prev_time = time(NULL); |
jzeeff | 0:24cdf76455c4 | 194 | |
jzeeff | 1:b5abc8ddd567 | 195 | } // for (;;) |
jzeeff | 0:24cdf76455c4 | 196 | |
jzeeff | 0:24cdf76455c4 | 197 | } // main() |
jzeeff | 0:24cdf76455c4 | 198 | |
jzeeff | 0:24cdf76455c4 | 199 | |
jzeeff | 0:24cdf76455c4 | 200 | //================================================================= |
jzeeff | 0:24cdf76455c4 | 201 | // This subroutine is called when the button is pressed, 10 seconds |
jzeeff | 3:eb60e36b03f6 | 202 | // before the pump is started. It does both open loop and closed |
jzeeff | 3:eb60e36b03f6 | 203 | // loop PWM power/heat control. |
jzeeff | 0:24cdf76455c4 | 204 | //================================================================= |
jzeeff | 0:24cdf76455c4 | 205 | |
jzeeff | 0:24cdf76455c4 | 206 | void brew(void) |
jzeeff | 0:24cdf76455c4 | 207 | { |
jzeeff | 1:b5abc8ddd567 | 208 | unsigned start_time = time(NULL); |
jzeeff | 3:eb60e36b03f6 | 209 | |
jzeeff | 1:b5abc8ddd567 | 210 | double adjust = 1; // default is no adjustment |
jzeeff | 3:eb60e36b03f6 | 211 | |
jzeeff | 2:22d9c714b511 | 212 | // adjust for higher or lower tank temp (assumed to be equal to ambient at startup) |
jzeeff | 3:eb60e36b03f6 | 213 | // add in "heat"?? |
jzeeff | 3:eb60e36b03f6 | 214 | //if (ambient_temp < MAX_ROOM_TEMP) // sanity check |
jzeeff | 3:eb60e36b03f6 | 215 | // adjust = (double)(ROOM_TEMP - TARGET_TEMP) / (double)(ambient_temp - TARGET_TEMP); |
jzeeff | 3:eb60e36b03f6 | 216 | |
jzeeff | 1:b5abc8ddd567 | 217 | debug("preheat/brew start, adjust = %F\r\n", adjust); |
jzeeff | 3:eb60e36b03f6 | 218 | led_color(WHITE); |
jzeeff | 3:eb60e36b03f6 | 219 | |
jzeeff | 3:eb60e36b03f6 | 220 | unsigned prev_brew_time = 999; |
jzeeff | 3:eb60e36b03f6 | 221 | unsigned brew_time; |
jzeeff | 3:eb60e36b03f6 | 222 | double pwm; |
jzeeff | 3:eb60e36b03f6 | 223 | |
jzeeff | 1:b5abc8ddd567 | 224 | for (;;) { |
jzeeff | 3:eb60e36b03f6 | 225 | brew_time = time(NULL) - start_time; // seconds into cycle |
jzeeff | 3:eb60e36b03f6 | 226 | |
jzeeff | 1:b5abc8ddd567 | 227 | if (brew_time >= BREW_PREHEAT + BREW_TIME) |
jzeeff | 3:eb60e36b03f6 | 228 | break; // brew is done |
jzeeff | 3:eb60e36b03f6 | 229 | |
jzeeff | 1:b5abc8ddd567 | 230 | if (brew_time == BREW_PREHEAT) |
jzeeff | 3:eb60e36b03f6 | 231 | led_color(BLUE); // set LED color to blue for start brew/pump now |
jzeeff | 3:eb60e36b03f6 | 232 | |
jzeeff | 3:eb60e36b03f6 | 233 | //pump = pump_table[brew_time]; // duty cycle |
jzeeff | 3:eb60e36b03f6 | 234 | |
jzeeff | 3:eb60e36b03f6 | 235 | pwm = table[brew_time] - (int)table[brew_time]; // decimal part only |
jzeeff | 3:eb60e36b03f6 | 236 | |
jzeeff | 2:22d9c714b511 | 237 | // if too cold, apply the PWM value, if too hot, do nothing |
jzeeff | 3:eb60e36b03f6 | 238 | if (read_temp(boiler) < (TARGET_TEMP + (table[brew_time] * AD_PER_DEGREE)) * adjust) { |
jzeeff | 3:eb60e36b03f6 | 239 | if (pwm > 0) { |
jzeeff | 3:eb60e36b03f6 | 240 | heater = ON; |
jzeeff | 3:eb60e36b03f6 | 241 | wait(pwm/2); |
jzeeff | 3:eb60e36b03f6 | 242 | heater = OFF; |
jzeeff | 3:eb60e36b03f6 | 243 | wait((1 - pwm)/2); |
jzeeff | 3:eb60e36b03f6 | 244 | } |
jzeeff | 2:22d9c714b511 | 245 | } // if PWM |
jzeeff | 3:eb60e36b03f6 | 246 | |
jzeeff | 3:eb60e36b03f6 | 247 | if (brew_time != prev_brew_time){ // every second |
jzeeff | 3:eb60e36b03f6 | 248 | group_log[brew_time] = read_temp(group); // record group temp |
jzeeff | 3:eb60e36b03f6 | 249 | boiler_log[brew_time] = read_temp(boiler); // record boiler temp |
jzeeff | 3:eb60e36b03f6 | 250 | debug("target temp %u = %F, temp = %u %u\r\n",brew_time,table[brew_time],read_temp(boiler),read_temp(group)); |
jzeeff | 3:eb60e36b03f6 | 251 | prev_brew_time = brew_time; |
jzeeff | 3:eb60e36b03f6 | 252 | } |
jzeeff | 0:24cdf76455c4 | 253 | |
jzeeff | 1:b5abc8ddd567 | 254 | } // for |
jzeeff | 3:eb60e36b03f6 | 255 | |
jzeeff | 0:24cdf76455c4 | 256 | debug("brew done\r\n"); |
jzeeff | 3:eb60e36b03f6 | 257 | |
jzeeff | 3:eb60e36b03f6 | 258 | } // brew() |
jzeeff | 0:24cdf76455c4 | 259 | |
jzeeff | 3:eb60e36b03f6 | 260 | //=========================================================== |
jzeeff | 3:eb60e36b03f6 | 261 | // control to a higher steam temperature for n seconds |
jzeeff | 3:eb60e36b03f6 | 262 | //=========================================================== |
jzeeff | 3:eb60e36b03f6 | 263 | |
jzeeff | 3:eb60e36b03f6 | 264 | void steam(int seconds) |
jzeeff | 3:eb60e36b03f6 | 265 | { |
jzeeff | 3:eb60e36b03f6 | 266 | unsigned start_time = time(NULL); |
jzeeff | 3:eb60e36b03f6 | 267 | |
jzeeff | 3:eb60e36b03f6 | 268 | debug("steam start, time = %d\r\n", seconds); |
jzeeff | 3:eb60e36b03f6 | 269 | |
jzeeff | 3:eb60e36b03f6 | 270 | while (time(NULL) - start_time < seconds) { |
jzeeff | 3:eb60e36b03f6 | 271 | if (read_temp(boiler) > STEAM_TEMP) { |
jzeeff | 3:eb60e36b03f6 | 272 | heater = OFF; // turn off heater |
jzeeff | 3:eb60e36b03f6 | 273 | led_color(AQUA); // set LED to aqua |
jzeeff | 3:eb60e36b03f6 | 274 | } else { |
jzeeff | 3:eb60e36b03f6 | 275 | heater = ON; // turn on heater |
jzeeff | 3:eb60e36b03f6 | 276 | led_color(PINK); // set LED to pink |
jzeeff | 3:eb60e36b03f6 | 277 | } |
jzeeff | 3:eb60e36b03f6 | 278 | } // while |
jzeeff | 3:eb60e36b03f6 | 279 | |
jzeeff | 3:eb60e36b03f6 | 280 | heater = OFF; // turn off |
jzeeff | 3:eb60e36b03f6 | 281 | |
jzeeff | 3:eb60e36b03f6 | 282 | } // steam() |
jzeeff | 0:24cdf76455c4 | 283 | |
jzeeff | 0:24cdf76455c4 | 284 | |
jzeeff | 0:24cdf76455c4 | 285 | // ============================================= |
jzeeff | 0:24cdf76455c4 | 286 | // set multi color LED state |
jzeeff | 0:24cdf76455c4 | 287 | // ============================================= |
jzeeff | 0:24cdf76455c4 | 288 | |
jzeeff | 0:24cdf76455c4 | 289 | DigitalOut r (LED_RED); |
jzeeff | 0:24cdf76455c4 | 290 | DigitalOut g (LED_GREEN); |
jzeeff | 0:24cdf76455c4 | 291 | DigitalOut b (LED_BLUE); |
jzeeff | 0:24cdf76455c4 | 292 | |
jzeeff | 3:eb60e36b03f6 | 293 | void led_color(int color) |
jzeeff | 0:24cdf76455c4 | 294 | { |
jzeeff | 0:24cdf76455c4 | 295 | // turn off |
jzeeff | 3:eb60e36b03f6 | 296 | r = g = b = 1; |
jzeeff | 0:24cdf76455c4 | 297 | |
jzeeff | 3:eb60e36b03f6 | 298 | switch (color) { |
jzeeff | 3:eb60e36b03f6 | 299 | case OFF: |
jzeeff | 3:eb60e36b03f6 | 300 | break; |
jzeeff | 3:eb60e36b03f6 | 301 | case GREEN: |
jzeeff | 3:eb60e36b03f6 | 302 | g = 0; |
jzeeff | 3:eb60e36b03f6 | 303 | break; |
jzeeff | 3:eb60e36b03f6 | 304 | case BLUE: |
jzeeff | 3:eb60e36b03f6 | 305 | b = 0; |
jzeeff | 3:eb60e36b03f6 | 306 | break; |
jzeeff | 3:eb60e36b03f6 | 307 | case RED: |
jzeeff | 3:eb60e36b03f6 | 308 | r = 0; |
jzeeff | 3:eb60e36b03f6 | 309 | break; |
jzeeff | 3:eb60e36b03f6 | 310 | case YELLOW: |
jzeeff | 3:eb60e36b03f6 | 311 | r = g = 0; |
jzeeff | 3:eb60e36b03f6 | 312 | break; |
jzeeff | 3:eb60e36b03f6 | 313 | case AQUA: |
jzeeff | 3:eb60e36b03f6 | 314 | b = g = 0; |
jzeeff | 3:eb60e36b03f6 | 315 | break; |
jzeeff | 3:eb60e36b03f6 | 316 | case PINK: |
jzeeff | 3:eb60e36b03f6 | 317 | r = b = 0; |
jzeeff | 3:eb60e36b03f6 | 318 | break; |
jzeeff | 3:eb60e36b03f6 | 319 | case WHITE: |
jzeeff | 3:eb60e36b03f6 | 320 | r = g = b = 0; |
jzeeff | 3:eb60e36b03f6 | 321 | break; |
jzeeff | 3:eb60e36b03f6 | 322 | } // switch |
jzeeff | 3:eb60e36b03f6 | 323 | |
jzeeff | 3:eb60e36b03f6 | 324 | } // led_color() |
jzeeff | 0:24cdf76455c4 | 325 | |
jzeeff | 0:24cdf76455c4 | 326 | //======================================= |
jzeeff | 0:24cdf76455c4 | 327 | // read A/D value from RTD |
jzeeff | 3:eb60e36b03f6 | 328 | // median and average for accuracy |
jzeeff | 0:24cdf76455c4 | 329 | //======================================= |
jzeeff | 0:24cdf76455c4 | 330 | |
jzeeff | 3:eb60e36b03f6 | 331 | unsigned read_temp(AnalogIn adc) |
jzeeff | 0:24cdf76455c4 | 332 | { |
jzeeff | 3:eb60e36b03f6 | 333 | uint32_t sum=0; |
jzeeff | 3:eb60e36b03f6 | 334 | int i; |
jzeeff | 1:b5abc8ddd567 | 335 | |
jzeeff | 3:eb60e36b03f6 | 336 | for (i = 0; i < 33; ++i) { // average multiple for more accuracy |
jzeeff | 3:eb60e36b03f6 | 337 | unsigned a, b, c; |
jzeeff | 3:eb60e36b03f6 | 338 | |
jzeeff | 3:eb60e36b03f6 | 339 | a = adc.read_u16(); // take median of 3 values |
jzeeff | 3:eb60e36b03f6 | 340 | b = adc.read_u16(); |
jzeeff | 3:eb60e36b03f6 | 341 | c = adc.read_u16(); |
jzeeff | 0:24cdf76455c4 | 342 | |
jzeeff | 3:eb60e36b03f6 | 343 | if ((a >= b && a <= c) || (a >= c && a <= b)) sum += a; |
jzeeff | 3:eb60e36b03f6 | 344 | else if ((b >= a && b <= c) || (b >= c && b <= a)) sum += b; |
jzeeff | 3:eb60e36b03f6 | 345 | else sum += c; |
jzeeff | 3:eb60e36b03f6 | 346 | } // for |
jzeeff | 1:b5abc8ddd567 | 347 | |
jzeeff | 3:eb60e36b03f6 | 348 | return sum / 33; |
jzeeff | 3:eb60e36b03f6 | 349 | |
jzeeff | 3:eb60e36b03f6 | 350 | } // read_temp() |
jzeeff | 3:eb60e36b03f6 | 351 | |
jzeeff | 3:eb60e36b03f6 | 352 | |
jzeeff | 3:eb60e36b03f6 | 353 | |
jzeeff | 3:eb60e36b03f6 | 354 |