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: mbed-rtos mbed C12832_lcd LM75B
main.cpp
- Committer:
- gatedClock
- Date:
- 2013-09-12
- Revision:
- 119:e14b0f6e97cb
- Parent:
- 118:d0e057d79acc
- Child:
- 120:64a969984af2
File content as of revision 119:e14b0f6e97cb:
/*----------------------------------------------//------------------------------
student : m-moore
class : rtos
directory : RTOS_HW_07
file : main.cpp
----description---------------------------------//------------------------------
gotchyas
1. using pc.printf inside a ticker routine will freeze the routine.
2. using queues (get, put) will not work within a ticker routine.
3. Ticker has a bug. http://mbed.org/questions/1563/Mbed-Tickerfunction-hangs-system-from-re/
improvements
countdown timer needs to be sync'd to start button press.
this could not be done, use granularity setting instead.
-----includes-----------------------------------//----------------------------*/
#include "mbed.h" // mbed class.
#include "rtos.h" // rtos class.
#include "LM75B.h" // thermometer class.
#include "C12832_lcd.h" // LCD class.
//---defines------------------------------------//------------------------------
#define LCD1 lcd.locate(0, 0); // LCD line 1.
#define LCD2 lcd.locate(0,11); // LCD line 2.
#define LCD3 lcd.locate(0,22); // LCD line 3.
#define DEBOUNCEmS 16 // debounce wait in mS.
#define uS_TIMEOUT 100 // Timer uS timeout.
#define LBSIG 1 // left button signal code.
#define PIPEuS 1000 // pipeline clock period.
#define SLOWCLOCKuS 500000 // slow-clock period.
#define TEMPCLOCKS 1 // temperature-measuring period in S.
#define PIPEDATASIZE 8 // dimension of tPipeData.
#define THREAD_1_WAITmS 400 // thread 1 wait in mS.
#define THREAD_2_WAITmS 40 // LCD thread wait.
#define THREAD_3_WAITmS 80 // thread 3 wait in mS.
#define THREAD_4_WAITmS 1 // thread 4 wait in mS.
#define THREAD_5_WAITmS 100 // FSM thread wait.
#define HB_MODULO 1024 // heartbeat modulo divisor.
#define MSG_INC_TIME 0x01
#define MSG_DEC_TIME 0x02
#define MSG_START 0x04
#define MSG_STOP 0x08
#define MSG_OPEN 0x10
#define MSG_CLOSED 0x20
#define FSM_IDLE 0x01 // cook-state state-machine.
#define FSM_COOK 0x02 // cook-state state-machine.
#define FSM_PAUSE 0x04 // cook-state state-machine.
#define FSM_CONTINUE 0x08 // cook-state state-machine.
#define FSM_DONE 0x10 // cook-state state-machine.
#define RT_PRELOAD 0x01 // remaining-time preload.
#define RT_DECREMENT 0x02 // remaining-time decrement.
#define RT_PAUSE 0x03 // remaining-time don't change.
#define RT_CLEAR 0x04 // remaining-time set to zero.
#define TEMP_READ 0x01 // temperature synthesizer control.
#define TEMP_CALC 0x02 // temperature synthesizer control.
#define TEMP_FREEZE 0x03 // temperature synthesizer control.
#define GRANULARITY 0x400 // 1-second countdown ticker granularity.
#define MAXSECONDS 180 // maximum microwave-on time.
#define BEEPTIME 3 // beep duration in S.
#define BEEPFREQ 300 // beep frequency in Hz.
#define TIMEINC 10 // time increment in seconds.
//--global_definitions--------------------------//------------------------------
struct tButtons // button ISR updates.
{
char cLeftButton; // cooktime +60S.
char cRightButton; // cooktime -60S.
char cTopButton; // start cook.
char cBottomButton; // stop cook.
char cCenterButton; // center button pressed.
char cDoorOpen; // door open.
};
struct tRemainingTime // remaining time related.
{
char cControl; // countdown control.
char cBeepEnable; // beep control.
char cMagnetron; // magnetron blink control.
char cCarousel; // carousel blink control.
int dTotalTime; // initialize to this.
int dRemainingTime; // the countdown value.
};
struct tLCD // LCD related.
{
int dTotalCookTime; // display time in seconds.
int dRemainingTime; // display time in seconds.
float fCelsius; // temperature in celsius.
};
Queue<int, 1> queueModTotalTime; // modify total time.
Queue<int, 1> queueUpdateFSM; // tell FSM what button was pressed.
Queue<int, 1> queueUpdateRemainingTime; // message to update remaining time.
Queue<int, 1> queueSetRemainingTime; // tell countdown it's start time.
Queue<int, 1> queueTemperatureControl; // control the temperature synthesizer.
Queue<int, 1> queueSuppressTimeAdjust; // total time control.
Queue<int, 1> queueClearTotalTime; // total time control.
//--global_variables----------------------------//------------------------------
tButtons giButtons; // ISR button updates.
tRemainingTime giRemainingTime; // structure instance.
tLCD giLCD; // structure instance.
//--global_instances----------------------------//------------------------------
Serial pc(USBTX, USBRX); // PuTTY terminal communication.
LM75B temperature(p28,p27); // on-board thermometer.
C12832_LCD lcd; // LCD object.
DigitalOut led0(LED4); // magnetron.
DigitalOut led1(LED3);
DigitalOut led2(LED2);
DigitalOut led3(LED1);
DigitalOut speaker(p26); // speaker device.
InterruptIn iJoyStickUp (p15); // joystick up rising edge.
InterruptIn iJoyStickDown (p12); // joystick down rising edge.
InterruptIn iJoyStickLeft (p13); // joystick left rising edge.
InterruptIn iJoyStickRight (p16); // joystick right rising edge.
InterruptIn iJoyStickCenter(p14); // 1 if joystick middle pressed.
Timer debounceTimer; // button debounce timer.
Timer beepTimer; // beep-duration timer.
Timer temperatureTimer; // how often to raise temperature.
Ticker tickerButtonStateManager; // manage the button states.
Ticker tickerCookCountdown; // remaining cook time.
Ticker tickerBeep; // beeper ticker.
Ticker tickerBlinkMagnetron; // magnetron LED blinker.
Ticker tickerBlinkCarousel; // caroulsel LED blinker.
//-------prototypes-----------------------------//------------------------------
void slowClock(); // 1Hz or thereabouts.
void initialization(); // initialize settings.
void ISRleftButtonRising(); // cook-time increase.
void ISRleftButtonFalling(); // button-release debounce.
void ISRrightButtonRising(); // cook-time decrease.
void ISRrightButtonFalling(); // button-release debounce.
void ISRtopButtonRising(); // cook start.
void ISRtopButtonFalling(); // button-release debounce.
void ISRbottomButtonRising(); // cook stop.
void ISRbottomButtonFalling(); // button-release debounce.
void ISRcenterButtonRising(); // door state toggle.
void ISRcenterButtonFalling(); // button-release debounce.
void disableSignalWaiting(); // break from signal waiting.
void threadButtonStateManager(void const *args);
void threadTotalTimeControl(void const *args);
void threadCookStateFSM(void const *args);
void tickCookRemainingTime(); // remaining time countdown.
void temperatureThread(void const *args); // temperature measurement.
void LCDthread (void const *args); // LCD display thread.
void tickerBeeper(); // beep oscillator.
void tickerMagnetron(); // blink magnetron LED.
void tickerCarousel(); // blink carousel LED.
//==============================================//==============================
int main(void)
{
initialization(); // initialize variables.
// ISR setup.
iJoyStickLeft.rise (&ISRleftButtonRising);
iJoyStickLeft.fall (&ISRleftButtonFalling);
iJoyStickRight.rise(&ISRrightButtonRising);
iJoyStickRight.fall(&ISRrightButtonFalling);
iJoyStickUp.rise (&ISRtopButtonRising);
iJoyStickUp.fall (&ISRtopButtonFalling);
iJoyStickDown.rise (&ISRbottomButtonRising);
iJoyStickDown.fall (&ISRbottomButtonFalling);
iJoyStickCenter.rise(&ISRcenterButtonRising);
iJoyStickCenter.fall(&ISRcenterButtonFalling);
debounceTimer.start(); // kick-off debounce timer.
// kick-off tickers.
tickerCookCountdown.attach_us(&tickCookRemainingTime,1000000/GRANULARITY);
tickerBeep.attach_us (&tickerBeeper ,2000);
tickerBlinkMagnetron.attach_us(&tickerMagnetron,250000);
tickerBlinkCarousel.attach_us(&tickerCarousel,250000);
// kick-off threads.
Thread thread_1(temperatureThread ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
Thread thread_2(LCDthread ,NULL,osPriorityNormal,DEFAULT_STACK_SIZE,NULL);
Thread thread_3(threadTotalTimeControl ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
Thread thread_4(threadButtonStateManager,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
Thread thread_5(threadCookStateFSM ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
while(1) Thread::wait(10000); // execute microwave controller.
}
/*----------------------------------------------//----------------------------*/
// this serves as the bottom-half for all of the button-press IRSs.
// it sends button-status messages to other threads, and it also
// clears the button-state globals to prepare them for the next
// button press.
void threadButtonStateManager(void const *args)
{
int dMessage; // message.
while(1) // thread loop.
{
//--- // TOTAL TIME CONTROL.
// encoded integers will be sent,
// not pointers.
if (giButtons.cLeftButton) // total time increment button.
{
dMessage = MSG_INC_TIME; // set message.
queueModTotalTime.put((int *) dMessage,1);// pretend it's a pointer.
giButtons.cLeftButton = 0; // clear the button state.
}
if (giButtons.cRightButton) // total time decrement button.
{
dMessage = MSG_DEC_TIME; // set message.
queueModTotalTime.put((int *) dMessage,1);// pretend it's a pointer.
giButtons.cRightButton = 0; // clear the button state.
}
//--- // COOK-STATE FSM.
if (giButtons.cTopButton) // start-cook button.
{
dMessage = MSG_START; // set message.
queueUpdateFSM.put((int *) dMessage,1); // pretend it's a pointer.
giButtons.cTopButton = 0; // clear the button state.
}
if (giButtons.cBottomButton) // stop-cook button.
{
dMessage = MSG_STOP; // set message.
queueUpdateFSM.put((int *) dMessage,1); // pretend it's a pointer.
giButtons.cBottomButton = 0; // clear the button state.
}
if (giButtons.cCenterButton) // door-state-toggle.
{
dMessage = giButtons.cDoorOpen; // determined in ISR.
queueUpdateFSM.put((int *) dMessage,1); // pretend it's a pointer.
giButtons.cCenterButton = 0; // clear the button state.
}
//---
Thread::wait(THREAD_4_WAITmS); // multitasking.
} // thread loop.
} // threadButtonStateManager.
/*----------------------------------------------//----------------------------*/
// total time controller.
void threadTotalTimeControl(void const *args)
{
static int dTotalTime = 0; // total time variable.
int dMessage; // message.
int dSuppress; // 1 to suppress operation.
osEvent queueEvent; // queue event.
dSuppress = 0; // initialize.
while(1) // thread loop.
{
// if FSM tells this to clear
// the total time.
queueEvent = queueClearTotalTime.get(1);
if (queueEvent.status == osEventMessage)
{
dTotalTime = 0;
queueSetRemainingTime.put((int *) dTotalTime,1);
giRemainingTime.dTotalTime = dTotalTime;
}
// suppression mail from FSM.
queueEvent = queueSuppressTimeAdjust.get(1);
if (queueEvent.status == osEventMessage)
{
dSuppress = (int) queueEvent.value.p;
}
queueEvent = queueModTotalTime.get(1); // get message.
if (queueEvent.status == osEventMessage)
{
dMessage = (int) queueEvent.value.p; // interpret as integer, not pointer.
if (!dSuppress) // increment total time.
if (dMessage == MSG_INC_TIME) dTotalTime += TIMEINC;
if (!dSuppress) // decrement total time.
if (dMessage == MSG_DEC_TIME) dTotalTime -= TIMEINC;
// saturations.
if (dTotalTime > 180) dTotalTime = 180;
if (dTotalTime < 0) dTotalTime = 0;
queueSetRemainingTime.put((int *) dTotalTime,1);
giRemainingTime.dTotalTime = dTotalTime;
}
Thread::wait(THREAD_3_WAITmS); // multitasking.
} // thread loop.
} // threadTotalTimeControl.
/*----------------------------------------------//----------------------------*/
void threadCookStateFSM(void const *args) // cook-cycle FSM.
{
int dFSMstate = FSM_IDLE; // state of this FSM.
int dFSMstateLast = FSM_IDLE; // previous FSM state.
int dButtonState = 0; // received button state.
int dRemainingTime = 0; // received remaining time.
int dButtonStart = 0; // received button state.
int dButtonStop = 0; // received button state.
int dDoorOpen = 0; // received door state.
osEvent queueEvent; // from button state manager.
beepTimer.start(); // run the beep timer.
// constantly read live temperature.
queueTemperatureControl.put((int *) TEMP_READ,1);
while(1) // thread loop.
{
switch (dFSMstate) // cook-mode state machine.
{
//---
case FSM_IDLE : // IDLE.
{
giRemainingTime.cMagnetron = 0; // highest priority.
giRemainingTime.cCarousel = 0; // turn on carousel.
if (dFSMstate != dFSMstateLast) // if just entered state.
{
// live read of temperature,
// allow total time adjustments,
// clear total time.
queueTemperatureControl.put((int *) TEMP_READ,1);
queueSuppressTimeAdjust.put((int*) 0,1);
queueClearTotalTime.put ((int*) 1,1);
}
// set global LCD data.
giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
giLCD.dRemainingTime = 0; // suppress remaining time display.
// remaining time loaded with total time.
giRemainingTime.cControl = RT_PRELOAD;
dFSMstateLast = dFSMstate; // determine next state.
// to FSM_COOK if the start button was
// pressed, the door is closed, and the
// remaining time is more than zero.
if ((dButtonStart == 1) && (dDoorOpen == 0) && (giRemainingTime.dTotalTime > 0)) dFSMstate = FSM_COOK;
break;
}
//---
case FSM_COOK : // COOK.
{
giRemainingTime.cMagnetron = 1; // highest priority.
giRemainingTime.cCarousel = 1; // turn on carousel.
if (dFSMstate != dFSMstateLast) // if just entered state.
{
// start decrementing remaining time.
// temperature synthesizer is now
// calculating the temperature,
// user can no longer adjust total time.
giRemainingTime.cControl = RT_DECREMENT;
queueTemperatureControl.put((int *) TEMP_CALC,1);
queueSuppressTimeAdjust.put((int*) 1,1);
}
// update global LCD data.
giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
giLCD.dRemainingTime = giRemainingTime.dRemainingTime;
dFSMstateLast = dFSMstate; // determine next state.
// pause on door-open if remaining time.
if ((dDoorOpen == 1) && (dRemainingTime > 0)) dFSMstate = FSM_PAUSE;
else
// stop button -> idle state.
if (dButtonStop) dFSMstate = FSM_IDLE;
else
// beeper state once countdown complete.
if (dRemainingTime <= 0) dFSMstate = FSM_DONE;
break;
}
//---
case FSM_PAUSE : // PAUSE.
{
giRemainingTime.cMagnetron = 0; // highest priority.
giRemainingTime.cCarousel = 0; // turn on carousel.
if (dFSMstate != dFSMstateLast) // if just entered state.
{
// suspend synthesized temperature calculation.
queueTemperatureControl.put((int *) TEMP_FREEZE,1);
}
// update LCD globals.
giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
giLCD.dRemainingTime = giRemainingTime.dRemainingTime;
giRemainingTime.cControl = RT_PAUSE;// pause remaining time countdown.
dFSMstateLast = dFSMstate; // determine next state.
// continue if user hits start button,
// and the door is closed, and there
// is some remaining time.
if ((dButtonStart == 1) && (dDoorOpen == 0) && (giRemainingTime.dTotalTime > 0)) dFSMstate = FSM_CONTINUE;
else
// to idle if user hits stop button.
if (dButtonStop) dFSMstate = FSM_IDLE;
break;
}
//---
case FSM_CONTINUE : // CONTINUE.
{
giRemainingTime.cMagnetron = 1; // highest priority.
giRemainingTime.cCarousel = 1; // turn on carousel.
if (dFSMstate != dFSMstateLast) // if just entered state.
{
// continue calculating synthetic temperature.
queueTemperatureControl.put((int *) TEMP_CALC,1);
}
// update LCD globals.
giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
giLCD.dRemainingTime = giRemainingTime.dRemainingTime;
// continue decrementing time.
giRemainingTime.cControl = RT_DECREMENT;
dFSMstateLast = dFSMstate; // determine next state.
// beep state when no more time.
if (dRemainingTime <= 0) dFSMstate = FSM_DONE;
else
// user stop causes jump to idle.
if (dButtonStop) dFSMstate = FSM_IDLE;
else
// back to pause if door open,
// and there's remaining time.
if ((dDoorOpen == 1) && (dRemainingTime > 0)) dFSMstate = FSM_PAUSE;
break;
}
//---
case FSM_DONE : // DONE.
{
giRemainingTime.cMagnetron = 0; // highest priority.
giRemainingTime.cCarousel = 0; // turn on carousel.
if (dFSMstate != dFSMstateLast) // if just entered state.
{
// freeze synthetic temperature.
queueTemperatureControl.put((int *) TEMP_FREEZE,1);
giRemainingTime.cBeepEnable = 1; // initiate beep.
beepTimer.reset(); // clear the beep timer.
}
// update LCD globals.
giLCD.dTotalCookTime = giRemainingTime.dTotalTime;
giLCD.dRemainingTime = giRemainingTime.dRemainingTime;
giRemainingTime.cControl = RT_CLEAR;// clear remaining time. (needed?)
dFSMstateLast = dFSMstate; // determine next state.
// to idle once beeper is done.
if (beepTimer.read() >= BEEPTIME) {dFSMstate = FSM_IDLE; giRemainingTime.cBeepEnable = 0;}
else dFSMstate = FSM_DONE; // (else stay here).
break;
}
//---
default : {dFSMstate = FSM_IDLE; break;}
}
queueEvent = queueUpdateFSM.get(1); // threadButtonStateManager
if (queueEvent.status == osEventMessage)// update state variable.
{
// interpret as integer, not pointer.
dButtonState = (int) queueEvent.value.p;
if (dButtonState == MSG_START)
{
dButtonStart = 1; // copy-in start info.
dButtonStop = 0;
if (dDoorOpen) dButtonStart = 0; // cancel start if door open.
}
if (dButtonState == MSG_STOP)
{
dButtonStart = 0; // copy-in stop state.
dButtonStop = 1;
queueClearTotalTime.put((int*) 1,1);// clear total time on stop.
}
if (dButtonState == MSG_OPEN) // if the door opens, clear current 'start' state.
{
dDoorOpen = 1;
dButtonStart = 0;
}
if (dButtonState == MSG_CLOSED) // detect door closed.
{
dDoorOpen = 0;
}
}
else // no queue update available.
{
dButtonStart = 0;
dButtonStop = 0;
}
// fetch from global scope.
dRemainingTime = giRemainingTime.dRemainingTime;
Thread::wait(THREAD_5_WAITmS); // multitasking.
} // thread loop.
} // threadCookStateFSM.
/*----------------------------------------------//----------------------------*/
void initialization(void) // program initializations.
{
led1 = 0;
giButtons.cDoorOpen = 0; // initialize with door closed.
giRemainingTime.cBeepEnable =0;
giRemainingTime.cMagnetron = 0;
giRemainingTime.cCarousel = 0;
}
/*----------------------------------------------//----------------------------*/
void ISRleftButtonRising(void) // cooktime plus 60s.
{
if (debounceTimer.read_ms() > DEBOUNCEmS)
giButtons.cLeftButton = 1; // detect left button.
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
void ISRleftButtonFalling(void) // button-release debounce.
{
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
void ISRrightButtonRising(void) // cooktime -60s.
{
if (debounceTimer.read_ms() > DEBOUNCEmS)
giButtons.cRightButton = 1; // detect right button.
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
void ISRrightButtonFalling(void) // button-release debounce.
{
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
void ISRtopButtonRising(void) // cook start.
{
if (debounceTimer.read_ms() > DEBOUNCEmS)
giButtons.cTopButton = 1; // detect top button.
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
void ISRtopButtonFalling(void) // button-release debounce.
{
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
// front-end control of magnetron off.
// due to physical danger, the magnetron is turned off immediately
// upon off-button press, in the interrupt that it generates.
void ISRbottomButtonRising(void) // cook stop.
{
if (debounceTimer.read_ms() > DEBOUNCEmS)
{
led0 = 0; // magnetron off.
giButtons.cBottomButton = 1; // detect bottom button.
}
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
void ISRbottomButtonFalling(void) // button-release debounce.
{
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
// front-end control of magnetron off.
// due to physical danger, the magnetron is turned off immediately
// upon detection of an open door.
void ISRcenterButtonRising(void) // toggle door state.
{
if (debounceTimer.read_ms() > DEBOUNCEmS)
{
if (giButtons.cDoorOpen == MSG_OPEN) // calculate door state.
giButtons.cDoorOpen = MSG_CLOSED;
else
giButtons.cDoorOpen = MSG_OPEN;
// magnetron off.
if (giButtons.cDoorOpen == MSG_OPEN) led0 = 0;
giButtons.cCenterButton = 1;
}
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
void ISRcenterButtonFalling(void) // button-release debounce.
{
debounceTimer.reset(); // begin debounce period.
}
/*----------------------------------------------//----------------------------*/
// this will measure live temperature, or calculate it to be
// increasing at 1/6 degree per second, or freeze it.
void temperatureThread(void const *args) // temperature measurement.
{
int dTempControl = 0; // temperature control.
float fLastMeasuredTemperature = 0.0; // last physically-measured temperature.
float fCelsius; // synthetic temperature.
osEvent queueEvent; // from button state manager.
while(1) // thread loop.
{
// obtain temperature command.
queueEvent = queueTemperatureControl.get(1);
if (queueEvent.status == osEventMessage)
{
dTempControl = (int) queueEvent.value.p;
}
if (dTempControl == TEMP_READ)
{
fCelsius = temperature.read(); // physical measurement.
fLastMeasuredTemperature = fCelsius;
}
if (dTempControl == TEMP_CALC) // calculate synthetic temperature.
fCelsius = ((float) (giRemainingTime.dTotalTime - giRemainingTime.dRemainingTime) /
(float) 6.0) + fLastMeasuredTemperature;
giLCD.fCelsius = fCelsius; // to global scope for LCD.
Thread::wait(THREAD_1_WAITmS); // multitasking.
} // thread loop.
} // temperatureThread.
/*----------------------------------------------//----------------------------*/
void LCDthread(void const *args) // LCD display thread.
{
static int dLCDtotalCookTimeSec = 0; // sample current values.
static int dCookTimeRemainingSec = 0;
static float fLCDcelsius = 0.0;
// remember previous values.
static int dLCDtotalCookTimeSecLast = 0;
static int dCookTimeRemainingSecLast = 0;
static float fLCDcelsiusLast = 0.0;
while(1) // thread loop.
{
// don't allow the values to
// change in the middle of the
// below else the anti-blink
// code won't work.
dLCDtotalCookTimeSec = giLCD.dTotalCookTime;
dCookTimeRemainingSec = giLCD.dRemainingTime;
fLCDcelsius = giLCD.fCelsius;
// clear display only when
// necessary, in order to avoid
// 'blinkieness'.
if (dLCDtotalCookTimeSec != dLCDtotalCookTimeSecLast ||
dCookTimeRemainingSec != dCookTimeRemainingSecLast ||
fLCDcelsius != fLCDcelsiusLast)
lcd.cls();
LCD1; // line 1.
lcd.printf(" total cook time: %d",dLCDtotalCookTimeSec);
LCD2; // line 2.
lcd.printf(" remaing cook time: %d",dCookTimeRemainingSec);
LCD3; // line 3.
lcd.printf(" temperature : %5.3f",fLCDcelsius);
// pipeline variables.
dLCDtotalCookTimeSecLast = dLCDtotalCookTimeSec;
dCookTimeRemainingSecLast = dCookTimeRemainingSec;
fLCDcelsiusLast = fLCDcelsius;
Thread::wait(THREAD_2_WAITmS); // multitasking.
} // thread loop.
} // LCDthread.
/*----------------------------------------------//----------------------------*/
// cook remaining time countdown counter.
// possibly due to a bug in Ticker
// http://mbed.org/questions/1563/Mbed-Tickerfunction-hangs-system-from-re/
// I've been unable to detach/attach this routine in order to reset its phase
// when I tried it at a 1s resolution. In order to provide the human perception
// of an immediate restart, I've increased the ticker frequency by the factor
// 'GRANULARITY' and likewise divide that factor out when this routine
// promotes the remaining time to the global variable.
// communication is via a global instance of struct tRemainingTime.
void tickCookRemainingTime(void) // cook-cycle countdown.
{
static int dRemainingTime = 0; // remaining time in seconds.
int dMaximum; // MAXSECONDS * GRANULARITY.
dMaximum = MAXSECONDS * GRANULARITY; // precalculate.
switch (giRemainingTime.cControl) // control processing.
{
case RT_PRELOAD : // preload with total time.
{
// the 'GRANULARITY - 1' factor
// compensates for integer division
// dropping the right-of-decimal result,
// that occuring at the bottom of this
// routine.
dRemainingTime = (giRemainingTime.dTotalTime * GRANULARITY) + (GRANULARITY - 1);
break;
}
case RT_DECREMENT : // count-down.
{
dRemainingTime--;
break;
}
case RT_PAUSE : // suspend countdown.
{
dRemainingTime = dRemainingTime;
break;
}
case RT_CLEAR : // clear countdown.
{
dRemainingTime = 0;
break;
}
default : // saturate, just in case.
{
}
} // control processing.
// saturate value.
if (dRemainingTime > dMaximum) dRemainingTime = dMaximum;
if (dRemainingTime < 0) dRemainingTime = 0;
// promote to global scope.
giRemainingTime.dRemainingTime = dRemainingTime/GRANULARITY;
} // cookRemainingTime.
/*----------------------------------------------//----------------------------*/
void tickerBeeper(void) // beep when giRemainingTime.
{
static char cState = 0;
if (giRemainingTime.cBeepEnable)
{
if (cState) {speaker = 1; cState = 0;}
else {speaker = 0; cState = 1;}
}
}
/*----------------------------------------------//----------------------------*/
void tickerMagnetron(void) // magnetron enunciator.
{
if (giRemainingTime.cMagnetron) led0 = !led0;
else led0 = 0;
}
/*----------------------------------------------//----------------------------*/
void tickerCarousel(void) // carousel enunciator.
{
if (giRemainingTime.cCarousel) led1 = !led1;
else led1 = 0;
}
/*----------------------------------------------//----------------------------*/