homework 7
Dependencies: mbed-rtos mbed C12832_lcd LM75B
main.cpp
- Committer:
- gatedClock
- Date:
- 2013-09-12
- Revision:
- 120:64a969984af2
- Parent:
- 119:e14b0f6e97cb
- Child:
- 121:c9d28cd59460
File content as of revision 120:64a969984af2:
/*----------------------------------------------//------------------------------ 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. global variables considerations (mutex) the global variables associated with joystick button presses are in the structure 'tButtons' (instance 'giButtons'). ISRs store that a button has been pressed in this struct, and since mutex can not be called within an interrupt, no mutex is used on these buttons. only the ISRs are 'authorized' to set those variables, and the bottom-half of the ISRs, 'threadButtonStateManager', is authorized to clear them once 'threadButtonStateManager' has forwarded the fact that the buttons were pressed. I don't expect there to be any collision of writing the variables. -----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. int dTotalTime; // initialize to this. int dRemainingTime; // the countdown value. }; struct tMagnetron // magnetron control. { char cMagnetron; // magnetron blink control. char cCarousel; // carousel blink control. }; 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. tMagnetron giMagnetron; // 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); 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); 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); giButtons.cTopButton = 0; // clear the button state. } if (giButtons.cBottomButton) // stop-cook button. { dMessage = MSG_STOP; // set message. queueUpdateFSM.put((int *) dMessage,1); giButtons.cBottomButton = 0; // clear the button state. } if (giButtons.cCenterButton) // door-state-toggle. { dMessage = giButtons.cDoorOpen; // determined in ISR. queueUpdateFSM.put((int *) dMessage,1); 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. { giMagnetron.cMagnetron = 0; // highest priority. giMagnetron.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. { giMagnetron.cMagnetron = 1; // highest priority. giMagnetron.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. { giMagnetron.cMagnetron = 0; // highest priority. giMagnetron.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. { giMagnetron.cMagnetron = 1; // highest priority. giMagnetron.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. { giMagnetron.cMagnetron = 0; // highest priority. giMagnetron.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; giMagnetron.cMagnetron = 0; giMagnetron.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 (giMagnetron.cMagnetron) led0 = !led0; else led0 = 0; } /*----------------------------------------------//----------------------------*/ void tickerCarousel(void) // carousel enunciator. { if (giMagnetron.cCarousel) led1 = !led1; else led1 = 0; } /*----------------------------------------------//----------------------------*/