Home › Forums › Mayfly Data Logger › Logging to SD Card More than Two Decimal Places
- This topic has 2 replies, 2 voices, and was last updated 2019-08-27 at 9:50 PM by Drew.
-
AuthorPosts
-
-
2019-08-23 at 5:18 PM #13114
Hello,
I am trying to read a voltage from a low-cost turbidity sensor, and log that to an SD Card. It is set as a float value (it is <float turbvoltage> in the code below, about 43 lines down when counting spaces), so only outputs to two decimal places when logging to the SD Card (near the end of the code string). I would like to get it to output three decimal places when logging, but I have not seen anything out there on how to do that. I know there is a way to get it to output to more decimal places on the serial monitor with the Serial.Print function, but that value does not log to the SD Card and nothing else I have tried works. I will paste my code below (I apologize if it is a little messy, I am somewhat new to this):
Arduino123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298#include <Wire.h>#include <avr/sleep.h>#include <avr/wdt.h>#include <SPI.h>#include <SD.h>#include <RTCTimer.h>#include <Sodaq_DS3231.h>#include <Sodaq_PcInt.h>#include <SeeedGrayOLED.h>#include <avr/pgmspace.h>RTCTimer timer;//RTC Interrupt pin#define RTC_PIN A7#define RTC_INT_PERIOD EveryMinute//Digital pin 12 is the MicroSD slave select pin on the Mayfly#define SD_SS_PIN 12//The data log file#define FILE_NAME "BaTurbE.txt"//Data header (these lines get written to the beginning of a file when it's created)#define LOGGERNAME "Mayfly Kelly Lake"#define DATA_HEADER "SampleNumber, Battery_volts, TurbSens_volts, intT_degC, date_Time"int currentminute;long currentepochtime = 0;int sampleinterval = 3; //time between samples, in secondsint delayTime = 500; //milliseconds, used for green LED flash at sample timeint samplenum = 1; // declare the variable "samplenum" and start with 1int batteryPin = A6; // on the Mayfly board, pin A6 is connected to a resistor divider on the battery inputint batterysenseValue = 0; // variable to store the value coming from the analogRead function at pin A6float batteryvoltage; // the battery voltage as calculated by the formula belowint TurbSens; // variable to store the value coming from the analogRead function at pin A0float turbvoltage; // the turbidity sensor voltage as calculated by the formula belowvoid setDisplayToOriginalState(){SeeedGrayOled.init(SH1107G);}void setup(){pinMode(22, OUTPUT); //pin D22 is the enable line for the Mayfly's switched 3.3/5v power lines//digitalWrite(22, HIGH); //set this pin high and leave it on for the rest of the sketchpinMode(8, OUTPUT); // declare the Green ledPin as an OUTPUTrtc.begin(); // read internal temperature//Initialise the serial connectionSerial.begin(57600);//Initialise log filesetupLogFile();setupTimer(); //Setup timer eventssetupSleep(); //Setup sleep mode//Echo the data header to the serial connectionSerial.println(DATA_HEADER);Wire.begin();}void loop(){//Update the timertimer.update();if(currentminute % 2 == 0) // change "2" to "5" to wake up logger every 5 minutes instead{ Serial.println("Multiple of 2! Initiating sensor reading and logging data to SDcard....");digitalWrite(8, HIGH); // turn the Green ledPin on//delay(delayTime);//digitalWrite(8, LOW);digitalWrite(22, HIGH); //set this pin highdelay(delayTime);digitalWrite(22, LOW);digitalWrite(8, LOW);String dataRec = createDataRecord();//Save the data record to the log filelogData(dataRec);//Echo the data to the serial connectionSerial.println(dataRec);}setDisplayToOriginalState();SeeedGrayOled.clearDisplay(); //Clear Display.SeeedGrayOled.setNormalDisplay(); //Set Normal Display ModeSeeedGrayOled.setVerticalMode(); // Set to vertical mode for displaying textfor(char i=0; i < 16 ; i++)SeeedGrayOled.setGrayLevel(15); //Set Grayscale level. Any number between 0 - 15.SeeedGrayOled.setTextXY(0,0); //Set the cursor to 0th line, 0th ColumnSeeedGrayOled.putNumber(samplenum); //Print numberSeeedGrayOled.setTextXY(1,0); //Set the cursor to 1st line, 0th ColumnSeeedGrayOled.putNumber(batteryvoltage); //Print numberSeeedGrayOled.setTextXY(2,0); //Set the cursor to 2nd line, 0th ColumnSeeedGrayOled.putNumber(turbvoltage); //Print numberdelay(10000);delay(sampleinterval*1000); //multiply by 1000 to convert from milliseconds to seconds//SleepsystemSleep();}void showTime(uint32_t ts){//Retrieve and display the current date/timeString dateTime = getDateTime();Serial.println(dateTime);}void setupTimer(){//Schedule the wakeup every minutetimer.every(1, showTime);//Instruct the RTCTimer how to get the current time readingtimer.setNowCallback(getNow);}void wakeISR(){//Leave this blank}void setupSleep(){pinMode(RTC_PIN, INPUT_PULLUP);PcInt::attachInterrupt(RTC_PIN, wakeISR);//Setup the RTC in interrupt modertc.enableInterrupts(RTC_INT_PERIOD);//Set the sleep modeset_sleep_mode(SLEEP_MODE_PWR_DOWN);}void systemSleep(){//This method handles any sensor specific sleep setupsensorsSleep();//Wait until the serial ports have finished transmittingSerial.flush();Serial1.flush();//The next timed interrupt will not be sent until this is clearedrtc.clearINTStatus();//Disable ADCADCSRA &= ~_BV(ADEN);//Sleep timenoInterrupts();sleep_enable();interrupts();sleep_cpu();sleep_disable();//Enbale ADCADCSRA |= _BV(ADEN);//This method handles any sensor specific wake setup// sensorsWake();}void sensorsSleep(){//Add any code which your sensors require before sleep}//void sensorsWake()//{// //Add any code which your sensors require after waking//}String getDateTime(){String dateTimeStr;//Create a DateTime object from the current timeDateTime dt(rtc.makeDateTime(rtc.now().getEpoch()));currentepochtime = (dt.get()); //Unix time in secondscurrentminute = (dt.minute());//Convert it to a Stringdt.addToString(dateTimeStr);return dateTimeStr;}uint32_t getNow(){currentepochtime = rtc.now().getEpoch();return currentepochtime;}void setupLogFile(){//Initialise the SD cardif (!SD.begin(SD_SS_PIN)){Serial.println("Error: SD card failed to initialise or is missing.");//Hang// while (true);}//Check if the file already existsbool oldFile = SD.exists(FILE_NAME);//Open the file in write modeFile logFile = SD.open(FILE_NAME, FILE_WRITE);//Add header information if the file did not already existif (!oldFile){logFile.println(LOGGERNAME);logFile.println(DATA_HEADER);}//Close the file to save itlogFile.close();}void logData(String rec){//Re-open the fileFile logFile = SD.open(FILE_NAME, FILE_WRITE);//Write the CSV datalogFile.println(rec);//Close the file to save itlogFile.close();}String createDataRecord(){//Create a String type data record in csv format//SampleNumber, Battery, TurbSens, Temp degCString data = "";data += samplenum; //creates a string called "data", put in the sample numberdata += ", "; //adds a comma between valuesbatterysenseValue = analogRead(batteryPin); // reads the analog voltage on the batteryPin, reported in bitsbatteryvoltage = (3.3/1023.) * 4.7 * batterysenseValue; // converts bits into volts (for Mayfly v0.5 and v0.5b)data += batteryvoltage; //adds the battery voltage to the data stringTurbSens = analogRead(A0); // read the input on analog pin 0turbvoltage = (TurbSens * 5.0 / 1023.0); // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5.0V):data += ", ";data += turbvoltage; //adds the turbidity sensor voltage to the data stringrtc.convertTemperature(); //convert current temperature into registersdata += ", ";data += (rtc.getTemperature()); //read registers and add temperature to data string//Create a String type data record in csv format//SampleNumber, BatteryDateTime now = rtc.now(); //get the current date-time//data += samplenum; //creates a string called "data", put in the sample numberdata += ", ";data += now.month(), DEC;data += "/";data += now.date(), DEC;data += "/";data += now.year(), DEC;data += " ";data += now.hour(), DEC;data += ":";data += now.minute(), DEC;data += ":";data += now.second(), DEC;data += " ";samplenum++; //increment the sample numberreturn data;}If anyone could help, it would be greatly appreciated.
-
2019-08-23 at 7:12 PM #13115
I edited your post to move the sketch code into code snippet box. Next time, use the “Add Code Snippet” button at the top of the text editor box when you’re writing a post or comment. It makes it much easier to read, especially for long sketches.
It’s very easy to add an integer or characters to a string, you did it correctly with the line 263: data += samplenum
However, that only works for integers and characters (or words). But you can’t do that with floating point numbers. To add a floating point number to a string, the best way to do that is with a separate generic function you can paste into the very bottom of any of your sketches:Arduino123456static void addFloatToString(String & str, float val, char width, unsigned char precision){char buffer[10];dtostrf(val, width, precision, buffer);str += buffer;}So then anytime you want to add floating point numbers (like batteryvoltage and turbvoltage) to your data string, just use these lines:
Arduino123addFloatToString(data, batteryvoltage, 4, 2);data += ",";addFloatToString(data, turbvoltage, 6, 4);Notice that you can adjust the number of significant digits (numbers after the decimal point) by changing the value for precision.
You can see an example of how I did all this in the Sleeping Mayfly Logger example on the sample code page:Also something to note, in line 269 you have 5.0 in the formula for the board voltage, but that should be 3.3 since the Mayfly board voltage is 3.3, and not 5 like in most other Arduino boards. Are you powering your turbidity sensor with 3.3v or 5v, and what is the output voltage range of your sensor? Feeding anything greater than 3.3v back into the analog input pin (A0 in your code) will damage the Mayfly, so you should either use a voltage divider or some other method to protect the Mayfly from excessive input voltage on the analog input.
Also, another fun trivia fact, if you simply want to print a float to the serial monitor, you don’t have to use the special function above, it’s only for adding floats to strings. To print a float to the serial monitor, just do this:
Serial.print(voltage);
But if you wanted to see 4 significant digits, do this:
Serial.print(voltage,4);
The default precision for printing a number in Arduino is only 2 significant digits. So if you want anything more than that, just put a comma followed by the number of places you want to see. It’s a handy trick to know, but not mentioned widely enough that it is common knowledge.
-
2019-08-27 at 9:50 PM #13123
Hello,
Thank you for the quick reply and the information. This was exactly what we were looking for, and now we are getting the data that we need. Thank you for your help.
-
-
-
AuthorPosts
- You must be logged in to reply to this topic.