Monday, February 11, 2013

LCD Game Part 4 - Catching the Button Press

Back three ahead four. In Part 3 we demonstrated how we can provide a visual clue to the user that let's him decided which digits to flip. If you haven't seen it, there is a video that shows it on YouTube.

Now that we need to catch a button press while the digits are marching left, some problems turn up that must be dealt with. 

We used a one second delay to slow Sparky down and make the interface useful. If we leave that in, the user might not see an instant response to the key press and has to hold it down until the delay is over before it gets read.

If we want to go into the realm of 'interupts' we could probably come up with a solution. Instead, I have chosen to abandon the delay(1000); function inside of shiftLeft().  We can't check a pin while this delay is active. So instead of using a delay, let's build a timer and only call the function once a second. We will need to declare a variable:
unsigned long myTime;
Then in setup() we will load it up with a value from the millis() function.
  
  scramblePrompt();
  scrambleString();
  displayWorkingString();
  delay(1000);
  myTime = millis();

This writes the number of milliseconds that have passed since Sparky was powered up into our variable, myTime. Instead of calling our shiftLeft() function every time we pass through loop() we only call it when 1000 milliseconds have elapsed. That's one second. And then we reset myTime so it won't happen again in the next pass.

Finally, we package the shiftLeft() call into an if structure that tests for this condition. Here it is:


  if(millis() - myTime > 1000){
    shiftLeft();
    myTime = millis();
  }

If we take the original delay(1000) out of shiftLeft() and run this code, we will see the same result we had in Part 3. The good news is that now we can also check P5 to see if our button is pressed without being shut out of that option during the delay. 

Just so we can study what is going on as we interact with the LCD and the button, we will toss a few lines (highlighted below) into loop() that will put a new number in the lower left corner of the display that represents how many digits were shifted left when the button was pressed. I'm simply adding our counter, tick, to the ASCII code for the number zero and printing it on the LCD. That works well until tick = 10. Then you will see a colon instead of a number. 
  
  btnPress = digitalRead(myButton);
  if (btnPress==1){
    digitalWrite(1,1);
    lcd.setCursor(0,1);
    lcd.print(char(tick+48));
    delay(1000);
  }

So it's time to give it try. Copy and paste the sketch below and experiment with it. In the next part, we will flip the order of the selected digits and have the bare minimum of the functions written to actually complete the puzzle. C U Then.



/* ATtiny85 as an I2C Master   Ex2        BroHogan                           1/21/11
 * Modified for Digistump - Digispark LCD Shield by Erik Kettenburg 11/2012
 * SETUP:
 * ATtiny Pin 1 = (RESET) N/U                      ATtiny Pin 2 = (D3) N/U
 * ATtiny Pin 3 = (D4) to LED1                     ATtiny Pin 4 = GND
 * ATtiny Pin 5 = SDA on DS1621  & GPIO            ATtiny Pin 6 = (D1) to LED2
 * ATtiny Pin 7 = SCK on DS1621  & GPIO            ATtiny Pin 8 = VCC (2.7-5.5V)
 * NOTE! - It's very important to use pullups on the SDA & SCL lines!
 * PCA8574A GPIO was used wired per instructions in "info" folder in the LiquidCrystal_I2C lib.
 * This ex assumes A0-A2 are set HIGH for an addeess of 0x3F
 * LiquidCrystal_I2C lib was modified for ATtiny - on Playground with TinyWireM lib.
 * TinyWireM USAGE & CREDITS: - see TinyWireM.h
 */

//#define DEBUG
#include <TinyWireM.h>                  // I2C Master lib for ATTinys which use USI - comment this out to use with standard arduinos
#include <LiquidCrystal_I2C.h>          // for LCD w/ GPIO MODIFIED for the ATtiny85

#define GPIO_ADDR     0x27             // (PCA8574A A0-A2 @5V) typ. A0-A3 Gnd 0x20 / 0x38 for A - 0x27 is the address of the Digispark LCD modules.


LiquidCrystal_I2C lcd(GPIO_ADDR,16,2);  // set address & 16 chars / 2 lines

String winner ="0123456789";            // a test string to easily see game is over
String workingString = "0123456789";    // all the digits that we will scramble at the beginning of the game
int rnd;     // will hold a random number for us.
int myButton = 5; // our button hooks up here
int btnPress;     // is it down or not
byte tick = 0;
unsigned long myTime;

void setup(){
  TinyWireM.begin();                    // initialize I2C lib - comment this out to use with standard arduinos
  lcd.init();                           // initialize the lcd 
  lcd.clear();
  lcd.backlight();
  pinMode (myButton, INPUT);
  pinMode(1, OUTPUT); //LED on Model A
  
  scramblePrompt();
  scrambleString();
  displayWorkingString();
  delay(1000);
  myTime = millis();
}

void loop()  {
  btnPress = digitalRead(myButton);
  if (btnPress==1){
    digitalWrite(1,1);
    lcd.setCursor(0,1);
    lcd.print(char(tick+48));
    delay(1000);
  }else{
    digitalWrite(1,0);
  }
  if(millis() - myTime > 1000){
    shiftLeft();
    myTime = millis();
  }
}

void shiftLeft(){
if (tick < 10){
    //delay(1000);
    lcd.setCursor(tick + 2,0);   
    lcd.print(workingString[tick]);
    lcd.print(' ');
    tick++;

  }else{
    delay(1500);
    lcd.clear();
    delay(1500);
    scrambleString();
    displayWorkingString();
    tick = 0;
    
  }
}

void scramblePrompt(){
  lcd.noCursor();
  lcd.print("NUMBER FLIP-FLOP");
  lcd.setCursor(0,1);
  lcd.print("Press Button Now");
  
  do {
    rnd=random(9);
  } while (!digitalRead(myButton));
 }



void scrambleString() {
  lcd.clear();
  lcd.print("NUMBER FLIP-FLOP");
  
  for (int i=0; i<10; i++){
    rnd=random(9);
    swap(i,rnd);
  }
  delay(1000);
  lcd.clear();
   
}

void swap(int x, int y){
  byte hold=workingString[x];
  workingString[x]=workingString[y];
  workingString[y]=hold;
}
  

void displayWorkingString(){
  lcd.setCursor(3,0);
  lcd.print(workingString);
  //cursorLocation=4;
  lcd.noCursor();
  //if(workingString==winner) YouWin();
}

 

No comments:

Post a Comment