I use the MAX31855 in a data logging application. I didn't use any library but read direct. Adafruit libraries are very capable but sometimes they seem to be to too want to use C++ objects for simple devices in simple programs.
The attached code is for an Arduino M0 (32 bit) but can easily be used in a 8bit Arduino by changing the interrupt syntax.
You should but the Clock and Data lines on the "std" Arduino SPI lines. Then put the CS\ 's on different pins. Remember CS\ is active low so both CS lines should be high then bring each low (one at a time) to read the device.
My board that looks like post #6 has a regulator. This board is by far superior as the two gray SMD parts on right side are inductors, they aid in filtering out noise.
EIC Interrupt Control:
EIC->CTRL.bit.ENABLE = 1; and EIC->CTRL.bit.ENABLE = 0;
Target Processor / Board:
WeMos SAMD21 M0 – a Variant of the Arduino M0
Hardware Description:
1) MAX31855k,4 SPI, performs conversion when CS goes high, No library req'd
2) SD Card, SPI, caution some boards don't tri-state MISO, SDFat library
3) DS3132 RTC, No library required.
4) OLED 128 x 32 ASCII1306 Library
*/
#define VERSION "Ver: RC13"
#define DEBOUNCE 2
//#define DEBUG
#include <Wire.h>
#include <SPI.h> // SD Card & TypeK
#include "SdFat.h"
SdFat SD; // keep existing code that used SD but still use the SdFat library
// OLED
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#include "FurnaceApp.h"
// *** declare Functions Prototypes ********************************************
// ***************************************************************************
void init_pins_int(void);
void initSD_Card(void);
void init_RTC(void);
void init_TypeK(void);
void init_OLED(void);
uint16_t ReadRawTemperature(void);
void ConvertSectoHour(int32_t n);
void WriteDataSD(void);
void WriteFileHeader(void);
// *** declare Objects *******************************************************
// ***************************************************************************
File myFile; // create instance of a "File" class for SD Card
SSD1306AsciiWire oled; // create an "oled" object
// *** declare gVariables ****************************************************
// ***************************************************************************
int16_t hour;
uint8_t minute;
uint8_t second;
byte ourInputs[] = {BurnerPin, CircPin, AquaPin, Level1Pin, Level2Pin, Level3Pin};
// pin # assignments 1 3 5 6 7 8
#define NUMINPUTS sizeof(ourInputs)
uint8_t Data[NUMINPUTS], prevData[NUMINPUTS], delayCnt[NUMINPUTS];
bool LogData = false; // goes true on input change resulting in the data written to SD
// *** Setup ****************************************************************
// ***************************************************************************
void setup() {
SerialUSB.begin(115200);
delay(1000);
SerialUSB.print(".....starting ");
SerialUSB.println(NUMINPUTS);
EIC->CTRL.bit.ENABLE = 0; // hold off any interrupts until setup complete.
init_pins_int();
// start I2C...
Wire.begin();
Wire.setClock(100000UL);
SPI.begin(); // not sure if this is needed for SD card?
// *** init Devices <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
init_TypeK();
initSD_Card();
init_RTC();
WriteFileHeader();
init_OLED();
// update display temperature here ??
EIC->CTRL.bit.ENABLE = 1;
} // --- setup ---
uint32_t oldMillis = 0; // aka "unsigned long"
// ***************************************************************************
// *** MAIN loop *************************************************************
// ***************************************************************************
void loop() {
if (millis() >= oldMillis + 100)
{
for (uint8_t i = 0; i <= NUMINPUTS-1; i=i+1)
{
// -----------------------------------------------------------
if (delayCnt[i] == 0) // no pending test |
{
Data[i] = digitalRead(ourInputs[i]);
if (prevData[i] != Data[i]) delayCnt[i] = 2;
}
else
{
--delayCnt[i];
if (delayCnt[i] == 0)
{
Data[i] = digitalRead(ourInputs[i]);
if (Data[i] != prevData[i]) LogData = true; prevData[i] = Data[i];
}
} // --- else --- |
// ----------------------------------------------------------
} // --- for ---
if (LogData) {
WriteDataSD();
LogData = false;
++logCount;
oled.SSD1306Ascii::setCursor(11*8,0); oled.print(logCount);
}
oldMillis = millis();
} // -- 100 millis --
if (gDisplaySeconds >= displayUpdate)
{
gDisplaySeconds = 0;
UpdateDisplay();
}
} // --- loop
// ************************************************************
// *** interrupt routine(s) *************************************
// ************************************************************
void ispSeconds() {
++SQWseconds;
++gDisplaySeconds;
}
// **********************************************************************
// *** functions ********************************************************
// **********************************************************************
// * *
// * *
// **********************************************************************
// *** Functions ********************************************************
// **********************************************************************
// RTC communication ------------------------------------------------------------------
uint8_t I2C_readByte(const uint8_t addr) {
uint8_t data;
Wire.beginTransmission(RTC_ADDRESS);
Wire.write(addr);
Wire.requestFrom(RTC_ADDRESS, (uint8_t)1);
data = Wire.read();
RTC_Error = Wire.endTransmission(); //returned status; 0 = success
return data;
} // readByte()
//--------------------------------------------------------------------------------------
void I2C_writeByte(const uint8_t addr, const uint8_t data) {
Wire.beginTransmission(RTC_ADDRESS);
Wire.write(addr);
Wire.write(data);
RTC_Error = Wire.endTransmission();
} // writeByte()
//--------------------------------------------------------------------------------------
void UpdateDisplay(void)
{
uint16_t RTemp;
RTemp = (ReadTemperature() >> 2) * 0.25;
oled.SSD1306Ascii::setCursor(0 * 8, 0);
if (RTemp < 100) oled.print(" ");
oled.print(RTemp);
oled.SSD1306Ascii::setCursor(0 * 8, 2);
oled.print("SRT");
oled.print(SD_Error);
oled.print(RTC_Error);
oled.print(TypeK_Error);
ConvertSectoHour(SQWseconds);
oled.SSD1306Ascii::setCursor(8 * 8, 2);
oled.print(hour);
oled.print(":");
if (minute < 10) oled.print("0");
oled.print(minute);
oled.print(":");
if (second < 10) oled.print("0");
oled.print(second);
}
//--------------------------------------------------------------------------------------
uint16_t ReadTemperature(void)
{
EIC->CTRL.bit.ENABLE = 0;
uint16_t _rawData = 0;
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(TK_CSPin, LOW); //set CS low to read SPI interface
_rawData = SPI.transfer16(0x0000); // TypeK is read only, doesn't matter what is sent in SPI.transfer16(0x000)
digitalWrite(TK_CSPin, HIGH); // de-select and start a new conversion to be read the next time through
SPI.endTransaction();
// SerialUSB.println(_rawData); // for debug only
EIC->CTRL.bit.ENABLE = 1;
TypeK_Error = false;
if (_rawData & 0b01)
{
TypeK_Error = true;
_rawData = 0;
}
return _rawData;
}
//--------------------------------------------------------------------------------------
void WriteDataSD(void) //----------------------------------------------***
{
#ifdef DEBUG
SerialUSB.print(!Data[0]); SerialUSB.print(", ");
SerialUSB.print(!Data[1]); SerialUSB.print(", ");
SerialUSB.print(!Data[2]); SerialUSB.print(", ");
SerialUSB.print(!Data[3]); SerialUSB.print(", ");
SerialUSB.print(!Data[4]); SerialUSB.print(", ");
SerialUSB.println(!Data[5]);
#endif
EIC->CTRL.bit.ENABLE = 0;
myFile = SD.open(gDataFile, FILE_WRITE);
if (myFile)
{
myFile.print(SQWseconds); myFile.print(", ");
myFile.print((ReadTemperature() >> 2) * 0.25); myFile.print(", ");
myFile.print(!Data[0]); myFile.print(", "); // Burner
myFile.print(!Data[1]); myFile.print(", "); // Circulator
myFile.print(!Data[2]); myFile.print(", "); // Aquastat
myFile.print(!Data[3]); myFile.print(", "); // Level 1
myFile.print(!Data[4]); myFile.print(", "); // Level 2
myFile.println(!Data[5]); // Level 3
myFile.close();
} // if (myFile), Loop time was: 18 ~ 19 ms with a few at 25 ms
else
{
SD_Error = true; // --- if (myFile) else
}
EIC->CTRL.bit.ENABLE = 1;
} // WriteDataSD
//--------------------------------------------------------------------------------------
// function convert second into hour minutes seconds
//--------------------------------------------------------------------------------------
void ConvertSectoHour(int32_t n)
{
hour = n / 3600;
n = n % 3600;
minute = n / 60;
n %= 60;
second = n;
}
// ************************************************************
// *** initialization functions *******************************
// ************************************************************
// --- SD Card initialization function ---
void initSD_Card(void) {
if (!SD.begin(SD_CSPin)) {
SD_Error = true;
}
// loop until we find a file that doesn't already exist.......
do
{
itoa(gFileNumb, gDataFile, 10); // (value, Array, base)
const char *extension = ".csv";
strcat(gDataFile, extension); // syntax: strcat(dest, source)
++gFileNumb;
} while (SD.exists(gDataFile)); // assume will Rtn false if no communication.
myFile = SD.open(gDataFile, FILE_WRITE);
if (myFile) { // if the file opened okay, write to it:
myFile.print(" init...");
//myFile.println(gDataFile);
myFile.close();
}
else {
SD_Error = true; // if the file didn't open, print an error:
}
return;
} // --- initSD_Card ---
//--------------------------------------------------------------------------------------
void init_RTC(void) {
gReg0x0F = I2C_readByte(RTC_0F); // (address, data)
if (gReg0x0F & 0b10000000) // test OSF bit
{
RTC_Error = true;
}
else
{
I2C_writeByte(RTC_0E, 0x0);
I2C_writeByte(RTC_0F, 0x0);
}
} // --- init_RTC ---
//--------------------------------------------------------------------------------------
// --- furnace setup function ---
void init_pins_int(void) {
// Setup CS pins first....
pinMode(TK_CSPin, HIGH); // enables pull-up immediately keeping pin high
digitalWrite(TK_CSPin, HIGH);
pinMode(SD_CSPin, HIGH);
digitalWrite(SD_CSPin, HIGH);
pinMode(ledPin, OUTPUT);
pinMode(Level3Pin, INPUT_PULLUP);
pinMode(Level2Pin, INPUT_PULLUP);
pinMode(Level1Pin, INPUT_PULLUP);
pinMode(AquaPin, INPUT_PULLUP);
pinMode(CircPin, INPUT_PULLUP);
pinMode(BurnerPin, INPUT_PULLUP);
pinMode(intSQWPin, INPUT);
attachInterrupt(digitalPinToInterrupt(intSQWPin), ispSeconds, RISING);
}
//--------------------------------------------------------------------------------------
void init_TypeK(void)
{
// doesn't really initialize, simply reads the error bit
int16_t _rawData = 0;
digitalWrite(TK_CSPin, LOW); //stop measurement/conversion
delayMicroseconds(1);
digitalWrite(TK_CSPin, HIGH); //start new measurement/conversion
delay(100);
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(TK_CSPin, LOW); //set CS low to read SPI interface
_rawData = SPI.transfer16(0x0000); // TypeK is read only, doesn't matter what is sent in SPI.transfer16(0x000)
digitalWrite(TK_CSPin, HIGH); // deselect
SPI.endTransaction();
if (_rawData & 0b01) TypeK_Error = true;
return;
}
//--------------------------------------------------------------------------------------
void init_OLED()
{
oled.begin(&Adafruit128x32, OLEDADDRESS);
oled.setFont(ZevvPeep8x16); // Screen = 4 (0,2,4,6) lines X 16 characters (0 to 15)
oled.clear();
oled.print(VERSION);
delay(5000);
oled.clear();
oled.SSD1306Ascii::setCursor(3 * 8, 0);
oled.print("$C,#Rdg"); // font hacked, $ prints °
}
//--------------------------------------------------------------------------------------
void WriteFileHeader()
{
Wire.beginTransmission(RTC_ADDRESS);
Wire.write(0x00); // This is the first register address (Seconds)
// ... read from here 7 uint8_ts
Wire.endTransmission(false);
Wire.requestFrom(RTC_ADDRESS, 7);
uint8_t ss = bcd2bin(Wire.read() & 0x7F); // why mask 8th bit here?
uint8_t mm = bcd2bin(Wire.read());
uint8_t hh = bcd2bin(Wire.read());
Wire.read(); // day of week, not used
uint8_t d = bcd2bin(Wire.read());
uint8_t m = bcd2bin(Wire.read());
uint16_t y = bcd2bin(Wire.read()) + 2000;
myFile = SD.open(gDataFile, FILE_WRITE);
if (myFile) {
myFile.print("DataFile Name: ");
myFile.println(gDataFile);
myFile.println();
myFile.print("Firmware Version: ");
myFile.println(VERSION);
myFile.println();
myFile.print("Creation Date - Time: ");
myFile.print(y);
myFile.print("-");
myFile.print(m);
myFile.print("-");
myFile.print(d);
myFile.print(" ");
myFile.print(hh);
myFile.print(":");
myFile.print(mm);
myFile.print(":");
myFile.println(ss); // <------- ,,,,,,,,,,,
myFile.println(); // or here
myFile.println("Δ seconds, Temp °C, Burner, Circulator, Aquastat, Level 1, Level 2, Level 3");
myFile.close();
}
else {
SD_Error = true;
}
return;
}
// --- end of code ---