using a rotary encoder to scroll through lcd "tabs"

Hi
I am working a very simple home management system, that uses a 16x2 lcd display to show inside tempurate, outside tempurate, the current time and date, and some other static messages.
In order to do this I am try to use a rotary encoder to "toggle" through each of these separate tabs. the encoder I am using is the KY-040.
currently my code looks like this

#include <dht.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include "RTClib.h"

dht DHT;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
RTC_DS1307 RTC;

int greenPin = 7;
int screenselect = 1;
int screenselectprev = 1;
int pinA = 10;  // Connected to CLK on KY-040
int pinB = 6;  // Connected to DT on KY-040
int encoderPosCount = 0;
int pinALast;
int aVal;

boolean bCW;


void setup() {
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  lcd.begin(16, 2);
  pinMode (pinA, INPUT);
  pinMode (pinB, INPUT);
  pinALast = digitalRead(pinA);
  Serial.begin (9600);

}


void loop() {
  Screen(); 
  aVal = digitalRead(pinA);
  if (aVal != pinALast) { // Means the knob is rotating
    if (digitalRead(pinB) != aVal) {  // Means pin A Changed first - Rotating Clockwise
      encoderPosCount ++;
      screenselect ++;
      bCW = true;
    } else {// Otherwise B changed first and we're moving CCW
      bCW = false;
      encoderPosCount--;
      screenselect--;
    }
    serialcheck(); //serialoutput of rotary encoders position (to check that it's reading)
  }
}


void Screen()
{
  if (screenselect > 3)
  {
    screenselect = 0;
  }

  if (screenselect < 0)
  {
    screenselect = 0;
  }

  switch (screenselect)
  {

    case 1:
      {
        temphum(); //tempurature/humidity function
      }

    case 2:
      {
        staticmessage(); //static message function
      }
    case 3:
      {
        showTime(); //time function, using rtc
      }
  }
}

I have tested each of the functions individually, and they all work on the screen.
The way the code is supposed to run is; when you turn the encoder, the screenselect variable increases(or decreases) and then it is tested to ensure it is a number between 1 and 3, then the corresponding function is brought up against the number. However, when I run this code the staticmessage() function comes onto the screen, the serialcheck() function doesnt output anything and turning the encoder doesnt achieve anything. when i remove the first line in the loop() function (Screen():wink: the serialcheck function works normally.
I'm fairly sure this code won't run the dynamic parts properly, however I am trying to get the basic part to work first.

I'm sure the problem is to do with my loop() function, however I have been trying for about a week now and cant get the code to work. can anybody see the fault in my code?

using an arduino uno my layout is like this:
RTC
DS-9
SCL-A5
SDA-A4
tempurature/humidity sensor
S-7
gnd-gnd

    • 5V
      encoder
      clk-10
      DT-6
    • 5V
      gnd-gnd
      display from 1-16
      gnd
      5V
      pot
      12
      gnd
      11

5
4
3
2
gnd

my first forum post, apologies if i missed any info or gave too much.
thanks in advance for the help.

In order to do this I am try to use a rotary encoder to "toggle" through each of these separate tabs.

First, you do NOT have tabs. You might want to cycle (not toggle) through a collection of data items, but you do not want to do what you said.

I find it difficult to understand why you call Screen() which displays some data, and then determine what you want to display.

    if (digitalRead(pinB) != aVal) {  // Means pin A Changed first - Rotating Clockwise

It means no such thing.

Of what possible use is encoderPosCount?

Where do you reset aVal?

Why did you post code that will not compile?

that's what I meant, to cycle through through data items

I've used the Screen() to make the code easier to follow, rather having it all within the loop() function

encoderPosCount is to determine the position of the rotary encoder, for the serialcheck()

aVal becomes the value of pinAlast every loop, does this not count as a reset?

fullcode:

#include <dht.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include "RTClib.h"

dht DHT;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
RTC_DS1307 RTC;

int greenPin = 7;
int screenselect = 1;
int screenselectprev = 1;
int pinA = 10;  // Connected to CLK on KY-040
int pinB = 6;  // Connected to DT on KY-040
int encoderPosCount = 0;
int pinALast;
int aVal;
boolean bCW;


void setup() {
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  lcd.begin(16, 2);
  pinMode (pinA, INPUT);
  pinMode (pinB, INPUT);
  /* Read Pin A
    Whatever state it's in will reflect the last position
  */
  pinALast = digitalRead(pinA);
  Serial.begin (9600);

}


void loop() {
  Screen();
  aVal = digitalRead(pinA);
  if (aVal != pinALast) { // Means the knob is rotating
    // if the knob is rotating, we need to determine direction
    // We do that by reading pin B.
    if (digitalRead(pinB) != aVal) {  // Means pin A Changed first - We're Rotating Clockwise
      encoderPosCount ++;
      screenselect ++;
      bCW = true;
    } else {// Otherwise B changed first and we're moving CCW
      bCW = false;
      encoderPosCount--;
      screenselect--;
    }
    serialcheck();
  }
}


void Screen()
{
  if (screenselect > 3)
  {
    screenselect = 0;
  }

  if (screenselect < 0)
  {
    screenselect = 0;
  }

  switch (screenselect)
  {

    case 1:
      {
        temphum();
      }

    case 2:
      {
        wifi();
      }
    case 3:
      {
        showTime();
      }
  }
}

void serialcheck() {
      Serial.print ("Rotated: ");
    if (bCW) {
      Serial.println ("clockwise");
    } else {
      Serial.println("counterclockwise");
    }
    Serial.print("Encoder Position: ");
    Serial.println(encoderPosCount);

}

  void temphum()
  {
  DHT.read11(greenPin);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Temp:");
  lcd.print(DHT.temperature);
  lcd.print("C");

  lcd.setCursor(0,1);
  lcd.print("Humidity:");
  lcd.print(DHT.humidity);
  lcd.print("%");
  }

  void showTime()
{
   DateTime now = RTC.now();
 lcd.clear();
 lcd.setCursor(0,0);
 lcd.print("Time:");
 lcd.setCursor(6,0);
 lcd.print(now.hour(),DEC);
 lcd.print(":");
 lcd.print(now.minute(),DEC);
 lcd.print(":");
 lcd.print(now.second(),DEC);
 
 lcd.setCursor(0,1);
 lcd.print("Date:");
 lcd.setCursor(6,1);
 lcd.print(now.day(),DEC);
 lcd.print("/");
 lcd.print(now.month(),DEC);
 lcd.print("/");
 lcd.print(now.year(),DEC);
}

  void wifi()
  {
  lcd.clear();
  lcd.setCursor(1,0);
  lcd.print("wifi password");

  lcd.setCursor(2,1);
  lcd.print("oakfordwifi");
  }

I've used the Screen() to make the code easier to follow, rather having it all within the loop() function

That's fine. The problem is this:

void loop()
{
   // Display some data.
   // Determine what to display.
}

Doing things in that order does not make sense.

encoderPosCount is to determine the position of the rotary encoder, for the serialcheck()

Why does the value in encoderPosCount matter? It is NOT what is used to determine what to display.

aVal becomes the value of pinAlast every loop, does this not count as a reset?

Yes. What I meant to ask was where do you reset the value in pinAlast? It makes no sense to call a variable pinAlast when it does not contain the last value of pinA.

Personally, I think your two variables should be called pinAcurr and pinAprev, so that it is obvious that they are related, and it is obvious that they contain the current state of pin A and the previous state of pin A. And, of course, at the end of loop(), you need to copy the current value of pin A to the previous value of pin A.

oh, right. I had it the other way around, I just tried it first before I posted this forum. but in saying that, screenselect is given an initial value of 1, so it shouldn't matter what order it is the body?
I understand that it makes far more sense to have it as

//determine what to display
//display some data

however the same problem arises whether it's that way around, or the other way.

Why does the value in encoderPosCount matter? It is NOT what is used to determine what to display.

encoderPosCount was used to determine that the encoder was being read, i suppose this can be done just as easily with screenselect.

Yes. What I meant to ask was where do you reset the value in pinAlast? It makes no sense to call a variable pinAlast when it does not contain the last value of pinA.

ah, right, I forgot to reassign the value of pinAlast. I changed this, however the same problem still arrises.

updated code (loop() and serialcheck())

#include <dht.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include "RTClib.h"

dht DHT;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
RTC_DS1307 RTC;

int greenPin = 7;
int screenselect = 1;
int screenselectprev = 1;
int pinA = 10;  // Connected to CLK on KY-040
int pinB = 6;  // Connected to DT on KY-040
int encoderPosCount = 0;
int pinALast;
int pinAcurr;
boolean bCW;


void setup() {
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  lcd.begin(16, 2);
  pinMode (pinA, INPUT);
  pinMode (pinB, INPUT);
  /* Read Pin A
    Whatever state it's in will reflect the last position
  */
  pinALast = digitalRead(pinA);
  Serial.begin (9600);

}


void loop() {

  pinAcurr = digitalRead(pinA);
  if (pinAcurr != pinALast) { // Means the knob is rotating
    // if the knob is rotating, we need to determine direction
    // We do that by reading pin B.
    if (digitalRead(pinB) != pinAcurr) {  // Means pin A Changed first - We're Rotating Clockwise
      screenselect ++;
      bCW = true;
    } else {// Otherwise B changed first and we're moving CCW
      bCW = false;
      screenselect--;
    }
    serialcheck();
  }
  pinALast = pinAcurr;
  Screen();

}
void serialcheck() {
      Serial.print ("Rotated: ");
    if (bCW) {
      Serial.println ("clockwise");
    } else {
      Serial.println("counterclockwise");
    }
    Serial.print("Encoder Position: ");
    Serial.println(screenselect);

}

I've updated the variable aval to pinAcurr, swapped the order of Screen() and the digital read on the encoder. This has not changed the initial problem.

How many pulses does your encoder output on one revolution? You may be missing pulses, if the number of pulses per revolution is high.

Why not print the value of screenselect in Screen(), to make sure it contains what you think it does?

Why do you talk about it containing 1, 2, or 3, when you constrain it to 0 to 3?