/* pfodUnoIRTempMenus Control your IR Temperature Meter from your Android mobile see www.pfod.com.au for other projects (c)2013 Forward Computing and Control Pty. Ltd. This code may be freely used for both private and commerical use. Provide this copyright is maintained. NOTE: This sketch uses Interrupt 1 and pins D2,D3,D4 */ #include "pfodIRTemp.h" #include "pfodEEPROM.h" #include "pfodParser.h" pfodIRTemp irTemp; // construct class to handle sensor pfodParser parser; // construct the pfod passer int lastTemperatureReading = 0; bool fahrenheit = false; // set to true for Farinheit instead of Celsius int lastAveragedTemperatureReading = 0; #define MAX_INITIAL_NO_SAMPLES 5 #define MAX_AVERAGE_BUFFER_SIZE (2< 8 sample in average, zero based 2 4 8 16 32 are the choices MUST be < MAX_INITIAL_NO_SAMPLES volatile int numberOfAverages = 2 << idxNoSamples; // numberOfAverages MUST be < MAX_AVERAGE_BUFFER_SIZE // max size of buffer is 32 // int reading for 25degC is 4770 // int reading for 200degC is 7568 // int is 65535 i.e. ~8.6 times 200degC // so need to use long for average so it does not over flow struct average_buffer_struct { unsigned int buffer[MAX_AVERAGE_BUFFER_SIZE]; unsigned int idx; long average; } average_buffer; /** switch between Fahrenheit and Celsius */ void switchScale() { fahrenheit = !fahrenheit; // toggle from fahrenheit to celsius } // send the main menu based with last Temp Reading void sendMainMenu() { Serial.print(F("{" // start message ".")); // tell pfodApp this is a menu screen sendMainMenuWithLatestTemp(); } // send the update to main menu void sendMainMenuUpdate() { Serial.print(F("{" // start message ":")); // tell pfodApp this is an update to the existing menu screen sendMainMenuWithLatestTemp(); } void sendMainMenuWithLatestTemp() { Serial.print(F("IR Temperature Sensor" // display name of menu "`1000" // tell pfodApp to re-request again this menu after 1sec "|t~IR Temperature\n")); // first menu item temp + reading if (fahrenheit) { Serial.print(irTemp.convertToFahrenheit(lastTemperatureReading)); Serial.print(F("\u2109")); } else { Serial.print(irTemp.convertToCelsius(lastTemperatureReading)); Serial.print(F("\u2103")); } Serial.print(F("|a~IR Average\n")); // secondt menu item avg + reading if (fahrenheit) { Serial.print(irTemp.convertToFahrenheit(lastAveragedTemperatureReading)); Serial.print(F("\u2109")); } else { Serial.print(irTemp.convertToCelsius(lastAveragedTemperatureReading)); Serial.print(F("\u2103")); } Serial.print(F("|c~Switch to ")); // next menu item if (fahrenheit) { Serial.print(F("\u2103")); } else { Serial.print(F("\u2109")); } Serial.print(F("|s~Show readings" // next menu item "|n~Set number readings to be averaged" // last menu item "}")); // close message } // send the screen to let the user select the Number of Reading to Average void sendNumberReadingToAverageMenu() { Serial.print(F("{?m`")); // single selection list returns index of selection 0 to n Serial.print(idxNoSamples); // current selection Serial.print(F("~Set number of samples to be averaged" // prompt "|Average 2 Readings|Average 4 Readings|Average 8 Readings|Average 16 Readings|Average 32 Readings" // choices "}")); } // set the new number of readings to be averaged // index goes from 0 to 4 // for samples 2 to 32 void setNoReadingsToAverage(int indexSelected) { numberOfAverages = 2 << indexSelected; // re-initialize the average clearAverage(lastTemperatureReading); } // add a new reading and return the new average deg K * 16 int average(int nextReading) { if (nextReading <= 0) { // invalid reading skip this one return (int)(average_buffer.average / numberOfAverages); // return last average } if (average_buffer.buffer[0] == 0) { // fill with this reading to start with clearAverage(nextReading); } int i = (unsigned int)(average_buffer.idx + 1) % numberOfAverages; average_buffer.idx = i; average_buffer.average = average_buffer.average - average_buffer.buffer[i]; average_buffer.buffer[i] = (long)nextReading; average_buffer.average = average_buffer.average + nextReading; return (int)(average_buffer.average / numberOfAverages); } // this method lets the user clear out the old averages int clearAverage(int startingReading) { if (startingReading < 0) { // invalid so just use 0 startingReading = 0; // seting zero in location [0] will force re-set on first valid reading } for (int i = 0; i < MAX_AVERAGE_BUFFER_SIZE; i++) { average_buffer.buffer[i] = startingReading; } average_buffer.idx = 0; average_buffer.average = ((long)startingReading) * numberOfAverages; } void setup() { Serial.begin(9600); for (int i = 3; i > 0; i--) { // wait a few secs to see if we are being programmed delay(1000); } parser.connect(&Serial); // connect the parser to the i/o stream } } void loop() { byte cmd = parser.parse(); if (cmd != 0) { // got something if (cmd == '.') { // main menu request sendMainMenu(); } else if (cmd == 'c') { switchScale(); sendMainMenuUpdate(); } else if (cmd == (byte)'a') { // clear the average to current temp clearAverage(lastTemperatureReading); sendMainMenuUpdate(); // send updated menu with new average } else if (cmd == 's') { // open Streaming Raw Data screen Serial.print(F("{=IR Temp Readings\n use BACK button to return\n to main menu}")); } else if (cmd == (byte)'n') { sendNumberReadingToAverageMenu(); } else if (cmd == (byte)'m') { byte* idxPtr = parser.getFirstArg(); // parse 1 arg as a number long longResult; parser.parseLong(idxPtr, &longResult); // only one arg idxNoSamples = (byte)longResult; // update current selection setNoReadingsToAverage((int)idxNoSamples); // set new average Serial.print(F("{}")); // always respond or pfodApp will timeout } else { // we don't handle message Serial.print(F("{}")); // BUT always respond or pfodApp will timeout } } irTemp.triggerSensor(); int reading = irTemp.getIRTemperature(); if (reading != pfodIRTemp::NO_DATA) { // have a reading Serial.print(millis() / 1000.0); // output secs since restart Serial.print(F(",Sec,")); // csv comma separator lastTemperatureReading = reading; // save reading for main menu if (reading < pfodIRTemp::NO_DATA) { if (reading == pfodIRTemp::INVALID_DATA) { Serial.println(F(" ,Invalid Reading")); } else { Serial.println(F(" ,Sensor Not Responding")); } } else { // reading valid if (fahrenheit) { // send raw reading not averaged Serial.print(irTemp.convertToFahrenheit(reading)); Serial.println(F(",F")); } else { Serial.print(irTemp.convertToCelsius(reading)); Serial.println(F(",C")); } lastAveragedTemperatureReading = average(reading); // average this one also } } }