the code is:
/*
April 15, 2019
Reddit electronic dice sketch
This is a electronic dice program for an Uno with a generic 16x2 LCD + keypad shield.
(The generic shield has resistive buttons; this is *NOT* the Adafruit shield with the MPC23017 i2c expander chip).
...This is a complete re-write of the original sketch, so the order of things is different than before...
How this sketch should work:
1. When no dice value is selected, the display should show two always-changing digits (values from 1 to 6) on the upper line.
...One issue here is that LCds can't really change values very fast.
Under normal circumstances they might require 1/10th of a second to update, and in cold weather they might take 1/4th of a second to update.
So there will be a delay value used to control how fast new numbers are drawn and written to the LCD.
2. Two random numbers are selected, both with values of 1 to 6, as if one were rolling a pair of normal 6-sided dice.
2. When the [select] button is pressed, the changing numbers should stop changing.
3. If the total of the two numbers is not 7, one message is displayed.
4. If the total of the two numbers is 7, then another message is displayed.
5. Either of the messages in (3) and (4) is maintained until any of the programmable keypad buttons is pushed again.
There is a 1-second delay after any programmable button press.
The button-debounce code here is not really the way that I would usually do it, but it is simple and it works reliably.
There is just a time lag after the button press, before anything happens.
*/
#include <LiquidCrystal.h> // <---------------- This is the standard Arduino IDE library.
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int keypad_pin = A0; // On the generic LCD+keypad shields, this is the Arduino pin that the buttons are connected to.
/*
If you are using the generic shield, then you don't need to use the code below at all.
This code was carried over from the Adafruit shield sketch out of convenience, when I converted that sketch to work with a generic 16x2LCD + keypad shield.
On the Adafruit shield, I think that each of the numbers of those buttons below corresponds to the pin of the MPC23017 i2c expander chip that each button is connected to.
The call to read the buttons goes to the MPC23017 chip, it doesn't just use regular Arduino I/O pins (even though there is direct I/O shield pins that could be used).
The generic shield does not use the MPC23017 chip, so there is really no reason to use these defined values.
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
*/
int random_number_draw_interval = 250; // This is the time in milliseconds to wait between drawing new random numbers, to allow the LCD screen to update.
// Normal LCDs usually take at least 1/10th of a second to change their state, and when cold (below freezing) they can take 1 second or more to change.
// If you don't give them long enough to change, then you don't really see anything displayed. You just faint flickering that can't be identified as any character.
int random_number = 0; // This is the variable for generating the random numbers.
int random_seed_pin = A1; // You can use an analog-input pin for a random seed, but the pin must not be connected to anything, so you can't use A0 since the buttons are connected to that.
// Also, analog input pins must start with the letter "A", unless you use the high-integer pin ID numbers.
int selected_state = 0; // There is two states that must be identifiable: when no values are selected (zero), and when values are selected (1).
// Since the below variables always get used, I would just declare them as globals...
long diceOne = 0;
long diceTwo = 0;
int total_dice = 0;
int button_pin_value = 0;
// setup() cannot be placed inside any other function.
void setup() {
Serial.begin(9600);
lcd.begin(16, 2); // start the LCD library
lcd.setCursor(0, 0);
lcd.print("select = dice"); // Message is shortened to less than 17 characters.
randomSeed(analogRead(random_seed_pin)); // Changed to use named random seed pin number
Serial.println("Exiting setup()");
}
// loop() cannot be placed inside any other function.
void loop() {
if (selected_state == 0) {
// As long as no number has been selected, this is the code that gets run.
roll_the_dice();
print_rolling_dice_to_LCD();
// The line below makes the sketch wait long enough to see the random values appearing on the LCD screen.
delay(random_number_draw_interval);
}
else { // if (selected_state == 1)
// There is not anything to do here.
// The important thing is that the code above gets skipped when selected_state is not zero.
}
read_LCD_buttons();
Serial.print("button value = ");
Serial.println(button_pin_value);
}
void roll_the_dice() {
diceOne = random(1, 7);
diceTwo = random(1, 7);
total_dice = diceOne + diceTwo;
}
void print_rolling_dice_to_LCD() {
// This function is only for showing the un-selected changing dice values.
lcd.clear();
lcd.setCursor(7, 0);
lcd.print(total_dice);
}
// read the buttons
int read_LCD_buttons() {
button_pin_value = analogRead(keypad_pin); // It is helpful to name your input/output pins, and then to refer to them only by name.
// Below is some troubleshooting code to see what values the buttons are putting out...
//if (button_pin_value < 900) {
//Serial.print("button value = ");
//Serial.println(button_pin_value);
//}
// my buttons when read are centered at these values: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
// The below values should work for yours and my shields, although the values are slightly different.
if (button_pin_value < 50) {
// This is the [right] button value.
if (selected_state == 1) {
selected_state = 0;
}
}
else if (button_pin_value > 49 && button_pin_value < 200) {
// This is the [up] button value.
if (selected_state == 1) {
selected_state = 0;
}
}
else if (button_pin_value > 250 && button_pin_value < 350) {
// This is the [down] button value.
if (selected_state == 1) {
selected_state = 0;
}
}
else if (button_pin_value > 450 && button_pin_value < 550) {
// This is the [left] button value.
if (selected_state == 1) {
selected_state = 0;
}
}
else if (button_pin_value > 600 && button_pin_value < 850) {
// This is the [select] button value.
// This button must do two different things, depending on if selected_state is set to zero or 1.
if (selected_state == 0) {
selected_state = 1;
display_dice_values(); // This is what happens when the [select] button is pressed, to stop the dice from changing.
}
else {
selected_state = 0;
}
}
else {
// This is the [none] button value.
}
delay(1000); // This is to prevent the buttons from bouncing.
}
void display_dice_values() {
// First of all, we will generate new dice values one more time, to make sure that the user can't press the button when they see dice values they want:
roll_the_dice();
// Clear both LCD lines:
clear_both_lcd_lines();
// Now there is two different displays to show, if the total value is 7 or not:
if (lcd_key == btnSELECT) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print(total_dice);
}
if (total_dice == 7) {
lcd.setCursor(7, 0);
lcd.print(total_dice);
// print second line
lcd.setCursor(2, 1);
lcd.print("the robber");
}
}
// The LCD already has a command to clear the whole thing,
// but often it is useful to write your own named functions to clear out just one line, or both lines.
void clear_both_lcd_lines() {
clear_lcd_top_line();
clear_lcd_bottom_line();
}
void clear_lcd_top_line() {
lcd.setCursor(0, 0);
lcd.print(" "); // Printing 16 spaces.
}
void clear_lcd_bottom_line() {
lcd.setCursor(0, 1);
lcd.print(" "); // Printing 16 spaces.
}