How to paginate my project

Hi everyone, I'm a total beginner and am looking for some help (so go easy on me). I have an Arduino Mega with a LCD screen from Adafruit. I'm attempting to design a testing unit to be able to read pulses from an encoder and hopefully eventually be able to do a count test, whereby counting only the A &B pulses on one rotation (from Z pulse to Z pulse).

So far, I have it working where it'll show the number of counts that have been sensed on screen. The LCD screen also has buttons; I'm hoping to be able to paginate information. Not sure exactly how to do that. I've been looking at the Adafruit "Hello,World" example and have been able to figure out how to paginate, but can't get it to update continuously. I've since reverted to my working project where everything working and is just on one screen. This is what I have thus far:

// Include the library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <PinChangeInterrupt.h>

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// Encoder output to Arduino Interrupt pin. Tracks the pulse count.
#define ENC_A 18
#define ENC_B 19
 
// Keep track of the number of pulses
volatile long pulse_count_a = 0;
volatile long pulse_count_b = 0;
volatile long pulse_count_z = 0;
 
void setup() {
  // Put your setup code here, to run once:
 
  // Open the serial port at 9600 bps
  Serial.begin(9600); 

  // Set up the LCD's number of columns and rows 
  lcd.begin(16, 2);

  // Print to the LCD.
  lcd.setCursor(0, 0);
  lcd.print("A:");
  lcd.setCursor(0, 1);
  lcd.print("B:");
  lcd.setCursor(11, 0);
  lcd.print("Z:");
 
  // Set pin states of the encoder
  pinMode(ENC_A , INPUT_PULLUP);
  pinMode(ENC_B , INPUT_PULLUP);
 
  // Every time the pin goes high, this is a pulse
  attachInterrupt(digitalPinToInterrupt(ENC_A), pulse_a, RISING);
  attachInterrupt(digitalPinToInterrupt(ENC_B), pulse_b, RISING);
  attachPinChangeInterrupt(23, pulse_z, RISING);
}

uint8_t i=0; 

void loop() {
  // Put your main code here, to run repeatedly:

  // Write pulse counts to display
  lcd.setCursor(2,0);
  lcd.print(pulse_count_a);
  lcd.setCursor(2,1);
  lcd.print(pulse_count_b);
  lcd.setCursor(13,0);
  lcd.print(pulse_count_z);
}
 
// Increment the number of A pulses by 1
void pulse_a() {
  pulse_count_a++;
}

// Increment the number of B pulses by 1
void pulse_b() {
  pulse_count_b++;
}

// Increment the number of Z pulses by 1
void pulse_z() {
  pulse_count_z++;
}

I know that the printing section in setup() is obviously going to have to move and that code will be need to be added to sense the buttons. I actually did that at one point, however I was unable to make it continuously update as it does now (would update when I hit the update button a second time). How can I accomplish this where, for example, pressing up would display what I have thus far, but pressing down clears the screen completely and would allow me to add a whole screen with different functionality? Any help would be greatly appreciated!

Adafruit have an overview where you will find links to the library for the buttons and more:

Yes, I have that. I'm not having luck trying to paginate using the buttons.

I do not see any calls to lcd.readButtons()

Page 19, bottom.

I’m also trying to figure out how to have the A and B count reset to zero each time Z goes high (once per revolution). I tried an if statement and setting the variables that retain the count to = 0, but couldn’t get it to work; I must be missing something. Seems like it’d be simple, but just can’t wrap my head around it; I’m not much of a programmer. Anyone have any ideas on how to do that?

Hi,

Are you detecting when Z changes state, or if Z attains a state.

That is when Z goes from LOW to HIGH, or HIGH to LOW.

Tom.. :smiley: :+1: :coffee: :australia:

You can work with switch case and menu index.

Try this:

// Include the library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <PinChangeInterrupt.h>

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// Encoder output to Arduino Interrupt pin. Tracks the pulse count.
#define ENC_A 18
#define ENC_B 19

// Keep track of the number of pulses
volatile long pulse_count_a = 0;
volatile long pulse_count_b = 0;
volatile long pulse_count_z = 0;

#define UPDATE_INTERVAL 1 // Time is seconds

int menuIndex = 0;
unsigned long prevMillis = 0;

void pulse_a();
void pulse_b();
void pulse_z();

void setup()
{
  // Put your setup code here, to run once:

  // Open the serial port at 9600 bps
  Serial.begin(9600);

  // Set up the LCD's number of columns and rows
  lcd.begin(16, 2);

  // Print to the LCD.
  lcd.setCursor(0, 0);
  lcd.print("A:");
  lcd.setCursor(0, 1);
  lcd.print("B:");
  lcd.setCursor(11, 0);
  lcd.print("Z:");

  // Set pin states of the encoder
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);

  // Every time the pin goes high, this is a pulse
  attachInterrupt(digitalPinToInterrupt(ENC_A), pulse_a, RISING);
  attachInterrupt(digitalPinToInterrupt(ENC_B), pulse_b, RISING);
  attachPinChangeInterrupt(23, pulse_z, RISING);
}

uint8_t i = 0;

void loop()
{
  uint8_t buttons = lcd.readButtons();
  if (buttons)
  {
    if (buttons & BUTTON_UP)
    {
      menuIndex--;
      prevMillis = millis() - (UPDATE_INTERVAL * 1000UL);
      if(menuIndex < 0)
      {
        menuIndex = 0;
      }
    }
    if (buttons & BUTTON_DOWN)
    {
      menuIndex++;
      prevMillis = millis() - (UPDATE_INTERVAL * 1000UL);
    }
  }

  switch (menuIndex)
  {
    case 0:
      {
        if((millis() - prevMillis) > (UPDATE_INTERVAL * 1000UL))
        {
          lcd.setCursor(2,0);
          lcd.print(pulse_count_a); // Write pulse counts to display
          lcd.setCursor(2,1);
          lcd.print(pulse_count_b);
          lcd.setCursor(13,0);
          lcd.print(pulse_count_z);
          prevMillis = millis();
        }
        break;
      }
    case 1:
      {
        if((millis() - prevMillis) > (UPDATE_INTERVAL * 1000UL))
        {
          lcd.setCursor(2,0);
          lcd.print("Menu 1");
          prevMillis = millis();
        }
        break;
      }
    case 2:
      {
        if((millis() - prevMillis) > (UPDATE_INTERVAL * 1000UL))
        {
          lcd.setCursor(2,0);
          lcd.print("Menu 2");
          prevMillis = millis();
        }
        break;
      }
    case 3:
      {
        if((millis() - prevMillis) > (UPDATE_INTERVAL * 1000UL))
        {
          lcd.setCursor(2,0);
          lcd.print("Menu 3");
          prevMillis = millis();
        }
        break;
      }
    default:
      {
        break;
      }
  }
}

// Increment the number of A pulses by 1
void pulse_a()
{
  pulse_count_a++;
}

// Increment the number of B pulses by 1
void pulse_b()
{
  pulse_count_b++;
}

// Increment the number of Z pulses by 1
void pulse_z()
{
  pulse_count_z++;
}

Thank you, although I couldn't get that to work. I wasn't able to get any type of menu system working from that. Here is my current code, minus any type of menu system (I've made some changes since my first post)

// Include the library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <PinChangeInterrupt.h>

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// Encoder output to Arduino Interrupt pin
#define ENC_A 18  // This is physical pin 18 on Arduino Mega
#define ENC_B 19  // This is physical pin 19 on Arduino Mega
#define ENC_Z 23  // This is physical pin A15 on Arduino Mega
 
// Keep track of the number of pulses
volatile long pulse_count_a = 0;
volatile long pulse_count_b = 0;
volatile long pulse_count_z = 0;
 
void setup() {
  // Put your setup code here, to run once:

  // Set up the LCD's number of columns and rows 
  lcd.begin(16, 2);

  // Print A, B, Z to the LCD once
  lcd.setCursor(0, 0);
  lcd.print("A:");
  lcd.setCursor(0, 1);
  lcd.print("B:");
  lcd.setCursor(11, 0);
  lcd.print("Z:");
 
  // Set pin states of the encoder
  pinMode(ENC_A , INPUT_PULLUP);
  pinMode(ENC_B , INPUT_PULLUP);
 
  // Every time the pin goes high, this is a pulse
  attachInterrupt(digitalPinToInterrupt(ENC_A), pulse_a, RISING);
  attachInterrupt(digitalPinToInterrupt(ENC_B), pulse_b, RISING);
  attachPinChangeInterrupt(ENC_Z, pulse_z, RISING);
}

uint8_t i=0; 

void loop() {
  // Put your main code here, to run repeatedly:

  // Write pulse counts to display
  lcd.setCursor(2,0);
  lcd.print(pulse_count_a);
  lcd.setCursor(2,1);
  lcd.print(pulse_count_b);
  lcd.setCursor(13,0);
  lcd.print(pulse_count_z);

  // Check if Z pulse has changed, if so, reset A & B counts to zero and clear the count on screen
  if (pulse_count_z != i) {
    pulse_count_a = 0;
    pulse_count_b = 0;
    i = pulse_count_z;
    lcd.setCursor(2, 0);
    lcd.print("         ");
    lcd.setCursor(2, 1);
    lcd.print("         ");
  }
}
 
// Increment the number of A pulses by 1
void pulse_a() {
  pulse_count_a++;
}

// Increment the number of B pulses by 1
void pulse_b() {
  pulse_count_b++;
}

// Increment the number of Z pulses by 1; reset A & B to zero when Z changes; clear count on screen
void pulse_z() {
  pulse_count_z++;
}

What doesn't works in my example?

There was no menu system. After looking at the code, I think pressing up or down was supposed to take you to different pages of information, correct? And thank you, I appreciate the help!!

What you can get using this example?

I can't see this wiring in your first pic.

What you did to connect SDA and SCL?

Nothing, I don't have anything connected to 20 and 21. I don't have anything hooked up like that. I have A, B & Z hooked up on 18, 19 and A15 respectively. Power and ground for the encoder is on the +5V and 0V on the pins labeled as such on the right side of the board (red and black wires).


// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.

Correct. I am not using those pins.

When I use the example from Adafruit, I can get information on other screens, however it doesn't update continuously; it only updates when the corresponding button is pressed. Is there a way to code this so that information on the pages can update continuously (similar to how I have it now, but just with one screen)?

Show me your current circuit.

I took it all out, as it didn't work out, but basically I had merged my code with the Adafruit code above. I had the info on separate screens, it just wouldn't update continuously; only when the corresponding button was pressed, would it actually update, which makes sense given the code.

// Include the library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <PinChangeInterrupt.h>

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// Encoder output to Arduino Interrupt pin
#define ENC_A 18  // This is physical pin 18 on Arduino Mega
#define ENC_B 19  // This is physical pin 19 on Arduino Mega
#define ENC_Z 23  // This is physical pin A15 on Arduino Mega
 
// Keep track of the number of pulses
volatile long pulse_count_a = 0;
volatile long pulse_count_b = 0;
volatile long pulse_count_z = 0;

float AB_Ratio;
 
void setup() {
  // Put your setup code here, to run once:

  // Set up the LCD's number of columns and rows 
  lcd.begin(16, 2);

  // Print A, B, Z to the LCD once
  lcd.setCursor(0, 0);
  lcd.print("A:");
  lcd.setCursor(0, 1);
  lcd.print("B:");
  lcd.setCursor(9, 0);
  lcd.print("Z:");
  lcd.setCursor(9,1);
  lcd.print("AB:");
 
  // Set pin states of the encoder
  pinMode(ENC_A , INPUT_PULLUP);
  pinMode(ENC_B , INPUT_PULLUP);
 
  // Every time the pin goes high, this is a pulse
  attachInterrupt(digitalPinToInterrupt(ENC_A), pulse_a, RISING);
  attachInterrupt(digitalPinToInterrupt(ENC_B), pulse_b, RISING);
  attachPinChangeInterrupt(ENC_Z, pulse_z, RISING);
}

uint8_t i=0; 

void loop() {
  // Put your main code here, to run repeatedly:

  // Write pulse counts to display
  lcd.setCursor(2,0);
  lcd.print(pulse_count_a);
  lcd.setCursor(2,1);
  lcd.print(pulse_count_b);
  lcd.setCursor(11,0);
  lcd.print(pulse_count_z);

  // Check if Z pulse has changed, if so, reset A & B counts to zero and clear the count on screen
  if (pulse_count_z != i) {
    pulse_count_a = 0;
    pulse_count_b = 0;
    i = pulse_count_z;
    lcd.setCursor(2, 0);
    lcd.print("       ");
    lcd.setCursor(2, 1);
    lcd.print("       ");
  }

  AB_Ratio = 360 * (pulse_count_a / pulse_count_b);

  if (AB_Ratio > 180) {
    AB_Ratio -= 360;
    lcd.setCursor(12,1);
    lcd.print(AB_Ratio);
  }
  else {
    lcd.setCursor(12,1);
    lcd.print(AB_Ratio);
  }
}
 
// Increment the number of A pulses by 1
void pulse_a() {
  pulse_count_a++;
}

// Increment the number of B pulses by 1
void pulse_b() {
  pulse_count_b++;
}

// Increment the number of Z pulses by 1; reset A & B to zero when Z changes; clear count on screen
void pulse_z() {
  pulse_count_z++;
}

I believe this is because the button code in the loop is dependent on the button being pressed. If the button isn't pressed, the code within that section/"page" isn't run. I ideally am looking for multiple pages of information, that can update continuously.

I can't help you if you can't do what I'm asking.

Try this:

// Include the library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <PinChangeInterrupt.h>

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// Encoder output to Arduino Interrupt pin. Tracks the pulse count.
#define ENC_A 18
#define ENC_B 19

// Keep track of the number of pulses
volatile long pulse_count_a = 0;
volatile long pulse_count_b = 0;
volatile long pulse_count_z = 0;

#define UPDATE_INTERVAL 1 // Time is seconds

int menuIndex = 0;
unsigned long prevMillis = 0;

void pulse_a();
void pulse_b();
void pulse_z();

void setup()
{
  // Put your setup code here, to run once:

  // Open the serial port at 9600 bps
  Serial.begin(9600);

  // Set up the LCD's number of columns and rows
  lcd.begin(16, 2);

  // Print to the LCD.
  lcd.setCursor(0, 0);
  lcd.print("A:");
  lcd.setCursor(0, 1);
  lcd.print("B:");
  lcd.setCursor(11, 0);
  lcd.print("Z:");

  // Set pin states of the encoder
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);

  // Every time the pin goes high, this is a pulse
  attachInterrupt(digitalPinToInterrupt(ENC_A), pulse_a, RISING);
  attachInterrupt(digitalPinToInterrupt(ENC_B), pulse_b, RISING);
  attachPinChangeInterrupt(23, pulse_z, RISING);
}

uint8_t i = 0;

void loop()
{
  switch (menuIndex)
  {
    case 0:
      {
        if((millis() - prevMillis) > (UPDATE_INTERVAL * 1000UL))
        {
          lcd.setCursor(2,0);
          lcd.print(pulse_count_a); // Write pulse counts to display
          lcd.setCursor(2,1);
          lcd.print(pulse_count_b);
          lcd.setCursor(13,0);
          lcd.print(pulse_count_z);
          menuIndex++;
          prevMillis = millis();
        }
        break;
      }
    case 1:
      {
        if((millis() - prevMillis) > (UPDATE_INTERVAL * 1000UL))
        {
          lcd.setCursor(2,0);
          lcd.print("Menu 1");
          menuIndex++;
          prevMillis = millis();
        }
        break;
      }
    case 2:
      {
        if((millis() - prevMillis) > (UPDATE_INTERVAL * 1000UL))
        {
          lcd.setCursor(2,0);
          lcd.print("Menu 2");
          menuIndex++;
          prevMillis = millis();
        }
        break;
      }
    case 3:
      {
        if((millis() - prevMillis) > (UPDATE_INTERVAL * 1000UL))
        {
          lcd.setCursor(2,0);
          lcd.print("Menu 3");
          menuIndex = 0;
          prevMillis = millis();
        }
        break;
      }
    default:
      {
        break;
      }
  }
}

// Increment the number of A pulses by 1
void pulse_a()
{
  pulse_count_a++;
}

// Increment the number of B pulses by 1
void pulse_b()
{
  pulse_count_b++;
}

// Increment the number of Z pulses by 1
void pulse_z()
{
  pulse_count_z++;
}