'Sensor-Matic!' ELEC2645 Jack Berriman - 200836573
Dependencies: N5110-JDB SRF02 SoftPWM-JDB TMP102 mbed
Diff: main.cpp
- Revision:
- 0:e8ca5d36a1e7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Thu May 05 14:55:30 2016 +0000 @@ -0,0 +1,674 @@ +/* + +ELEC2645 - Embedded Systems Project - "Sensor-matic!" + +Distance and Temperature Sensors Displayed on Nokia 5110 Screen + + +Week 19 - Testing SRF02 Distance Sensor + +Week 20 - Creating Splash Screens + +Week 21 - Diagrams for Temperature and Distance + +Easter - Navigation Between Menus + +Week 22 - Piezo/LEDs Interfaced + +Week 23 - DOxygen Commenting + +Week 24 - Cleaning Up & Submission + + +(c) Jack Berriman, University of Leeds, Summer 2016 + +*/ + +/** +@file main.cpp +@brief Program Implementation +*/ + + +#include "main.h" + + +// ------------------------- MAIN FUNCTION ------------------------- // + +int main() // Main Function +{ + + init_K64F(); // Initialise FRDM K64F Micrcontroller + init_buzzer(); // Initialise Piezo Buzzer + init_program(); // Initialise Other Program Requirements (Screen/Ticker/Baud Rate) + + welcomeScreen(); // Display Welcome Screen + screen.clear(); // Clear Screen + + while (1) { // Infinite Program While Loop + + if (screenNumber == 0) { // Main Menu = 0 + mainMenu(); + } else if (screenNumber == 1) { // Sensor Menu = 1 + sensorMenu(); + } else if (screenNumber == 2) { // Options Menu = 2 + optionsMenu(); + } else if (screenNumber == 3) { // Distance Display = 3 + distanceDisplay(); + } else { // Temperature Display = 4 + temperatureDisplay(); + } + + screen.refresh(); // Refresh Screen AFTER Each Iteration + sleep(); // Put Peripherals To Sleep (Due to InterruptIn) + + } +} + + +// ------------------------- INITIALISE FUNCTIONS ------------------------- // + +void clearAll() // Clears Current Buffer (Text/Pixels) -- ADAPTED FROM ELEC1620 (GAME OF LIFE PROJECT) +{ + for (int xPixel = 0; xPixel < 84; xPixel++) { // Loops Through X-Pixels + for (int yPixel = 0; yPixel < 48; yPixel++) { // Loops Through Y-Pixels + screen.clearPixel(xPixel,yPixel); // Clears + } + } + screen.refresh(); // Refreshes Screen AFTER Clearing +} + + +void init_K64F() // Initialise K64F Function +{ + // On-Board LEDs are Active-Low + r_led = 1; + g_led = 1; // Set to 1 (High) to Turn OFF + b_led = 1; + + allLEDOff(); // Turn off All LEDs + + forward.rise(&forward_isr); // Interrupts Fire on Rising Clock Edge + backward.rise(&backward_isr); + + forward.mode(PullDown); // Push Buttons are Connected to +3V3 - Pull-Down to Ground when Pressed + backward.mode(PullDown); +} + + +void init_buzzer() // Initialise Piezo Buzzer Function +{ + piezo.period(1.0/2000.0); // Set Frequency to 2 kHz + piezo.write(0.0); // Turn OFF (Duty Cycle = 0) +} + + +void init_program() // Initialise Other Program Requirements +{ + screen.init(); // Initialise Screen + screen.clear(); // Clear Buffer + systemTicker.attach(&system_isr,0.5); // Attach Ticker + pc.baud(115200); // Set Serial Port Baud Rate to 115200 Hz +} + + +void welcomeScreen() // Prints Welcome Screen on Start-Up +{ + + // printString is a function from N5110.h + screen.printString("ELEC2645", 20, 0); // Format: screen.printString("Text", Number of Pixels 'in' (X-Position), Bank Number (Y-Position)) + screen.printString("Sensor-matic!", 5, 2); // Project Title + screen.printString("By", 35, 4); + screen.printString("Jack Berriman", 3, 5); + + wait(2); // Delay (To Read Text) + +} + + +// ------------------------- STRUCTS ------------------------- // + +AverageValues getAverageValues() // Struct for Calculating Average Values of Distance and Temperature +{ + AverageValues values; // Access Struct + int temporaryDistanceSum = 0; + int temporaryTemperatureSum = 0; // Initialise Temporary 'Sum' Variables Equal to Zero + + for (int i = 0; i <= 10; i++) { // Loop Through 10 Samples + + int distanceRead = srf02.getDistanceCm(); // Each Iteration: Get Distance and Write to Variable 'distanceRead' + temporaryDistanceSum += distanceRead; // Add to Sum + + int temperatureRead = tmp102.get_temperature(); // Each Iteration: Get Temperature and Write to Variable 'distanceRead' + temporaryTemperatureSum += temperatureRead; // Add to Sum + } + + values.averageDistance = temporaryDistanceSum/10; // Divide by Number of Samples (10) + values.averageTemperature = temporaryTemperatureSum/10; + + return values; // Return 'values' to Struct +} + + +// ------------------------- CURSOR POSITION (POTENTIOMETER) FUNCTIONS ------------------------- // + +int getCursorPosition() // Read Potentiometer Value & Convert to Bank Value +{ + int bank = floor(controller * 5) + 1; // Read Potentioementer & Multiply by 5 + // 'Floor' = Rounds Down + + if (bank == 6) { // If Bank value us greater that 5... + bank = 5; // A value of 5 is returned + } + + return bank; // Return Bank Value +} + + +void printCursorPositionMain(int cursor) // Print Cursor as Rectangle Next to Option in Main/Sensor Menu (Used with 'getCursorPosition') +{ + // Prevents Cursor Position From Being Unselectable + if (cursor != 1 && cursor != 3 && cursor != 5) { // If Cursor in Banks 2 or 4 - Print Rectangle + + y_axis_rect_main = (cursor * 8) + 3; // Multiply Cursor by 8 to Return Y-Position & Add 3 to Align in Bank + + screen.drawRect(75,y_axis_rect_main,2,2,0); // Print Rectangle (Depending on Potentiometer/Cursor) + } else { + screen.drawRect(75,y_axis_rect_main,2,2,0); // If Bank is 1, 3 or 5 - Still Print Rectangle + } +} + + +void printCursorPositionOptions(int cursor, int stateOfLED, int stateOfSound) // Print Cursor as Rectangle Next to Option in Options Menu (Used with 'getCursorPosition') +{ + // stateOfLed & stateOfSound Return 1 or 0 + // 1 or 0 Passed into 'drawRect' - Fills or Unfills Rectangle + + y_axis_rect_options = (cursor * 8) + 3; // Multiply Cursor by 8 to Return Y-Position & Add 3 to Align in Bank + cursor == 1 ? screen.drawRect(81,y_axis_rect_options,2,2,stateOfLED):screen.drawRect(81,y_axis_rect_options,2,2,stateOfSound); + // If Cursor is 1 = Draw Rectangle OR If Cursor is 3 = Draw Rectangle +} + + +// ------------------------- MENU FUNCTIONS (MAIN/SENSORS/OPTIONS ------------------------- // + +void mainMenu() // Function for Main Menu +{ + y_axis_rect_main = 19; // Set Initial Y-Position to 19th Pixel + + while (screenNumber == 0) { // While Main Menu Screen On... + + int cursor = getCursorPosition(); // Read Position of Cursor + + if (g_system_flag) { + g_system_flag = 0; // Reset System Flag to 0 + + clearAll(); // Clears Previous Text String (Welcome Screen) + + screen.printString("MAIN MENU", 16, 0); // Print String 'Main Menu' + screen.drawLine(5,11,79,11,1); // Draw Line Above Sensors String + screen.printString("Sensors", 3, 2); // Print String 'Sensors' + screen.printString("Options", 3, 4); // Print String 'Options' + screen.drawLine(5,44,79,44,1); // Draw Line Underneath Options String + + // Used to Ensure Cursor is Set in Bank + if (cursor <= 2) { // If Position of Cursor is 2 or Less + cursor = 2; // Set Cursor to Equal 2 + } + if (cursor >= 3) { // If Position of Cursor is 3 or Greater + cursor = 4; // Set Cursor to Equal 4 + } + + printCursorPositionMain(cursor); // Print Cursor to Screen + pc.printf("Controller = %d \n",cursor); // Debug in 'CoolTerm.exe' + + // Check Flag IF 'forward' Button Interrupt Pressed + if (g_forward_flag == 1) { + g_forward_flag = 0; // Clear Flag + + // Determine Next Screen + if (cursor == 2) { + screenNumber = 1; // Go to Sensor Menu + } + if (cursor == 4) { + screenNumber = 2; // Go to Options Menu + } + } + } + returnToMenu(); // Back Button Function + screen.refresh(); // Refresh Screen + } +} + +void sensorMenu() // Function for Sensor Menu +{ + while (screenNumber == 1) { // While Sensor Menu is On... + + int cursor = getCursorPosition(); // Read Position of Cursor + + if (g_system_flag) { + g_system_flag = 0; // Reset System Flag to 0 + + clearAll(); // Clears Previous Text String (Main Menu Screen) + + screen.printString("SENSOR MENU", 10, 0); // Prints String 'SensorMenu' + screen.drawLine(5,11,79,11,1); // Draw Line Above Dist Sensor + screen.printString("Dist Sensor", 3, 2); // Prints String 'Dist Sensor' + screen.printString("Temp Sensor", 3, 4); // Prints String 'Temper Sensor' + screen.drawLine(5,44,79,44,1); // Draw Line Below Temp Sensor + + // Used to Ensure Cursor is Set in Bank + if (cursor <= 2) { // If Position of Cursor is 2 or Less + cursor = 2; // Set Cursor to Equal 2 + } + if (cursor >= 3) { // If Position of Cursor is 3 or Greater + cursor = 4; // Set Cursor to Equal 4 + } + + printCursorPositionMain(cursor); // Print Cursor to Screen + pc.printf("Controller = %d \n",cursor); // Debug in 'CoolTerm.exe' + + // Check Flag IF 'forward' Button Interrupt Pressed + if (g_forward_flag == 1) { + g_forward_flag = 0; // Clear Flag + + // Determine Next Screen + if (cursor == 2) { + screenNumber = 3; // Go to Distance Display + } + if (cursor == 4) { + screenNumber = 4; // Go to Temperature Display + } + } + } + returnToMenu(); // Back Button Function + screen.refresh(); // Refresh Screen + } +} + +void optionsMenu() // Function for Options Menu +{ + y_axis_rect_options = 27; // Set Initial Y-Position to 27th Pixel + + while (screenNumber == 2) { // While Options Menu is On... + + int cursor = getCursorPosition(); // Read Position of Cursor + + if (g_system_flag) { + g_system_flag = 0; // Reset System Flag to 0 + + clearAll(); // Clears Previous Text String (Main Menu Screen) + + screen.printString("Toggle LEDs", 1, 1); // Print String 'Toggle LEDs' + screen.printString("Toggle Sound", 1, 3); // Print String 'Toggle Sound' + screen.printString("Toggle Colour", 1, 5); // Print String 'Toggle Colour' + + // Used to Ensure Cursor is Set in Bank + if (cursor <= 2) { // If Position of Cursor is 2 or Less + cursor = 1; // Set Cursor to Equal 1 + } + if (cursor > 2 && cursor <= 4) { // If Position of Cursor is Between 2 or 4 + cursor = 3; // Set Cursor to Equal 3 + } + if (cursor > 4) { // If Position of Cursor is Greater than 4 + cursor = 5; // Set Cursor to Equal 5 + } + + if (triggerLEDs == 1) { // Read Trigger of LED + allLEDOn(); // If Trigger = 1, Turn ON LEDs + } + + printCursorPositionOptions(cursor, stateOfLED, stateOfSound); // Print Position of Cursor + + // Check Flag IF 'forward' Button Interrupt Pressed + if (g_forward_flag == 1) { + g_forward_flag = 0; // Clear Flag + + // Determine Options to Edit + if (cursor == 1) { + stateOfLED = toggleLEDs(); // Toggle LEDs & Write 1 or 0 to 'stateOfLED' + } + if (cursor == 3) { + stateOfSound = toggleSound(); // Toggle Sound & Write 1 or 0 to 'stateOfLED' + } + if (cursor == 5) { + toggleColour(); // Toggle Colour + } + } + } + returnToMenu(); // Back Button Function + screen.refresh(); // Refresh Screen + } +} + +void distanceDisplay() // Function to Display Distance +{ + AverageValues values; // Call Struct For Average Values + + while(screenNumber == 3) { // While Temperature Display is On... + + values = getAverageValues(); + int Distance = values.averageDistance; // Access Struct Value + + if (g_system_flag) { + g_system_flag = 0; // Reset System Flag to 0 + + clearAll(); + + if (triggerLEDs == 1) { + LEDs_Distance(Distance); // Call Distance LED Function + } + + char buffer[14]; // Each Character = 6 pixels wide & Screen = 84 pixels (84/6 = 14) + int length = sprintf(buffer,"Dist = %d CM",Distance); // Print Distance Value to Buffer + pc.printf("DistAv = %f \n DistNorm = %f \n", Distance, srf02.getDistanceCm()); // Debug in 'CoolTerm.exe' + + if (length <= 14) // If String Fits on Display + screen.printString(buffer,3,2); // Display on Screen + + if (Distance <= 14 || Distance >= 250) { // If Sensor is Out of Range + clearAll(); // Clear Buffer + screen.drawLine(4,2,80,2,2); // Draw Dotted Line Above Text + screen.printString("DISTANCE OUT", 6, 1); + screen.printString("OF RANGE", 18, 2); + screen.drawLine(4,27,80,27,2); // Draw Dotted Line Below Text + screen.printString("MIN = 15 CM", 10, 4); + screen.printString("MAX = 250 CM", 7, 5); + + if (triggerSound == 1) { // Play Continuous Buzz When Out of Range + buzzerOn(); + } + } else { // If Sensor is In Range + + screen.printString("DIST SENSOR", 10, 0); // Print String 'Distance Sensor' (Title) + + screen.drawRect(5,26,74,12,0); // Draw Rectangle Outline + int fillLength = floor(PIXEL_PER_CM * Distance); // Update Fill Length Depending on Distance Value + + screen.drawRect(6,27,fillLength,11,1); // Fill the Distance Bar (Left to Right) + + screen.drawRect(17,26,2,12,0); // Puts in Dividers at 50 cm Intervals + screen.drawRect(33,26,2,12,0); + screen.drawRect(48,26,2,12,0); + screen.drawRect(63,26,2,12,0); + + screen.printString("15",0,5); // Prints Lower Bound Marker (15 cm) + screen.printString("250",67,5); // Prints Upper Bound Marker (250 cm) + + if (Distance <= 50) { + if (triggerSound == 1) { // Check Trigger Value of Buzzer + buzzerClose(); // Play Highly Freuquent Buzz + } + } else if (Distance <= 100) { + if (triggerSound == 1) { // Check Trigger Value of Buzzer + buzzerNormal(); // Play Moderately Freuquent Buzz + } + } else if (Distance <= 200) { + if (triggerSound == 1) { // Check Trigger Value of Buzzer + buzzerFar(); // Play Lowly Freuquent Buzz + } + } + } + + + returnToMenu(); // Function for Back Button + screen.refresh(); // Refreshes Screen + } + } +} + +void temperatureDisplay() // Function to Display Temperature +{ + AverageValues values; // Call Struct For Average Values + + while(screenNumber == 4) { // While Temperature Display is On... + + values = getAverageValues(); + int Temperature = values.averageTemperature; // Access Struct Value + + if (g_system_flag) { + g_system_flag = 0; // Reset System Flag to 0 + + clearAll(); // Clears Previous Text String (Sensor Menu Screen) + + screen.printString("TEMP SENSOR", 10, 0); // Print String 'Temp Sensor' (Title) + + LEDs_Temperature(Temperature); // Call Temperature LED Function + + char buffer[14]; // Each Character = 6 pixels wide & Screen = 84 pixels (84/6 = 14) + int length = sprintf(buffer,"Temp = %d -C",Temperature); // Print Temperature Value to Buffer + pc.printf("TempAv = %f \n TempNorm = %f \n", Temperature, tmp102.get_temperature()); // Debug in 'CoolTerm.exe' + + if (length <= 14) // If String Fits on Display + screen.printString(buffer,6,2); // Display on Screen + + screen.drawCircle(15,36,7,1); // Circular End of Thermometer + screen.drawRect(22,32,6,8,1); // Start of Thermometer + screen.drawRect(26,32,48,8,0); // Outline of the Thermometer + + int fillLength = floor(PIXEL_PER_DEGREE * Temperature); // Update Fill Length Depending on Thermometer Value + + screen.drawRect(27,33,fillLength,6,1); // Fill the Thermometer (Left to Right) + screen.refresh(); // Refresh Screen + } + returnToMenu(); // Function for Back Button + } +} + + +// ------------------------- OPTIONS MENU (TOGGLE) FUNCTIONS ------------------------- // + +bool toggleLEDs() // Toggles LED (Enable/Disable) +{ + if (triggerLEDs == 0) { + allLEDOn(); // Turn ON LEDs (While on Options Screen) + triggerLEDs = 1; // 'Flip' Trigger + } else { + allLEDOff(); // Turn OFF LEDs (While on Options Screen + triggerLEDs = 0; // 'Flip' Trigger + } + + bool stateOfLED = triggerLEDs; // Set Trigger Value (1 or 0) into Bool + return stateOfLED; // Return Bool (Used in Printing Rectangle) +} + + +bool toggleSound() // Toggles Sound (Enable/Disable) +{ + if (triggerSound == 0) { + piezo.write(0.5); // Play Bleep Noise + wait(0.1); + piezo.write(0.0); + triggerSound = 1; // 'Flip' Trigger + } else { + triggerSound = 0; // 'Flip' Trigger + } + + bool stateOfSound = triggerSound; // Set Trigger Value (1 or 0) into Bool + return stateOfSound; // Return Bool (Used in Printing Rectangle) +} + + +void toggleColour() // Toggles Colour (Black-on-White/White-on-Black) +{ + if (triggerColour == 0) { + screen.inverseMode(); // Set Colour to Inverse Mode (White-on-Black) + triggerColour = 1; // 'Flip' Trigger + } else { + screen.normalMode(); // Set Colour to Normal Mode (Black-on-White) + triggerColour = 0; // 'Flip' Trigger + } +} + + +// ------------------------- LED & SOFT-PWM FUNCTIONS ------------------------- // + +void allLEDOn() // Function to Turn ON All LEDs +{ + red_led = 0; + yellow_led = 0; + green_led = 0; +} + + +void allLEDOff() // Function to Turn OFF All LEDs +{ + red_led = 1; + yellow_led = 1; + green_led = 1; +} + + +void LEDs_Flashing() +{ + redPWM = 0.5; // Turn ON Soft PWM LEDs + yellowPWM = 0.5; + greenPWM = 0.5; + + redPWM.period(0.25); // Set Period = 0.25 seconds + yellowPWM.period(0.25); + greenPWM.period(0.25); +} + + +void cancel_LEDs_Flashing() +{ + redPWM = 0; // Turn OFF Soft PWM LEDs + yellowPWM = 0; + greenPWM = 0; + + redPWM.stop(); // Stop Soft PWM + yellowPWM.stop(); + greenPWM.stop(); +} + + +void LEDs_Distance(int d) // LEDs Illuminate (Depending on Distance) +{ + + if (d < 15 || d > 250) { // All ON + LEDs_Flashing(); // Enable Soft PWM Flashing LEDs + } else if (d >= 15 && d < 50) { // Red ON + cancel_LEDs_Flashing(); // Prevent Soft PWM Overwritting Digital LEDs + red_led = 0; + yellow_led = 1; + green_led = 1; + } else if (d >= 50 && d < 100) { // Red & Yellow ON + cancel_LEDs_Flashing(); + red_led = 0; + yellow_led = 0; + green_led = 1; + } else if (d >= 100 && d < 150) { // Yellow ON + cancel_LEDs_Flashing(); + red_led = 1; + yellow_led = 0; + green_led = 1; + } else if (d >= 150 && d < 200) { // Yellow & Green ON + cancel_LEDs_Flashing(); + red_led = 1; + yellow_led = 0; + green_led = 0; + } else if (d >= 200 && d < 250) { // Green ON + cancel_LEDs_Flashing(); + red_led = 1; + yellow_led = 1; + green_led = 0; + } +} + + +void LEDs_Temperature(int t) // LEDs Illuminate (Depending on Temperature) +{ + + if (t < 10 || t >= 40) { // All ON + allLEDOn(); + } else if (t >= 10 && t < 15) { // Red ON + red_led = 0; + yellow_led = 1; + green_led = 1; + } else if (t >= 15 && t < 20) { // Red & Yellow ON + red_led = 0; + yellow_led = 0; + green_led = 1; + } else if (t >= 20 && t < 25) { // Green ON + red_led = 0; + yellow_led = 0; + green_led = 1; + } else if (t >= 25 && t < 30) { // Red & Yellow ON + red_led = 0; + yellow_led = 0; + green_led = 1; + } else if (t >= 30 && t < 40) { // Red ON + red_led = 0; + yellow_led = 1; + green_led = 1; + } +} + + +// ------------------------- BUZZER FUNCTIONS ------------------------- // + +void buzzerOn() // Buzz Continuously +{ + piezo.write(0.5); // Set Duty Cycle - 50% + wait_ms(10); // Wait 10 Milli-Seconds +} + + +void buzzerClose() // Buzz Every 0.1 Seconds +{ + piezo.write(0.5); + wait(0.1); // Wait 0.1 Seconds + piezo.write(0.0); +} + + +void buzzerNormal() // Buzz Every 0.3 Seconds +{ + piezo.write(0.5); + wait(0.3); + piezo.write(0.0); +} + + +void buzzerFar() // Buzz Every 0.5 Seconds +{ + piezo.write(0.5); + wait(0.5); + piezo.write(0.0); +} + + +// ------------------------- ISR & INTERRUPT FUNCTIONS ------------------------- // + +void returnToMenu() // Function for Returning to Main Menu (if 'backward' Button Pressed) +{ + // Check Flag IF 'forward' Button Interrupt Pressed + if (g_backward_flag) { + g_backward_flag = 0; // Clear Flag + + screenNumber = 0; // Go to Screen Number = 0 (Main Menu) + cancel_LEDs_Flashing(); + allLEDOff(); // Turn OFF LEDs + piezo.write(0.0); // Write 0% Duty Cycle to Piezo (Turn OFF) + } + +} + + +void system_isr() // ISR For 'systemTicker' +{ + g_system_flag = 1; // Set 'systemTicker' Flag +} + + +void forward_isr() // ISR For 'forward' Buttom +{ + g_forward_flag = 1; // Set 'forward' Button Flag +} + + +void backward_isr() // ISR For 'backward' Button +{ + g_backward_flag = 1; // Set 'backward' Button Flag +}