
A simple microwave demo
Dependencies: C12832_lcd LM75B mbed-rtos mbed
rtos_hwk7.cpp
- Committer:
- joeroop
- Date:
- 2014-03-16
- Revision:
- 2:324dc8b89365
- Parent:
- 1:896789dcc911
- Child:
- 3:4fb0721ce794
File content as of revision 2:324dc8b89365:
#include "mbed.h" #include "rtos.h" #include "C12832_lcd.h" //LCD interface #include "LM75B.h" //temperature interface #define DEBOUNCE_TIME_MS 10 #define MAX_COOK_TIME_S 20 //3min #define INIT_COOK_TIME_S 5 #define TEMP_INTERVAL_S 5 //globals and types DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); C12832_LCD lcd; PwmOut spkr(p26); LM75B therm(p28,p27); 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_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, //interrupts signals TIMEUP, TIMEDN, START, STOP, DOOR } state_t; 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 struct { state_t state; type_t type; union { float temp; int time_elapsed; //seconds of cooking int time_request; //seconds } data; } message_t; MemoryPool<message_t,10> mpool; //used to hold all messages Queue<message_t,10> queue; //used to hold the messages bool debounce(void); void blink_led(void const *args); void send_time(void const *args); //Threads void thread_state(void const *args); void thread_lcd(void const *args); void thread_temp(void const *args); void thread_sound(void const *args); void thread_led(void const *args); void thread_timer(void const *args); //ISRs void isrTimeUp(void); void isrTimeDn(void); void isrStart(void); void isrStop(void); void isrDoor(void); int main(void){ debounceTimer.start(); //interrupts irptTimeUp.rise(&isrTimeUp); irptTimeDn.rise(&isrTimeDn); irptStart.rise(&isrStart); irptStop.rise(&isrStop); irptDoor.rise(&isrDoor); //debounce everything except for the door Thread t1(thread_state); Thread t2(thread_temp); Thread t3(thread_sound); Thread t4(thread_lcd); 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; t1.set_priority(osPriorityRealtime); proxy_state->signal_set(WAITING); //initialize all the threads while(1){ Thread::wait(250); } } //function for a global debounce on the isrstick bool debounce(void){ if(debounceTimer.read_ms() > DEBOUNCE_TIME_MS){ debounceTimer.reset(); return true; }else{ return false; } } //ISRs void isrTimeUp(void){ if(debounce()){ proxy_state->signal_set(TIMEUP); //left } } void isrTimeDn(void){ if(debounce()){ proxy_state->signal_set(TIMEDN); //right } } void isrStart(void){ if(debounce()){ proxy_state->signal_set(START); //up } } void isrStop(void){ if(debounce()){ proxy_state->signal_set(STOP); //down } } void isrDoor(void){ //no debounce this is most important function! proxy_state->signal_set(DOOR); } //State thread to do most of the main state machine logic void thread_state(void const *args){ osEvent evt; int32_t mask; bool openDoor = false; //start with door closed state_t state = WAITING; //WAITING, COOKING, DONE while(1){ evt = Thread::signal_wait(0); mask = evt.value.signals; switch(mask){ case WAITING: 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 state = COOKING; proxy_led->signal_set(state); proxy_timer->signal_set(state); proxy_temp->signal_set(state); } break; case DONE: //timer can signal this state = DONE; //tell everyone we are done proxy_led->signal_set(state); proxy_timer->signal_set(state); proxy_temp->signal_set(state); proxy_state->signal_set(WAITING); //goto waiting break; case TIMEUP: //change the timer up if(state == WAITING) proxy_timer->signal_set(TIMEUP); break; case TIMEDN: //change the timer down if(state == WAITING) proxy_timer->signal_set(TIMEDN); break; case START: if(state == WAITING){ state = COOKING; proxy_state->signal_set(state); } break; case STOP: if(state == COOKING){ state = DONE; proxy_state->signal_set(state); } break; case DOOR: //door changed state openDoor = !openDoor; state = (openDoor == true) ? DONE : WAITING; //open door then done else state back to waiting led4 = openDoor; proxy_state->signal_set(state); //signal back to state thread break; } } } //helper function for the timer thread 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){ state = DONE; proxy_state->signal_set(state); //tell all 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 msg->state = state; msg->type = TIME_ELPS; msg->data.time_elapsed = time; queue.put(msg); } void thread_timer(void const *args){ int time_set, time; time_set = INIT_COOK_TIME_S; int *ptime = &time; RtosTimer timer(send_time, osTimerPeriodic,(void*)ptime); osEvent evt; int32_t sig; state_t state; while(1){ evt = Thread::signal_wait(0); //will time out then loop not needed sig = evt.value.signals; switch(sig){ case WAITING: 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 } break; case DONE: if(state != DONE){ state = DONE; 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 } break; case TIMEDN: if(state == WAITING) time_set = (--time_set) < 1 ? 1 : 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); } } } //Threads void thread_lcd(void const *args){ osEvent evt; int32_t sig; state_t state; int time_set = 0; lcd.cls(); while(1){ evt = queue.get(10); //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) 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); break; case TIME_ELPS: lcd.locate(0,10); lcd.printf("Elapsed: %3d ",time_set - msg->data.time_elapsed); break; case TEMP_VAL: lcd.locate(0,20); lcd.printf("Temp: %-3.2f ",msg->data.temp); break; } mpool.free(msg); } } } void thread_temp(void const *args){ osEvent evt; int32_t sig; int seconds = -1; float temp = 0.0; while(1){ evt = Thread::signal_wait(0); sig = evt.value.signals; switch(sig){ case COOKING: if(!(seconds++ % TEMP_INTERVAL_S)){ temp+= 10.0; }else{ sig = 0x0; //set to zero so don't print since no changes } break; case WAITING: case DONE: seconds = -1; temp = 0.0; break; } 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); } } } void thread_sound(void const *args){ osEvent evt; int32_t sig; while(1){ evt = Thread::signal_wait(0); sig = evt.value.signals; switch(sig){ case DONE: spkr.period(1.0/5000); spkr=0.5; Thread::wait(1000); spkr=0.0; break; } } } //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 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){ case COOKING: timer.start(250); break; case DONE: timer.stop(); led1 = 0; break; default: //Thread::wait(2000); if wait can miss signal break; } } }