Addition of FSM to try and set initial starting temperature for use throughout project. Additional menu option. Joystick input 'bouncing' during FSM use - to be debugged
Dependencies: mbed N5110v02 TMP102 JoystickIoT
main.cpp
- Committer:
- legstar85
- Date:
- 2022-01-20
- Revision:
- 11:a6eec09b546e
- Parent:
- 10:357b3329620f
File content as of revision 11:a6eec09b546e:
/* * @ File main.cpp * @ Author - David Leaming - 25574043 * @ Date - January 2022 * Acknowledgements * Craig A. Evans, University of Leeds, TMP102 Library ,Feb 2016 * Dr Edmond Nurellari, University of Lincoln, Joystick & N5110 Libraries */ #include "mbed.h" // include the library header, ensure the library has been imported into the project #include "TMP102.h" #include "N5110.h" #include "Joystick.h" #include "Bitmap.h" TMP102 tmp102(I2C_SDA,I2C_SCL); // Create TMP102 object // VCC,SCE,RST,D/C,MOSI,SCLK,LED N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11); // Create Screen Object - K64F - pwr from 3V3, GND Pin also needs connecting // y x button Joystick joystick(PTB10,PTB11,PTC16); // Define Joystick Object Serial pc(USBTX,USBRX); // UART connection for PC struct State { // Struct for state int output; // output value float time; // time in state int nextState[9]; // array of next states }; State fsm[11] = { {15,0.5,{0,1,0,0,0,10,0,0,0}}, // Start Temp = 15 Degrees {16,0.5,{1,2,1,1,1,0,1,1,1}}, // 1 {17,0.5,{2,3,2,2,2,1,2,2,2}}, // {18,0.5,{3,4,3,3,3,2,3,3,3}}, // {19,0.5,{4,5,4,4,4,3,4,4,4}}, // {20,0.5,{5,6,5,5,5,4,5,5,5}}, // {21,0.5,{6,7,6,6,6,5,6,6,6}}, // {22,0.5,{7,8,7,7,7,6,7,7,7}}, // {23,0.5,{8,9,8,8,8,7,8,8,8}}, // {24,0.5,{9,10,9,9,9,8,9,9,9}}, // {25,0.5,{10,1,10,10,10,9,10,10,10}} // }; Ticker ticker_menu; // Create Menu ticker object DigitalOut r_led(LED_RED); // K64F on-board LEDs DigitalOut g_led(LED_GREEN); // K64F on-board LEDs DigitalOut b_led(LED_BLUE); // K64F on-board LEDs PwmOut LED01 (PTA1); // PCB Surface Mounted LED's - LED1 PwmOut LED02 (PTA2); // PCB Surface Mounted LED's - LED2 PwmOut LED03 (PTC2); // PCB Surface Mounted LED's - LED3 PwmOut LED04 (PTC3); // PCB Surface Mounted LED's - LED4 PwmOut LED05 (PTC4); // PCB Surface Mounted LED's - LED5 PwmOut LED06 (PTD3); // PCB Surface Mounted LED's - LED6 PwmOut Buzzer (PTC10); // PCB Surface Mounted Piezo Buzzer InterruptIn sw2(SW2); // K64F on-board switches InterruptIn sw3(SW3); // K64F on-board switches InterruptIn ButtonA (PTB9); // PCB Button - A InterruptIn ButtonB (PTD0); // PCB Button - B InterruptIn ButtonBack (PTB10); // PCB Button - Back volatile int g_ButtonA_flag = 0; // flag - must be volatile as changes within ISR - g_ prefix makes it easier to distinguish it as global volatile int g_ButtonB_flag = 0; // flag - must be volatile as changes within ISR - g_ prefix makes it easier to distinguish it as global volatile int g_ButtonBack_flag = 0; // flag - must be volatile as changes within ISR - g_ prefix makes it easier to distinguish it as global volatile int g_sw2_flag = 0; // flag - must be volatile as changes within ISR - g_ prefix makes it easier to distinguish it as global volatile int g_menu_timer_flag = 0; // flag - must be volatile as changes within ISR - g_ prefix makes it easier to distinguish it as global volatile int option = 0; // Menu option selection based on joystick direction volatile int g_state = 0; // volatile int g_StartTemp = 0; // void error(); // error function hangs flashing an LED void init_serial(); // setup serial port void init_K64F(); // set-up the on-board LEDs and switches void init_PCB(); // set-up the PCB LEDs and buttons void ButtonA_isr(); // void ButtonB_isr(); // void ButtonBack_isr(); // void sw2_isr(); // void menu_timer_isr(); // void OnStartup(); // void Run(); // void ConstantMonitoring(); // void StartTemp(); // int main() { init_K64F(); // initialise the board init_serial(); // initialise the serial port init_PCB(); // initialise the PCB tmp102.init(); // call the sensor init method using dot syntax lcd.init(); // initialise display joystick.init(); // initialise joystick ticker_menu.attach(&menu_timer_isr,0.2); // Attach ticker for the Joystick sw2.fall(&sw2_isr); // SW2 has a pull-up resistor, so the pin will be at 3.3 V by default and fall to 0 V when pressed. We therefore need to look for a falling edge on the pin to fire the interrupt ButtonA.rise(&ButtonA_isr); // External push button, pin set to 0V by pull down command, means a rising edge is looked for ButtonB.rise(&ButtonB_isr); // External push button, pin set to 0V by pull down command, means a rising edge is looked for lcd.setContrast(0.5); // change set contrast in range 0.0 to 1.0 OnStartup(); // Call intro screen Run(); // Call main-menu and functions } void init_serial() { pc.baud(115200); // set to highest baud - ensure terminal software matches } void init_K64F() { r_led = 1; // on-board LEDs are active-low, so set pin high to turn them off. g_led = 1; // on-board LEDs are active-low, so set pin high to turn them off. b_led = 1; // on-board LEDs are active-low, so set pin high to turn them off. sw2.mode(PullNone); // since the on-board switches have external pull-ups, we should disable the internal pull-down sw3.mode(PullNone); // resistors that are enabled by default using InterruptIn } void init_PCB () { LED01 = 1; // PCB surface mounted LED's are active low - write a 1 to turn them off initiallly LED02 = 1; // PCB surface mounted LED's are active low - write a 1 to turn them off initiallly LED03 = 1; // PCB surface mounted LED's are active low - write a 1 to turn them off initiallly LED04 = 1; // PCB surface mounted LED's are active low - write a 1 to turn them off initiallly LED05 = 1; // PCB surface mounted LED's are active low - write a 1 to turn them off initiallly LED06 = 1; // PCB surface mounted LED's are active low - write a 1 to turn them off initiallly Buzzer = 0; // Ensure Piezo Buzzer is off ButtonA.mode(PullDown); // Set pin to Pull Down to OV, meaning that a rising edge is looked for when button is pressed ButtonB.mode(PullDown); // Set pin to Pull Down to OV, meaning that a rising edge is looked for when button is pressed } void ButtonA_isr() // ButtonA event-triggered interrupt { g_ButtonA_flag = 1; // set flag in ISR } void ButtonB_isr() // ButtonB event-triggered interrupt { g_ButtonB_flag = 1; // set flag in ISR } void ButtonBack_isr() // ButtonB event-triggered interrupt { g_ButtonBack_flag = 1; // set flag in ISR } void sw2_isr() // SW2 event-triggered interrupt { g_sw2_flag = 1; // set flag in ISR } void menu_timer_isr() { g_menu_timer_flag = 1; // set flag in ISR } void OnStartup() // Run some start up display { //Buzzer.period(1.0/659.0); // Welcome sounds from Piezo //Buzzer = 0.5; // // wait(0.5); // //Buzzer.period(1.0/494.0); // // Buzzer = 0.5; // // wait(0.5); // //Buzzer.period(1.0/554.0); // // Buzzer = 0.5; // //wait(0.5); // // Buzzer = 0; // Turn off welcome sounds lcd.clear(); // Clear buffer at start of every loop lcd.printString("--------------",0,0); // Can directly print strings at specified co-ordinates (must be less than 84 pixels to fit on display) lcd.printString(" Smart Cold",0,1); // Just a welcome message before auto moving to main menu lcd.printString(" Storage",0,2); // lcd.printString(" Monitoring",0,3); // lcd.printString("V11 - Jan 2022",0,4); // lcd.printString("--------------",0,5); // lcd.refresh(); // Need to refresh display after setting pixels or writing strings wait(5.0); // Leave welcome screen on for designated amount of time lcd.clear(); // Clear buffer at start of every loop lcd.refresh(); // Need to refresh display after setting pixels or writing strings lcd.printString("--------------",0,0); // lcd.printString(" Use Joystick",0,1); // Instruction for use of menu lcd.printString(" To Navigate",0,2); // lcd.printString("",0,3); // Blank Line lcd.printString(" A = Select",0,4); // lcd.printString("--------------",0,5); // lcd.refresh(); // Need to refresh display after setting pixels or writing strings wait(5.0); // init_PCB(); // Ran again to ensure all LED's etc are turned off } enum EMenuState // An enum controlling the current state of the display. { MENUSTATE_StartTemp, // MENUSTATE_Main, // Defining each menu state to be called upon later MENUSTATE_Monitor, // Defining each menu state to be called upon later MENUSTATE_OneOff, // Defining each menu state to be called upon later MENUSTATE_About, // Defining each menu state to be called upon later MENUSTATE_Author, // Defining each menu state to be called upon later MENUSTATTE_Num, // This is a special enum value that just gives is a way to get the number of elements in the enum. }; void Run() { int MenuState; // int SelectedItem = 0; // int NumMenuItems = 1; // char buffer[14]; // each character is 6 pixels wide, screen is 84 pixels (84/6 = 14) while(1){ if (g_menu_timer_flag){ // g_menu_timer_flag = 0; // bool bAButtonWasPressed = g_ButtonA_flag; // Get the value of the input flags and reset them bool bBButtonWasPressed = g_ButtonB_flag; // Get the value of the input flags and reset them g_ButtonA_flag = 0; // g_ButtonB_flag = 0; // lcd.clear(); // clear buffer at start of every loop int NewMenuState = MENUSTATTE_Num; // The new menu we want to transition to, if any. switch(MenuState) // Update and Draw whichever menu we're on. { case MENUSTATE_StartTemp: // { NumMenuItems = 1; // Dont for get to set this when changing number of items in the menu. We need this to wrap the selection around properly etc. if(SelectedItem >= NumMenuItems) // { SelectedItem = 0; // Something has gone wrong, reset selected item. } Direction d = joystick.get_direction(); StartTemp(); float g_StartTemp = fsm[g_state].output; // read temperature and print to lcd pc.printf("T = %f K\n",g_state); // Print to serial - allows testing without device attached printf ("Joystick Direction Points = %i\n",d); // printf ("State selected = %i\n", g_StartTemp); // int length = sprintf(buffer," T = %.2f C",g_StartTemp); // print formatted data to buffer - it is important the format specifier ensures the length will fit in the buffer if (length <= 14) // if string will fit on display (assuming printing at x=0) lcd.printString("- Set Target -",0,0); // lcd.printString("---- Temp ----",0,1); // lcd.printString(buffer,0,3); // display on screen lcd.printString("'A' to Select",0,5); // lcd.refresh(); // need to refresh display after setting pixels or writing strings // if(bAButtonWasPressed) // If A was pressed then we transition to the selected screen. { if(SelectedItem == 0) // If 0 line is selected, move to detailed menu { // Actually 0 line + 1, see circle draw and selection below NewMenuState = MENUSTATE_Main; // } } } break; // case MENUSTATE_Main: // { NumMenuItems = 4; // Dont for get to set this when changing number of items in the menu. We need this to wrap the selection around properly etc. if(SelectedItem >= NumMenuItems) // { SelectedItem = 0; // Something has gone wrong, reset selected item. } lcd.printString("---- MENU ----",0,0); // Menu title and selectable options lcd.printString("M1 - Monitor",0,1); // Printed to the LCD screen lcd.printString("M2 - One-off",0,2); // lcd.printString("About",0,3); // lcd.printString("Author",0,4); // if(bAButtonWasPressed) // If A was pressed then we transition to the selected screen. { if(SelectedItem == 0) // If 0 line is selected, move to detailed menu { // Actually 0 line + 1, see circle draw and selection below NewMenuState = MENUSTATE_Monitor; // } else if(SelectedItem == 1) // If 1 line is selected, move to detailed menu { // Actually 1 line + 1, see circle draw and selection below NewMenuState = MENUSTATE_OneOff; // } else if(SelectedItem == 2) // If 2 line is selected, move to detailed menu { // Actually 2 line + 1, see circle draw and selection below NewMenuState = MENUSTATE_About; // } else if(SelectedItem == 3) // If 3 line is selected, move to detailed menu { // Actually 3 line + 1, see circle draw and selection below NewMenuState = MENUSTATE_Author; // } } } break; // case MENUSTATE_Monitor: // Call constant measurement menu following top menu selection { NumMenuItems = 1; // Detail the number of items in Menu - need this to wrap the selection around properly etc. if(SelectedItem >= NumMenuItems) // { NewMenuState = MENUSTATE_Main; // Something has gone wrong, drop back to the main menu. } float T = tmp102.get_temperature(); // read temperature and print to lcd pc.printf("T = %f K\n",T); // Print to serial - allows testing without device attached int length = sprintf(buffer," T = %.2f C",T); // print formatted data to buffer - it is important the format specifier ensures the length will fit in the buffer if (length <= 14) // if string will fit on display (assuming printing at x=0) lcd.printString("-- Constant --",0,0); // lcd.printString("- Monitoring -",0,1); // lcd.printString(buffer,0,3); // display on screen lcd.printString(" 'A' to Menu",0,5); // lcd.refresh(); // need to refresh display after setting pixels or writing strings wait(0.5); // float high_temp = tmp102.get_temperature(); // read temperature if (high_temp >= 25) { // High temp alarm condition - in real world would be lot lower!! LED01 = 0; // Light LED01 if temperature is over specified - Simulated starting of cold blowers LED02 = 0; // Light LED02 if temperature is over specified - Simulated starting of cold blowers LED03 = 0; // Light LED03 if temperature is over specified - Simulated starting of cold blowers printf("WARNING - High Temp!! \n"); // } else { LED01 = 1; // LED01 off if temperature is below specified - Simulated stopping of cold blowers LED02 = 1; // LED01 off if temperature is below specified - Simulated stopping of cold blowers LED03 = 1; // LED01 off if temperature is below specified - Simulated stopping of cold blowers Buzzer = 0; // } float low_temp = tmp102.get_temperature(); // Read temperature if (low_temp <= 22) { // Low temp alarm condition - in real world would be lot lower!! LED04 = 0; // Light LED04 if temperature is over specified - Simulated starting of heaters LED05 = 0; // Light LED05 if temperature is over specified - Simulated starting of heaters LED06 = 0; // Light LED06 if temperature is over specified - Simulated starting of heaters printf("WARNING - Low Temp!! \n"); // } else { LED04 = 1; // LED04 off if temperature is above specified - Simulated stopping of heaters LED05 = 1; // LED05 off if temperature is above specified - Simulated stopping of heaters LED06 = 1; // LED06 off if temperature is above specified - Simulated stopping of heaters } if(bAButtonWasPressed) // Check if button was pressed { if(SelectedItem == 0) // { NewMenuState = MENUSTATE_Main; // Transition back to the main menu LED01 = 1; // Turn off LED upon transition back to main menu LED02 = 1; // Turn off LED upon transition back to main menu LED03 = 1; // Turn off LED upon transition back to main menu LED04 = 1; // Turn off LED upon transition back to main menu LED05 = 1; // Turn off LED upon transition back to main menu LED06 = 1; // Turn off LED upon transition back to main menu } } } break; case MENUSTATE_OneOff: // Call a one off measurement menu following top menu selection { NumMenuItems = 1; // Detail the number of items in Menu - need this to wrap the selection around properly etc. if(SelectedItem >= NumMenuItems) // { NewMenuState = MENUSTATE_Main; // Something has gone wrong, drop back to the main menu. } float T = tmp102.get_temperature(); // read temperature and print to lcd pc.printf("T = %f K\n",T); // Print to serial - allows testing without device attached int length = sprintf(buffer," T = %.2f C",T); // print formatted data to buffer - it is important the format specifier ensures the length will fit in the buffer if (length <= 14) // if string will fit on display (assuming printing at x=0) lcd.printString("-- One-Off --",0,0); // lcd.printString("-- Measure --",0,1); // lcd.printString(buffer,0,3); // display on screen lcd.printString(" 'A' to Menu",0,5); // if(bAButtonWasPressed) // Check if button was pressed { if(SelectedItem == 0) // { NewMenuState = MENUSTATE_Main; // Take us back to top menu } } } break; case MENUSTATE_About: // Call About menu following top menu selection { NumMenuItems = 1; // Detail the number of items in Menu - need this to wrap the selection around properly etc. if(SelectedItem >= NumMenuItems) // { NewMenuState = MENUSTATE_Main; // Something has gone wrong, drop back to the main menu. } lcd.printString("--- About ---",0,0); // lcd.printString("ELE3006M - IoT",0,1); // lcd.printString(" Project",0,2); // lcd.printString("Uni of Lincoln",0,3); // lcd.printString(" 'A' to Menu",0,5); // lcd.refresh(); // if(bAButtonWasPressed) // Check if button was pressed { if(SelectedItem == 0) // { NewMenuState = MENUSTATE_Main; // Transition back to Main Menu } } } break; case MENUSTATE_Author: // Call Author menu following top menu selection { NumMenuItems = 1; // Detail the number of items in Menu - need this to wrap the selection around properly etc. if(SelectedItem >= NumMenuItems) // { NewMenuState = MENUSTATE_Main; // Something has gone wrong, drop back to the main menu. } lcd.printString("--- Author ---",0,0); // lcd.printString("David Leaming ",0,1); // lcd.printString(" 25574043 ",0,2); // lcd.printString(" VolkerRail",0,3); // lcd.printString(" 'A' to Menu",0,5); // if(bAButtonWasPressed) // Check if button was pressed { if(SelectedItem == 0) // { NewMenuState = MENUSTATE_Main; // Take us back to top menu } } } break; default: { NewMenuState = MENUSTATE_Main; // Something has gone wrong, drop back to the main menu. } }; if(NewMenuState != MENUSTATTE_Num) // If we have requested a new menu state. { printf("Transitioning to MenuState: %i\n", NewMenuState); // Observe on serial port - ensure transition to correct screen MenuState = NewMenuState; // We want to transition the menu to a new state. // Do any bookkeeping needed when moving to new state. SelectedItem = 0; // Reset the selected item. lcd.clear(); // Clear the display for one frame on state transition. } else { unsigned int SelectionMarkerRadius = 4; // If we have not selected to move to a new menu. unsigned int SelectionMarkerX = WIDTH - (2 * SelectionMarkerRadius); // Draw a marker circle at end of line to show which is the currently selected item. unsigned int SelectionMarkerY = (HEIGHT / 5) * (SelectedItem + 1); // +1 because of the menu title being on first row lcd.drawCircle(SelectionMarkerX, SelectionMarkerY, SelectionMarkerRadius, FILL_BLACK); // Fill the circle black so it can be seen easily // Handle Joystick Input switch (joystick.get_direction()) { // Call to check direction joystick is pointing printf("Direction = %i\n"); // Print direction to serial case N: // SelectedItem--; // break; // case S: // SelectedItem++; // break; // } if(SelectedItem < 0) // Wrap the selection around to the start/end of the menu if it goes below 0 or above NumMenuItems. { SelectedItem = NumMenuItems - 1; // } else if(SelectedItem >= NumMenuItems) // { SelectedItem = 0; // } } lcd.refresh(); //Finally update the display. } } } void StartTemp() // { Direction d = joystick.get_direction(); // joystick.init(); g_StartTemp = fsm[g_state].output; // set ouput depending on current state wait(fsm[g_state].time); // wait in that state for desired time g_state = fsm[g_state].nextState[d]; // read input and update curent state }