Cycling Cursor through LCD with Keypad Shield

Hello I am trying to build a decoder style, fill-in-the-blank mini game using the sainsmart LCD keypad shield.

I am trying set it up so that the LEFT and RIGHT arrows move through the display and up and down buttons cycle through a-z for the user to fill in blank spots in text.

My main problem is that the cursor movement works to the right properly but only on the first time through (with a successful reset at lcd.setCursor(0,0), but the second time it fails by continuing right offscreen

My other problem is that the left button doesn’t work at all and I have tried mirroring the code(in reverse) and other ways.
Here is my current code:

#include <LiquidCrystal.h>

//USING DFROBOT/SainSmart Keypad Shield

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);           // select the pins used on the LCD panel

//set variables for LCD Cursor control
int letter = 0;
int line = 0;
int letter2 = 0;
//LCD library variables
int rows = 2;
int columns = 16;

//keypad button variables
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
 
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5
 
int read_LCD_buttons(){               // read the buttons
    adc_key_in = analogRead(0);       // read the value from the sensor 
 
    // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
    // we add approx 50 to those values and check to see if we are close
    // We make this the 1st option for speed reasons since it will be the most likely result
 
    if (adc_key_in > 1000) return btnNONE; 
 
    // For V1.1 us this threshold
    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;  
    return btnNONE;     // when all others fail, return this.
}

//setup placeholder text and start cursor
void setup(){
  Serial.begin(9600);
  lcd.begin(rows, columns);
  lcd.home();
  lcd.print("Th_s is a te_t");
  lcd.setCursor(letter, line + 1);
  lcd.print("t_ cycle ov_r");
  lcd.home();
  lcd.cursor();
  lcd.blink();
  
}

void loop(){
    // read buttons through shield
    lcd_key = read_LCD_buttons();

    
    //determine what to do when each button is pressed
        
    switch (lcd_key){
      
       case btnRIGHT: {
        lcd.setCursor(letter++, line);
        
         //constrain movement values to display limits and move to next line
         
         //** doesn't work after second time cycling through**
        if (letter >= 17){
              line = 1;
              lcd.setCursor(letter2, line);
              letter2++;
           if (letter >= 33){
              letter = 0;
              line = 0;      
          }
        }
        //reset to lcd.home after second line limit reached
      
        delay(300);
        break;
       }
       // move cursor left one space
       case btnLEFT: {
        lcd.setCursor(letter--, line);
        
        //if immediately left reset to end of line 2
        //**NOT WORKING**
        
        if(letter < 0){
            letter = 15;
            letter2 = 15;
            line = 1;
            lcd.setCursor(letter2, line);
            letter2--;
            delay(300);
            if(letter2 < 0){
              line = 0;
              lcd.setCursor(letter, line);
              letter--;
              delay(300);
            }
          }
        
        
        break;
       }
       case btnUP: {
        //insert code to cycle characters
        break;
       }
       case btnDOWN: {
        // insert code to cycle characters in opposite order
        break;
       }
    }
}

I haven’t started on the UP and DOWN buttons yet but any recommendations would be appreciated!

Thanks for the help!

-Icy

Do all the tests work which are specified in the instructions you supplied? : Key Press Tests Key Grab Guess the number.

If so, then it is simply a problem with your code and not a problem with the SainSmart module.

Anyway, first add some Serial.print statements to all the buttons simply to test your ability to read them.

An obvious thing I notice in read_LCD_buttons() is that an analogRead value of zero will be treated as a btnRight.

Oh hang on - it's supposed to be like that. Ok.

Please explain exactly what the variables letter and letter2 are supposed to contain. Why two variables? I think you are using one variable for your position on line 1 and the other one for your position on line 2, but when you go right you increment only the line1 position. It's really screwy.

Look. Use one variable named letter with a value between 0 and 29. The cursor position should be x = letter % 15, y = letter / 15. Note that that division is integer division, so it will round down.

Oh, and are you aware that the postincrement and postdecment operators use the value of the variable before performing the increment? This

lcd.setCursor(letter--, line);

probably isn't what you want.

to increment, letter = (letter + 1 ) % 30; to decrement, letter = (letter+29) % 30; to position the cursor, lcd.setCursor(letter % 15, letter / 15);

Job done.