Using multiple Adafruit MCP9601's over I2C for logging project

Hi, I'm aiming to use an Uno to log 3 channels of temperature data over a long period.

My code currently successfully logs 1 thermocouple hot junction temperature, with a timestamp, and saves it to a .csv file on an SD card. I am using one Adafruit MCP9601 for each thermocouple (3 total) along with the rev B Adafruit data logger shield (ADA1141) for recording to storage, which also has a PCF8523 real-time clock on board. I have come up with my code mainly using the example codes for these products on Adafruit's website.

What I'm struggling to work out is how to get data from all three MCP9601's at once. My aim is to print it to a .csv file like this:

[timestamp 1], channel 1 (°C), channel 2 (°C), channel 3 (°C)
[timestamp 2], channel 1 (°C), channel 2 (°C), channel 3 (°C)
[timestamp 3], channel 1 (°C), channel 2 (°C), channel 3 (°C)
[timestamp 4], channel 1 (°C), channel 2 (°C), channel 3 (°C)
.......etc etc etc

Currently I can log the timestamp and channel 1 but I am unsure of how to get the data from the other MCP9601's at the same time.
I thought that I may be able to use three lines of "mcp.readThermocouple()" from the MCP9601 documentation, with a variation for each different i2c address but I don't think this is possible.
The i2c addresses for my devices are as follows: 0x65, 0x66, 0x67 for the MCP9601's (addr jumpers soldered as applicable) and 0x68 for the RTC.

The period between each logging will be half an hour or longer when the project is complete. I intend to run it from a battery and use some kind of sleep mode in between to save power, but I'll cross that bridge once I've got this working.

I'm learning a lot of this as I go, so any advice or pointers would be very gratefully appreciated.
So if anyone has any suggestions on how I could change this code to log from 3 MCP9601's rather than 1 I'd be very thankful.

My code so far:

#include "Adafruit_MCP9601.h"
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"

#define ECHO_TO_SERIAL   1 // echo data to serial port

RTC_PCF8523 RTC; // define the Real Time Clock object



// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = 10;

// the logging file
File logfile;

void error(char *str)
{
  Serial.print("error: ");
  Serial.println(str);

  while(1);
}

void setup(void)
{
  Serial.begin(9600);
  Serial.println();
  
  // initialize the SD card
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    error("Card failed, or not present");
  }
  Serial.println("card initialized.");
  
  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE); 
      break;  // leave the loop!
    }
  }
  
  if (! logfile) {
    error("couldnt create file");
  }
  
  Serial.print("Logging to: ");
  Serial.println(filename);

  // connect to RTC
  Wire.begin();  
  if (!RTC.begin()) {
    logfile.println("RTC failed");
#if ECHO_TO_SERIAL
    Serial.println("RTC failed");
#endif  //ECHO_TO_SERIAL
  }
}


void loop(void)
{
  Adafruit_MCP9601 mcp; // define the i2c thermocouple amplifier

  DateTime now;

  // delay for the amount of time we want between readings
  delay(1000);
  
  // fetch the time
  now = RTC.now();
  
  // log time
  
  logfile.println((mcp.readThermocouple()));
  logfile.print(now.year(), DEC);
  logfile.print("/");
  logfile.print(now.month(), DEC);
  logfile.print("/");
  logfile.print(now.day(), DEC);
  logfile.print(" ");
  logfile.print(now.hour(), DEC);
  logfile.print(":");
  logfile.print(now.minute(), DEC);
  logfile.print(":");
  logfile.print(now.second(), DEC);
  logfile.print(",");
  logfile.print(" ");
  logfile.flush();


#if ECHO_TO_SERIAL
  Serial.println((mcp.readThermocouple()));
  Serial.print(now.year(), DEC);
  Serial.print("/");
  Serial.print(now.month(), DEC);
  Serial.print("/");
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(":");
  Serial.print(now.minute(), DEC);
  Serial.print(":");
  Serial.print(now.second(), DEC);
  Serial.print(",");
  Serial.print(" ");
#endif //ECHO_TO_SERIAL

}

I thought that I may be able to use three lines of "mcp.readThermocouple()" from the MCP9601 documentation, with a variation for each different i2c address but I don't think this is possible.

You'll have 3 instances of the Adafruit_MCP9601 class that are instantiated (usually globally) with their respective addresses. Then you could call the readThermocouple() function for each class and log all the data.

1 Like

Just as @Power_Broker has posted!

Here is a description how to do it in the sketch

https://forums.adafruit.com/viewtopic.php?p=866385#p866385

Seems (as stated in that linked post) that the respective I2C_address has to be use in the .begin() function ...

Good luck!
ec2021

(The link refers to MCP9600 but the handling of MCP9601 seems to be exactly the same from what I saw here https://github.com/adafruit/Adafruit_MCP9600/blob/master/Adafruit_MCP9601.h )

image

1 Like

The first thing to do is to use the solder pads on the back of each sensor board to give them different addresses. Then attach all 3 to the Arduino and run the i2c scanner sketch to confirm that all 3 are visible on the bus and have the expected addresses.

1 Like

Was also my first idea, but I guess that's already done ... :wink:

1 Like
#include "Adafruit_MCP9601.h"
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"

#define ECHO_TO_SERIAL   1 // echo data to serial port

#define NUM_SENSORS 3

RTC_PCF8523 RTC; // define the Real Time Clock object

Adafruit_MCP9601 mcp[NUM_SENSORS]; // define the i2c thermocouple amplifiers

const byte mcpAdrs[NUM_SENSORS] = {0x65, 0x66, 0x67};

// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = 10;

// the logging file
File logfile;

void error(char *str)
{
  Serial.print("error: ");
  Serial.println(str);

  while(1);
}

void setup(void)
{
  Serial.begin(9600);
  Serial.println();
  
  // initialize the SD card
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    error("Card failed, or not present");
  }
  Serial.println("card initialized.");
  
  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE); 
      break;  // leave the loop!
    }
  }
  
  if (! logfile) {
    error("couldnt create file");
  }
  
  Serial.print("Logging to: ");
  Serial.println(filename);

  // connect to RTC
  Wire.begin();  
  if (!RTC.begin()) {
    logfile.println("RTC failed");
#if ECHO_TO_SERIAL
    Serial.println("RTC failed");
#endif  //ECHO_TO_SERIAL

  }
  for(byte s=0; s<NUM_SENSORS; s++)
    mcp[s].begin(mcpAdrs[s]);
}


void loop(void)
{

  DateTime now;
  char buffer[128], temp[10];

  // delay for the amount of time we want between readings
  delay(1000);
  
  // fetch the time
  now = RTC.now();
  sprintf(buffer, "%04d/%02d/%02d %02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());

  for(byte s=0; s<NUM_SENSORS; s++) {
    strcat(buffer, ",");
    dtostrf(mcp[s].readThermocouple(), 1, 2, temp);
    strcat(buffer, temp);
  }
  
  // log time
  
  logfile.println(buffer);
  logfile.flush();

#if ECHO_TO_SERIAL
  Serial.println(buffer);
#endif //ECHO_TO_SERIAL

}
1 Like

Thank you so much, your code works perfectly. I am very grateful for your help :slightly_smiling_face:

This was my first post on the forum, and I'm so pleasantly surprised just how helpful and great everyone was. Thank you so much everyone!

You are welcome!

How pleasant and helpful a thread may become depends a lot on how

  • the TO formulates his/her expectations
  • provides the necessary information

So the good job you did in your entry post is reflected in the answers.

In German there is a saying "As you call into the forest, so it echoes out."
In English "What comes around goes around."

Good luck!
ec2021

Good to hear. Please ask if there are any changes I made that are not clear to you in how they work. It's much more important to me that you have learned something useful than that I have given you the code you wanted.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.