Need help with interrupts

Hey there! I integrated a small oled display into my car´s dashboard to display two temperatures (oil and outside). The whole thing is switchable using an obsolete switch (fog lights).

Hardware is:

Arduino Nano
2x DS18B20
128x32 OLED

Everything works, except the instant switching, as the DS18B20 need an amount of time to get read.

I´m not that good at programming, so i´ve never used interrupts, which should help me with my problem.

If anyone is willing to help me out, it would be appreciated!

Please don´t bash me, the code isn´t that professional.

I need a way to integrate an interrupt, so that the display switches instantly, no matter of delays and stuff.

#include <SPI.h>
#include <Wire.h>
#include <Bounce2.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);
//******************************************************************************************************************************************************

//int tempoil, tempout;
int wahl = 1;
int ox, oy, ax, ay;
float tempoil, tempout;

DeviceAddress oiltemp, outtemp;

void setup()   {       
  pinMode(3, INPUT_PULLUP);
  sensors.setResolution(9);    
  sensors.begin();     
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 
  display.display();
  //delay(2000);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  delay(2500); //verzoegerung fuer bootlogo
}

void loop() {
  sensors.setResolution(9);
  sensors.requestTemperatures();
  float tempoil = sensors.getTempCByIndex(0);
  float tempout = sensors.getTempCByIndex(1);
 
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(30,18);
  if(digitalRead(3) == LOW)
    {
      wahl = 1 - wahl;
    }
  if(tempoil < -10) ox = 41 ; oy = 18 ;  
  if(tempoil > -10) ox = 53 ; oy = 18 ;
  if(tempoil == 0) ox = 65 ; oy = 18 ;
  if(tempoil > 0) ox = 65 ; oy = 18 ;
  if(tempoil == 10) ox = 53 ; oy = 18 ;
  if(tempoil > 10) ox = 53 ; oy = 18 ;
  if(tempoil == 100) ox = 41 ; oy = 18 ;
  if(tempoil > 100) ox = 41 ; oy = 18 ;
  
  if(tempout < -10) ax = 41 ; ay = 18 ;
  if(tempout > -10) ax = 53 ; ay = 18 ;
  if(tempout == 0) ax = 65 ; ay = 18 ;
  if(tempout > 0) ax = 65 ; ay = 18 ;
  if(tempout == 10) ax = 53 ; ay = 18 ;
  if(tempout > 10) ax = 53 ; ay = 18 ;
   
  if(wahl == 1)
    {
      display.setCursor(ox,oy); //30, 18
      display.print(tempoil, 1);
      display.setCursor(0,0);
      display.setTextSize(1);
      display.print("Oeltemperatur:");
      display.drawCircle(110, 18, 2, WHITE);
      display.setCursor(115,18);
      display.setTextSize(2);
      display.print("C");
      display.display();    
    }
   if(wahl == 0)
    {
      display.setCursor(ax,ay);
      display.print(tempout, 1);
      display.setCursor(0,0);
      display.setTextSize(1);
      display.print("Aussentemperatur:");
      display.drawCircle(110, 18, 2, WHITE);
      display.setCursor(115,18);
      display.setTextSize(2);
      display.print("C");
      display.display();
    }
  
  delay(1000);
  display.clearDisplay();
}

Thanks in advance

PS: English isn´t my motherlanguage :slight_smile:

Welcome to the forums! +1 for actually posting your code inside code tags!

You don't need to implement interrupts, you need to get rid of your delay(1000) inside loop(). Have a look at the BlinkWithoutDelay example to see how to track elapsed time.

By doing it that way, you can very quickly run through loop() to detect the button press and then display the proper information. You should also look at the StateChangeDetection example since you really want to react to the button changing state, not necessarily to what the current state of the button happens to be. This will debounce the button and avoid needlessly redrawing the same information.

Why do you think that using interrupts may help ?

You would almost certainly be better off removing delay()s and using millis() for timing.

See Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

Incidentally in this portion of code

  if (tempoil < -10) ox = 41 ;
  oy = 18 ;
  if (tempoil > -10) ox = 53 ;
  oy = 18 ;
  if (tempoil == 0) ox = 65 ;
  oy = 18 ;
  if (tempoil > 0) ox = 65 ;
  oy = 18 ;
  if (tempoil == 10) ox = 53 ;
  oy = 18 ;
  if (tempoil > 10) ox = 53 ;
  oy = 18 ;
  if (tempoil == 100) ox = 41 ;
  oy = 18 ;
  if (tempoil > 100) ox = 41 ;
  oy = 18 ;
  if (tempout < -10) ax = 41 ;
  ay = 18 ;
  if (tempout > -10) ax = 53 ;
  ay = 18 ;
  if (tempout == 0) ax = 65 ;
  ay = 18 ;
  if (tempout > 0) ax = 65 ;
  ay = 18 ;
  if (tempout == 10) ax = 53 ;
  ay = 18 ;
  if (tempout > 10) ax = 53 ;
  ay = 18 ;

oy and ay will always be set to 18. You only need to do it once, if that is what you want to do

Everything works, except the instant switching, as the DS18B20 need an amount of time to get read.

The DS18B20 takes, MAYBE, tens of micro-seconds to read! You could read it 1000 times in a row, and not be able to perceive the delay that caused.

Right now, you read the sensor, update the display, then do absolutely NOTHING ("delay(1000);") for a full second. That is your problem.

Instead, read the sensor perhaps 10X/second, and update the display after each read. NEVER use delay() but instead use the techniques here:

Your display updates will appear instantaneous, and you will still have 99% of your processing power left over to do other things.

Regards,
Ray L.

blh64:
By doing it that way, you can very quickly run through loop() to detect the button press and then display the proper information.

Thanks for the quick response! problem is, that even if i spare out the delays, the reading of the DS18B20 take some milliseconds, in which the nano does not react to button presses.

Besides the delays that you must get rid of (use millis()-based timing and State Machine techniques), the way you're using the DallasTemperature is causing you unnecessary delays. Interrupts are definitely not the solution.

Your first problem with the library is use of the getTempCByIndex() function. That causes a complete OneWire bus scan to get the required device addresses every time you call it. Instead, you can scan the bus to get and save the addresses once in setup().

Second (and most importantly), use the non-blocking version by calling sensors.setWaitForConversion(false) -- only once in setup(). This will force the library to return immediately after your call to sensors.requestTemperatures(). Then, in loop(), you call sensors. getTempC() with the device address pointer as a parameter. But, you only do this after the required time has elapsed. IMPORTANT -- don't use delay() for this, use a millis() timer and keep the loop() function looping. The amount of time you must wait is determined by sensors.millisToWaitForConversion() which you should call only once in setup().

Finally, only call sensors.setResolution(9) once in setup(), not every time through loop().

The above techniques will allow your code to do other things (and be responsive to buttons) while you're waiting for the devices to be ready to send the temperature -- and ONLY IF YOU DO NOT USE delay()!!!

Okay. I deleted the second resolution setting.
Now im about to find the adresses. I did use an example code, which gave me two adresses:

Locating devices...Found 2 devices.
Parasite power is: OFF
Found device 0 with address: 28AA8BE33B140161
Setting resolution to 9
Resolution actually set to: 9
Found device 1 with address: 28FFBCFDB117043E
Setting resolution to 9
Resolution actually set to: 9

I have n0 idea how to set and request those adresses. :frowning:

The DS18B20 can take a long time to read using a lot of the libraries, which wait for conversion depending on the resolution requested (upto 700mS?)

You can set it to convert , do other stuff then read , or store values for instant reading , when your program has nothing else to do. You need to google a bit on the DS18B20 for that .

Nevermind. I got it to work. Set the adresses and used sensors.requestTemperaturesByAddress(xxx);

Thanks for your help, especially gfvalvo :grinning:

You can still do better. Use sensors.requestTemperatures(). This will request a temperature conversion from all devices simultaneously. It executes faster and conversion time will be the same since all sensors have the same resolution. Then, use getTempC(xxx) to get the temperature of sensor w/ address xxx.

BockwurstBernd:
Thanks for the quick response! problem is, that even if i spare out the delays, the reading of the DS18B20 take some milliseconds, in which the nano does not react to button presses.

sensors.requestTemperatures(); is a blocking code; it waits until the conversion is complete. Instead, you can use the following code; where, the MCU can check the closing condition of your button while polling the end-of-conversion status.

ds.write(0x44);    //conversion command
  do   //let sensor take as much time as it needs to finish conversion
  {
    busStatus = ds.read();
    bool n = digitalRead(3);    //sensing button closure
    if(n == 0)
    {
        flag1 = true;                //closed button found
        break;
    }
  }
  while (busStatus != 0xFF);
  
  if(flag1 == true)
  {
     //button closed; take action as needed
     flag1 = false;
  }
  else
  {
     //read temperature data from DS18B20
  }

GolamMostafa:
sensors.requestTemperatures(); is a blocking code; it waits until the conversion is complete.

Reply #5 shows how to make that a non-blocking call which is what was suggested.