Assistance with button inputs and OLED

Can I please have more assistance with the below code. The issues that I have now are:

  • At times the button does not change the set point and requires pressing 2 or 3 times to change ++ or -- (would a debounce benefit here?)
  • The OLED shifts down by one full row of pixels at times????
  • How can I re-write the code so that the "Steinhart" print to the OLED doesn't flash? I can change the flashing frequency by altering the delay after the samples but as I understand it the samples are required. More so looking for how I can constantly print (Steinhart) without the flashing to the OLED.
//Working OLED Set Point Sketch
//Working 100K Thermistor Temp Display

// which analog pin to connect
#define THERMISTORPIN A0         
// resistance at 25 degrees C
#define THERMISTORNOMINAL 100000      
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25   
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR 100000 

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

//Key connections with arduino
const int up_key=3;
const int down_key=2;

int samples[NUMSAMPLES];

int ledPin = 13;       // pin that the LED is attached to

int SetPoint=35;

//=================================================================
//                  SETUP
//=================================================================

void setup()
{
  //Setting Reference for Thermistor
  analogReference(EXTERNAL);
  
  //Seting buttons as Inputs
  pinMode(up_key,INPUT);
  pinMode(down_key,INPUT);
  
  //Pull up for setpoint keys
  digitalWrite(up_key,HIGH);
  digitalWrite(down_key,HIGH);
  
   // Clear the buffer.
  
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);// initialize with the I2C addr 0x3C (for the 128x32)(initializing the display)
  display.clearDisplay();
  delay(2000);


  // Clear the buffer.
  display.clearDisplay();

// text display tests
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(5,5);
  display.print(" "); display.println("Sous Vide");
  display.display();
  delay(2000);

   // Clear the buffer.
  display.clearDisplay();


  //Rectangle Display
  for (int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i, display.height()/4, WHITE);
    display.display();
    delay(1000);
   }

    // Clear the buffer.
  display.clearDisplay();
  delay(100);

}


//=================================================================
//                  LOOP
//=================================================================


void loop()
{

uint8_t i;
  float average;

  // take N samples in a row, with a slight delay
  for (i=0; i< NUMSAMPLES; i++) {
   samples[i] = analogRead(THERMISTORPIN);
   delay(100);
  }

  // average all the samples out
  average = 0;
  for (i=0; i< NUMSAMPLES; i++) {
     average += samples[i];
  }
  average /= NUMSAMPLES;

  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  //Serial.print("Thermistor resistance "); 
  //Serial.println(average);

  float steinhart;
  steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                         // convert to C

  Serial.print("Temperature "); 
  Serial.print(round(steinhart));
  Serial.println(" *C");

  
  //Get user input for setpoints  
  if(digitalRead(down_key)==LOW)
  {
    if(SetPoint>0)
    {
      SetPoint--;    
    }
    delay(10);
  }
  if(digitalRead(up_key)==LOW)
  {
    if(SetPoint<150)
    {
      SetPoint++;
    }
    delay(10);
  }
  
  //Serial Monitor printing od Set Point
  Serial.println(SetPoint);
  delay(100); //Update at every 100mSeconds
  
// text display tests
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(64,18);
  display.print(SetPoint);
  display.display();
  delay(100);

   display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(64,0);
  display.print(round(steinhart));
  display.display();
  delay(100);
  
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(0,0);
  display.print("Temp=   C");
  delay(10);
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(0,18);
  display.print("Set =   C");
  delay(10);

  // if temperature is less than Set Point Switch LED on
if (steinhart < SetPoint) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }

  
}
  • At times the button does not change the set point and requires pressing 2 or 3 times to change ++ or -- (would a debounce benefit here?)

All of those delay()s are making your sketch unresponsive. The processor is virtually frozen during delay(). The blink without delay example and the several things at a time post show how to do non-blocking timing. If you want responsive code you need to not use for loops (especially with delay()s in them) and while loops unless they execute quickly.

  // take N samples in a row, with a slight delay
  for (i=0; i< NUMSAMPLES; i++) {
   samples[i] = analogRead(THERMISTORPIN);
   delay(100);
  }

How can you expect to react to switch press events, in a timely fashion, when you are sticking your head in the sand for nearly a second on every pass through loop()?

  // average all the samples out
  average = 0;
  for (i=0; i< NUMSAMPLES; i++) {
     average += samples[i];
  }
  average /= NUMSAMPLES;

Why not just increment average in the first loop? There is no reason to keep an array of values just to determine the average.

PaulS:

  // take N samples in a row, with a slight delay

for (i=0; i< NUMSAMPLES; i++) {
  samples[i] = analogRead(THERMISTORPIN);
  delay(100);
  }



How can you expect to react to switch press events, in a timely fashion, when you are sticking your head in the sand for nearly a second on every pass through loop()?



// average all the samples out
  average = 0;
  for (i=0; i< NUMSAMPLES; i++) {
    average += samples[i];
  }
  average /= NUMSAMPLES;



Why not just increment average in the first loop? There is no reason to keep an array of values just to determine the average.

How would you suggest I rectify this issue? Sorry but how would I go about the increment average in the first loop? Also if I were to lower the delay to say 1 ms would that be of benefit or would it create a more transient reading?

PaulS:
Why not just increment average in the first loop? There is no reason to keep an array of values just to determine the average.

Because the quickest way to compute the average is to add the new value that just arrived to the total and subtract the oldest one in the array, then store the new value in the array. If you can afford the storage then it's much faster than any other method. It's called the "recursive implementation" of a moving-average filter.

Cycling through the entire array every time is naturally one of the slowest ways. 8)

mack85n:
Also if I were to lower the delay to say 1 ms would that be of benefit or would it create a more transient reading?

Delays are bad. You have a processor capable of 16 million operations per second and you want it to do a few hundred. Spend the other 15,999,699 operations doing something useful like checking if you pushed the button already. Fortunately it will never get bored of saying "Are we there yet?" millions of times per second.