microwave simulator

Dependencies:   C12832_lcd LM75B mbed

main.cpp

Committer:
rabad1
Date:
2013-10-24
Revision:
2:9f6bdaddefff
Parent:
1:fac01d40d819

File content as of revision 2:9f6bdaddefff:

#include "mbed.h"

#include "LM75B.h"
#include "C12832_lcd.h"
#include "keypad.h"

// uncomment to allow DEBUG
//#define DEBUG

#define BUTTON_LEFT     (p13)
#define BUTTON_RIGHT    (p16)
#define BUTTON_START    (p15)
#define BUTTON_STOP     (p12)
#define BUTTON_DOOR     (p14)
#define TEMP_SCL        (p27)
#define TEMP_SDA        (p28)
#define ALARM           (p26)

#define DOOR_CLOSED     (0)
#define DOOR_OPEN       (1)

#define LED_OFF         (0)
#define LED_ON          (1)

#define TRUE            (1)
#define FALSE           (0)

#define MIN_COOKING_TIME        (0)     // secs
#define MAX_COOKING_TIME        (180)
#define COOKING_TIME_INCREMENT  (60)
#define MAX_TICKER_TIME         (60)
#define WDOG_TIME               (1)

#define TEMP_INCREMENT          (10.0f) // degC

typedef enum
{
    STATUS_IDLE = 0,
    STATUS_COOKING,
    STATUS_DONE
} etSTATUS;

#ifdef DEBUG
  #define MAX_LATENCY           (10)        // msec
  #define ERROR_MICROWAVE_SM    (1L<<0)
  #define ERROR_LATENCY_DOOR    (1L<<1)
  #define ERROR_LATENCY_STOP    (1L<<2)
#endif /* DEBUG */

// forward declarations
void init_microwave(void);
void press_left(void);
void press_right(void);
void press_start(void);
void press_stop(void);
void press_door(void);
void wdog_update(void);
void update_output(void);

void microwave_sm(void);    // microwave state machine

// input peripherals
Keypad keypad( BUTTON_LEFT, press_left,     // keypad
               BUTTON_RIGHT, press_right,
               BUTTON_START, press_start,
               BUTTON_STOP, press_stop,
               BUTTON_DOOR, press_door );
LM75B tmp(TEMP_SDA,TEMP_SCL);              // temperature sensor


// output peripherals
C12832_LCD lcd;                     // LCD screen
DigitalOut cooking_status(LED1);    // LED for cooking progress
DigitalOut carousel_status(LED2);   // LED for carousel
#ifdef DEBUG
  DigitalOut debugLED(LED4);        // general debug LED
#endif /* DEBUG */
PwmOut alarm(ALARM);                // alarm

// Timers
Ticker wdog;            // 1sec watchdog
#ifdef DEBUG
  Timer latency_wdog;
#endif /* DEBUG */

// global status variables
volatile signed short ssCookingTime;
unsigned char ucDoorStatus = DOOR_CLOSED;
float fTemp = 0.0f;
etSTATUS opStatus;
volatile unsigned char start_requested;
volatile unsigned char stop_requested;
volatile unsigned char temp_ticker;
unsigned char reset_wdog;
#ifdef DEBUG
  unsigned long ulErrorCode = 0UL;
#endif /* DEBUG */

/* Name: main()
 * Desc: entry point of application.  This will also invoke the microwave
 *       state machine and update output
 * Inputs: none
 * Outputs: none
 */
int main()
{
    unsigned int while_loop_counter = 0;
    
    init_microwave();
    
    while(1)
    {
        while_loop_counter++;
        
        microwave_sm(); // execute state machine
        
        // do not need to update LCD as often
        if ( while_loop_counter & 0x4000 )
        {
            update_output();
        }
    }
}

/* Name: init_microwave()
 * Desc: initializes the microwave state machine to STATUS_IDLE
 * Inputs: none
 * Outputs: none
 */
void init_microwave(void)
{
    ssCookingTime = 0L;
    cooking_status = LED_OFF;
    carousel_status = LED_OFF;
    opStatus = STATUS_IDLE;
    start_requested = FALSE;
    stop_requested = FALSE;
    reset_wdog = FALSE;
}

/* Name: press_left()
 * Desc: ISR callback function for left button.
 * Inputs: none
 * Outputs: none
 */
void press_left(void)
{
    if ( opStatus == STATUS_DONE )
    {
        return;
    }
    ssCookingTime += COOKING_TIME_INCREMENT;
    if ( ssCookingTime >= MAX_COOKING_TIME )
    {
        ssCookingTime = MAX_COOKING_TIME;
    }
}

/* Name: press_right()
 * Desc: ISR callback function for right button.
 * Inputs: none
 * Outputs: none
 */
void press_right(void)
{
    if ( opStatus != STATUS_IDLE )
    {
        return;
    }
    ssCookingTime -= COOKING_TIME_INCREMENT;
    if ( ssCookingTime <= MIN_COOKING_TIME )
    {
        ssCookingTime = MIN_COOKING_TIME;
    }
}

/* Name: press_start()
 * Desc: ISR callback function for start button.
 * Inputs: none
 * Outputs: none
 */
void press_start(void)
{
    if ( opStatus != STATUS_IDLE )
    {
        return;
    }
    
    if ( ssCookingTime && (ucDoorStatus == DOOR_CLOSED) )
    {
        start_requested = TRUE;
    }
}

/* Name: press_stop()
 * Desc: ISR callback function for stop button.
 * Inputs: none
 * Outputs: none
 */
void press_stop(void)
{
    if ( opStatus == STATUS_IDLE )
    {
        init_microwave();
        return;
    }
    else
    {
#ifdef DEBUG
        latency_wdog.start();
#endif
        stop_requested = TRUE;
    }
}

/* Name: press_door()
 * Desc: ISR callback function for door button.
 * Inputs: none
 * Outputs: none
 */
void press_door(void)
{
    ucDoorStatus = !ucDoorStatus;
    if ( opStatus == STATUS_COOKING )
    {
#ifdef DEBUG
        latency_wdog.start();
#endif
    }
}

/* Name: wdog_update()
 * Desc: callback function for watchdog timer.  This watchog updates the
 *       cooking time when the microwave is running (STATUS_COOKING).
 * Inputs: none
 * Outputs: none
 */
void wdog_update(void)
{
    if ( opStatus == STATUS_COOKING )
    {
        ssCookingTime--;
        
        // reset wdog
        if ( ssCookingTime )
        {
            reset_wdog = TRUE;
        }
        
        if ( temp_ticker )
        {
            temp_ticker--;
        }
    }
}

/* Name: microwave_sm()
 * Desc: This is the microwave state machine.  It processes all input and
 *       updates all state variables.
 * Inputs: none
 * Outputs: none
 */
void microwave_sm(void)
{
    switch ( opStatus )
    {
    case STATUS_IDLE:
        if ( ssCookingTime && !ucDoorStatus && start_requested )
        {
            fTemp = tmp.read();
            start_requested = FALSE;
            wdog.attach(wdog_update, 1);
            temp_ticker = (ssCookingTime > MAX_TICKER_TIME) ? MAX_TICKER_TIME : ssCookingTime;
            opStatus = STATUS_COOKING;
        }
        break;
    
    case STATUS_COOKING:
        if ( ucDoorStatus == DOOR_OPEN )
        {
#ifdef DEBUG
            if (latency_wdog.read_ms() > MAX_LATENCY)
            {
                ulErrorCode |= ERROR_LATENCY_DOOR;
            }
            latency_wdog.stop();
#endif /* DEBUG */
            init_microwave();
        }
        else if ( stop_requested )
        {
#ifdef DEBUG
            if (latency_wdog.read_ms() > MAX_LATENCY)
            {
                ulErrorCode |= ERROR_LATENCY_STOP;
            }
            latency_wdog.stop();
#endif /* DEBUG */
            init_microwave();
        }
        else
        {
            if ( !ssCookingTime )
            {
                opStatus = STATUS_DONE;
            }
            if ( !temp_ticker )
            {
                fTemp += TEMP_INCREMENT;
                temp_ticker = (ssCookingTime > MAX_TICKER_TIME) ? MAX_TICKER_TIME : ssCookingTime;
            }
            if ( reset_wdog )
            {
                wdog.attach(wdog_update, 1);
                reset_wdog = FALSE;
            }
        }
        break;
        
    case STATUS_DONE:
        if ( ucDoorStatus == DOOR_OPEN || stop_requested )
        {
            init_microwave();
        }
        break;
        
    default:
#ifdef DEBUG
        // something is wrong if we got here!
        ulErrorCode |= ERROR_MICROWAVE_SM;
#endif /* DEBUG */        
        break;        
    }
}

/* Name: update_output()
 * Desc: Updates all output based on status variables.
 * Inputs: none
 * Outputs: none
 */
void update_output(void)
{
    static unsigned char toggle_alarm = 0;
    static unsigned char toggle_leds = 0;
    static etSTATUS previousState = (etSTATUS) 0xFF;
    
    // clear the screen only when we transition states to prevent flicker
    if ( previousState != opStatus )
    {
        lcd.cls();
        previousState = opStatus;
    }
    lcd.locate(0,0);
    lcd.printf("Cooking Time: %3d secs\n",ssCookingTime);

    switch ( opStatus )
    {
    case STATUS_IDLE:
        // alarm should be off in this state
        toggle_alarm = 0;
        alarm = 0.0;
        break;
        
    case STATUS_COOKING:
        // display temp
        lcd.locate(0,10);
        lcd.printf("Temp: %.2f degC\n", fTemp);
        
        // update LEDs
        toggle_leds++;
        if ( toggle_leds & 0x10 )
        {
            cooking_status = !cooking_status;
            carousel_status = !carousel_status;
        }
        
        // alarm should be off in this state
        toggle_alarm = 0;
        alarm = 0.0;
        break;
    
    case STATUS_DONE:
        // LEDs off in this state
        cooking_status = LED_OFF;
        carousel_status = LED_OFF;

        // sound alarm
        toggle_alarm++;
        if ( toggle_alarm & 0x10 )
        {
            alarm.period(1.0/5000);
            alarm = 0.5;
        }
        else
        {
            alarm = 0.0;
        }
        
        lcd.locate(0,10);
        lcd.printf("ENJOY YOUR MEAL!\n");
        break;
    }
    lcd.locate(0,23);
    lcd.printf("door %s\n", ucDoorStatus ? "open  " : "closed");
#ifdef DEBUG
    lcd.locate(95,23);
    lcd.printf("0x%04X\n", ulErrorCode);
#endif /* DEBUG */        
}