Temperature sensor reading seems to break interrupts

Hi,

I'm working on a room/wall thermostat that includes a display, rotary encoder, button and temperature sensor. The purpose is to control the room AC and heating when entering.

Apart from each other all the code works fine, but as soon as I enable the temperature sensor the rotary encoder (driven by ISR) starts to behave erratic and after a few interrupts stops working altogether. I have tried both DHT (on digital inputs) and SHT (on I2C), but both give the same behaviour. Even if I only run the readTemperature() every 10 seconds (using millis() with a timeout counter)

I have scanned the code of the librairies, but I don't see any noInterrupts() that would explain this or anything else.

Anyone any ideas on what is causing this and what might fix it?

I'll post relevant code below.

Thanks in advance for any help!

#include <U8g2lib.h>
#include "GroveEncoder.h"
#include <Arduino.h>
#include <Wire.h>
#include "Adafruit_SHT31.h"

#define ENC_PIN 2
#define BTN_PIN 5

int tmp_minVal = 5; 
int tmp_maxVal = 30;
int btn_prevState = LOW; 
int btn_setState = btn_prevState;    
int mode_saveState = 2; // default saved state is HEAT
int mode_setState = mode_saveState;

bool displayState = 1; // start display high (not yet implemented)

unsigned long btn_timeout = 0;
unsigned long read_interval = 0;

float tmp_setVal = 21.0; // default set temp
float tmp_prevVal;
float tmp_readVal = 22.0; // for debugging simulate temperature value
float tmp_prevReadVal;

char *mode_stateName[4] = {" OFF","COOL","HEAT"};

U8G2_SSD1306_128X64_NONAME_2_HW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);  // High speed I2C

Adafruit_SHT31 sht31 = Adafruit_SHT31();

void setup() {
  Serial.begin(9600);
  u8g2.begin();
  u8g2.clearDisplay();
  updateDisplay();
  
  pinMode(BTN_PIN, INPUT_PULLUP);

  GroveEncoder Encoder(ENC_PIN, &isrEncoder, tmp_minVal, tmp_maxVal);
  Encoder.setValue(tmp_setVal);

  sht31.begin(0x44);
 
  
}

void loop() {

  btn_setState = digitalRead(BTN_PIN);
  if(btn_prevState == LOW && btn_setState == HIGH) {
    btnPressed();
  }
  
  btn_prevState = btn_setState;  

  if (btn_timeout <= millis() && btn_timeout > 0) { 
    btnTimeout();
  }

  // if backlight timeout, dim 
  // dimDisplay(); / function to do 
  
  if (tmp_prevVal != tmp_setVal) {
    Serial.println("--");
    Serial.println(tmp_setVal);
    tmp_prevVal = tmp_setVal;
  }

  if (read_interval <= millis()) {
    
    tmp_readVal = sht31.readTemperature();
    if (tmp_prevReadVal != tmp_readVal) {
      tmp_prevReadVal = tmp_readVal;
  
      Serial.println(tmp_readVal);

    } 
    Serial.println("---");
    read_interval = millis() + 10000;
  } 
  
  updateDisplay();
  //delay (1000); // slow down for debugging 
}

void isrEncoder(int tmp_newVal) {

  Serial.println("-INTERRUPT-");
  Serial.println(tmp_setVal);
  Serial.println(tmp_newVal);
  Serial.println("-INTERRUPT-");

  tmp_setVal = tmp_newVal;

}


void btnPressed() {

  if (mode_setState == 0) {
    mode_setState = mode_saveState;

  } else if (btn_timeout > millis()) {

    switch (mode_saveState) {
      case 1:
        if (mode_setState++ >= 2) mode_setState = 0;
        break;
      case 2:
        if (mode_setState-- <= 0) mode_setState = 2;
        break;
    }

  } else {
    mode_setState = 0;
  }

  btn_timeout = millis() + 3000;

  Serial.println(mode_stateName[mode_setState]);


}

void btnTimeout() {

  Serial.println("--");
  if ( mode_saveState != mode_setState && mode_setState != 0) {
    mode_saveState = mode_setState;
    Serial.print("New state saved: ");
    Serial.println(mode_stateName[mode_setState]);
  } else if (mode_setState == 0) {
    Serial.println("switch off");
  }

  btn_timeout = 0; 

}

void updateDisplay() {

  int tmp_dgt_1 = tmp_readVal / 10;
  int tmp_dgt_2 = (tmp_readVal - tmp_dgt_1*10);
  int tmp_dgt_3 = (tmp_readVal*10 - tmp_dgt_1*100 - tmp_dgt_2*10) + 0.5;

  int tset_dgt_1 = tmp_setVal / 10;
  int tset_dgt_2 = (tmp_setVal - tset_dgt_1*10);
  int tset_dgt_3 = (tmp_setVal*10 - tset_dgt_1*100 - tset_dgt_2*10) + .5;
  
  u8g2.firstPage();
  do {
    
    u8g2.setFont(not7seg32);
    // set dot and C
    u8g2.setCursor(42, 32);
    u8g2.print(".");
    u8g2.setCursor(68, 14);
    u8g2.print("/");
    // display temp
    u8g2.setCursor(0, 32);
    u8g2.print(tmp_dgt_1);
    u8g2.print(tmp_dgt_2);
    u8g2.setCursor(48, 32);
    u8g2.print(tmp_dgt_3);

      
    u8g2.setFont(not7seg16);
    // set dot, 0 and C
    u8g2.setCursor(105, 24);
    u8g2.print(".");
    u8g2.setCursor(120, 21);
    u8g2.print("/");
    // display set temp
    u8g2.setCursor(83, 24);
    u8g2.print(tset_dgt_1);
    u8g2.print(tset_dgt_2);
    u8g2.setCursor(109, 24);
    u8g2.print(tset_dgt_3);

    // display mode
    u8g2.setFont(not7seg12);
    u8g2.setCursor(82, 58);
    u8g2.print(mode_stateName[mode_setState]);

  } while ( u8g2.nextPage() );

}

/* to do
void dimDisplay() {
  } 
*/

I had similar problem with the DMD2 library for display.

The problem was precisely in the lack of timer interrupt stop.

This is a problem. I see in the library this callback is called from the actual ISR. You should never perform serial I/O in an interrupt!

Why on earth do you need an interrupt to read a temperature sensor? Temperature will NEVER change quickly, so reading using polling should be FAR MORE than adequate. I cannot imagine it needs to be read even once per second, as the time constant for actual temperature change surely measures at least multiple minutes.

Thanks. These lines are in there for debugging purposes. Doesn’t make a difference in the behavior when commented out.

The interrupt is used for the rotary encoder only.

Thank you. Probably my lack of experience, but not sure what the actual solution was in your case and how that would translate?
Hope you can help clarify!
Many thanks

You are printing to Serial IN the ISR. You should not do that, as it can cause the program to hang in the ISR if the Serial buffer is full.

Yes, I am aware. As said, this was for debugging purposes. I only added this after the problem occurred and this doesn't seem to have any impact whatsoever on the observed problematic behaviour as this occurs, both with and without these lines.
I'll post a cleaned up version of the code below if that helps.

Thanks again!

#include <U8g2lib.h>
#include "GroveEncoder.h"
#include <Arduino.h>
#include <Wire.h>
#include "Adafruit_SHT31.h"

#define ENC_PIN 2
#define BTN_PIN 5

int tmp_minVal = 5; 
int tmp_maxVal = 30;
int btn_prevState = LOW; 
int btn_setState = btn_prevState;    
int mode_saveState = 2; // default saved state is HEAT
int mode_setState = mode_saveState;

bool displayState = 1; // start display high (not yet implemented)

unsigned long btn_timeout = 0;
unsigned long read_interval = 0;

float tmp_setVal = 21.0; // default set temp
float tmp_prevVal;
float tmp_readVal = 22.0; // for debugging simulate temperature value
float tmp_prevReadVal;

char *mode_stateName[4] = {" OFF","COOL","HEAT"};

U8G2_SSD1306_128X64_NONAME_2_HW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);  // High speed I2C

Adafruit_SHT31 sht31 = Adafruit_SHT31();

void setup() {
  u8g2.begin();
  u8g2.clearDisplay();
  updateDisplay();
  
  pinMode(BTN_PIN, INPUT_PULLUP);

  GroveEncoder Encoder(ENC_PIN, &isrEncoder, tmp_minVal, tmp_maxVal);
  Encoder.setValue(tmp_setVal);

  sht31.begin(0x44);
 
  
}

void loop() {

  btn_setState = digitalRead(BTN_PIN);
  if(btn_prevState == LOW && btn_setState == HIGH) {
    btnPressed();
  }
  
  btn_prevState = btn_setState;  

  if (btn_timeout <= millis() && btn_timeout > 0) { 
    btnTimeout();
  }

  if (tmp_prevVal != tmp_setVal) {
    tmp_prevVal = tmp_setVal;
  }

  if (read_interval <= millis()) {
    
    tmp_readVal = sht31.readTemperature();
    if (tmp_prevReadVal != tmp_readVal) {
      tmp_prevReadVal = tmp_readVal;
    } 
    read_interval = millis() + 10000;
  } 
  
  updateDisplay();

}

void isrEncoder(int tmp_newVal) {
  tmp_setVal = tmp_newVal;
}


void btnPressed() {

  if (mode_setState == 0) {
    mode_setState = mode_saveState;

  } else if (btn_timeout > millis()) {

    switch (mode_saveState) {
      case 1:
        if (mode_setState++ >= 2) mode_setState = 0;
        break;
      case 2:
        if (mode_setState-- <= 0) mode_setState = 2;
        break;
    }

  } else {
    mode_setState = 0;
  }

  btn_timeout = millis() + 3000;

}

void btnTimeout() {

  if ( mode_saveState != mode_setState && mode_setState != 0) {
    mode_saveState = mode_setState;
  } else if (mode_setState == 0) {
    // switch off (yet to be done)
  }

  btn_timeout = 0; 

}

void updateDisplay() {

  int tmp_dgt_1 = tmp_readVal / 10;
  int tmp_dgt_2 = (tmp_readVal - tmp_dgt_1*10);
  int tmp_dgt_3 = (tmp_readVal*10 - tmp_dgt_1*100 - tmp_dgt_2*10) + 0.5;

  int tset_dgt_1 = tmp_setVal / 10;
  int tset_dgt_2 = (tmp_setVal - tset_dgt_1*10);
  int tset_dgt_3 = (tmp_setVal*10 - tset_dgt_1*100 - tset_dgt_2*10) + .5;
  
  u8g2.firstPage();
  do {
    
    u8g2.setFont(not7seg32);
    // set dot and C
    u8g2.setCursor(42, 32);
    u8g2.print(".");
    u8g2.setCursor(68, 14);
    u8g2.print("/");
    // display temp
    u8g2.setCursor(0, 32);
    u8g2.print(tmp_dgt_1);
    u8g2.print(tmp_dgt_2);
    u8g2.setCursor(48, 32);
    u8g2.print(tmp_dgt_3);

      
    u8g2.setFont(not7seg16);
    // set dot, 0 and C
    u8g2.setCursor(105, 24);
    u8g2.print(".");
    u8g2.setCursor(120, 21);
    u8g2.print("/");
    // display set temp
    u8g2.setCursor(83, 24);
    u8g2.print(tset_dgt_1);
    u8g2.print(tset_dgt_2);
    u8g2.setCursor(109, 24);
    u8g2.print(tset_dgt_3);

    // display mode
    u8g2.setFont(not7seg12);
    u8g2.setCursor(82, 58);
    u8g2.print(mode_stateName[mode_setState]);

  } while ( u8g2.nextPage() );

}


`Preformatted text`

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