/*
* Code by Ty Palowski for Automated Beerpong Game
* https://youtube.com/c/typalowski
*/
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ClickEncoder.h>
#include <TimerOne.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// defines pins numbers
const int dirPin = 2;
const int stepPin = 4;
const int enPin = 5;
int menuitem = 1;
int frame = 1;
int page = 1;
int lastMenuItem = 1;
String menuItem1 = "Motor: OFF";
String menuItem2 = "Difficulty";
String menuItem3 = "Mode";
String menuItem4 = "Reset";
boolean motor = true;
int stepdelay;
int maxDelay = 240;
int diffDelta = 22;
String difficulty[10] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
int selectedDifficulty = 0;
String mode[2] = { "EASY", "HARD"};
int selectedMode = 1;
boolean up = false;
boolean down = false;
boolean middle = false;
ClickEncoder *encoder;
int16_t last, value;
// '85062033-beer-pong-or-beirut-drinking-game-with-cups-with-ball-line-art-vector-icon-for-apps-and-websites-', 128x32px
const unsigned char myBitmap [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0x83, 0x83, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0x38, 0x38, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xc3, 0xc3, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x83, 0x83, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xff, 0xff, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x98, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x9c, 0x71, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x9f, 0xf1, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x90, 0x13, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x98, 0x13, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc8, 0x23, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#define home_switch 9 // Pin 9 connected to Home Switch (MicroSwitch)
int direction; // Variable to set Rotation (CW-CCW) of the motor
int steps; // Used to set HOME position after Homing is completed
int fullDist = 32766;
int halfDist = fullDist/2;
void setup() {
Serial.begin(9600);
// Sets the two pins as Outputs
pinMode(stepPin,OUTPUT);
pinMode(dirPin,OUTPUT);
pinMode(enPin,OUTPUT);
digitalWrite(enPin,LOW);
pinMode(7,OUTPUT);
encoder = new ClickEncoder(A1, A0, A2);
encoder->setAccelerationEnabled(false);
display.begin();
display.clearDisplay();
Timer1.initialize(1000);
Timer1.attachInterrupt(timerIsr);
last = encoder->getValue();
display.setRotation (2);
display.drawBitmap(0, 0, myBitmap, 128, 64, WHITE); // display.drawBitmap(x position, y position, bitmap data, bitmap width, bitmap height, color)
// Show the display buffer on the screen.
display.display();
// Start Homing procedure of Stepper Motor at startup
Serial.println("Homing...");
while (digitalRead(home_switch)) { // Do this until the switch is activated
digitalWrite(dirPin, HIGH); // (HIGH = anti-clockwise / LOW = clockwise)
digitalWrite(stepPin, HIGH);
delayMicroseconds(75); // Delay to slow down speed of Stepper
digitalWrite(stepPin, LOW);
delayMicroseconds(75);
}
while (!digitalRead(home_switch)) { // Do this until the switch is not activated
digitalWrite(dirPin, LOW);
digitalWrite(stepPin, HIGH);
delay(5); // More delay to slow even more while moving away from switch
digitalWrite(stepPin, LOW);
delay(5);
}
steps=0; // Reset position variable to zero
digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction
// Makes 200 pulses for making one full cycle rotation
for(int x = 0; x < halfDist+400; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(50);
digitalWrite(stepPin,LOW);
delayMicroseconds(50);
}
Serial.println("Ready!");
delay(1000);
}
void loop() {
stepdelay = maxDelay - selectedDifficulty*diffDelta;
if (motor == true)
{
turnMotorOff();
}
else
{
turnMotorOn();
}
drawMenu();
readRotaryEncoder();
ClickEncoder::Button b = encoder->getButton();
if (b != ClickEncoder::Open) {
switch (b) {
case ClickEncoder::Clicked:
middle=true;
break;
}
}
if (up && page == 1 ) //We have turned the Rotary Encoder CounterClockwise
{
up = false;
if(menuitem==1 && frame ==2)
{
frame--;
}
if(menuitem==2 && frame ==3)
{
frame--;
}
if(menuitem==3 && frame ==4)
{
frame--;
}
lastMenuItem = menuitem;
menuitem--;
if (menuitem==0)
{
menuitem=1;
}
}
else if (up && page == 2 && menuitem==2 )
{
up = false;
selectedDifficulty--;
if(selectedDifficulty == -1)
{
selectedDifficulty = 9;
}
}
else if (up && page == 2 && menuitem==4 ) {
up = false;
}
else if (up && page == 2 && menuitem==3 ) {
up = false;
selectedMode--;
if(selectedMode == -1)
{
selectedMode = 1;
}
}
if (down && page == 1) //We have turned the Rotary Encoder Clockwise
{
down = false;
if(menuitem==2 && lastMenuItem == 1)
{
frame ++;
}
else if(menuitem==3 && lastMenuItem == 2)
{
frame ++;
}
else if(menuitem==4 && lastMenuItem == 3 && frame!=3)
{
frame ++;
}
lastMenuItem = menuitem;
menuitem++;
if (menuitem==5)
{
menuitem--;
}
}
else if (down && page == 2 && menuitem==2 ) {
down = false;
selectedDifficulty++;
if(selectedDifficulty == 10)
{
selectedDifficulty = 0;
}
}
else if (down && page == 2 && menuitem==3 ) {
down = false;
selectedMode++;
if(selectedMode == 2)
{
selectedMode = 0;
}
}
if (middle) //Middle Button is Pressed
{
middle = false;
if (page == 1 && menuitem==1) // Motor Control
{
if (motor)
{
menuItem1 = "Motor: ON";
motor = false;
turnMotorOff();
//Left to Center
digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction
for(int x = 0; x < halfDist; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(stepdelay);
digitalWrite(stepPin,LOW);
delayMicroseconds(stepdelay);
}
}
else
{
menuItem1 = "Motor: OFF";
motor = true;
turnMotorOn();
//Center to Right
digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction
for(int x = 0; x < halfDist; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(stepdelay);
digitalWrite(stepPin,LOW);
delayMicroseconds(stepdelay);
}
}
}
if(page == 1 && menuitem ==4)// Reset
{
resetDefaults();
}
else if (page == 1 && menuitem==2) {
page=2;
}
else if (page == 1 && menuitem==3) {
page=2;
}
else if (page == 2)
{
page=1;
}
}
}
void drawMenu()
{
if (page==1)
{
display.setTextSize(1);
display.clearDisplay();
display.setTextColor(WHITE, BLACK);
display.setCursor(15, 0);
display.print("MAIN MENU");
display.drawFastHLine(0,10,128,WHITE);
if(menuitem==1 && frame ==1)
{
displayMenuItem(menuItem1, 15,true); //FRAME 1
displayMenuItem(menuItem2, 25,false);
}
else if(menuitem == 2 && frame == 1)
{
displayMenuItem(menuItem1, 15,false);
displayMenuItem(menuItem2, 25,true);
}
else if(menuitem == 3 && frame == 2)
{
displayMenuItem(menuItem2, 15,false); //FRAME 2
displayMenuItem(menuItem3, 25,true);
}
else if(menuitem == 2 && frame == 2)
{
displayMenuItem(menuItem2, 15,true);
displayMenuItem(menuItem3, 25,false);
}
else if(menuitem == 4 && frame == 3)
{
displayMenuItem(menuItem3, 15,false); //FRAME 3
displayMenuItem(menuItem4, 25,true);
}
else if(menuitem == 3 && frame == 3)
{
displayMenuItem(menuItem3, 15,true);
displayMenuItem(menuItem4, 25,false);
}
else if(menuitem == 2 && frame == 3)
{
displayMenuItem(menuItem2, 15,true); //FRAME 2
displayMenuItem(menuItem3, 25,false);
}
else if(menuitem == 1 && frame == 2)
{
displayMenuItem(menuItem1, 15,true); //FRAME 1
displayMenuItem(menuItem2, 25,false);
}
display.display();
}
else if (page==2 && menuitem == 2)
{
displayStringMenuPage(menuItem2, difficulty[selectedDifficulty]);
}
else if (page==2 && menuitem == 3)
{
displayStringMenuPage(menuItem3, mode[selectedMode]);
}
}
void resetDefaults()
{
selectedDifficulty = 0;
selectedMode = 0;
motor = true;
menuItem1 = "Motor: OFF";// Start Homing procedure of Stepper Motor at startup
while (digitalRead(home_switch)) { // Do this until the switch is activated
digitalWrite(dirPin, HIGH); // (HIGH = anti-clockwise / LOW = clockwise)
digitalWrite(stepPin, HIGH);
delayMicroseconds(75); // Delay to slow down speed of Stepper
digitalWrite(stepPin, LOW);
delayMicroseconds(75);
}
while (!digitalRead(home_switch)) { // Do this until the switch is not activated
digitalWrite(dirPin, LOW);
digitalWrite(stepPin, HIGH);
delay(5); // More delay to slow even more while moving away from switch
digitalWrite(stepPin, LOW);
delay(5);
}
steps=0; // Reset position variable to zero
digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction
for(int x = 0; x < halfDist+400; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(50);
digitalWrite(stepPin,LOW);
delayMicroseconds(50);
}
}
void setstepdelay()
{
// display.setContrast(contrast);
display.display();
}
void turnMotorOn()
{
//Left limit to Right Limit
digitalWrite(dirPin,HIGH);
for(int x = 0; x < fullDist; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(stepdelay);
digitalWrite(stepPin,LOW);
delayMicroseconds(stepdelay);
}
//Right limit to Left
digitalWrite(dirPin,LOW);
for(int x = 0; x < fullDist; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(stepdelay);
digitalWrite(stepPin,LOW);
delayMicroseconds(stepdelay);
}
}
void turnMotorOff()
{
digitalWrite(7,HIGH);
}
void timerIsr() {
encoder->service();
}
void displayIntMenuPage(String menuItem, int value)
{
display.setTextSize(1);
display.clearDisplay();
display.setTextColor(WHITE, BLACK);
display.setCursor(10, 0);
display.print(menuItem);
display.drawFastHLine(0,10,80,WHITE);
display.setCursor(5, 15);
display.print("Value");
display.setTextSize(2);
display.setCursor(80, 10);
display.print(value);
display.setTextSize(2);
display.display();
}
void displayStringMenuPage(String menuItem, String value)
{
display.setTextSize(2);
display.clearDisplay();
display.setTextColor(WHITE, BLACK);
display.setCursor(0, 0);
display.print(menuItem);
display.setCursor(50, 15);
display.print(value);
display.setTextSize(2);
display.display();
}
void displayMenuItem(String item, int position, boolean selected)
{
if(selected)
{
display.setTextColor(BLACK, WHITE);
}else
{
display.setTextColor(WHITE, BLACK);
}
display.setCursor(0, position);
display.print(">"+item);
}
void readRotaryEncoder()
{
value += encoder->getValue();
if (value/2 > last) {
last = value/2;
down = true;
delay(150);
}else if (value/2 < last) {
last = value/2;
up = true;
delay(150);
}
}
Comments