Volkan Esendag / Mbed 2 deprecated mbed_PortableWeatherStation

Dependencies:   BMP180 N5110 PowerControl mbed

main.cpp

Committer:
Volcano_498
Date:
2015-04-19
Revision:
7:104ac8e707e6
Parent:
6:0aca5c17c988
Child:
8:29ac7d274ae0

File content as of revision 7:104ac8e707e6:

/**
@file main.cpp
@brief Code for a Portable Weather Station to be built on PCB.
@brief Design Specs: *A small, portable battery-powered data logger that records sensor data at regular intervals.
@brief -- Minimises mbed power consumption to the greatest extent possible.
@brief -- Displays the information to the user.
@brief -- Features a BMP180 pressure and temperature sensor. (TMP102 is unnecessary as BMP180 also takes temp. readings)
@brief -- Features a Nokia 5110 display to print the sensor readings over and display them to the user.
@brief -- Sensor information is recorded on Flash memory on the mbed.
@brief -- Graph to display data to the user.
@brief -- mbed is powered by a Buck regulator (5V output) that is in turn supplied by a 9V PP3 battery which powers the PCB.
@brief -- Audible and visual alert when a threshold reading is obtained.
@brief -- Celsius-to-Fahrenheit and Celsius-to-Kelvin conversions of temperature readings and displaying them.
@brief -- Adjusting the unit the pressure is displayed in: millibars(mb), Pascals(Pa) and Atmospheres (atm).
@brief -- Displaying a brief splash screen to show changes in the unit display settings.
@author Volkan Esendag (SID:200795870)
@date 11 March 2015 (created) / 19 April 2015(last modified)
*/

#include "mbed.h"
#include "N5110.h"
#include "BMP180.h"
//import the PowerControl/EthernetPowerControl header files from the Power Control library
//to enable the power down features for the microprocessor and the Ethernet feature.
#include "PowerControl/PowerControl.h"
#include "PowerControl/EthernetPowerControl.h"

#ifndef USR_POWERDOWN
#define USR_POWERDOWN (0x104)    //defines USB interface powerdown.
#endif

#ifndef PNought
#define PNought  1013.25  //Po = 101325 Pa or 1 atm or 1013.25 mb.
#endif

/**
Custom struct for logging intervals. Fetch state number and select recording interval via the use of a button.
*/

struct RecState {
    int recordState;
    float time;
};
//once struct has been declared, define a pointer type with it.
typedef const struct RecState RecS;

//RecS object to determine states for logging intervals. Array size 10.
RecS recInterval[10] = {
    {0,600.0},    //state 0, 10 minutes
    {1,1200.0},   //state 1, 20 minutes
    {2,1800.0},   //state 2, 30 minutes
    {3,3600.0},   //state 3, 1 hour. Default State.
    {4,7200.0},   //state 4, 2 hours
    {5,10800.0},  //state 5, 3 hours
    {6,14400.0},  //state 6, 4 hours
    {7,21600.0},  //state 7, 6 hours
    {8,28800.0}, //state 8, 8 hours
    {9,43200.0}  //state 9, 12 hours
};

//Use the same struct again to create another object, this time for reading display intervals. Array size 6.
RecS dispInterval [6] = {
    {0,1.0},    //state 0, 1 second. Default state.
    {1,2.0},   //state 1, 2 seconds
    {2,3.0},   //state 2, 3 seconds
    {3,4.0},   //state 3, 4 seconds
    {4,5.0},   //state 4, 5 seconds
    {5,0.5},  //state 5, 500 milliseconds
};

/**Struct to set the temperature threshold after which point the device gives off a warning.*/
struct TempThreshold {
    int tempState;
    float thresTemp;
};

//define the TempTyp pointer type using the TempThreshold struct.
typedef const struct TempThreshold TempTyp;

//using this type create an object which contains an array of threshold states. Array size 5.
TempTyp tempThres[5] = {
    {0,30.0},   //state 0, 30'C
    {1,40.0},   //state 1, 40'C
    {2,50.0},   //state 2, 50'C. Default threshold.
    {3,60.0},   //state 3, 60'C
    {4,70.0}    //state 4, 70'C
};

char tempUnit [4] = {'C','F','K','R'}; //character that stores temperature unit type.

char pressUnit[3] = {'M','P','A'}; //character that stores pressure units. M - millibars P - Pascals A - atmospheres

char AltUnit[3] = {'m','f','y'}; //character that stores altitude units. m - metres f - feet y - yards

/**
@namespace bmp180
@brief A special structed type of I2C object created for the BMP180.
@brief For more info, see the BMP180 library by Craig Evans.
@see http://developer.mbed.org/users/eencae/code/BMP180/
*/
BMP180 bmp180(p28,p27);
//Pins are declared in the public domain and the sensor itself acts on private variables.

/**
@namespace buzzerPwm
@brief PwmOut object to apply a PWM signal with a duty ratio of 50% to the buzzer as an improvised square wave.
@brief Used for an audible feedback should the temperature reading exceed a certain value.
*/
PwmOut buzzerPwm(p24);

/**
@namespace redLED
@brief PwmOut object to apply a PWM signal to the red visual feedback LED via pin 22.
@brief Used for visual feedback to tell the user a certain temperature threshold has been reached.
*/
PwmOut redLED(p22);

/**
@namespace greenLED
@brief PwmOut object to apply a PWM signal to the green visual feedback LED via pin 23.
@brief Used to let the user know the device is operating normally.
*/
PwmOut greenLED(p23);

/**
@namespace serial
@brief Serial object to print readings over a USB cable and display them on a terminal.
*/
Serial serial(USBTX,USBRX); //serial object to print readings for debugging WHILE the USB cable is connected.

/**
@namespace menuButton
@brief Interrupt object to call ISR for the designated menu button when an input to p15 is applied.
@namespace buttonOne
@brief Interrupt object to call ISR for Button 1 when an input to p16 is applied.
@namespace buttonTwo
@brief Interrupt object to call ISR for Button 2 when an input to p17 is applied.
@namespace buttonThree
@brief Interrupt object to call ISR for Button 3 when an input to p18 is applied.
*/

InterruptIn menuButton(p15);  //Interrupt object for the designated menu button.
InterruptIn buttonOne(p16);   //Interrupt objects for the other buttons.
InterruptIn buttonTwo(p17);
InterruptIn buttonThree(p18);

/**
@namespace potAin
@brief Analogue input from potentiometer whose Vout is connected to pin 20.
*/

AnalogIn potAin(p20); //Potentiometer feedback pin to the mbed.

/**
@namespace logTimer
@brief Ticker object to record/log readings with a specified interval. Can be varied with Interrupt Service Routines.
*/

Ticker logTimer;   //Ticker object to call ISR for a specified period of time.

/**
@namespace displayTimer
@brief Ticker object to display readings on screen with a specified interval. Can be varied with Interrupt Service Routines.
*/
Ticker displayTimer; //ticker object to display readings

/*
@namespace leds
@brief GPIO output for status LEDs - used to display error message or as a flash memory overwrite operation feedback.
*/

BusOut leds(LED1,LED2,LED3,LED4);  //BusOut object for error feedback LEDs.
//configure pins of the LCD display...

/**
@namespace splashFlip
@brief Calls an ISR only once when attached. Used to delay splash screen for a few seconds before commencing with the program flow.
*/
Timeout splashFlip;

/**
@namespace lcd
@brief Object that belongs to the N5110 class. Set up pin outputs for the Nokia 5110 display. Defined in N5110.h.
@see https://developer.mbed.org/users/eencae/code/N5110/
*/
void printReadings();  // declare function to print readings here, which is then defined after the main() function.
void clearCells();   //declare function to clear all cells should there be a need for it. Even though lcd.clear() also does the job this can be handy in case of failure.

float temp = 0.0;  //declare the temp variable for temperature universally so that it can be shared across functions to represent temperature.
float press = 0.0; //do the same for pressure using press.
float altitude = 0.0;  //and altitude using, well, altitude :P

int i = 0;  //represents the column number (horizontal pixel number) of the display.
int j = 0;  //represents the row number of the display.

int dispSetting = 0; //set display setting to default.
int recSetting = 3;  //set log setting to default.
int tempSetting = 2; //set temperature threshold to default.

int tempUnitSetting = 0; //set temperature unit setting to default.
int pressUnitSetting = 0; //set pressure unit setting to default.
int altUnitSetting = 0; //and do the same for altitude.
int subMenuId = 0; //int used to store sub-menu number. For instance pressing the menu button once and then Button One gives Sub-Menu 1.

N5110 lcd(p7,p8,p9,p10,p11,p13,p21);    //VCC,SCE,RST,DC,MOSI,SCLK,BACKLIGHT

///////////The following pieces of code are to configure real-time clock for the data logger.*************

char rxString[16]; // buffer to store received string. Each character is a byte long - hence the char pointer type.

int setTimeFlag = 0; /*!< set time flag set in serial ISR */

/**
Reads string input via serial interrupt and converts it into real time
@param rxString - string received from serial
@param time - integer that represents time, converted from input string (rxString).

*/
void setTime()
{
// print time for debugging
    serial.printf("set_time - %s",rxString);
// atoi() converts a string to an integer
    int time = atoi(rxString);
// update the time
    set_time(time);
}

void serialISR()
{
// when a serial interrupt occurs, read rx string into buffer. Holds 16 characters. gets implies fetching a string from serial port.
    serial.gets(rxString,16);
// set flag
    setTimeFlag = 1;
}

/**
Disables USB interface when the mbed's USB cable isn't attached.
@param arg - argument function (pointer type int/uint32_t)
@returns __semihost(USR_POWERDOWN, &arg)
*/

int semihost_powerdown()
{

    uint32_t arg;  //variable for return function
    return __semihost(USR_POWERDOWN, &arg);    //return semihost state...

} //...to power down the USB interface when the USB cable is detached.

LocalFileSystem local("local"); // create local filesystem

void writeDataToFile(float data, float dataTwo, char dataThree[30])
{
    time_t seconds = time(NULL); // get current time
    strftime(dataThree, 30 , "%R %x", localtime(&seconds)); //convert it into a string, from an array size of 30.

    leds = 15; // turn on LEDs for feedback
    FILE *fp = fopen("/local/tempLog.csv", "a"); // open 'log.txt' for appending. Instance of class FILE.
// if the file doesn't exist it is created, if it exists, data is appended to the end
    fprintf(fp,"%s, %.2f , %.2f \n",dataThree,dataTwo,data); // print string to file
    fclose(fp); // close file
    leds = 0; // turn off LEDs to signify file access has finished
}

int menuButtonFlag = 0; /*!< menu button flag set in ISR */

int buttonOneFlag = 0; /*!< Button One flag set in ISR */
int buttonOneAltFlag = 0;  /*!< Button One Alternate flag set in ISR */

void buttonOnePressed()
{
    if(menuButtonFlag > 0) { //if menu button has been pressed and main menu entered
        buttonOneAltFlag = !buttonOneAltFlag;  //set/reset-if-set alternate flag and proceed to next menu
    } 
    else {
        buttonOneFlag = !buttonOneFlag;  //set/reset-if-set flag if not navigated to a menu
    }
}

int buttonTwoFlag = 0; /*!< Button Two flag set in ISR */
int buttonTwoAltFlag = 0; /*!< Button Two Alternate flag set in ISR */

void buttonTwoPressed()
{
    if(menuButtonFlag > 0) {
        buttonTwoAltFlag = !buttonTwoAltFlag;
    } 
    else {
        buttonTwoFlag = !buttonTwoFlag;
    }
}

int buttonThreeFlag = 0; /*!< Button Three flag set in ISR */
int buttonThreeAltFlag = 0; /*!< Button Three Alternate flag set in ISR */

void buttonThreePressed()
{
    if(menuButtonFlag > 0) {
        buttonThreeAltFlag = !buttonThreeAltFlag;
    } 
    else
        buttonThreeFlag = !buttonThreeFlag;
}

void menuButtonPressed()
{
    if(buttonOneAltFlag == 0 && buttonTwoAltFlag == 0 && buttonThreeAltFlag == 0){ //if no flag is set and therefore no menu accessed
        menuButtonFlag++; //increment the flag to access different menu states.

        if(menuButtonFlag > 2) { //if menu button has been clicked three times
            menuButtonFlag = 0; //go back to the measurements menu
        }
    }
}

int splashFlag = 1;  /*!< Splash flag set to continue with program flow for the main function before proceeding with program flow */

/**
Interrupt Service Routine to reset splashFlag when Timeout has been performed.
No parameters to be entered by, or values to be returned to, the user.
*/

void splashDelay()
{
    splashFlag = 0;
}

int dispTimerFlag = 0; /*!< Display flag set to 0 initially. Used to update values on the display when the ISR is called.*/

/**
Interrupt Service Routine to set dispTimerFlag when Ticker duration has elapsed.
No parameters to be entered by, or values to be returned to, the user.
*/
void timerExpiDisplay()
{
    dispTimerFlag = 1;
}

int logTimerFlag = 0; /*!< Log flag set to 0 initially. Used to overwrite the Flash Memory when the ISR is called.*/

/**
Interrupt Service Routine to set logTimerFlag when Ticker duration has elapsed.
No parameters to be entered by, or values to be returned to, the user.
*/
void timerExpiLog()
{
    logTimerFlag = 1;
}

void displayInitSplash()  //display splash screen
{
    lcd.printString("Welcome to",15,1);
    lcd.printString("Portable Weat.",3,2);
    lcd.printString("Station",20,3);
    lcd.printString("by Volkan",20,4);
    lcd.printString("Esendag",20,5);
}

void displayMenuOne(){
    lcd.printString("Settings Menu",0,0);
    lcd.printString("One",0,1);
    lcd.printString("Use Buttons",0,2);
    lcd.printString("To change",0,3);
    lcd.printString("Settings",0,4);
    lcd.refresh();
}

void displayMenuTwo(){
    lcd.printString("Settings Menu",0,0);
    lcd.printString("Two",0,1);
    lcd.printString("Use menuButton",0,2);
    lcd.printString("To Go Back To",0,3);
    lcd.printString("Display menu",0,4);
    lcd.refresh();
}

void displayTempUnit(){
    lcd.printString("Use Button 2",0,0);
    lcd.printString("To decrease",0,1);
    lcd.printString("Temp. Setting;",0,2);
    lcd.printString("Button 3",0,3);
    lcd.printString("To increase.",0,4);
    
    char bufferSt[14];  //buffer to store string
    sprintf(bufferSt,"current:%c",tempUnit[tempUnitSetting]); //write the typed string and the current unit setting onto the buffer
    
    lcd.printString(bufferSt,0,5); //print the buffer
    lcd.refresh();  //needs to refresh to write the string buffers to the display
}

void displayPressUnit(){
    lcd.printString("Use Button 1",0,0);
    lcd.printString("To decrease",0,1);
    lcd.printString("Press Setting;",0,2);
    lcd.printString("Button 3",0,3);
    lcd.printString("To increase.",0,4);
    
    char bufferSt[14];  //buffer to store string
    sprintf(bufferSt,"current:%c",pressUnit[pressUnitSetting]);
    
    lcd.printString(bufferSt,0,5);
    lcd.refresh();
}

void displayDispMenu(){
    lcd.printString("Use Button 2",0,0);
    lcd.printString("To decrease",0,1);
    lcd.printString("Time Setting;",0,2);
    lcd.printString("Button 3",0,3);
    lcd.printString("To increase.",0,4);
    
    char bufferSt[14];  //buffer to store string
    //just a universally applicable if-else if statement to create a string out of current time setting should more time settings be added...
    if(dispInterval[dispSetting].time >= 1.0){ //if time setting is a second or more
        sprintf(bufferSt,"set:%.1f s",dispInterval[dispSetting].time);
    }
    else if(dispInterval[dispSetting].time < 1.0){ //if time setting is less than a second
        float tempTime = dispInterval[dispSetting].time * 1000.0; //convert time to milliseconds
        sprintf(bufferSt,"set:%.1f ms",tempTime);
    }    
    lcd.printString(bufferSt,0,5);
    lcd.refresh();
}

void displayThresholdTemp(){
    lcd.printString("Use Button 1",0,0);
    lcd.printString("To decrease",0,1);
    lcd.printString("Temp Thresh;",0,2);
    lcd.printString("Button 3",0,3);
    lcd.printString("To increase.",0,4);
    
    char bufferSt[14];  //buffer to store string
    sprintf(bufferSt,"current:%.1f",tempThres[tempSetting].thresTemp);
    
    lcd.printString(bufferSt,0,5);
    lcd.refresh();
}

void displayAltitudeUnit(){
    lcd.printString("Use Button 1",0,0);
    lcd.printString("To decrease",0,1);
    lcd.printString("Altitude Set;",0,2);
    lcd.printString("Button 2",0,3);
    lcd.printString("To increase.",0,4);
    
    char bufferSt[14];  //buffer to store string
    sprintf(bufferSt,"current:%c",AltUnit[altUnitSetting]);
    
    lcd.printString(bufferSt,0,5);
    lcd.refresh();
}

//1 bar is 100000 Pa. An atm is 101325 Pa. Therefore an mb is 100 Pa.

int main()
{

    splashFlip.attach(&splashDelay,3.0); //attach timer and wait for ISR to be called

    displayTimer.attach(&timerExpiDisplay,dispInterval[dispSetting].time); //do the same for display dispInterval[dispSetting].time

    //logTimer.attach(&timerExpiLog,recInterval[recSetting].time);

    menuButton.rise(&menuButtonPressed); //event generated on rising edge (a positive spike in voltage), indicated by .rise

    buttonOne.rise(&buttonOnePressed);
    
    buttonTwo.rise(&buttonTwoPressed);
    
    buttonThree.rise(&buttonThreePressed);

    // first need to initialise display
    lcd.init();

    displayInitSplash();

    //initialise barometer
    bmp180.init();

    PHY_PowerDown();    //powers down the Ethernet feature.

    int result = semihost_powerdown();   //as a result, power down the USB connection
    //unless the cable is connected.

    Measurement measurement; // object created for pressure & temperature using the structure declared in BMP180 class

    while(1) {

        if(splashFlag == 0) { //if ISR has been called proceed with program flow
            splashFlip.detach();    //detach Timeout object
            lcd.clear();
            clearCells();
            lcd.refresh(); //need to refresh to write buffer on lcd

            if(dispTimerFlag) {
                //read values (T in degrees Celsius and P in mb).
                measurement = bmp180.readValues();
                temp = measurement.temperature;
                press = measurement.pressure;
                /*formula for calculating altitude from sea level by using atmospheric pressure. Unit in metres.
                Use pow(double a,double b) for indices, not the ^ sign. Just a reminder! Also check out this site:
                http://www.mide.com/products/slamstick/air-pressure-altitude-calculator.php
                */
                altitude = 44330.0*(1.0-(pow((press/PNought),(1.0/5.255))));
                dispTimerFlag = 0;
                
                printReadings();
                lcd.refresh();
            }
            
            if(menuButtonFlag == 1){  //if menu button has been pressed once
                
                lcd.clear();  //clear the lcd display
                displayMenuOne();  //display the menu strings function
                subMenuId = 0; //initially set subMenuId to zero in case it is not
                while(buttonOneAltFlag){ //if Button One is pressed AND the menu button is;
                    if(subMenuId == 0){  //if initially the UI wasn't in a sub-menu
                        lcd.clear(); //clear lcd
                    }
                    displayTempUnit();  //display unit change menu
                    lcd.refresh();
                    //this helps avoid vertical swipe blurs and re-overwrites on the display while in sub-menu.
                    subMenuId = 1; //set sub-menu number to avoid confusions for the processor as it might change other settings!
                        
                    if(buttonTwoAltFlag && subMenuId == 1){  //if added to the above conditions button 2 is pressed
                        tempUnitSetting--;  //decrease the unit setting
                        buttonTwoAltFlag = 0;  //reset flag to avoid repeated unit changes on loop
                        if(tempUnitSetting < 0)  //if it goes below 0
                            tempUnitSetting = 3; //go back to the highest value
                    }
                    if(buttonThreeAltFlag && subMenuId == 1){  //if otherwise button 3 has been pressed
                        tempUnitSetting++;  //increase temp setting
                        buttonThreeAltFlag = 0;
                        if(tempUnitSetting > 3)  //if the upper limit has been exceeded (3)
                            tempUnitSetting = 0;  //reset it to zero
                    }
                } //close button one alt
                buttonOneAltFlag = 0;
                lcd.clear();
                displayMenuOne();  //display the menu strings function
                subMenuId = 0; //reset sub-menu ID when loop has finished executing so it can be applied to other sub-menus.
                
                while(buttonTwoAltFlag){ //if Button Two flag is set AND the menu button is;
                    if(subMenuId == 0){
                        lcd.clear(); //clear lcd
                    }
                    displayPressUnit();  //display unit change menu
                    lcd.refresh();    
                    subMenuId = 2;
                    
                    if(buttonOneAltFlag && subMenuId == 2){  //if added to the above conditions button 1 is pressed
                        pressUnitSetting--;  //decrease the unit setting
                        buttonOneAltFlag = 0;  //reset flag to avoid repeated unit changes on loop
                        if(pressUnitSetting < 0)  //if it goes below 0
                            pressUnitSetting = 2; //go back to the highest value
                    }
                    if(buttonThreeAltFlag && subMenuId == 2){  //if otherwise button 3 has been pressed
                        pressUnitSetting++;  //increase pressure setting
                        buttonThreeAltFlag = 0;
                        if(pressUnitSetting > 2)  //if the upper limit has been exceeded (2)
                            pressUnitSetting = 0;  //reset it to zero
                    }
                } //close button two alt
                buttonTwoAltFlag = 0;
                lcd.clear();
                displayMenuOne();  //display the menu strings function
                subMenuId = 0;
            } //close menu button flag
            
            subMenuId = 0; //reset sub-menu ID after going through first menu in case it is not already
            if(menuButtonFlag == 2){  //if menu button has been pressed twice
                
                lcd.clear();  //clear the lcd display
                displayMenuTwo();  //display the menu strings function
                while(buttonOneAltFlag){ //if Button One is pressed AND the menu button is;
                    if(subMenuId == 0){
                        lcd.clear(); //clear lcd
                    }
                    displayDispMenu();  //display unit change menu
                    lcd.refresh();
                    subMenuId = 4;
                    lcd.refresh();
                    if(buttonTwoAltFlag && subMenuId == 4){  //if added to the above conditions button 2 is pressed
                        dispSetting--;  //decrease setting
                        buttonTwoAltFlag = 0;  //reset flag to avoid repeated unit changes on loop
                        if(dispSetting < 0)  //if it goes below 0
                            dispSetting = 5; //go back to the highest value
                    }
                    if(buttonThreeAltFlag && subMenuId == 4){  //if otherwise button 3 has been pressed
                        dispSetting++;  //increase setting
                        buttonThreeAltFlag = 0;
                        if(dispSetting > 5)  //if the upper limit has been exceeded (3)
                            dispSetting = 0;  //reset it to zero
                    }
                } //close button one alt
                buttonOneAltFlag = 0;
                lcd.clear();  //clear the lcd display
                displayMenuTwo();  //display the menu strings function
                subMenuId = 0;
                
                while(buttonTwoAltFlag){ //if Button Two flag is set AND the menu button is;
                    if(subMenuId == 0){
                        lcd.clear(); //clear lcd
                    }
                    displayThresholdTemp();  //display unit change menu
                    lcd.refresh();
                    subMenuId = 5;
                    if(buttonOneAltFlag && subMenuId == 5){  //if added to the above conditions button 1 is pressed
                        tempSetting--;  //decrease setting
                        buttonOneAltFlag = 0;  //reset flag to avoid repeated unit changes on loop
                        if(tempSetting < 0)  //if it goes below 0
                            tempSetting = 4; //go back to the highest value
                    }
                    if(buttonThreeAltFlag && subMenuId == 5){  //if otherwise button 3 has been pressed
                        tempSetting++;  //increase setting
                        buttonThreeAltFlag = 0;
                        if(tempSetting > 4)  //if the upper limit has been exceeded (2)
                            tempSetting = 0;  //reset it to zero
                    }
                } //close button two alt
                buttonTwoAltFlag = 0;
                lcd.clear();  //clear the lcd display
                displayMenuTwo();  //display the menu strings function
                subMenuId = 0;
                
                while(buttonThreeAltFlag){ //if Button Three flag is set AND the menu button is;
                    if(subMenuId == 0){
                        lcd.clear(); //clear lcd
                    }
                    displayAltitudeUnit();  //display unit change menu
                    lcd.refresh();
                    subMenuId = 6;
                    if(buttonOneAltFlag && subMenuId == 6){  //if added to the above conditions button 1 is pressed
                        altUnitSetting--;  //decrease the unit setting
                        buttonOneAltFlag = 0;  //reset flag to avoid repeated unit changes on loop
                        if(altUnitSetting < 0)  //if it goes below 0
                            altUnitSetting = 2; //go back to the highest value
                    }
                    if(buttonTwoAltFlag && subMenuId == 6){  //if otherwise button 2 has been pressed
                        altUnitSetting++;  //increase pressure setting
                        buttonTwoAltFlag = 0;
                        if(altUnitSetting > 2)  //if the upper limit has been exceeded (2)
                            altUnitSetting = 0;  //reset it to zero
                    }
                } //close button three alt
                buttonThreeAltFlag = 0;
                lcd.clear();  //clear the lcd display
                displayMenuTwo();  //display the menu strings function
                subMenuId = 0;
            } //close menu button flag
            


            Sleep();  //put the mbed to sleep once the program flow has been completed.


        } //close if
    } //close while
} //terminate main()

/**
Fetches readings from the sensor via the main() function and calculates altitude from pressure data.
Then prints them on the screen.
@param temp - temperature reading from the BMP180(˚C).
@param press - pressure reading from the BMP180(mb).
@param altitude - altitude calculated from the pressure reading (m).
*/

void printReadings()
{
    char buffer[14];  // each character is 6 pixels wide, screen is 84 pixels (84/6 = 14)
    // so can display a string of a maximum 14 characters in length
    // or create formatted strings - ensure they aren't more than 14 characters long
    
    if(tempUnitSetting == 0){ //if Celsius has been selected as the temperature unit
        int length = sprintf(buffer,"T = %.2f 'C",temp); // 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
            lcd.printString(buffer,0,1);  // display on screen. Column 0, row 1.
        }
    } //close unit setting 0
    else if(tempUnitSetting == 1){ //Fahrenheit
        float tempTemp = (temp*1.8) + 32;
        int length = sprintf(buffer,"T = %.2f F",tempTemp); // 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
            lcd.printString(buffer,0,1);  // display on screen. Column 0, row 1.
        }
    } //close unit setting 1
    else if(tempUnitSetting == 2){ //Kelvin
        float tempTemp = temp + 273.15;
        int length = sprintf(buffer,"T = %.1f K",tempTemp); // 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
            lcd.printString(buffer,0,1);  // display on screen. Column 0, row 1.
        }
    } //close unit setting 2
    
    else if(tempUnitSetting == 3){ //Rankine
        float tempTemp = (temp + 273.15)*1.8;
        int length = sprintf(buffer,"T = %.1f 'R",tempTemp); // 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
            lcd.printString(buffer,0,1);  // display on screen. Column 0, row 1.
        }
    } //close unit setting 3
    
    if(pressUnitSetting == 0){ //if pressure is to be displayed in mb
        int length = sprintf(buffer,"P = %.2f mb",press); //use single letters to represent parameters or string may not fit in the banks!
        if (length <= 14) {
            lcd.printString(buffer,0,2); // Column 0, row 2.
        }
    } //close unit setting 0
    
    else if(pressUnitSetting == 1){ //Pa
        float tempPress = press*100; //convert from mb to Pa
        int length = sprintf(buffer,"P = %.0f Pa",tempPress); //use single letters to represent parameters or string may not fit in the banks!
        if (length <= 14) {
            lcd.printString(buffer,0,2); // Column 0, row 2.
        }
    } //close unit setting 1
    else if(pressUnitSetting == 2){ //atm
        float tempPress = press/1013.25; //an atm is 1013.25 mb; therefore dividing press by that gives pressure in atm.
        int length = sprintf(buffer,"P = %.1f atm",tempPress); //use single letters to represent parameters or string may not fit in the banks!
        if (length <= 14) {
            lcd.printString(buffer,0,2); // Column 0, row 2.
        }
    } //close unit setting 2
    
    //Now for the altitude display settings. Bear in mind that a metre is 3.2808399 feet; or 1.0936133 yards. Three feet equals a yard.
    if(altUnitSetting == 0){ //if metres have been selected
        int length = sprintf(buffer,"A = %.1f m",altitude);
        if (length <= 14) {
            lcd.printString(buffer,0,3);  //Column 0, row 3.
        }
    } // close unit setting 0
    else if(altUnitSetting == 1){ //feet
        float tempAlt = altitude*3.2808399; //convert to feet
        int length = sprintf(buffer,"A = %.1f ft",tempAlt);
        if (length <= 14) {
            lcd.printString(buffer,0,3);  //Column 0, row 3.
        }
    } //close unit setting 1
    else if(altUnitSetting == 2){ //yards
        float tempAlt = altitude*1.0936133; //convert to yards
        int length = sprintf(buffer,"A = %.1f ft",tempAlt);
        if (length <= 14) {
            lcd.printString(buffer,0,3);  //Column 0, row 3.
        }
    } //close unit setting 2
    
    
    if (press++) {
        lcd.printString("Hotter Weather",2,4); //column 2, row 4.
        lcd.printString("On the Way!",2,5);   //column 2 , row 5.
    } 
    else if (press--) {
        lcd.printString("The temperature",2,4); //column 2, row 4.
        lcd.printString("is predicted",2,5);   //column 2 , row 5.
        lcd.printString("to fall!",2,6); //column 2, row 4.
    }
}

void clearCells()
{
    //loop through cells, and clear them
    for (int i = 0; i < 83 ; i++) {
        for (int j = 0; j < 47; j++) {
            lcd.clearPixel(i,j);         //function to "kill" all cells after looping through.
        }
    }
    lcd.refresh(); //must refresh to write buffer to display
}