KY-040 does not respond // Arduino Dehydrator

Yes this is true
at the bottom of your loop there is a delay(2000);

  // update Sequenz DHT11
  delay(2000);

  lcd.clear();
}

This means that all and every action only happends after 2 seconds.

Your code is one of that very often occuring cases where the command delay is delaying the development-process much more than taking time to learn non-blocking timing.
@Arduino-Team: take out the command delay() out of EVERY example-code!
take in a non-blocking version of timing.

There are very good reasons to execute parts of the code only once every two seconds or even longer time-intervals. This should be programmed using non-blocking timing.

There might be users that don't like my version of non-blocking timing
my opinion:
The advantages far outweigh the disadvantages because the external function is fairly easy to understand. And this is what is important for beginners.

As your programming knowledge grows, you will also understand the inner workings.

And I made a very conscious decision by posting my version very often to try to make it the new de-facto-standard against the common used version.
If somebody feels the need to go against this. Of course you are free to do so. I claim: most users are just used to use the "standard"-nonblocking timing and are too lazy to learn my version. Users you will have to give up lazyness and take the effort of posting your version including easy to understand explanations each time.

Back to programming:
the basic principle of non-blocking timing is to check if a defined timeinterval
has passed by.

This can be done by using the function millis()
The function millis() gives back the amount of milliseconds (hence the name millis)
that have passed by since power-up of the microcontroller.
It counts up to 2^32 which means reaching the max-value is reached after 49 days.
There is a calculation-technique that even "rollover" from max to zero is handled
automatically the right way

This non-blocking timing needs a timer-variable which is used for taking
snapshots of time as a comparison-point

The variable-type for this variable MUST be of type unsigned long
to make it work reliably all the time

unsigned long myLcdUpdateTimer;

now the following construction executes the code inside the if-condition
only once every two seconds

  if ( TimePeriodIsOver(myLcdUpdateTimer,2000) ) {
     // time for timed action
  }  

Here is the modified version of your function loop()

void loop() {

  // Read temperature und humidity from DHT11 and Print to LCD
  solltemperatur = 0; // The manually set temperature
  temperatur = dht.readTemperature(); // The environment temperature
  luftfeuchtigkeit = dht.readHumidity(); // The environment humidity (not in use atm)

  //lcd.clear();

  // read the "now" value
  clkaktuell = digitalRead(CLK);

  // notice turns
  if (clkaktuell != clkletzter) {
    // count up if CLK is triggered first
    if (digitalRead(DT) != clkaktuell) {
      solltemperatur ++;
    }
    // count down if DT is triggered first
    else {
      solltemperatur --;
    }
  }

  // low end limit of set temperature
  if (solltemperatur < 25) {
    solltemperatur = 25;
  }
  // high end limit of set temperature
  if (solltemperatur > 70) {
    solltemperatur = 70;
  }

  // turn the relay on if the environment temperature is lower
  // than the set temperature
  if (solltemperatur < temperatur) {
    digitalWrite(10, HIGH);
    digitalWrite(11, HIGH);
  }
  // turn of if not
  else {
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
  }

  // update Sequenz DHT11
  //delay(2000);
  if ( TimePeriodIsOver(myLcdUpdateTimer, 2000) ) {
    printToLCD(); // update LCD only once every 2000 milliseconds
  }

the difference is at the bottom: This code makes the loop "looping at high speed but updates the LCD only once every 2 seconds. This enables to detect turning the rotary-encoder again.

But I want to add something: The basic intention of understanding code is good. But If a part of the code works 100% reliably and is used in always the same manner it can be hided away.
Example

digitalWrite(10,HIGH);

there is a lt of going on "under the hood" to switch an IO-pin HIGH
but you simply don't know the details and you don't feel any need to do so.

It is the same thing with libraries.
Did you analyse a single line of code inside the files
LiquidCrystal_I2C.h // LiquidCrystal_I2C.cpp
I'm pretty sure you didn't even know that there is a second file LiquidCrystal_I2C.cpp

So with the timing function "IfTimePeriodIsOver() that I inserted into your code it is the same. Still understanding this function is 90% easy. (There are 10% left caused by the "&"-symbol in front of the first parameter)

Here is the full code that compiles. I have marked each part that has been modified by me with a looooong line like this

// ********************************************************************
// Doofenschmirtz Dörrinator
// Mads Duggen
// Interactive Prototyping 2021
// Muthesius Kunsthochschule

// ARDUINO PIN USAGE

// LCD with I2C module
// A5 - SCL
// A4 - SDA
// 5v - VCC
// GND - GND

// DHT 11 sensor
// 8 - OUTPUT
// 5v - VCC
// GND - GND

// Heater and fan relay CH1 & CH2
// 10 - CH1
// 11 - CH2
// 5v - DC+
// GND - DC-

// KY-040 rotary encoder
// 3 - CLK
// 4 - DT
// 5 - SW
// 5v - +
// GND - GND

//Utilised libarys
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

// Data-Pin and sensortype
#define DHTPIN 8
#define DHTTYPE DHT11

// KY-040 pins
int CLK = 3;
int DT = 4;
int SW = 5;

int solltemperatur;
int temperatur;
float luftfeuchtigkeit;
int clkletzter;
int clkaktuell;

// LCD und DHT objects
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);

//***********************************************
unsigned long myLcdUpdateTimer;

//*****************************************************************
// helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();  
  if ( currentMillis - expireTime >= TimePeriod )
  {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}
// ********************************************************************


void setup() {

  // initialising relay pins
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);

  // initialising KY-040 pins
  pinMode(CLK, INPUT);
  pinMode(DT, INPUT);
  pinMode(SW, INPUT);

  digitalWrite(CLK, true);
  digitalWrite(DT, true);
  digitalWrite(SW, true);

  //initial read CLK pin
  clkletzter = digitalRead(CLK);

  // Welcoming Screen

  dht.begin(); // initialising DHT11 sensor
  lcd.backlight(); // Start backlight
  lcd.begin(); // initialising LCD

  delay(2000);

  lcd.setCursor( 0, 0);
  lcd.print(" Doofenschmirtz");
  lcd.setCursor( 0, 1);
  lcd.print(" Doerrinator");

  delay(5000);
}

//**************************************************
// each part of the code that form a senseful unit
// should be inside its own function
void printToLCD() {
  lcd.clear();

  //print the environment temperature to the first row of the LCD
  lcd.setCursor( 0, 0);
  lcd.print("Temp. :");
  lcd.print(temperatur);
  lcd.print("C");

  //print the environment humidity to the second row of the LCD
  lcd.setCursor( 0, 1);
  lcd.print("Soll. :");
  lcd.print(solltemperatur); // Changeable Value representing the set temperature of the Dehydrator
  lcd.print("C");
}
// **********************************************************************

void loop() {

  // Read temperature und humidity from DHT11 and Print to LCD
  solltemperatur = 0; // The manually set temperature
  temperatur = dht.readTemperature(); // The environment temperature
  luftfeuchtigkeit = dht.readHumidity(); // The environment humidity (not in use atm)

  //lcd.clear();

  // read the "now" value
  clkaktuell = digitalRead(CLK);

  // notice turns
  if (clkaktuell != clkletzter) {
    // count up if CLK is triggered first
    if (digitalRead(DT) != clkaktuell) {
      solltemperatur ++;
    }
    // count down if DT is triggered first
    else {
      solltemperatur --;
    }
  }

  // low end limit of set temperature
  if (solltemperatur < 25) {
    solltemperatur = 25;
  }
  // high end limit of set temperature
  if (solltemperatur > 70) {
    solltemperatur = 70;
  }

  // turn the relay on if the environment temperature is lower
  // than the set temperature
  if (solltemperatur < temperatur) {
    digitalWrite(10, HIGH);
    digitalWrite(11, HIGH);
  }
  // turn of if not
  else {
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
  }

  // update Sequenz DHT11
  //delay(2000);
  if ( TimePeriodIsOver(myLcdUpdateTimer, 2000) ) {
    printToLCD(); // update LCD only once every 2000 milliseconds
  }

}

best regards Stefan

1 Like