Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BMP180 N5110 PowerControl mbed
main.cpp
- Committer:
- Volcano_498
- Date:
- 2015-04-13
- Revision:
- 5:6d85cafa1085
- Parent:
- 4:da904413485a
- Child:
- 6:0aca5c17c988
File content as of revision 5:6d85cafa1085:
/**
@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) / 13 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
};
/**
@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;
/*
@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();
void clearCells();
float temp = 0.0;
float press = 0.0;
float altitude = 0.0;
int i = 0;
int j = 0;
int dispSetting = 0; //set display setting to default.
int recSetting = 3; //set log setting to default.
int tempSetting = 2; //set temperature threshold to default.
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 */
void menuButtonPressed()
{
menuButtonFlag = !menuButtonFlag; //if set to 1, set it back to 0. If not set, set the flag.
}
int buttonOneFlag = 0; /*!< Button One flag set in ISR */
int buttonOneAltFlag = 0; /*!< Button One Alternate flag set in ISR */
void buttonOnePressed()
{
if(menuButtonFlag) { //if menu button has been pressed and main menu entered
menuButtonFlag = 0; //set menu button flag to 0 so that one can proceed to the temperature setting menu and go back by pressing again
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) {
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;
}
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 = 0;
}
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);
}
//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,1.0); //do the same for display dispInterval[dispSetting].time
logTimer.attach(&timerExpiLog,recInterval[recSetting].time); //do the same for logging
// 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();
if(dispTimerFlag) {
dispTimerFlag = 0;
//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
Also to bear in mind is that a metre is 3.2808399 feet; or 1.0936133 yards. Three feet equals a yard.
*/
altitude = 44330.0*(1.0-(pow((press/PNought),(1.0/5.255))));
printReadings();
lcd.refresh();
}
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
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.
}
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.
}
length = sprintf(buffer,"A = %.1f m",altitude);
if (length <= 14) {
lcd.printString(buffer,0,3); //Column 0, row 3.
}
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
}