microwave simulator

Dependencies:   C12832_lcd LM75B mbed

Committer:
rabad1
Date:
Fri Oct 18 21:50:14 2013 +0000
Revision:
1:fac01d40d819
Parent:
0:2f825861a3a2
Child:
2:9f6bdaddefff
fixed LED flicker

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rabad1 0:2f825861a3a2 1 #include "mbed.h"
rabad1 0:2f825861a3a2 2
rabad1 0:2f825861a3a2 3 #include "LM75B.h"
rabad1 0:2f825861a3a2 4 #include "C12832_lcd.h"
rabad1 0:2f825861a3a2 5 #include "keypad.h"
rabad1 0:2f825861a3a2 6
rabad1 0:2f825861a3a2 7 // uncomment to allow DEBUG
rabad1 1:fac01d40d819 8 //#define DEBUG
rabad1 0:2f825861a3a2 9
rabad1 0:2f825861a3a2 10 #define BUTTON_LEFT (p13)
rabad1 0:2f825861a3a2 11 #define BUTTON_RIGHT (p16)
rabad1 0:2f825861a3a2 12 #define BUTTON_START (p15)
rabad1 0:2f825861a3a2 13 #define BUTTON_STOP (p12)
rabad1 0:2f825861a3a2 14 #define BUTTON_DOOR (p14)
rabad1 1:fac01d40d819 15 #define TEMP_SCL (p27)
rabad1 1:fac01d40d819 16 #define TEMP_SDA (p28)
rabad1 1:fac01d40d819 17 #define ALARM (p26)
rabad1 0:2f825861a3a2 18
rabad1 0:2f825861a3a2 19 #define DOOR_CLOSED (0)
rabad1 0:2f825861a3a2 20 #define DOOR_OPEN (1)
rabad1 0:2f825861a3a2 21
rabad1 0:2f825861a3a2 22 #define LED_OFF (0)
rabad1 0:2f825861a3a2 23 #define LED_ON (1)
rabad1 0:2f825861a3a2 24
rabad1 0:2f825861a3a2 25 #define TRUE (1)
rabad1 0:2f825861a3a2 26 #define FALSE (0)
rabad1 0:2f825861a3a2 27
rabad1 0:2f825861a3a2 28 #define MIN_COOKING_TIME (0) // secs
rabad1 0:2f825861a3a2 29 #define MAX_COOKING_TIME (180)
rabad1 0:2f825861a3a2 30 #define COOKING_TIME_INCREMENT (60)
rabad1 0:2f825861a3a2 31 #define MAX_TICKER_TIME (60)
rabad1 0:2f825861a3a2 32 #define WDOG_TIME (1)
rabad1 0:2f825861a3a2 33
rabad1 0:2f825861a3a2 34 #define TEMP_INCREMENT (10.0f) // degC
rabad1 0:2f825861a3a2 35
rabad1 0:2f825861a3a2 36 typedef enum
rabad1 0:2f825861a3a2 37 {
rabad1 0:2f825861a3a2 38 STATUS_IDLE = 0,
rabad1 0:2f825861a3a2 39 STATUS_COOKING,
rabad1 0:2f825861a3a2 40 STATUS_DONE
rabad1 0:2f825861a3a2 41 } etSTATUS;
rabad1 0:2f825861a3a2 42
rabad1 0:2f825861a3a2 43 #ifdef DEBUG
rabad1 0:2f825861a3a2 44 #define MAX_LATENCY (10) // msec
rabad1 0:2f825861a3a2 45 #define ERROR_MICROWAVE_SM (1L<<0)
rabad1 0:2f825861a3a2 46 #define ERROR_LATENCY_DOOR (1L<<1)
rabad1 0:2f825861a3a2 47 #define ERROR_LATENCY_STOP (1L<<2)
rabad1 0:2f825861a3a2 48 #endif /* DEBUG */
rabad1 0:2f825861a3a2 49
rabad1 0:2f825861a3a2 50 // forward declarations
rabad1 0:2f825861a3a2 51 void init_microwave(void);
rabad1 0:2f825861a3a2 52 void press_left(void);
rabad1 0:2f825861a3a2 53 void press_right(void);
rabad1 0:2f825861a3a2 54 void press_start(void);
rabad1 0:2f825861a3a2 55 void press_stop(void);
rabad1 0:2f825861a3a2 56 void press_door(void);
rabad1 0:2f825861a3a2 57 void wdog_update(void);
rabad1 0:2f825861a3a2 58 void update_output(void);
rabad1 0:2f825861a3a2 59
rabad1 0:2f825861a3a2 60 void microwave_sm(void); // microwave state machine
rabad1 0:2f825861a3a2 61
rabad1 0:2f825861a3a2 62 // input peripherals
rabad1 0:2f825861a3a2 63 Keypad keypad( BUTTON_LEFT, press_left, // keypad
rabad1 0:2f825861a3a2 64 BUTTON_RIGHT, press_right,
rabad1 0:2f825861a3a2 65 BUTTON_START, press_start,
rabad1 0:2f825861a3a2 66 BUTTON_STOP, press_stop,
rabad1 0:2f825861a3a2 67 BUTTON_DOOR, press_door );
rabad1 1:fac01d40d819 68 LM75B tmp(TEMP_SDA,TEMP_SCL); // temperature sensor
rabad1 0:2f825861a3a2 69
rabad1 0:2f825861a3a2 70
rabad1 0:2f825861a3a2 71 // output peripherals
rabad1 0:2f825861a3a2 72 C12832_LCD lcd; // LCD screen
rabad1 0:2f825861a3a2 73 DigitalOut cooking_status(LED1); // LED for cooking progress
rabad1 0:2f825861a3a2 74 DigitalOut carousel_status(LED2); // LED for carousel
rabad1 0:2f825861a3a2 75 #ifdef DEBUG
rabad1 0:2f825861a3a2 76 DigitalOut debugLED(LED4); // general debug LED
rabad1 0:2f825861a3a2 77 #endif /* DEBUG */
rabad1 1:fac01d40d819 78 PwmOut alarm(ALARM); // alarm
rabad1 0:2f825861a3a2 79
rabad1 0:2f825861a3a2 80 // Timers
rabad1 0:2f825861a3a2 81 Ticker wdog; // 1sec watchdog
rabad1 0:2f825861a3a2 82 #ifdef DEBUG
rabad1 0:2f825861a3a2 83 Timer latency_wdog;
rabad1 0:2f825861a3a2 84 #endif /* DEBUG */
rabad1 0:2f825861a3a2 85
rabad1 0:2f825861a3a2 86 // global status variables
rabad1 0:2f825861a3a2 87 volatile signed short ssCookingTime;
rabad1 0:2f825861a3a2 88 unsigned char ucDoorStatus = DOOR_CLOSED;
rabad1 0:2f825861a3a2 89 float fTemp = 0.0f;
rabad1 0:2f825861a3a2 90 etSTATUS opStatus;
rabad1 0:2f825861a3a2 91 volatile unsigned char start_requested;
rabad1 0:2f825861a3a2 92 volatile unsigned char stop_requested;
rabad1 0:2f825861a3a2 93 volatile unsigned char temp_ticker;
rabad1 1:fac01d40d819 94 unsigned char reset_wdog;
rabad1 0:2f825861a3a2 95 #ifdef DEBUG
rabad1 0:2f825861a3a2 96 unsigned long ulErrorCode = 0UL;
rabad1 0:2f825861a3a2 97 #endif /* DEBUG */
rabad1 0:2f825861a3a2 98
rabad1 0:2f825861a3a2 99 int main()
rabad1 0:2f825861a3a2 100 {
rabad1 1:fac01d40d819 101 unsigned int while_loop_counter = 0;
rabad1 0:2f825861a3a2 102
rabad1 0:2f825861a3a2 103 init_microwave();
rabad1 0:2f825861a3a2 104
rabad1 0:2f825861a3a2 105 while(1)
rabad1 0:2f825861a3a2 106 {
rabad1 0:2f825861a3a2 107 while_loop_counter++;
rabad1 0:2f825861a3a2 108
rabad1 0:2f825861a3a2 109 microwave_sm(); // execute state machine
rabad1 0:2f825861a3a2 110
rabad1 0:2f825861a3a2 111 // do not need to update LCD as often
rabad1 1:fac01d40d819 112 if ( while_loop_counter & 0x4000 )
rabad1 0:2f825861a3a2 113 {
rabad1 0:2f825861a3a2 114 update_output();
rabad1 0:2f825861a3a2 115 }
rabad1 0:2f825861a3a2 116 }
rabad1 0:2f825861a3a2 117 }
rabad1 0:2f825861a3a2 118
rabad1 0:2f825861a3a2 119 void init_microwave(void)
rabad1 0:2f825861a3a2 120 {
rabad1 0:2f825861a3a2 121 ssCookingTime = 0L;
rabad1 0:2f825861a3a2 122 cooking_status = LED_OFF;
rabad1 0:2f825861a3a2 123 carousel_status = LED_OFF;
rabad1 0:2f825861a3a2 124 opStatus = STATUS_IDLE;
rabad1 0:2f825861a3a2 125 start_requested = FALSE;
rabad1 0:2f825861a3a2 126 stop_requested = FALSE;
rabad1 1:fac01d40d819 127 reset_wdog = FALSE;
rabad1 0:2f825861a3a2 128 }
rabad1 0:2f825861a3a2 129
rabad1 0:2f825861a3a2 130 void press_left(void)
rabad1 0:2f825861a3a2 131 {
rabad1 0:2f825861a3a2 132 if ( opStatus == STATUS_DONE )
rabad1 0:2f825861a3a2 133 {
rabad1 0:2f825861a3a2 134 return;
rabad1 0:2f825861a3a2 135 }
rabad1 0:2f825861a3a2 136 ssCookingTime += COOKING_TIME_INCREMENT;
rabad1 0:2f825861a3a2 137 if ( ssCookingTime >= MAX_COOKING_TIME )
rabad1 0:2f825861a3a2 138 {
rabad1 0:2f825861a3a2 139 ssCookingTime = MAX_COOKING_TIME;
rabad1 0:2f825861a3a2 140 }
rabad1 0:2f825861a3a2 141 }
rabad1 0:2f825861a3a2 142
rabad1 0:2f825861a3a2 143 void press_right(void)
rabad1 0:2f825861a3a2 144 {
rabad1 0:2f825861a3a2 145 if ( opStatus != STATUS_IDLE )
rabad1 0:2f825861a3a2 146 {
rabad1 0:2f825861a3a2 147 return;
rabad1 0:2f825861a3a2 148 }
rabad1 0:2f825861a3a2 149 ssCookingTime -= COOKING_TIME_INCREMENT;
rabad1 0:2f825861a3a2 150 if ( ssCookingTime <= MIN_COOKING_TIME )
rabad1 0:2f825861a3a2 151 {
rabad1 0:2f825861a3a2 152 ssCookingTime = MIN_COOKING_TIME;
rabad1 0:2f825861a3a2 153 }
rabad1 0:2f825861a3a2 154 }
rabad1 0:2f825861a3a2 155
rabad1 0:2f825861a3a2 156 void press_start(void)
rabad1 0:2f825861a3a2 157 {
rabad1 0:2f825861a3a2 158 if ( opStatus != STATUS_IDLE )
rabad1 0:2f825861a3a2 159 {
rabad1 0:2f825861a3a2 160 return;
rabad1 0:2f825861a3a2 161 }
rabad1 0:2f825861a3a2 162
rabad1 0:2f825861a3a2 163 if ( ssCookingTime && (ucDoorStatus == DOOR_CLOSED) )
rabad1 0:2f825861a3a2 164 {
rabad1 0:2f825861a3a2 165 start_requested = TRUE;
rabad1 0:2f825861a3a2 166 }
rabad1 0:2f825861a3a2 167 }
rabad1 0:2f825861a3a2 168
rabad1 0:2f825861a3a2 169 void press_stop(void)
rabad1 0:2f825861a3a2 170 {
rabad1 0:2f825861a3a2 171 if ( opStatus == STATUS_IDLE )
rabad1 0:2f825861a3a2 172 {
rabad1 0:2f825861a3a2 173 init_microwave();
rabad1 0:2f825861a3a2 174 return;
rabad1 0:2f825861a3a2 175 }
rabad1 0:2f825861a3a2 176 else
rabad1 0:2f825861a3a2 177 {
rabad1 0:2f825861a3a2 178 #ifdef DEBUG
rabad1 0:2f825861a3a2 179 latency_wdog.start();
rabad1 0:2f825861a3a2 180 #endif
rabad1 0:2f825861a3a2 181 stop_requested = TRUE;
rabad1 0:2f825861a3a2 182 }
rabad1 0:2f825861a3a2 183 }
rabad1 0:2f825861a3a2 184
rabad1 0:2f825861a3a2 185 void press_door(void)
rabad1 0:2f825861a3a2 186 {
rabad1 0:2f825861a3a2 187 ucDoorStatus = !ucDoorStatus;
rabad1 0:2f825861a3a2 188 if ( opStatus == STATUS_COOKING )
rabad1 0:2f825861a3a2 189 {
rabad1 0:2f825861a3a2 190 #ifdef DEBUG
rabad1 0:2f825861a3a2 191 latency_wdog.start();
rabad1 0:2f825861a3a2 192 #endif
rabad1 0:2f825861a3a2 193 }
rabad1 0:2f825861a3a2 194 }
rabad1 0:2f825861a3a2 195
rabad1 0:2f825861a3a2 196 void wdog_update(void)
rabad1 0:2f825861a3a2 197 {
rabad1 0:2f825861a3a2 198 if ( opStatus == STATUS_COOKING )
rabad1 0:2f825861a3a2 199 {
rabad1 0:2f825861a3a2 200 ssCookingTime--;
rabad1 0:2f825861a3a2 201
rabad1 0:2f825861a3a2 202 // reset wdog
rabad1 0:2f825861a3a2 203 if ( ssCookingTime )
rabad1 0:2f825861a3a2 204 {
rabad1 1:fac01d40d819 205 reset_wdog = TRUE;
rabad1 0:2f825861a3a2 206 }
rabad1 0:2f825861a3a2 207
rabad1 0:2f825861a3a2 208 if ( temp_ticker )
rabad1 0:2f825861a3a2 209 {
rabad1 0:2f825861a3a2 210 temp_ticker--;
rabad1 0:2f825861a3a2 211 }
rabad1 0:2f825861a3a2 212 }
rabad1 0:2f825861a3a2 213 }
rabad1 0:2f825861a3a2 214
rabad1 0:2f825861a3a2 215 void microwave_sm(void)
rabad1 0:2f825861a3a2 216 {
rabad1 0:2f825861a3a2 217 switch ( opStatus )
rabad1 0:2f825861a3a2 218 {
rabad1 0:2f825861a3a2 219 case STATUS_IDLE:
rabad1 0:2f825861a3a2 220 if ( ssCookingTime && !ucDoorStatus && start_requested )
rabad1 0:2f825861a3a2 221 {
rabad1 1:fac01d40d819 222 fTemp = tmp.read();
rabad1 0:2f825861a3a2 223 start_requested = FALSE;
rabad1 0:2f825861a3a2 224 wdog.attach(wdog_update, 1);
rabad1 0:2f825861a3a2 225 temp_ticker = (ssCookingTime > MAX_TICKER_TIME) ? MAX_TICKER_TIME : ssCookingTime;
rabad1 0:2f825861a3a2 226 opStatus = STATUS_COOKING;
rabad1 0:2f825861a3a2 227 }
rabad1 0:2f825861a3a2 228 break;
rabad1 0:2f825861a3a2 229
rabad1 0:2f825861a3a2 230 case STATUS_COOKING:
rabad1 0:2f825861a3a2 231 if ( ucDoorStatus == DOOR_OPEN )
rabad1 0:2f825861a3a2 232 {
rabad1 0:2f825861a3a2 233 #ifdef DEBUG
rabad1 0:2f825861a3a2 234 if (latency_wdog.read_ms() > MAX_LATENCY)
rabad1 0:2f825861a3a2 235 {
rabad1 0:2f825861a3a2 236 ulErrorCode |= ERROR_LATENCY_DOOR;
rabad1 0:2f825861a3a2 237 }
rabad1 0:2f825861a3a2 238 latency_wdog.stop();
rabad1 0:2f825861a3a2 239 #endif /* DEBUG */
rabad1 0:2f825861a3a2 240 init_microwave();
rabad1 0:2f825861a3a2 241 }
rabad1 0:2f825861a3a2 242 else if ( stop_requested )
rabad1 0:2f825861a3a2 243 {
rabad1 0:2f825861a3a2 244 #ifdef DEBUG
rabad1 0:2f825861a3a2 245 if (latency_wdog.read_ms() > MAX_LATENCY)
rabad1 0:2f825861a3a2 246 {
rabad1 0:2f825861a3a2 247 ulErrorCode |= ERROR_LATENCY_STOP;
rabad1 0:2f825861a3a2 248 }
rabad1 0:2f825861a3a2 249 latency_wdog.stop();
rabad1 0:2f825861a3a2 250 #endif /* DEBUG */
rabad1 0:2f825861a3a2 251 init_microwave();
rabad1 0:2f825861a3a2 252 }
rabad1 0:2f825861a3a2 253 else
rabad1 0:2f825861a3a2 254 {
rabad1 0:2f825861a3a2 255 if ( !ssCookingTime )
rabad1 0:2f825861a3a2 256 {
rabad1 0:2f825861a3a2 257 opStatus = STATUS_DONE;
rabad1 0:2f825861a3a2 258 }
rabad1 1:fac01d40d819 259 if ( !temp_ticker )
rabad1 0:2f825861a3a2 260 {
rabad1 0:2f825861a3a2 261 fTemp += TEMP_INCREMENT;
rabad1 0:2f825861a3a2 262 temp_ticker = (ssCookingTime > MAX_TICKER_TIME) ? MAX_TICKER_TIME : ssCookingTime;
rabad1 0:2f825861a3a2 263 }
rabad1 1:fac01d40d819 264 if ( reset_wdog )
rabad1 1:fac01d40d819 265 {
rabad1 1:fac01d40d819 266 wdog.attach(wdog_update, 1);
rabad1 1:fac01d40d819 267 reset_wdog = FALSE;
rabad1 1:fac01d40d819 268 }
rabad1 0:2f825861a3a2 269 }
rabad1 0:2f825861a3a2 270 break;
rabad1 0:2f825861a3a2 271
rabad1 0:2f825861a3a2 272 case STATUS_DONE:
rabad1 0:2f825861a3a2 273 if ( ucDoorStatus == DOOR_OPEN || stop_requested )
rabad1 0:2f825861a3a2 274 {
rabad1 0:2f825861a3a2 275 init_microwave();
rabad1 0:2f825861a3a2 276 }
rabad1 0:2f825861a3a2 277 break;
rabad1 0:2f825861a3a2 278
rabad1 0:2f825861a3a2 279 default:
rabad1 0:2f825861a3a2 280 #ifdef DEBUG
rabad1 0:2f825861a3a2 281 // something is wrong if we got here!
rabad1 0:2f825861a3a2 282 ulErrorCode |= ERROR_MICROWAVE_SM;
rabad1 0:2f825861a3a2 283 #endif /* DEBUG */
rabad1 0:2f825861a3a2 284 break;
rabad1 0:2f825861a3a2 285 }
rabad1 0:2f825861a3a2 286 }
rabad1 0:2f825861a3a2 287
rabad1 0:2f825861a3a2 288 void update_output(void)
rabad1 0:2f825861a3a2 289 {
rabad1 0:2f825861a3a2 290 static unsigned char toggle_alarm = 0;
rabad1 1:fac01d40d819 291 static unsigned char toggle_leds = 0;
rabad1 0:2f825861a3a2 292 static etSTATUS previousState = (etSTATUS) 0xFF;
rabad1 0:2f825861a3a2 293
rabad1 0:2f825861a3a2 294 // clear the screen only when we transition states to prevent flicker
rabad1 0:2f825861a3a2 295 if ( previousState != opStatus )
rabad1 0:2f825861a3a2 296 {
rabad1 0:2f825861a3a2 297 lcd.cls();
rabad1 0:2f825861a3a2 298 previousState = opStatus;
rabad1 0:2f825861a3a2 299 }
rabad1 0:2f825861a3a2 300 lcd.locate(0,0);
rabad1 0:2f825861a3a2 301 lcd.printf("Cooking Time: %3d secs\n",ssCookingTime);
rabad1 0:2f825861a3a2 302
rabad1 0:2f825861a3a2 303 switch ( opStatus )
rabad1 0:2f825861a3a2 304 {
rabad1 0:2f825861a3a2 305 case STATUS_IDLE:
rabad1 0:2f825861a3a2 306 // alarm should be off in this state
rabad1 0:2f825861a3a2 307 toggle_alarm = 0;
rabad1 0:2f825861a3a2 308 alarm = 0.0;
rabad1 0:2f825861a3a2 309 break;
rabad1 0:2f825861a3a2 310
rabad1 0:2f825861a3a2 311 case STATUS_COOKING:
rabad1 0:2f825861a3a2 312 // display temp
rabad1 0:2f825861a3a2 313 lcd.locate(0,10);
rabad1 0:2f825861a3a2 314 lcd.printf("Temp: %.2f degC\n", fTemp);
rabad1 0:2f825861a3a2 315
rabad1 0:2f825861a3a2 316 // update LEDs
rabad1 1:fac01d40d819 317 toggle_leds++;
rabad1 1:fac01d40d819 318 if ( toggle_leds & 0x10 )
rabad1 1:fac01d40d819 319 {
rabad1 1:fac01d40d819 320 cooking_status = !cooking_status;
rabad1 1:fac01d40d819 321 carousel_status = !carousel_status;
rabad1 1:fac01d40d819 322 }
rabad1 0:2f825861a3a2 323
rabad1 0:2f825861a3a2 324 // alarm should be off in this state
rabad1 0:2f825861a3a2 325 toggle_alarm = 0;
rabad1 0:2f825861a3a2 326 alarm = 0.0;
rabad1 0:2f825861a3a2 327 break;
rabad1 0:2f825861a3a2 328
rabad1 0:2f825861a3a2 329 case STATUS_DONE:
rabad1 0:2f825861a3a2 330 // LEDs off in this state
rabad1 0:2f825861a3a2 331 cooking_status = LED_OFF;
rabad1 0:2f825861a3a2 332 carousel_status = LED_OFF;
rabad1 0:2f825861a3a2 333
rabad1 0:2f825861a3a2 334 // sound alarm
rabad1 0:2f825861a3a2 335 toggle_alarm++;
rabad1 1:fac01d40d819 336 if ( toggle_alarm & 0x10 )
rabad1 0:2f825861a3a2 337 {
rabad1 0:2f825861a3a2 338 alarm.period(1.0/5000);
rabad1 0:2f825861a3a2 339 alarm = 0.5;
rabad1 0:2f825861a3a2 340 }
rabad1 0:2f825861a3a2 341 else
rabad1 0:2f825861a3a2 342 {
rabad1 0:2f825861a3a2 343 alarm = 0.0;
rabad1 0:2f825861a3a2 344 }
rabad1 0:2f825861a3a2 345
rabad1 0:2f825861a3a2 346 lcd.locate(0,10);
rabad1 0:2f825861a3a2 347 lcd.printf("ENJOY YOUR MEAL!\n");
rabad1 0:2f825861a3a2 348 break;
rabad1 0:2f825861a3a2 349 }
rabad1 0:2f825861a3a2 350 lcd.locate(0,23);
rabad1 0:2f825861a3a2 351 lcd.printf("door %s\n", ucDoorStatus ? "open " : "closed");
rabad1 0:2f825861a3a2 352 #ifdef DEBUG
rabad1 0:2f825861a3a2 353 lcd.locate(95,23);
rabad1 0:2f825861a3a2 354 lcd.printf("0x%04X\n", ulErrorCode);
rabad1 0:2f825861a3a2 355 #endif /* DEBUG */
rabad1 0:2f825861a3a2 356 }