1

Background:

I am using a Teensy 3.6 to data log over a dozen sensors. I am printing to Serial1 for local Serial access, Serial3 for remote access (via xbee, same data is on Serial1 as on Serail3, just different physical connection) as well as datalog to SDCard (CSV format). My code is expanding and is incredibly repetitive, and I am looking for a more efficient way of writing the following. I am trying to move a lot of the rest of my code to classes using this and this tutorial, but I'm not sure this is the best option for the datalogging as there are many more strings in this portion.

The variables we are dealing with:

  • Live sensor value (eOilTempF)
  • A visual flag for if the sensor is out of bounds (checkEngine)
  • A auditory alarm if it's further out of bounds (eOilTempAlarm)
  • The max value we've recorded (engineOilStats.maximum())
  • The minimum value (engineOilStats.minimum())

As well as all the little bits to make it attractive and human readable for the Serial stuff.

Code:

Local serial:

Serial.print("Engine Oil Temp:\t");
Serial.print(eOilTempF);
Serial.print("F\t   ");
Serial.print("Flag: ");
Serial.print(checkEngine);
Serial.print("\t Alarm:");
Serial.print(eOilTempAlarm);
Serial.print("\tMAX: ");
Serial.print(engineOilStats.maximum());
Serial.print(" F");
Serial.print("\t\t\t\tAVG: ");
Serial.print(engineOilStats.average());
Serial.println(" F");

Xbee serial:

Serial3.print("Engine Oil Temp:\t");
Serial3.print(eOilTempF);
Serial3.print("F\t   ");
Serial3.print("Flag: ");
Serial3.print(checkEngine);
Serial3.print("\t Alarm:");
Serial3.print(eOilTempAlarm);
Serial3.print("\tMAX: ");
Serial3.print(engineOilStats.maximum());
Serial3.print(" F");
Serial3.print("\t\t\t\tAVG: ");
Serial3.print(engineOilStats.average());
Serial3.println(" F");

SD Card Logging:

logfile.print(eOilTempF);
logfile.print(",");
logfile.print(checkEngine);
logfile.print(",");
logfile.print(engineOilStats.maximum());
logfile.print(",");
logfile.print(engineOilStats.average());
logfile.print(",");

tl;dr

My datalogging section of my sketch is 567 lines of mostly repeated code, and I'm new at programming and need some tutorials/terms to google to make it more effecient.

5
  • put the two serial prints and the datalog into one function ... call the function for each parameter to be logged ... use an array for the text ... pass parameter value and index to text to the function ... log(1, eOilTempF); ... 1 points to Engine Oil Temp:\t – jsotola Aug 9 '20 at 18:23
  • IIRC there's a library around that lets you use << with Serial. I can't recall what it's called though and my google-fu isn't strong enough. – Majenko Aug 9 '20 at 18:25
  • simplify code by using an array to hold values ... e[ OilTempF ] instead of eOilTempF ... that way you can loop through values – jsotola Aug 9 '20 at 18:31
  • @Majenko Streaming might be what you're talking about: github.com/janelia-arduino/Streaming. This would help a lot with taking out all of the Serial.print and extra lines, but it would still be duplicated code between Serial, Serial3, and Logfile – TheAutomator Aug 9 '20 at 18:31
  • @TheAutomator Yeah, that's the one. It would certainly make each block smaller, and you may be able to use it with a wrapper class that mirrors the output to two serial devices. – Majenko Aug 9 '20 at 18:33
1

You can combine the Streaming library with a wrapper class that sends data to multiple serial destinations.

Here's a little example:

#include <Streaming.h>

class DualSerial : public Print {
    private:
        Print *_dev1;
        Print *_dev2;

    public:
        DualSerial(Print &s1, Print &s2) : _dev1(&s1), _dev2(&s2) {}

        size_t write(uint8_t c) {
            _dev1->write(c);
            _dev2->write(c);
        }      
};

DualSerial remote(Serial, Serial3);

void setup() {
    Serial.begin(115200);
    Serial3.begin(115200);
}

void loop() {
    // Both Serial and Serial3 will receive this
    remote << "The time is: " << millis() << endl;
    delay(1000);
}

The Streaming class will work with anything that inherits from the Print class, which includes the SD card's File class, so you can also use it for writing to the SD card:

logfile << eOilTempF << "," 
        << checkEngine << "," 
        << engineOilStats.maximum() << ","
        << engineOilStats.average() << endl;
2
  • You don't need to use pointers, eg. DualSerial(Print & s1, Print & s2) : _dev1(s1), _dev2(s2) {} and change the member variables to Print & _dev1; Print & _dev2;. In the write function change -> to .. You can initialise a reference in a constructor. – Nick Gammon Aug 9 '20 at 22:10
  • 1
    @NickGammon I know. But I like using pointers. – Majenko Aug 9 '20 at 22:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.