Program the Feather M0 datalogger via Arduino IDE to read and record 1-6 thermocouple probes.
This sketch provides subroutines to complete the following operations with a Feather M0 Adalogger:
https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
)The sketch assumes the wiring is like so:
The following libraries contain necessary functions. All are available through the Arduino IDE.
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include <Adafruit_MAX31855.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "RTClib.h"
First, the OLED screen and the real-time clock:
Adafruit_SSD1306 oled = Adafruit_SSD1306();
RTC_DS3231 rtc;
Define two integer counters and the logging interval (milliseconds):
int StartSec = 0;
int counter = 0;
int LogInt = 250 ;
The Feather M0 Adalogger communicates with its microSD card on pin 4:
const int chipSelect = 4;
If monitoring the inner case temperature is desired, the sketch reads a TMP36 on A0
:
int TempSense = A0 ;
Identify the thermocouple inputs.
This sketch is written for 6 (K-type) thermocouples connected to MAX3185 breakout boards. Users can reduce or increase the number of probes as desired.
#define DO 10
#define CLK 12
#define CS1 A1
#define CS2 A2
#define CS3 A3
#define CS4 A4
#define CS5 A5
#define CS6 6
// Set number of thermocouples
int i ;
int SensNum =7; // n + 1
double temp[7];
Initialize thermocouples. The Adafruit functions will do all of the Seebeck effect maths and return the temperature in degrees C.
Adafruit_MAX31855 thermocouple1(CLK, CS1, DO);
Adafruit_MAX31855 thermocouple2(CLK, CS2, DO);
Adafruit_MAX31855 thermocouple3(CLK, CS3, DO);
Adafruit_MAX31855 thermocouple4(CLK, CS4, DO);
Adafruit_MAX31855 thermocouple5(CLK, CS5, DO);
Adafruit_MAX31855 thermocouple6(CLK, CS6, DO);
Create an object called SixLoggerData
for data storage:
struct dataStruct{
String timestamp ;
float tc1 ;
float tc2;
float tc3 ;
float tc4 ;
float tc5 ;
float tc6 ;
float CaseTempC ;
}SixLoggerData;
Turn everything on via initialization sub-routines
If testing the system while connected to a computer, one can uncomment while (!Serial);
to have the sketch wait until Serial port is ready.
void setup() {
// while (!Serial);
Serial.begin(115200);
oledInit() ;
rtc.begin();
RTCcheck();
SDcheck() ;
delay(100);
}
For brevity, the sketch calls a series of sub-routines (described below) in this order:
void loop() {
TimeStamper();
CaseTemp() ;
TempStruct6() ;
TempLog() ;
oledSixLogger() ;
SerialDisplay() ;
delay(LogInt) ;
}
These subroutines are called in this order in setup()
.
Initialize the OLED display:
void oledInit (void) {
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); // I2C addr 0x3C
oled.display();
delay(500);
oled.clearDisplay();
oled.display();
}
Check the real-time clock (RTC). In case the RTC has lost power (if the coin battery died or was pulled out), this part of the sketch is supposed to reset to the current time. If you have issues with incorrect timestamps, I have another sketch on GitHub that I use to force the RTC to reset, and then I go back to the FeatherFlame sketch we’re going through here.
void RTCcheck (void) {
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power. Resetting date/time.");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
DateTime now = rtc.now();
Serial.println("Date/time updated. Current date/time from new reference: ");
Serial.print(now.year(), DEC); Serial.print('-');
if (now.month() <10) Serial.print('0');
Serial.print(now.month(), DEC); Serial.print('-');
if (now.day() <10) Serial.print('0');
Serial.print(now.day(), DEC); Serial.print(' ');
Serial.print(now.hour(), DEC); Serial.print(':');
if (now.minute() <10) Serial.print('0');
Serial.print(now.minute(), DEC); Serial.print(':');
if (now.second() <10) Serial.print('0');
Serial.println(now.second(), DEC);
delay(1000);
}
else {
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
DateTime now = rtc.now();
Serial.println("RTC initialized. Using previous time reference.");
Serial.println("Current date/time:");
if (now.month() <10) Serial.print('0');
Serial.print(now.month(), DEC); Serial.print('-');
if (now.day() <10) Serial.print('0');
Serial.print(now.day(), DEC); Serial.print('-');
Serial.print(now.year(), DEC); Serial.print(' ');
Serial.print(now.hour(), DEC); Serial.print(':');
if (now.minute() <10) Serial.print('0');
Serial.print(now.minute(), DEC); Serial.print(':');
if (now.second() <10) Serial.print('0');
Serial.println(now.second(), DEC);
oled.setTextSize(1);
oled.setTextColor(WHITE);
oled.setCursor(0,0);
oled.clearDisplay();
delay(1);
oled.println("RTC initialized w/");
oled.println("previous time ref.");
oled.println("Current date/time:");
if (now.month() <10) oled.print('0');
oled.print(now.month(), DEC); oled.print('-');
if (now.day() <10) oled.print('0');
oled.print(now.day(), DEC); oled.print('-');
oled.print(now.year(), DEC); oled.print(' ');
oled.print(now.hour(), DEC); oled.print(':');
if (now.minute() <10) oled.print('0');
oled.print(now.minute(), DEC); oled.print(':');
if (now.second() <10) oled.print('0');
oled.println(now.second(), DEC);
oled.display();
delay(3000);
}
}
Check that the logger is ready to go (microSD card in, file ready). Status is printed to the OLED screen, and serial, if connected to computer.
void SDcheck (void) {
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
oled.setTextSize(1.5);
oled.setTextColor(WHITE);
oled.setCursor(0,0);
oled.clearDisplay();
delay(1);
oled.println("Card failed...");
oled.println("...or not in?");
oled.display();
return;
}
Serial.println("card initialized.");
oled.setTextSize(1.5);
oled.setTextColor(WHITE);
oled.setCursor(0,0);
oled.clearDisplay();
delay(1);
oled.println("Card initialized.");
oled.display();
delay(1000);
File dataFile = SD.open("log.txt", FILE_WRITE);
if (dataFile) {
Serial.println("File open. Logging!");
oled.setTextSize(2);
oled.setTextColor(WHITE);
oled.setCursor(0,0);
oled.clearDisplay();
delay(1);
oled.println("Logging!");
oled.display();
delay(1000);
delay(1000);
}
// If the file is not open, return error message
else {
Serial.println("No file! Not logging!");
oled.setTextSize(1.5);
oled.setTextColor(WHITE);
oled.setCursor(0,0);
oled.clearDisplay();
delay(1);
oled.println("No file!");
oled.println("Not logging!");
oled.display();
delay(1000);
return;
}
}
These of course are where the action is. The order of operations is as follows:
.csv
format.Build the time stamp and store in struct:
void TimeStamper (void) {
DateTime now = rtc.now();
// This little guy gives unique ID to sub-second samples
int ThisSec = now.second();
if(StartSec==ThisSec) {
counter=counter+ 1;
StartSec=StartSec;
} else {
counter=0;
StartSec=now.second();
}
SixLoggerData.timestamp = String(String(now.year(), DEC)+
"-"+String(now.month(), DEC)+
"-"+String(now.day(), DEC)+
" "+String(now.hour(), DEC)+
":"+String(now.minute(), DEC)+
":"+String(now.second(), DEC)+
"."+String(counter, DEC));
}
Get the interior case temperature & store to struct as degrees C:
void CaseTemp (void) {
int InnerTherm = analogRead(TempSense);
float voltage = InnerTherm * 3.3;
voltage /= 1024.0;
SixLoggerData.CaseTempC = (voltage - 0.5) * 100 ;
}
Read thermocouple data, process electric signals into degree C, and write to struct:
void TempStruct6 (void) {
SixLoggerData.tc1 = thermocouple1.readCelsius();
SixLoggerData.tc2 = thermocouple2.readCelsius();
SixLoggerData.tc3 = thermocouple3.readCelsius();
SixLoggerData.tc4 = thermocouple4.readCelsius();
SixLoggerData.tc5 = thermocouple5.readCelsius();
SixLoggerData.tc6 = thermocouple6.readCelsius();
}
Print the timestamp + current thermocouple temperatures to the OLED display:
void oledSixLogger (void) {
oled.setTextSize(1);
oled.setTextColor(WHITE);
oled.setCursor(0,0);
oled.clearDisplay();
delay(1);
oled.println(SixLoggerData.timestamp);
oled.print("1: ");
oled.print(SixLoggerData.tc1);
oled.print(", ");
oled.print("4: ");
oled.println(SixLoggerData.tc4);
oled.print("2: ");
oled.print(SixLoggerData.tc2);
oled.print(", ");
oled.print("5: ");
oled.println(SixLoggerData.tc5);
oled.print("3: ");
oled.print(SixLoggerData.tc3);
oled.print(", ");
oled.print("6: ");
oled.println(SixLoggerData.tc6);
oled.display();
}
And finally, if the Adalogger is connect to the computer, it will print the timestamp + thermocouple values to the serial monitor:
void SerialDisplay (void) {
Serial.print(SixLoggerData.timestamp); Serial.print(", ");
Serial.print(SixLoggerData.tc1); Serial.print(", ");
Serial.print(SixLoggerData.tc2); Serial.print(", ");
Serial.print(SixLoggerData.tc3); Serial.print(", ");
Serial.print(SixLoggerData.tc4); Serial.print(", ");
Serial.print(SixLoggerData.tc5); Serial.print(", ");
Serial.print(SixLoggerData.tc6); Serial.print(", ");
Serial.println(SixLoggerData.CaseTempC);
}
comments powered by Disqus