Hello. I'm currently using multiple Adafruit MCP9600 thermocouple sensors and an Arduino R3 to monitor a system. The goal is to be able to dynamically initialize them and call upon them in further lines of code. The basic function of said code is 'if temp > setPoint relayPin = high;'
When I initialize them individually such as
Adafruit_MCP9600 mcp;
Adafruit_MCP9600 mcp2;
and so on, I have no issues. However, if I initialize them as an array such as
Adafruit_MCP9600 mcpArray[4];
int I2C_ADDRESS[4] = {0x60, 0x67, 0x64, 0x65};
The arduino resets to the beginning of the code.
I have two prompts at the beginning of my code. The first asking how many thermocouples I have. This sets the tcChannels int which the array relies on. The second asks to reuse the previous setpoint. Currently, it makes it through each prompt, and then when it transitions to the IDLE state, it resets. I've put in a few debugging serial prints, and this is the output I get from the serial monitor:
Serial Begin!
MCP9600 HW test
Found MCP9600!
ADC resolution set to 18 bits
Thermocouple type set to K type
Filter coefficient value set to: 3
Setpoint Prompt
transitioning to Serial Begin!
Here is my complete code:
#include <Wire.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_I2CRegister.h>
#include "Adafruit_MCP9600.h"
#include <LiquidCrystal.h>
#include <EEPROM.h> // Include the EEPROM library
#define upButtonPin A0
#define downButtonPin A1
#define menuButtonPin A2
#define selectButtonPin A3
#define alarmPin 7
//#define I2C_ADDRESS (0x67)
//#define I2C_ADDRESS2 (0x60)
//Adafruit_MCP9600 mcp;
//Adafruit_MCP9600 mcp2;
Adafruit_MCP9600 mcpArray[4];
int I2C_ADDRESS[4] = {0x60, 0x67, 0x64, 0x65};
const int relayPin = 8; // Digital pin connected to the relay
int setPoint = 30.0; // Setpoint temperature in degrees Celsius
float responseTime = 0; // Response time in seconds
int relayTrigger = HIGH; // Relay trigger behavior
int storedSetPointAddr = 0;
int storedSetPoint = EEPROM.read(storedSetPointAddr);
float hysteresis = 0.00; // Initial hysteresis value
int tcChannels = 1;
float temp[4];
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // RS, EN, D4, D5, D6, D7
enum State
{
SETUP,
IDLE,
MENU,
SET_SETPOINT,
SET_RESPONSE_TIME,
SET_RELAY_TRIGGER,
SET_HYSTERESIS,
SET_TCCHANNELS
};
State currentState = SETUP;
unsigned long lastButtonPressTime = 0;
const unsigned long menuTimeout = 10000; // 10 seconds timeout for menu
void setup()
{
Serial.begin(115200);
Serial.println("Serial Begin!");
pinMode(relayPin, OUTPUT);
pinMode(upButtonPin, INPUT_PULLUP);
pinMode(downButtonPin, INPUT_PULLUP);
pinMode(menuButtonPin, INPUT_PULLUP);
pinMode(selectButtonPin, INPUT_PULLUP);
pinMode(alarmPin, OUTPUT);
digitalWrite(relayPin, !relayTrigger);
digitalWrite(alarmPin, LOW);
lcd.begin(16, 2);
delay(10);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Number of TCs: ");
lcd.setCursor(0, 1);
lcd.print(tcChannels);
int chosenChannels = tcChannels;
while (true) {
if (digitalRead(upButtonPin) == LOW) {
chosenChannels ++; // Increase channels by 1
lcd.setCursor(0, 1);
lcd.print(chosenChannels); // Display
delay(500);
} else if (digitalRead(downButtonPin) == LOW) {
chosenChannels--; // Decrease channels by 1
lcd.setCursor(0, 1);
lcd.print(chosenChannels); // Display with two decimal places
delay(500);
} else if (digitalRead(selectButtonPin) == LOW) {
tcChannels = chosenChannels;
lcd.clear();
delay(500);
break;
}
}
// Serial.println("MCP9600 HW test");
//
//
//// /* Initialise the driver with I2C_ADDRESS and the default I2C bus. */
//// if (! mcp.begin(I2C_ADDRESS)) {
//// Serial.println("Sensor not found. Check wiring!");
//// while (1);
//// }
//// if (! mcp2.begin(I2C_ADDRESS2)) {
//// Serial.println("Sensor not found. Check wiring!");
//// while (1);
//// }
Serial.println("MCP9600 HW test");
lcd.clear();
lcd.print("Initializing TCs");
delay(500);
for (int i = 0; i <= tcChannels-1; i++) {
// Initialize each MCP9600 object with the appropriate I2C address
if (!mcpArray[i].begin(I2C_ADDRESS[i])) {
Serial.println("Sensor not found. Check wiring!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("No TC CH:");
lcd.print(i);
//while (1);
}
}
Serial.println("Found MCP9600!");
for (int i = 0; i <= tcChannels-1; i++) {
mcpArray[i].setADCresolution(MCP9600_ADCRESOLUTION_18);
Serial.print("ADC resolution set to ");
switch (mcpArray[i].getADCresolution()) {
case MCP9600_ADCRESOLUTION_18: Serial.print("18"); break;
case MCP9600_ADCRESOLUTION_16: Serial.print("16"); break;
case MCP9600_ADCRESOLUTION_14: Serial.print("14"); break;
case MCP9600_ADCRESOLUTION_12: Serial.print("12"); break;
}
Serial.println(" bits");
}
for (int i = 0; i <= tcChannels-1; i++) {
mcpArray[i].setThermocoupleType(MCP9600_TYPE_K);
Serial.print("Thermocouple type set to ");
switch (mcpArray[i].getThermocoupleType()) {
case MCP9600_TYPE_K: Serial.print("K"); break;
case MCP9600_TYPE_J: Serial.print("J"); break;
case MCP9600_TYPE_T: Serial.print("T"); break;
case MCP9600_TYPE_N: Serial.print("N"); break;
case MCP9600_TYPE_S: Serial.print("S"); break;
case MCP9600_TYPE_E: Serial.print("E"); break;
case MCP9600_TYPE_B: Serial.print("B"); break;
case MCP9600_TYPE_R: Serial.print("R"); break;
}
Serial.println(" type");
}
for (int i = 0; i <= tcChannels-1; i++) {
mcpArray[i].setFilterCoefficient(3);
Serial.print("Filter coefficient value set to: ");
Serial.println(mcpArray[i].getFilterCoefficient());
}
for (int i = 0; i <= tcChannels-1; i++) {
mcpArray[i].enable(true);
}
// mcp.setAlertTemperature(1, 30);
// Serial.print("Alert #1 temperature set to ");
// Serial.println(mcp.getAlertTemperature(1));
// mcp.configureAlert(1, true, true); // alert 1 enabled, rising temp
// mcp2.enable(true);
// Serial.println(F("------------------------------"));
// Show the prompt to use the last setpoint or clear it with auto-scroll
Serial.println("Setpoint Prompt");
lcd.clear();
lcd.setCursor(0, 0);
//lcd.autoscroll();
lcd.print("Use last setpoint?");
lcd.print(storedSetPoint + "C");
lcd.setCursor(0, 1);
//lcd.noAutoscroll();
lcd.print("Up=Yes Down=Clear");
// Wait for button press
while (true) {
if (digitalRead(upButtonPin) == LOW) {
// Use the last setpoint
setPoint = storedSetPoint;
lcd.clear();
lcd.print("Setpoint: ");
lcd.print(setPoint);
lcd.print((char)223); // Print the degree symbol
lcd.print("C");
delay(1000); // Show the setpoint for a moment
currentState = IDLE; // Transition to IDLE state
break;
} else if (digitalRead(downButtonPin) == LOW) {
// Clear the stored setpoint
EEPROM.write(storedSetPointAddr, 0);
lcd.clear();
lcd.print("Setpoint cleared");
delay(1000); // Show the message for a moment
lcd.clear();
lcd.print("Setpoint: "); //Show the default setpoint
lcd.print(setPoint);
lcd.print((char)223);
delay(1000);
delay(1000);
Serial.println("transitioning to IDLE");
break;
}
}
currentState = IDLE; // Transition to IDLE state
}
void handleMenu() {
const char *menuOptions[] = {"Setpoint ", "Response Time ", "Relay Trigger ", "Hysteresis ", "Multi Channel "};
int currentOption = 0;
unsigned long menuStartTime = millis();
lcd.clear();
while (currentState == MENU) {
lcd.setCursor(0, 0);
lcd.print("Menu: ");
lcd.setCursor(0, 1);
lcd.print(menuOptions[currentOption]);
if (digitalRead(upButtonPin) == LOW) {
currentOption = (currentOption + 1) % 5; // Cycle through options
delay(200); // Debounce delay
} else if (digitalRead(downButtonPin) == LOW) {
currentOption = (currentOption + 3) % 5; // Cycle through options in reverse
delay(200); // Debounce delay
} else if (digitalRead(selectButtonPin) == LOW) {
switch (currentOption) {
case 0:
currentState = SET_SETPOINT;
break;
case 1:
currentState = SET_RESPONSE_TIME;
break;
case 2:
currentState = SET_RELAY_TRIGGER;
break;
case 3:
currentState = SET_HYSTERESIS;
break;
case 4:
currentState = SET_TCCHANNELS;
break;
}
delay(200); // Debounce delay
} else if (digitalRead(menuButtonPin) == LOW && currentState == MENU &&
millis() - menuStartTime >= 1000) {
currentState = IDLE; // Exit to IDLE state if 10 seconds have passed
lcd.clear();
delay(500); // Debounce delay
}
lastButtonPressTime = millis();
delay(100);
}
}
void handleSetSetpoint()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Setpoint: ");
lcd.setCursor(0, 1);
lcd.print(setPoint);
lcd.print((char)223); // Print the degree symbol
lcd.print("C");
int chosenSetPoint = setPoint;
while (currentState == SET_SETPOINT)
{
if (digitalRead(upButtonPin) == LOW)
{
chosenSetPoint++;
lcd.setCursor(0, 1);
lcd.print(chosenSetPoint);
lcd.print((char)223); // Print the degree symbol
lcd.print("C ");
}
else if (digitalRead(downButtonPin) == LOW)
{
chosenSetPoint--;
lcd.setCursor(0, 1);
lcd.print(chosenSetPoint);
lcd.print((char)223); // Print the degree symbol
lcd.print("C ");
}
else if (digitalRead(menuButtonPin) == LOW)
{
currentState = MENU;
}
else if (digitalRead(selectButtonPin) == LOW)
{
setPoint = chosenSetPoint;
EEPROM.write(storedSetPointAddr, setPoint);
currentState = IDLE; // Exit to IDLE state if 10 seconds have passed
lcd.clear();
delay(500);
}
lastButtonPressTime = millis();
delay(100); // Debounce delay
}
}
void handleSetResponseTime()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Response Time:");
lcd.setCursor(0, 1);
lcd.print(responseTime);
lcd.print(" sec");
while (currentState == SET_RESPONSE_TIME)
{
if (digitalRead(upButtonPin) == LOW)
{
responseTime += 0.01;
lcd.setCursor(0, 1);
lcd.print(responseTime, 2);
lcd.print("s ");
//delay(100); // Debounce delay
}
else if (digitalRead(downButtonPin) == LOW)
{
if (responseTime > 0)
{
responseTime -= 0.01;
lcd.setCursor(0, 1);
lcd.print(responseTime);
lcd.print(" sec ");
}
//delay(100); // Debounce delay
}
else if (digitalRead(menuButtonPin) == LOW)
{
currentState = MENU;
}
else if (digitalRead(selectButtonPin) == LOW)
{
currentState = IDLE; // Exit to IDLE state if 10 seconds have passed
lcd.clear();
delay(500);
}
lastButtonPressTime = millis();
delay(100); // Debounce delay
}
}
void handleSetRelayTrigger()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Relay Trigger: ");
while (currentState == SET_RELAY_TRIGGER)
{
lcd.setCursor(0, 1);
lcd.print((relayTrigger == HIGH) ? "High " : "Low ");
if (digitalRead(upButtonPin) == LOW || digitalRead(downButtonPin) == LOW) {
relayTrigger = (digitalRead(upButtonPin) == LOW) ? HIGH : LOW;
lcd.setCursor(0, 1);
lcd.print((relayTrigger == HIGH) ? "High " : "Low ");
delay(200); // Debounce delay
}
else if (digitalRead(menuButtonPin) == LOW)
{
currentState = MENU;
delay(200); // Debounce delay
}
else if (digitalRead(selectButtonPin) == LOW)
{
currentState = IDLE; // Exit to IDLE state if 10 seconds have passed
lcd.clear();
delay(500);
}
lastButtonPressTime = millis();
delay(100); // Debounce delay
}
}
void handleSetHysteresis() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Hysteresis: ");
lcd.setCursor(0, 1);
lcd.print(hysteresis, 2); // Display hysteresis with two decimal places
lcd.print((char)223); // Print the degree symbol
lcd.print("C");
float chosenHysteresis = hysteresis;
while (currentState == SET_HYSTERESIS) {
if (digitalRead(upButtonPin) == LOW) {
chosenHysteresis += 0.01; // Increase hysteresis by 0.01
lcd.setCursor(0, 1);
lcd.print(chosenHysteresis, 2); // Display with two decimal places
lcd.print((char)223); // Print the degree symbol
lcd.print("C ");
} else if (digitalRead(downButtonPin) == LOW) {
chosenHysteresis -= 0.01; // Decrease hysteresis by 0.01
lcd.setCursor(0, 1);
lcd.print(chosenHysteresis, 2); // Display with two decimal places
lcd.print((char)223); // Print the degree symbol
lcd.print("C ");
} else if (digitalRead(menuButtonPin) == LOW) {
currentState = MENU;
} else if (digitalRead(selectButtonPin) == LOW) {
hysteresis = chosenHysteresis;
currentState = IDLE; // Exit to IDLE state if 10 seconds have passed
lcd.clear();
delay(500);
}
lastButtonPressTime = millis();
delay(100); // Debounce delay
}
}
void handleSetChannels() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Number of TCs: ");
lcd.setCursor(0, 1);
lcd.print(tcChannels);
int chosenChannels = tcChannels;
while (currentState == SET_TCCHANNELS) {
if (digitalRead(upButtonPin) == LOW) {
chosenChannels ++; // Increase channels by 1
lcd.setCursor(0, 1);
lcd.print(chosenChannels); // Display
} else if (digitalRead(downButtonPin) == LOW) {
chosenChannels--; // Decrease hysteresis by 1
lcd.setCursor(0, 1);
lcd.print(chosenChannels); // Display with two decimal places
} else if (digitalRead(menuButtonPin) == LOW) {
currentState = MENU;
} else if (digitalRead(selectButtonPin) == LOW) {
tcChannels = chosenChannels;
currentState = IDLE; // Exit to IDLE state if 10 seconds have passed
lcd.clear();
delay(500);
}
lastButtonPressTime = millis();
delay(100); // Debounce delay
}
}
void overtempControl() {
for (int i = 0; i < 4; i++) {
temp[i] = mcpArray[i].readThermocouple();
}
unsigned long currentTime = millis();
static unsigned long lastOvertempTime = 0;
if (tcChannels == 1) {
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temp[0]);
lcd.print((char)223);
lcd.print("C ");
}
else if (tcChannels == 2) {
lcd.setCursor(0, 0);
lcd.print("1: ");
lcd.print(temp[0], 1);
lcd.print("C ");
lcd.setCursor(8, 0); // Adjust the cursor position for the second channel
lcd.print("2: ");
lcd.print(temp[1], 1);
lcd.print("C ");
}
lcd.setCursor(0, 1);
lcd.print("Setpoint: ");
lcd.print(setPoint);
lcd.print((char)223);
lcd.print("C ");
if (temp[0] >= (setPoint + hysteresis) || temp[1] >= (setPoint + hysteresis)) {
if (currentTime - lastOvertempTime >= responseTime * 1000) {
lcd.setCursor(0, 1);
lcd.print("Overtemp!");
digitalWrite(relayPin, relayTrigger);
digitalWrite(alarmPin, HIGH);
}
else
{
digitalWrite(relayPin, !relayTrigger);
digitalWrite(alarmPin, LOW);
lastOvertempTime = currentTime; // Reset overtemp time when temperature is below setpoint
}
}
if (digitalRead(menuButtonPin) == LOW)
{
currentState = MENU;
lastButtonPressTime = currentTime;
}
}
void loop()
{
// Serial.print("Hot Junction: "); Serial.println(mcp.readThermocouple());
// Serial.print("Cold Junction: "); Serial.println(mcp.readAmbient());
// Serial.print("ADC: "); Serial.print(mcp.readADC() * 2); Serial.println(" uV");
// delay(1000);
// float temp = mcp.readThermocouple();
// float temp2 = mcp2.readThermocouple();
//get_temperature(&temp);
//digitalWrite(relayPin,relayTrigger);
switch (currentState)
{
case IDLE:
overtempControl();
break;
case MENU:
handleMenu();
break;
case SET_SETPOINT:
handleSetSetpoint();
break;
case SET_RESPONSE_TIME:
handleSetResponseTime();
break;
case SET_RELAY_TRIGGER:
handleSetRelayTrigger();
break;
case SET_HYSTERESIS:
handleSetHysteresis();
break;
case SET_TCCHANNELS:
handleSetChannels();
break;
}
delay(100);
}
Please forgive me if I've left out any details. I'm aware that it could be an issue with SRAM, and I'm open to solutions to reduce the amount of SRAM being used. Here's my current upload output:
Sketch uses 14226 bytes (44%) of program storage space. Maximum is 32256 bytes.
Global variables use 1084 bytes (52%) of dynamic memory, leaving 964 bytes for local variables. Maximum is 2048 bytes