Encoder state values

I am using a rotary quadrature encoder to read the position of a 19-value matrix. This is used to trigger an audio track and display the track name. I have set up a scheme where if the counter drops below zero, it resets at 18. If the counter rises above 18, it resets at 0. I have also set up a serial monitor to detect the counter position. The basic scheme works, except for when I go past 0, the monitor displays a "-1" value (with no change in system output). When I continue to turn the encoder, we pick up "17" and all is well. And when I go past 18, the monitor displays a "19" value. Same issue, in that the recounting starts back at "1". From the erroneous counter reading, I can reverse the direction and ultimately find "0".

Also, at startup, I'm trying to initialize at "0" (which is called out at the top of the sketch as "int counter1 = 0;". When I start the sketch, however, it doesn't detect 0 either.

I have this encoder function placed in my void.loop() section for reference. Any help as to where I may be missing "0" initially would be helpful. Below is the pertinent section of code:

static void encoder1() {

  aState1 = digitalRead(encoder1A);
  if (aState1 != aLastState1) {
    if (digitalRead(encoder1B) != aState1) {
      counter1 ++;
      wTrig.stopAllTracks();
    }
    else {
      counter1 --;
      wTrig.stopAllTracks();
    }

    int i_voice1 = 0;
    i_voice1 = i_voice1 + counter1;
    voice1 = voices1[i_voice1];

    lcd.setCursor(0, 0);
    lcd.print(Bank1[i_voice1]);

    Serial.print("Position: ");
    Serial.println(counter1);
    Serial.println(Bank1[i_voice1]);

    if (counter1 > 18) {
      counter1 = 0;
    }
    if (counter1 < 0) {
      counter1 = 18;
    }
  }
  aLastState1 = aState1;

}

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

  encoder1();
  scan();

}

You add or subtract from counter then display that value then check for over or under flow. Do the check and then do the display after.

Please, in the future, post all the code. Snippets almost always leave out important information.

#include <AltSoftSerial.h>
#include <wavTrigger.h>       // wavTrigger.h is changed to use hardware serial1 
#include <LiquidCrystal_I2C.h>    // LCD Library
#include <OneButton.h>
#include <TimerOne.h>

LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

#define NUM_BTN_COLUMNS (8)
#define NUM_BTN_ROWS (5)
#define NUM_KEYS (37)
#define MAX_DEBOUNCE (10)
#define encoder1A 42
#define encoder1B 43

// Global variables
static const uint8_t btnrowpins[NUM_BTN_ROWS] = {30, 31, 32, 33, 34};
static const uint8_t btncolumnpins[NUM_BTN_COLUMNS]       = {22, 23, 24, 25, 26, 27, 28, 29};

static int8_t debounce_count[NUM_BTN_ROWS][NUM_BTN_COLUMNS];

wavTrigger wTrig;             // WAV Trigger object
int  gWTrigState = 0;         // WAV Trigger state
int  gRateOffset = 0;         // WAV Trigger sample-rate offset
int  gain = 0;

int counter1 = 0;
int Track = 0;
int voice1 = 0;
int voice1_old = 0;
int Keys[NUM_KEYS];

char buffer1[17];  // lcd display line 1
char buffer2[17];  // lcd display line 2

const int numOfScreens = 19;
int currentScreen1 = 0;
int currentScreen2 = 0;

char* Bank1[numOfScreens] = {
  /* "1234567890123456",  "1234567890123456",  "1234567890123456", */
  /* 1*/ "A: MkII Flute   ",  "A: MkII 3 Violin",  "A: MkII Guitar  ",
  /* 2*/ "A: MkII Organ   ",  "A: MkII Brass   ",  "A: MkII Accordio",
  /* 3*/ "A: MKII Sax     ",  "A: MkII Vibes   ",  "A: MkII Tibia   ",
  /* 4*/ "A: M300 StringsA",  "A: M300 StringsB",  "A: M400 Cello   ",
  /* 5*/ "A: M400 Viola   ",  "A: M400 16Violin",  "A: M400 Strings ",
  /* 6*/ "A: M400 8 Voices",  "A: M400 Boy Chor",  "A: M400 Mix Chor",
  /* 7*/ "A: M400 GC Brass"
};

int voices1[19] = {
  /* 1*/  1,    36,    71,
  /* 2*/  106,   141,   176,
  /* 3*/  211,   246,   281,
  /* 4*/  316,   351,   386,
  /* 5*/  421,   456,   491,
  /* 6*/  526,   561,   596,
  /* 7*/  631
};

int i_key;
int key_input;

int aState1;
int aLastState1;

void setup()
{
  // put your setup code here, to run once:
  lcd.init();                      // initialize the lcd
  lcd.init();
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Mellowtron");
  lcd.setCursor(2, 1);
  lcd.print("Version 1.0");
  delay(5000);
  lcd.begin(16, 2);
  lcd.clear();

  Serial.begin(9600);
  wTrig.start();      // WAV Trigger startup at 57600
  wTrig.samplerateOffset(gRateOffset);
  wTrig.masterGain(gain);
  Serial.print("Starting Setup...");
  // setup hardware
  setuppins();
  Serial.println("Setup Complete.");
  for (Track = 1; Track <= 665; Track++) {
    wTrig.trackGain(Track, -10);
  }

  pinMode (encoder1A, INPUT);
  pinMode (encoder1B, INPUT);

}

static void setuppins()
{
  uint8_t i;

  // initialize
  // select lines
  // button columns
  for (i = 0; i < NUM_BTN_ROWS; i++)
  {
    pinMode(btnrowpins[i], OUTPUT);

    // with nothing selected by default
    digitalWrite(btnrowpins[i], HIGH);
  }

  // button row input lines
  for (i = 0; i < NUM_BTN_COLUMNS; i++)
  {
    pinMode(btncolumnpins[i], INPUT_PULLUP);
  }

  // Initialize the debounce counter array
  for (uint8_t i = 0; i < NUM_BTN_ROWS; i++)
  {
    for (uint8_t j = 0; j < NUM_BTN_COLUMNS; j++)
    {
      debounce_count[i][j] = 0;
    }
  }
}

static void scan()
{
  static uint8_t current = 0;
  uint8_t key_input;
  uint8_t i, j;

  // Select current columns

  digitalWrite(btnrowpins[current], LOW);

  // pause a moment
  delay(0);

  // Read the button inputs
  for ( j = 0; j < NUM_BTN_COLUMNS; j++)
  {
    key_input = digitalRead(btncolumnpins[j]);
    i_key = (current * NUM_BTN_COLUMNS) + j;

    if (key_input == LOW)
    {
      // active low: val is low when btn is pressed
      if ( debounce_count[current][j] < MAX_DEBOUNCE)
      {
        debounce_count[current][j]++;
        if ( debounce_count[current][j] == MAX_DEBOUNCE )
        {
          if ( 1 < i_key && i_key <= 36) {
            Serial.print("Key Down ");
            Serial.println(i_key);
            wTrig.trackPlayPoly(voice1 + i_key - 2);
          }
        }
      }
    }
    else
    {
      // otherwise, button is released
      if ( debounce_count[current][j] > 0)
      {
        debounce_count[current][j]--;
        if ( debounce_count[current][j] == 0 )
        {
          Serial.print("Key Up ");
          Serial.println((current * NUM_BTN_COLUMNS) + j);
          wTrig.trackStop(voice1 + i_key - 2);

          // If you want to do something when a key is released, do it here:

        }
      }
    }
  }

  delay(1);

  digitalWrite(btnrowpins[current], HIGH);

  current++;
  if (current >= NUM_BTN_ROWS)
  {
    current = 0;
  }
}

void encoder1() {

  aState1 = digitalRead(encoder1A);
  if (aState1 != aLastState1) {
    if (digitalRead(encoder1B) != aState1) {
      counter1 ++;
      wTrig.stopAllTracks();
    }
    else {
      counter1 --;
      wTrig.stopAllTracks();
    }

    int i_voice1 = 0;
    i_voice1 = i_voice1 + counter1;
    voice1 = voices1[i_voice1];

    lcd.setCursor(0, 0);
    lcd.print(Bank1[i_voice1]);

    Serial.print("Position: ");
    Serial.println(counter1);
    Serial.println(Bank1[i_voice1]);

    if (counter1 > 18) {
      counter1 = 0;
    }
    if (counter1 < 0) {
      counter1 = 18;
    }
  }
  aLastState1 = aState1;

}

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

  encoder1();
  scan();

}

Try this:

    else {
if (counter1>=1){    // allow decrement if above 0  
counter1 --;
} 
else {
counter1 = 18; // if already 0, rollupto 18
}
      wTrig.stopAllTracks();
    }

CrossRoads,

Thanks for your help. One thing I probably didn’t explain well enough is basic functionality I’m looking for:

  1. At startup, call up value 0 of the matrix
  2. Ability to loop around (decrementing from 0 takes you to 18, going past 18 returns back to 0).

Hope this clears up what I’m tying to accomplish.

I only came up with the change to allow proper wrapping from 0 to 18.
Looked like you already had 18 back to 0.

Same here

  if (aState1 != aLastState1) {
    if (digitalRead(encoder1B) != aState1) {
if (counter1 <18){ // allow count to increase
      counter1 ++;
}
else { 
counter1 = 0; // already at 18, or more, wrap back to 0
}
      wTrig.stopAllTracks();
    }

You're on a Mega? Why use software serial?
#include <AltSoftSerial.h>
You have Serial, Serial1, Serial2, Serial3 available, use them.

CrossRoads,

Thanks. It looks like the only residual result of these changes are:

  1. System boots up with a "-1" value
  2. Scrolling past 0 or 18 results in a -1. Turning past -1 brings me to the right spot.

The counter tracking is now working properly. The only thing bug I’m still chasing is that my displayed values do not come up at startup. I have to turn the encoder either direction to pick up a value. Thoughts?

If you make changes to your code, please post the latest version so we can keep up.

#include <AltSoftSerial.h>
#include <wavTrigger.h>       // wavTrigger.h is changed to use hardware serial1 
#include <LiquidCrystal_I2C.h>    // LCD Library
#include <OneButton.h>
#include <TimerOne.h>

LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

#define NUM_BTN_COLUMNS (8)
#define NUM_BTN_ROWS (5)
#define NUM_KEYS (37)
#define MAX_DEBOUNCE (10)
#define encoder1A 42
#define encoder1B 43
#define encoder2A 44
#define encoder2B 45

// Global variables
static const uint8_t btnrowpins[NUM_BTN_ROWS] = {30, 31, 32, 33, 34};
static const uint8_t btncolumnpins[NUM_BTN_COLUMNS]       = {22, 23, 24, 25, 26, 27, 28, 29};

static int8_t debounce_count[NUM_BTN_ROWS][NUM_BTN_COLUMNS];

wavTrigger wTrig;             // WAV Trigger object
int  gWTrigState = 0;         // WAV Trigger state
int  gRateOffset = 0;         // WAV Trigger sample-rate offset
int  gain = 0;

int counter1;
int counter2;
int aState1;
int aLastState1;
int aState2;
int aLastState2;

int Track = 0;
int voice1 = 0;
int voice2 = 0;
int voice1_old = 0;
int voice2_old = 0;
int Keys[NUM_KEYS];

char buffer1[17];  // lcd display line 1
char buffer2[17];  // lcd display line 2

const int numOfScreens = 19;
int currentScreen1 = 0;
int currentScreen2 = 0;

char* Bank1[numOfScreens] = {
  /*     "1234567890123456",  "1234567890123456",  "1234567890123456", */
  /* 1*/ "A:MkII Flute    ",  "A:MkII 3 Violins",  "A:MkII Guitar   ",
  /* 2*/ "A:MkII Organ    ",  "A:MkII Brass    ",  "A:MkII Accordion",
  /* 3*/ "A:MKII Sax      ",  "A:MkII Vibes    ",  "A:MkII Tibia Org",
  /* 4*/ "A:M300 Strings A",  "A:M300 Strings B",  "A:M400 Cello    ",
  /* 5*/ "A:M400 Viola    ",  "A:M400 16Violins",  "A:M400 Strings  ",
  /* 6*/ "A:M400 8-V Choir",  "A:M400 Boy Choir",  "A:M400 Mix Choir",
  /* 7*/ "A:M400 GC Brass "
};

char* Bank2[numOfScreens] = {
  /*     "1234567890123456",  "1234567890123456",  "1234567890123456", */
  /* 1*/ "B:MkII Flute    ",  "B:MkII 3 Violins",  "B:MkII Guitar   ",
  /* 2*/ "B:MkII Organ    ",  "B:MkII Brass    ",  "B:MkII Accordion",
  /* 3*/ "B:MKII Sax      ",  "B:MkII Vibes    ",  "B:MkII Tibia Org",
  /* 4*/ "B:M300 Strings A",  "B:M300 Strings B",  "B:M400 Cello    ",
  /* 5*/ "B:M400 Viola    ",  "B:M400 16Violins",  "B:M400 Strings  ",
  /* 6*/ "B:M400 8-V Choir",  "B:M400 Boy Choir",  "B:M400 Mix Choir",
  /* 7*/ "B:M400 GC Brass "
};

int voices1[19] = {
  /* 1*/  1,    36,    71,
  /* 2*/  106,   141,   176,
  /* 3*/  211,   246,   281,
  /* 4*/  316,   351,   386,
  /* 5*/  421,   456,   491,
  /* 6*/  526,   561,   596,
  /* 7*/  631
};

int voices2[19] = {
  /* 1*/  1,    36,    71,
  /* 2*/  106,   141,   176,
  /* 3*/  211,   246,   281,
  /* 4*/  316,   351,   386,
  /* 5*/  421,   456,   491,
  /* 6*/  526,   561,   596,
  /* 7*/  631
};

int i_key;
int key_input;



void setup()
{
  // put your setup code here, to run once:
  lcd.init();                      // initialize the lcd
  lcd.init();
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("Mellowtron");
  lcd.setCursor(2, 1);
  lcd.print("Version 1.0");
  delay(5000);
  lcd.begin(16, 2);
  lcd.clear();

  Serial.begin(9600);
  wTrig.start();      // WAV Trigger startup at 57600
  wTrig.samplerateOffset(gRateOffset);
  wTrig.masterGain(gain);
  Serial.print("Starting Setup...");
  // setup hardware
  setuppins();
  Serial.println("Setup Complete.");
  for (Track = 1; Track <= 665; Track++) {
    wTrig.trackGain(Track, -10);
  }

  pinMode (encoder1A, INPUT);
  pinMode (encoder1B, INPUT);
  pinMode (encoder2A, INPUT);
  pinMode (encoder2B, INPUT);

  aLastState1 = digitalRead(encoder1A);
  aLastState2 = digitalRead(encoder2A);

  counter1 = 0;
  counter2 = 0;

}

static void setuppins()
{
  uint8_t i;

  // initialize
  // select lines
  // button columns
  for (i = 0; i < NUM_BTN_ROWS; i++)
  {
    pinMode(btnrowpins[i], OUTPUT);

    // with nothing selected by default
    digitalWrite(btnrowpins[i], HIGH);
  }

  // button row input lines
  for (i = 0; i < NUM_BTN_COLUMNS; i++)
  {
    pinMode(btncolumnpins[i], INPUT_PULLUP);
  }

  // Initialize the debounce counter array
  for (uint8_t i = 0; i < NUM_BTN_ROWS; i++)
  {
    for (uint8_t j = 0; j < NUM_BTN_COLUMNS; j++)
    {
      debounce_count[i][j] = 0;
    }
  }
}

static void scan()
{
  static uint8_t current = 0;
  uint8_t key_input;
  uint8_t i, j;

  // Select current columns

  digitalWrite(btnrowpins[current], LOW);

  // pause a moment
  delay(0);

  // Read the button inputs
  for ( j = 0; j < NUM_BTN_COLUMNS; j++)
  {
    key_input = digitalRead(btncolumnpins[j]);
    i_key = (current * NUM_BTN_COLUMNS) + j;

    if (key_input == LOW)
    {
      // active low: val is low when btn is pressed
      if ( debounce_count[current][j] < MAX_DEBOUNCE)
      {
        debounce_count[current][j]++;
        if ( debounce_count[current][j] == MAX_DEBOUNCE )
        {
          if ( 1 < i_key && i_key <= 36) {
            Serial.print("Key Down ");
            Serial.println(i_key);
            wTrig.trackPlayPoly(voice1 + i_key - 2);
            /*     wTrig.trackPlayPoly(voice2 + i_key - 2);*/
          }
        }
      }
    }
    else
    {
      // otherwise, button is released
      if ( debounce_count[current][j] > 0)
      {
        debounce_count[current][j]--;
        if ( debounce_count[current][j] == 0 )
        {
          Serial.print("Key Up ");
          Serial.println((current * NUM_BTN_COLUMNS) + j);
          wTrig.trackStop(voice1 + i_key - 2);
          /*    wTrig.trackStop(voice2 + i_key - 2);*/
          // If you want to do something when a key is released, do it here:

        }
      }
    }
  }

  delay(1);

  digitalWrite(btnrowpins[current], HIGH);

  current++;
  if (current >= NUM_BTN_ROWS)
  {
    current = 0;
  }
}

void encoder1() {

  aState1 = digitalRead(encoder1A);
  if (aState1 != aLastState1) {
    if (digitalRead(encoder1B) != aState1) {
      if (counter1 < 18) {
        counter1 ++;
      }
      else {
        counter1 = 0;
      }
      wTrig.trackStop(voice1 + i_key - 2);
    }
    else {
      if (counter1 >= 1) {
        counter1 --;
      }
      else {
        counter1 = 18;
      }
      wTrig.trackStop(voice1 + i_key - 2);
    }
    int i_voice1 = 0;
    i_voice1 = i_voice1 + counter1;
    voice1 = voices1[i_voice1];

    lcd.setCursor(0, 0);
    lcd.print(Bank1[i_voice1]);

    Serial.print("Position1: ");
    Serial.println(counter1);
    Serial.println(Bank1[i_voice1]);
  }
  aLastState1 = aState1;

  aState2 = digitalRead(encoder2A);
  if (aState2 != aLastState2) {
    if (digitalRead(encoder2B) != aState2) {
      if (counter2 < 18) {
        counter2 ++;
      }
      else {
        counter2 = 0;
      }
      wTrig.trackStop(voice2 + i_key - 2);
    }
    else {
      if (counter2 >= 1) {
        counter2 --;
      }
      else {
        counter2 = 18;
      }
      wTrig.trackStop(voice2 + i_key - 2);
    }
    int i_voice2 = 0;
    i_voice2 = i_voice2 + counter2;
    voice2 = voices2[i_voice2];

    lcd.setCursor(0, 1);
    lcd.print(Bank2[i_voice2]);

    Serial.print("Position2: ");
    Serial.println(counter2);
    Serial.println(Bank2[i_voice2]);
  }
  aLastState2 = aState2;
}

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

  encoder1();
  scan();

}

Here is the updated code. You'll see a 2nd encoder (allows me to control individually two separate sound banks). I merely duplicated that for Encoder1, so the same issue follows both encoders.

my displayed values do not come up at startup.

  if (aState1 != aLastState1) {

The Serial prints that print the position is inside this if bock. The prints cant happen until a state changes (the encoder is moved).

Somehow moving that outside of the bracket, which requires me to move the definitions, now forces a decrement not matter how I turn the encoder.

Somehow moving that outside of the bracket, which requires me to move the definitions, now forces a decrement not matter how I turn the encoder.

You've done something incorrectly. Please post the revised code.

The only thing bug I'm still chasing is that my displayed values do not come up at startup.

At startup you have these values

counter1 = 0;
 counter2 = 0;

You can certainly add some display code to startup to show them before turning any encoder.

cattledog:
You've done something incorrectly. Please post the revised code.

At startup you have these values

counter1 = 0;

counter2 = 0;




You can certainly add some display code to startup to show them before turning any encoder.

Now you're just making too much sense. I don't know why I never thought of adding display code as part of setup. It works perfectly now! Thanks for your help everyone. I'll close out this post.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.