A simple microwave demo
Dependencies: C12832_lcd LM75B mbed-rtos mbed
Revision 4:cd87e2050344, committed 2014-04-04
- Comitter:
- joeroop
- Date:
- Fri Apr 04 02:16:32 2014 +0000
- Parent:
- 3:4fb0721ce794
- Commit message:
- for first publish no changes
Changed in this revision
rtos_hwk7.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/rtos_hwk7.cpp Sun Mar 16 02:18:48 2014 +0000 +++ b/rtos_hwk7.cpp Fri Apr 04 02:16:32 2014 +0000 @@ -1,4 +1,23 @@ +/* +Assignment: Hwk 7_1 +Due: 3/18/14 +Objective: + Finish lab #7. The purpose of this program is to use the RTOS along with + Interprocess comunication (IPC). In this program the IPC method utilizes + a MemoryPool and a Queue for a messaging system. Anytime a new message comes + through the LCD is updated. A union is used to reduce the size of the message + data structure. The prgram simulates a microwave with a requirement of having + the system shutdown within 1ms. There are no globals that are written to by the + threads this reduces the need for mutexes. All communcation is done by signals + and IPC in order to reduce global variables. + + Additions are LED4 light for door open and display the STATE (WAIT, COOK) on the lcd. + +Test Condition Pass/Fail Criteria Result +--------------------- --------------------------------------- --------- +See attached sheet +*/ #include "mbed.h" @@ -6,14 +25,23 @@ #include "C12832_lcd.h" //LCD interface #include "LM75B.h" //temperature interface +#ifndef DEBUG + //#define DEBUG +#endif /* DEBUG */ + #define DEBOUNCE_TIME_MS 10 #define MAX_COOK_TIME_S 20 //3min +#define MIN_COOK_TIME_S 1 #define INIT_COOK_TIME_S 5 #define TEMP_INTERVAL_S 5 +#define TEMP_INCREASE_F 10 //globals and types +#ifdef DEBUG + Timer test_timer; //used to instrument the code +#endif DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); @@ -21,59 +49,54 @@ C12832_LCD lcd; PwmOut spkr(p26); LM75B therm(p28,p27); +Mutex lcd_mutex; //don't really need this but just to be safe Timer debounceTimer; InterruptIn irptTimeDn(p16); //cook down InterruptIn irptTimeUp(p13); //cook up InterruptIn irptStart(p15); //start cooking InterruptIn irptStop(p12); //stop cooking InterruptIn irptDoor(p14); //door interrupt -Thread *proxy_lcd; +Thread *proxy_lcd; //pointers to the threads used for signalling Thread *proxy_temp; Thread *proxy_sound; Thread *proxy_state; Thread *proxy_led; Thread *proxy_timer; - typedef enum { //start at one as we are using this as signals //states - WAITING = 1, - COOKING, - DONE, + WAITING = 1, //everything is ready for cooking, you can change the request time etc + COOKING, + DONE, //signal for threads to buzz, trurn off lights etc //interrupts signals TIMEUP, TIMEDN, START, STOP, DOOR -} state_t; +} state_t; //this is for signaling of threads with proxies char *stateStr[] = {"NULL","WAIT","COOK","DONE"}; -typedef enum {TEMP_VAL, TIME_ELPS, TIME_RQST} type_t; -typedef enum {STATE, TEMP, SOUND, LCD, LED, TIMER, ALL} thread_t; -char *threadStr[] = {"STATE", "TEMP", "SOUND", "LCD", "LED", "TIMER", "ALL"}; +typedef enum {TEMP_VAL, TIME_ELPS, TIME_RQST} data_t; //message data types typedef struct { state_t state; - type_t type; + data_t type; union { - float temp; + float temp; int time_elapsed; //seconds of cooking int time_request; //seconds } data; -} message_t; - - - +} message_t; //used to pass messages to the lcd thread MemoryPool<message_t,10> mpool; //used to hold all messages -Queue<message_t,10> queue; //used to hold the messages +Queue<message_t,10> queue; bool debounce(void); -void blink_led(void const *args); -void send_time(void const *args); +void blink_led(void const *args); //helper function to led thread +void send_time(void const *args); //helper function to timer thread //Threads void thread_state(void const *args); @@ -83,8 +106,6 @@ void thread_led(void const *args); void thread_timer(void const *args); - - //ISRs void isrTimeUp(void); void isrTimeDn(void); @@ -92,17 +113,16 @@ void isrStop(void); void isrDoor(void); - - int main(void){ debounceTimer.start(); - //interrupts + //interrupts debounce everything except for the door irptTimeUp.rise(&isrTimeUp); irptTimeDn.rise(&isrTimeDn); irptStart.rise(&isrStart); irptStop.rise(&isrStop); - irptDoor.rise(&isrDoor); //debounce everything except for the door - + irptDoor.rise(&isrDoor); + + //init the threads Thread t1(thread_state); Thread t2(thread_temp); Thread t3(thread_sound); @@ -110,16 +130,14 @@ Thread t5(thread_led); Thread t6(thread_timer); - proxy_state = &t1; - proxy_temp = &t2; - proxy_sound = &t3; - proxy_lcd = &t4; - proxy_led = &t5; - proxy_timer = &t6; + proxy_state = &t1; + proxy_temp = &t2; + proxy_sound = &t3; + proxy_lcd = &t4; + proxy_led = &t5; + proxy_timer = &t6; - - - //t1.set_priority(osPriorityRealtime); + t1.set_priority(osPriorityRealtime); //state machine most important thread proxy_state->signal_set(WAITING); //initialize all the threads while(1){ @@ -159,10 +177,15 @@ } void isrDoor(void){ //no debounce this is most important function! +#ifdef DEBUG + test_timer.start(); +#endif proxy_state->signal_set(DOOR); } -//State thread to do most of the main state machine logic +/* +* State thread to do most of the main state machine logic this is where control happens +*/ void thread_state(void const *args){ osEvent evt; int32_t mask; @@ -172,14 +195,14 @@ evt = Thread::signal_wait(0); mask = evt.value.signals; switch(mask){ - case WAITING: + case WAITING: //come from DONE to here state = WAITING; proxy_led->signal_set(state); proxy_timer->signal_set(state); proxy_temp->signal_set(state); break; case COOKING: - if(!openDoor){ //can't cook if door is open + if(!openDoor && state == WAITING){ //can't cook if door is open state = COOKING; proxy_led->signal_set(state); proxy_timer->signal_set(state); @@ -188,12 +211,14 @@ break; case DONE: //timer can signal this state = DONE; - //tell everyone we are done + //tell everyone we are done so they can buzz, dispaly and stop blinking proxy_led->signal_set(state); proxy_timer->signal_set(state); proxy_temp->signal_set(state); - - proxy_state->signal_set(WAITING); //goto waiting +#ifdef DEBUG + //test_timer.stop(); // ~21 us to here from interrupt +#endif + proxy_state->signal_set(WAITING); //goto WAITING break; case TIMEUP: //change the timer up if(state == WAITING) proxy_timer->signal_set(TIMEUP); @@ -202,38 +227,42 @@ if(state == WAITING) proxy_timer->signal_set(TIMEDN); break; case START: - if(state == WAITING) proxy_state->signal_set(COOKING); // + proxy_state->signal_set(COOKING); break; case STOP: - if(state == COOKING) proxy_state->signal_set(state); + proxy_state->signal_set(DONE); break; case DOOR: //door changed state openDoor = !openDoor; state = (openDoor == true) ? DONE : WAITING; //open door then done else state back to waiting - led4 = openDoor; + led4 = openDoor; //visual for when door is open proxy_state->signal_set(state); //signal back to state thread break; } } } -//helper function for the timer thread +/* +* Helper function for the timer thread gets called at 1sec intervals +*/ void send_time(void const *args){ int time = (*((int*)args))--; //have the time in seconds send to lcd now state_t state = COOKING; - if(time == 0){ + if(time == 0){ //time is up signal state machine to done state = DONE; - proxy_state->signal_set(state); //tell all threads cooking time up - proxy_sound->signal_set(state); + proxy_state->signal_set(state); //tell threads cooking time up + proxy_sound->signal_set(state); } proxy_temp->signal_set(state); //use this timer to schedule temperature read - message_t *msg = mpool.alloc(); //allocate a new message + message_t *msg = mpool.alloc(); //allocate a new message lcd is recipient msg->state = state; msg->type = TIME_ELPS; msg->data.time_elapsed = time; queue.put(msg); } - +/* +* Timer thread to keep track of all the time requirements for temp reading and elapsed time +*/ void thread_timer(void const *args){ int time_set, time; time_set = INIT_COOK_TIME_S; @@ -250,73 +279,85 @@ state = WAITING; break; case COOKING: - if(state != COOKING){ //protect agains multiple start pushed if already cooking - timer.stop(); - state = COOKING; - time = time_set; - timer.start(1000); //this is the increments of the timer 1s - } + state = COOKING; + timer.stop(); //stop the timer + time = time_set; + send_time(ptime); //initialize the elpased time + timer.start(1000); //this is the increments of the timer 1s using RtosTimer break; case DONE: - if(state != DONE){ - state = DONE; - time = INIT_COOK_TIME_S; - timer.stop(); - } + state = DONE; + time = INIT_COOK_TIME_S; + //if(time > 0) time_set = time; + //else time = INIT_COOK_TIME_S; + timer.stop(); break; case TIMEUP: - if(state == WAITING){ - time_set = (++time_set) > MAX_COOK_TIME_S ? MAX_COOK_TIME_S : time_set; //check limits - } + time_set = (++time_set) > MAX_COOK_TIME_S ? MAX_COOK_TIME_S : time_set; //check limits break; case TIMEDN: - if(state == WAITING) - time_set = (--time_set) < 1 ? 1 : time_set; //check limits + time_set = (--time_set) < MIN_COOK_TIME_S ? MIN_COOK_TIME_S : time_set; //check limits break; } if(sig){ - message_t *msg = mpool.alloc(); //allocate a new message - msg->state = state; - msg->type = TIME_RQST; - msg->data.time_request = time_set; - queue.put(msg); + message_t *msg = mpool.alloc(); //allocate a new message to the lcd + if(msg != NULL){ + msg->state = state; + msg->type = TIME_RQST; + msg->data.time_request = time_set; + queue.put(msg); + } } } } -//Threads +/* +* LCD thread used to receive data from several other threads in the form of a message queue +*/ void thread_lcd(void const *args){ osEvent evt; - int32_t sig; - state_t state; - int time_set = 0; + int time_set = 0; //used to calculate the elapsed time lcd.cls(); while(1){ - evt = queue.get(10); //wait for data message to post + evt = queue.get(osWaitForever); //wait for data message to post if(evt.status == osEventMessage){ - message_t *msg = (message_t*)evt.value.p; - lcd.locate(70,0); - if(msg->state) + message_t *msg = (message_t*)evt.value.p; //get the message + lcd_mutex.lock(); //dont really need this as this is the only thread that uses the lcd + + if(msg->state){ +#ifdef DEBUG + if(msg->state == DONE){ + test_timer.stop(); //~75 us, if move print ahead it is 3145 us! printing takes a while + lcd.locate(70,20); + lcd.printf("%dus",test_timer.read_us()); + test_timer.reset(); + } +#endif + lcd.locate(70,0); lcd.printf("State: %s ",stateStr[msg->state]); + } switch(msg->type){ case TIME_RQST: time_set = msg->data.time_request; lcd.locate(0,0); - lcd.printf("Request: %3d ",time_set); + lcd.printf("Request: %3ds ",time_set); //requested time break; case TIME_ELPS: lcd.locate(0,10); - lcd.printf("Elapsed: %3d ",time_set - msg->data.time_elapsed); + lcd.printf("Elapsed: %3ds ",time_set - msg->data.time_elapsed); //elapesed time break; case TEMP_VAL: lcd.locate(0,20); - lcd.printf("Temp: %-3.2f ",msg->data.temp); + lcd.printf("Temp: %-3.2fF ",msg->data.temp); //current cooking temp updated at different intervals break; } - mpool.free(msg); + lcd_mutex.unlock(); //free the mutex + mpool.free(msg); //free the message } } } - +/* +* Thread function to send the lcd the temp recieves timing from timer thread +*/ void thread_temp(void const *args){ osEvent evt; int32_t sig; @@ -327,8 +368,8 @@ sig = evt.value.signals; switch(sig){ case COOKING: - if(!(seconds++ % TEMP_INTERVAL_S)){ - temp+= 10.0; + if(!(seconds++ % TEMP_INTERVAL_S)){ //increase the temp if meets the interval + temp+= TEMP_INCREASE_F; }else{ sig = 0x0; //set to zero so don't print since no changes } @@ -341,13 +382,18 @@ } if(sig){ message_t *msg = mpool.alloc(); //allocate a new message - msg->state = (state_t)0; //don't pass a value - msg->type = TEMP_VAL; - msg->data.temp = seconds > 0 ? temp+9.0/5.0*therm.read()+32.0 : 0.0; - queue.put(msg); + if(msg != NULL){ + msg->state = (state_t)0; //don't pass a value + msg->type = TEMP_VAL; + msg->data.temp = seconds > 0 ? temp+9.0/5.0*therm.read()+32.0 : 0.0; + queue.put(msg); + } } } } +/* +* Simple sound thread using pwm to buzz when cooking timer is finished +*/ void thread_sound(void const *args){ osEvent evt; int32_t sig; @@ -364,17 +410,20 @@ } } } -//helper function to thread_led used to blink led +/* +* Helper function to thread_led used to blink led +*/ void blink_led(void const *args){ led1 = !led1; } -//Thread led to blink the light when cooking and stop when done +/* +* Thread led to blink the light when cooking and stop when done +*/ void thread_led(void const *args){ RtosTimer timer(blink_led, osTimerPeriodic); osEvent evt; int32_t sig; while(1){ - //may need to sleep somewhere to give up thread check to see if signal_wait equiv of wait evt = Thread::signal_wait(0); //will time out then loop not needed sig = evt.value.signals; switch(sig){ @@ -385,9 +434,6 @@ timer.stop(); led1 = 0; break; - default: - //Thread::wait(2000); if wait can miss signal - break; } } }