homework 7
Dependencies: mbed-rtos mbed C12832_lcd LM75B
main.cpp
- Committer:
- gatedClock
- Date:
- 2013-09-12
- Revision:
- 78:7df160e0db7b
- Parent:
- 77:73e4fd83642f
- Child:
- 79:4286319e48b4
File content as of revision 78:7df160e0db7b:
/*----------------------------------------------//------------------------------ 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/ -----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 20 // 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 1 // 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 DEBUG1 // debug preprocessor control. //--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. int dTotalTime; // initialize to this. int dRemainingTime; // the countdown value. }; Queue<int, 1> queueModTotalTime; // message to modify total time. Queue<int, 1> queueUpdateFSM; // message to inform FSM. Queue<int, 1> queueUpdateRemainingTime; // message to update remaining time. Queue<int, 1> queueSetRemainingTime; // tell countdown it's start time. Queue<int, 1> queueFSMnewState; // latest FSM state. //--global_variables----------------------------//------------------------------ char gcSignalWaitEnable; // 1 to wait on a signal. char gcSlowClock; // slow-clock signal. char gcInitializePipeline; // 1 to initialize pipeline state. float gfCelsius; // from thermometer. float gfLCDcelsius; // feed into LCD. int gdLCDtotalCookTimeSec; // feed into LCD. int gdCookTimeRemainingSec; // feed into LCD. tButtons gtButtons; // ISR button updates. tRemainingTime giRemainingTime; // structure instance. int gdDiagTotalTime; //--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); 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. Ticker tickerButtonStateManager; // manage the button states. Ticker tickerSlowClock; // generate a ~1Hz clock. Ticker tickerCookCountdown; // remaining cook time. // Timer timerFSMdone; // duration of FSM 'done' state. //-------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. //==============================================//============================== int main(void) { char cLeftButtonState; // 1 means button was pressed. 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. gcInitializePipeline = 1; // tell pipeline to initialize. initialization(); // initialize variables. gcSlowClock = 0; led1 = 0; gtButtons.cDoorOpen = 0; // initialize with door closed. // timerFSMdone.start(); // start 'done' timer. tickerSlowClock.attach_us(&slowClock ,SLOWCLOCKuS); tickerCookCountdown.attach(&tickCookRemainingTime,1); Thread thread_1(temperatureThread ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); Thread thread_2(LCDthread ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); Thread thread_3(threadTotalTimeControl ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); Thread thread_4(threadButtonStateManager,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); // was osPriorityIdle Thread thread_5(threadCookStateFSM ,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); //Thread thread_4(threadButtonStateManager); // the message-receiving threads need 'else' for message-receive-timeout. while(1) { // pc.printf("\n\r gdDiagTotalTime %d",gdDiagTotalTime); Thread::wait(1000); } } /*----------------------------------------------//----------------------------*/ // 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 (gtButtons.cLeftButton) // total time increment button. { dMessage = MSG_INC_TIME; // set message. queueModTotalTime.put((int *) dMessage,1);// pretend it's a pointer. gtButtons.cLeftButton = 0; // clear the button state. // pc.printf("\n\r time increment button."); } if (gtButtons.cRightButton) // total time decrement button. { dMessage = MSG_DEC_TIME; // set message. queueModTotalTime.put((int *) dMessage,1);// pretend it's a pointer. gtButtons.cRightButton = 0; // clear the button state. // pc.printf("\n\r time decrement button."); } //--- // COOK-STATE FSM. if (gtButtons.cTopButton) // start-cook button. { dMessage = MSG_START; // set message. queueUpdateFSM.put((int *) dMessage,1); // pretend it's a pointer. gtButtons.cTopButton = 0; // clear the button state. } if (gtButtons.cBottomButton) // stop-cook button. { dMessage = MSG_STOP; // set message. queueUpdateFSM.put((int *) dMessage,1); // pretend it's a pointer. gtButtons.cBottomButton = 0; // clear the button state. } if (gtButtons.cCenterButton) // door-state-toggle. { dMessage = gtButtons.cDoorOpen; // determined in ISR. queueUpdateFSM.put((int *) dMessage,1); // pretend it's a pointer. gtButtons.cCenterButton = 0; // clear the button state. } //--- Thread::wait(THREAD_4_WAITmS); // multitasking. } // thread loop. } // threadButtonStateManager. /*----------------------------------------------//----------------------------*/ // the incoming messages are mutually-exclusive. // total time controller. void threadTotalTimeControl(void const *args) { static int dTotalTime = 0; // total time variable. int dMessage; // message. osEvent queueEvent; // queue event. int dRC; while(1) // thread loop. { queueEvent = queueModTotalTime.get(1); // get message. if (queueEvent.status == osEventMessage) { dMessage = (int) queueEvent.value.p; // interpret as integer, not pointer. // increment total time. if (dMessage == MSG_INC_TIME) dTotalTime += 60; // decrement total time. if (dMessage == MSG_DEC_TIME) dTotalTime -= 60; // saturations. if (dTotalTime > 180) dTotalTime = 180; if (dTotalTime < 0) dTotalTime = 0; dRC = queueSetRemainingTime.put((int *) dTotalTime,1); pc.printf("\n\r just queueSetRemainingTime.put %d, dRC = %d",dTotalTime,dRC); giRemainingTime.dTotalTime = dTotalTime; } gdLCDtotalCookTimeSec = dTotalTime; // transmit to LCD. // pretend it's a pointer. // queueUpdateTotalTime.put((int *) dTotalTime); Thread::wait(THREAD_3_WAITmS); // multitasking. } // thread loop. } // threadTotalTimeControl. /*----------------------------------------------//----------------------------*/ /* #define FSM_IDLE 0x00 // cook-state state-machine. #define FSM_COOK 0x01 // cook-state state-machine. #define FSM_PAUSE 0x02 // cook-state state-machine. #define FSM_DONE 0x04 // cook-state state-machine. #define MSG_START 0x04 #define MSG_STOP 0x08 #define MSG_OPEN 0x10 #define MSG_CLOSED 0x20 */ void threadCookStateFSM(void const *args) // cook-cycle FSM. { static int dFSMstate = FSM_IDLE; // state of this FSM. static int dFSMstateLast = FSM_IDLE; // previous FSM state. static int dButtonState; // received button state. static int dRemainingTime = 0; // received remaining time. static int dButtonStart = 0; static int dButtonStop = 0; static int dDoorOpen = 0; static char cAttached = 0; // track ticker attachment. osEvent queueEvent; // queue event. /* struct tRemainingTime // remaining time related. { char cControl; // countdown control. int dTotalTime; // initialize to this. int dRemainingTime; // the countdown value. } giRemainingTime. #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. */ while(1) // thread loop. { //pc.printf("\n\rFSM state, stateLast: %d %d- start, open, remaining, total %d %d %d %d",dFSMstate,dFSMstateLast,dButtonStart,dDoorOpen,dRemainingTime,giRemainingTime.dTotalTime); switch (dFSMstate) // cook-mode state machine. { case FSM_IDLE : // IDLE. { if (dFSMstate != dFSMstateLast) // if just entered state. { // giRemainingTime.cControl = RT_CLEAR; // tickCookRemainingTime(); } giRemainingTime.cControl = RT_PRELOAD; dFSMstateLast = dFSMstate; // determine next state. if ((dButtonStart == 1) && (dDoorOpen == 0) && (giRemainingTime.dTotalTime > 0)) dFSMstate = FSM_COOK; break; } case FSM_COOK : // COOK. { if (dFSMstate != dFSMstateLast) // if just entered state. { led3 = 1; // giRemainingTime.cControl = RT_PRELOAD; // questionable section. // tickCookRemainingTime(); giRemainingTime.cControl = RT_DECREMENT; } dFSMstateLast = dFSMstate; // determine next state. if ((dDoorOpen == 1) && (dRemainingTime > 0)) dFSMstate = FSM_PAUSE; else if (dButtonStop) dFSMstate = FSM_IDLE; else if (dRemainingTime <= 0) dFSMstate = FSM_DONE; break; } case FSM_PAUSE : // PAUSE. { if (dFSMstate != dFSMstateLast) // if just entered state. { } giRemainingTime.cControl = RT_PAUSE; // determine next state. dFSMstateLast = dFSMstate; if ((dButtonStart == 1) && (dDoorOpen == 0) && (giRemainingTime.dTotalTime > 0)) dFSMstate = FSM_CONTINUE; else if (dButtonStop) dFSMstate = FSM_IDLE; break; } case FSM_CONTINUE : // continue { if (dFSMstate != dFSMstateLast) // if just entered state. { } giRemainingTime.cControl = RT_DECREMENT; // determine next state. dFSMstateLast = dFSMstate; if (dRemainingTime <= 0) dFSMstate = FSM_DONE; else if (dButtonStop) dFSMstate = FSM_IDLE; break; } case FSM_DONE : // DONE. { if (dFSMstate != dFSMstateLast) // if just entered state. { } giRemainingTime.cControl = RT_CLEAR; // determine next state. dFSMstateLast = dFSMstate; dFSMstate = FSM_IDLE; 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) { // pc.printf("\n\r message start."); dButtonStart = 1; dButtonStop = 0; } if (dButtonState == MSG_STOP) { // pc.printf("\n\r message stop."); dButtonStart = 0; dButtonStop = 1; } if (dButtonState == MSG_OPEN) { // pc.printf("\n\r message open."); dDoorOpen = 1; } if (dButtonState == MSG_CLOSED) { // pc.printf("\n\r message closed."); dDoorOpen = 0; } } // fetch from global scope. dRemainingTime = giRemainingTime.dRemainingTime; // pipeline variable. Thread::wait(THREAD_5_WAITmS); // multitasking. } // thread loop. } // threadCookStateFSM. /*----------------------------------------------//----------------------------*/ void slowClock(void) // 1Hz or thereabouts. { gcSlowClock = !gcSlowClock; // toggle clock. } /*----------------------------------------------//----------------------------*/ void initialization(void) // program initializations. { gcSignalWaitEnable = 1; } /*----------------------------------------------//----------------------------*/ void ISRleftButtonRising(void) // cooktime plus 60s. { if (debounceTimer.read_ms() > DEBOUNCEmS) gtButtons.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) gtButtons.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) gtButtons.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. gtButtons.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 (gtButtons.cDoorOpen == MSG_OPEN) // calculate door state. gtButtons.cDoorOpen = MSG_CLOSED; else gtButtons.cDoorOpen = MSG_OPEN; // magnetron off. if (gtButtons.cDoorOpen == MSG_OPEN) led0 = 0; gtButtons.cCenterButton = 1; } debounceTimer.reset(); // begin debounce period. } /*----------------------------------------------//----------------------------*/ void ISRcenterButtonFalling(void) // button-release debounce. { debounceTimer.reset(); // begin debounce period. } /*----------------------------------------------//----------------------------*/ void temperatureThread(void const *args) // temperature measurement. { while(1) // thread loop. { gfCelsius = temperature.read(); // physical measurement. 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 = gdLCDtotalCookTimeSec; dCookTimeRemainingSec = giRemainingTime.dRemainingTime; fLCDcelsius = gfLCDcelsius; // 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. /*----------------------------------------------//----------------------------*/ /* struct tRemainingTime // remaining time related. { char cControl; // countdown control. int dTotalTime; // initialize to this. int dRemainingTime; // the countdown value. } giRemainingTime. #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. */ void tickCookRemainingTime(void) // cook-cycle countdown. { static int dRemainingTime = 0; // remaining time in seconds. switch (giRemainingTime.cControl) // control processing. { case RT_PRELOAD : // preload with total time. { dRemainingTime = giRemainingTime.dTotalTime; if (dRemainingTime > 180) dRemainingTime = 180; if (dRemainingTime < 0) dRemainingTime = 0; break; } case RT_DECREMENT : // count-down. { dRemainingTime--; if (dRemainingTime > 180) dRemainingTime = 180; if (dRemainingTime < 0) dRemainingTime = 0; break; } case RT_PAUSE : // suspend countdown. { dRemainingTime = dRemainingTime; if (dRemainingTime > 180) dRemainingTime = 180; if (dRemainingTime < 0) dRemainingTime = 0; break; } case RT_CLEAR : // clear countdown. { dRemainingTime = 0; led3 = 1; break; } default : // saturate, just in case. { if (dRemainingTime > 180) dRemainingTime = 180; if (dRemainingTime < 0) dRemainingTime = 0; } } // control processing. // promote to global scope. giRemainingTime.dRemainingTime = dRemainingTime; } // cookRemainingTime. /*----------------------------------------------//----------------------------*/