Components and supplies
Arduino Nano R3
Rotary Encoder with Push-Button
OLED Display, Blue on Black
Stepper Motor, Mini Step
HC-06 Bluetooth Module
Tools and machines
Soldering iron (generic)
Apps and platforms
Processing
Arduino IDE
Project description
Code
Updated Arduino Code
c_cpp
This is the code with added serial port monitoring, when the Arduino receives "on" through the serial port, it runs the cups back and forth at defined speed.
1/* 2 * Code by Ty Palowski for Automated Beerpong Game V2 3 * https://youtube.com/c/typalowski 4 */ 5 6 7#include <Adafruit_GFX.h> 8#include <Adafruit_SSD1306.h> 9#include <ClickEncoder.h> 10#include <TimerOne.h> 11 12#define SCREEN_WIDTH 128 // OLED display width, in pixels 13#define SCREEN_HEIGHT 32 // OLED display height, in pixels 14 15// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) 16#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) 17 18Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 19 20// defines pins numbers 21const int dirPin = 2; 22const int stepPin = 4; 23const int enPin = 5; 24 25int menuitem = 1; 26int frame = 1; 27int page = 1; 28int lastMenuItem = 1; 29 30String menuItem1 = "Motor: OFF"; 31String menuItem2 = "Difficulty"; 32String menuItem3 = "Mode"; 33String menuItem4 = "Reset"; 34 35boolean motor = true; 36int stepdelay; 37 38int maxDelay = 240; 39int diffDelta = 23; 40 41String difficulty[10] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; 42int selectedDifficulty = 9; 43 44String mode[2] = { "EASY", "HARD"}; 45int selectedMode = 1; 46 47boolean up = false; 48boolean down = false; 49boolean middle = false; 50 51ClickEncoder *encoder; 52int16_t last, value; 53 54// '85062033-beer-pong-or-beirut-drinking-game-with-cups-with-ball-line-art-vector-icon-for-apps-and-websites-', 128x32px 55const unsigned char myBitmap [] PROGMEM = { 56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0x83, 0x83, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0x38, 0x38, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xc3, 0xc3, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x83, 0x83, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xff, 0xff, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x98, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x9c, 0x71, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x9f, 0xf1, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x90, 0x13, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x98, 0x13, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc8, 0x23, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 88}; 89 90#define home_switch 9 // Pin 9 connected to Home Switch (MicroSwitch) 91 92int direction; // Variable to set Rotation (CW-CCW) of the motor 93int steps; // Used to set HOME position after Homing is completed 94 95int fullDist = 32766; 96int halfDist = fullDist/2; 97 98 99void setup() { 100 Serial.begin(57600); 101 102 103 // Sets the two pins as Outputs 104 pinMode(stepPin,OUTPUT); 105 pinMode(dirPin,OUTPUT); 106 107 pinMode(enPin,OUTPUT); 108 digitalWrite(enPin,LOW); 109 110 111 pinMode(7,OUTPUT); 112 113 114 encoder = new ClickEncoder(A1, A0, A2); 115 encoder->setAccelerationEnabled(false); 116 117 display.begin(); 118 display.clearDisplay(); 119 120 Timer1.initialize(1000); 121 Timer1.attachInterrupt(timerIsr); 122 123 last = encoder->getValue(); 124 125 display.setRotation (2); 126 127 display.drawBitmap(0, 0, myBitmap, 128, 64, WHITE); // display.drawBitmap(x position, y position, bitmap data, bitmap width, bitmap height, color) 128 129 // Show the display buffer on the screen. 130 display.display(); 131 132 133// Start Homing procedure of Stepper Motor at startup 134Serial.println("Homing..."); 135 while (digitalRead(home_switch)) { // Do this until the switch is activated 136 digitalWrite(dirPin, HIGH); // (HIGH = anti-clockwise / LOW = clockwise) 137 digitalWrite(stepPin, HIGH); 138 delayMicroseconds(75); // Delay to slow down speed of Stepper 139 digitalWrite(stepPin, LOW); 140 delayMicroseconds(75); 141} 142 143 while (!digitalRead(home_switch)) { // Do this until the switch is not activated 144 digitalWrite(dirPin, LOW); 145 digitalWrite(stepPin, HIGH); 146 delay(5); // More delay to slow even more while moving away from switch 147 digitalWrite(stepPin, LOW); 148 delay(5); 149 } 150 151 steps=0; // Reset position variable to zero 152 153 digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction 154 for(int x = 0; x < halfDist+425; x++) { 155 digitalWrite(stepPin,HIGH); 156 delayMicroseconds(50); 157 digitalWrite(stepPin,LOW); 158 delayMicroseconds(50); 159 } 160 Serial.println("Ready!"); 161 delay(1000); 162 163} 164 165void loop() { 166 167String readString; 168String Q; 169 170while (Serial.available()){ 171 delay(1); 172 if(Serial.available()>0){ 173 char c = Serial.read(); 174 if (isControl(c)){ 175 break; 176 } 177 readString += c; 178 } 179} 180 181Q = readString; 182if (Q=="on"){ 183 Serial.println("on"); 184 //Center to Left Limit 185 digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction 186 for(int x = 0; x < halfDist; x++) { 187 digitalWrite(stepPin,HIGH); 188 delayMicroseconds(stepdelay); 189 digitalWrite(stepPin,LOW); 190 delayMicroseconds(stepdelay); 191 } 192 //Left Limit to Right Limit 193 digitalWrite(dirPin,LOW); 194 for(int x = 0; x < fullDist; x++) { 195 digitalWrite(stepPin,HIGH); 196 delayMicroseconds(stepdelay); 197 digitalWrite(stepPin,LOW); 198 delayMicroseconds(stepdelay); 199 } 200//Right limit to Center 201 digitalWrite(dirPin,HIGH); 202 for(int x = 0; x < halfDist; x++) { 203 digitalWrite(stepPin,HIGH); 204 delayMicroseconds(stepdelay); 205 digitalWrite(stepPin,LOW); 206 delayMicroseconds(stepdelay); 207 } 208 } 209 210 211stepdelay = maxDelay - selectedDifficulty*diffDelta; 212 213 if (motor == true) 214 { 215 turnMotorOff(); 216 } 217 else 218 { 219 turnMotorOn(); 220 } 221 222 drawMenu(); 223 224 readRotaryEncoder(); 225 226 ClickEncoder::Button b = encoder->getButton(); 227 if (b != ClickEncoder::Open) { 228 switch (b) { 229 case ClickEncoder::Clicked: 230 middle=true; 231 break; 232 } 233 } 234 235 if (up && page == 1 ) //We have turned the Rotary Encoder CounterClockwise 236 { 237 up = false; 238 if(menuitem==1 && frame ==2) 239 { 240 frame--; 241 } 242 if(menuitem==2 && frame ==3) 243 { 244 frame--; 245 } 246 if(menuitem==3 && frame ==4) 247 { 248 frame--; 249 } 250 251 lastMenuItem = menuitem; 252 menuitem--; 253 if (menuitem==0) 254 { 255 menuitem=1; 256 } 257 } 258 else if (up && page == 2 && menuitem==2 ) 259 { 260 up = false; 261 selectedDifficulty--; 262 if(selectedDifficulty == -1) 263 { 264 selectedDifficulty = 9; 265 } 266 } 267 else if (up && page == 2 && menuitem==4 ) { 268 up = false; 269 } 270 else if (up && page == 2 && menuitem==3 ) { 271 up = false; 272 selectedMode--; 273 if(selectedMode == -1) 274 { 275 selectedMode = 1; 276 } 277 } 278 279 if (down && page == 1) //We have turned the Rotary Encoder Clockwise 280 { 281 282 down = false; 283 if(menuitem==2 && lastMenuItem == 1) 284 { 285 frame ++; 286 } 287 else if(menuitem==3 && lastMenuItem == 2) 288 { 289 frame ++; 290 } 291 else if(menuitem==4 && lastMenuItem == 3 && frame!=3) 292 { 293 frame ++; 294 } 295 lastMenuItem = menuitem; 296 menuitem++; 297 if (menuitem==5) 298 { 299 menuitem--; 300 } 301 } 302 else if (down && page == 2 && menuitem==2 ) { 303 down = false; 304 selectedDifficulty++; 305 if(selectedDifficulty == 10) 306 { 307 selectedDifficulty = 0; 308 } 309 } 310 else if (down && page == 2 && menuitem==3 ) { 311 down = false; 312 selectedMode++; 313 if(selectedMode == 2) 314 { 315 selectedMode = 0; 316 } 317 } 318 319 if (middle) //Middle Button is Pressed 320 { 321 middle = false; 322 323 if (page == 1 && menuitem==1) // Motor Control 324 { 325 if (motor) 326 { 327 menuItem1 = "Motor: ON"; 328 motor = false; 329 turnMotorOff(); 330 //Left to Center 331 digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction 332 for(int x = 0; x < halfDist; x++) { 333 digitalWrite(stepPin,HIGH); 334 delayMicroseconds(stepdelay); 335 digitalWrite(stepPin,LOW); 336 delayMicroseconds(stepdelay); 337 } 338 } 339 else 340 { 341 menuItem1 = "Motor: OFF"; 342 motor = true; 343 turnMotorOn(); 344 //Center to Right 345 digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction 346 for(int x = 0; x < halfDist; x++) { 347 digitalWrite(stepPin,HIGH); 348 delayMicroseconds(stepdelay); 349 digitalWrite(stepPin,LOW); 350 delayMicroseconds(stepdelay); 351 } 352 } 353 } 354 355 if(page == 1 && menuitem ==4)// Reset 356 { 357 resetDefaults(); 358 } 359 else if (page == 1 && menuitem==2) { 360 page=2; 361 } 362 else if (page == 1 && menuitem==3) { 363 page=2; 364 } 365 else if (page == 2) 366 { 367 page=1; 368 } 369 } 370 } 371 372 void drawMenu() 373 { 374 375 if (page==1) 376 { 377 display.setTextSize(1); 378 display.clearDisplay(); 379 display.setTextColor(WHITE, BLACK); 380 display.setCursor(15, 0); 381 display.print("MAIN MENU"); 382 display.drawFastHLine(0,10,128,WHITE); 383 384 if(menuitem==1 && frame ==1) 385 { 386 displayMenuItem(menuItem1, 15,true); //FRAME 1 387 displayMenuItem(menuItem2, 25,false); 388 } 389 else if(menuitem == 2 && frame == 1) 390 { 391 displayMenuItem(menuItem1, 15,false); 392 displayMenuItem(menuItem2, 25,true); 393 } 394 else if(menuitem == 3 && frame == 2) 395 { 396 displayMenuItem(menuItem2, 15,false); //FRAME 2 397 displayMenuItem(menuItem3, 25,true); 398 } 399 400 else if(menuitem == 2 && frame == 2) 401 { 402 displayMenuItem(menuItem2, 15,true); 403 displayMenuItem(menuItem3, 25,false); 404 } 405 else if(menuitem == 4 && frame == 3) 406 { 407 displayMenuItem(menuItem3, 15,false); //FRAME 3 408 displayMenuItem(menuItem4, 25,true); 409 } 410 411 else if(menuitem == 3 && frame == 3) 412 { 413 displayMenuItem(menuItem3, 15,true); 414 displayMenuItem(menuItem4, 25,false); 415 } 416 else if(menuitem == 2 && frame == 3) 417 { 418 displayMenuItem(menuItem2, 15,true); //FRAME 2 419 displayMenuItem(menuItem3, 25,false); 420 } 421 else if(menuitem == 1 && frame == 2) 422 { 423 displayMenuItem(menuItem1, 15,true); //FRAME 1 424 displayMenuItem(menuItem2, 25,false); 425 } 426 display.display(); 427 } 428 else if (page==2 && menuitem == 2) 429 { 430 displayStringMenuPage(menuItem2, difficulty[selectedDifficulty]); 431 } 432 else if (page==2 && menuitem == 3) 433 { 434 displayStringMenuPage(menuItem3, mode[selectedMode]); 435 } 436 } 437 438 439 void resetDefaults() 440 { 441 selectedDifficulty = 0; 442 selectedMode = 0; 443 motor = true; 444 menuItem1 = "Motor: OFF";// Start Homing procedure of Stepper Motor at startup 445 446 while (digitalRead(home_switch)) { // Do this until the switch is activated 447 digitalWrite(dirPin, HIGH); // (HIGH = anti-clockwise / LOW = clockwise) 448 digitalWrite(stepPin, HIGH); 449 delayMicroseconds(75); // Delay to slow down speed of Stepper 450 digitalWrite(stepPin, LOW); 451 delayMicroseconds(75); 452} 453 454 while (!digitalRead(home_switch)) { // Do this until the switch is not activated 455 digitalWrite(dirPin, LOW); 456 digitalWrite(stepPin, HIGH); 457 delay(5); // More delay to slow even more while moving away from switch 458 digitalWrite(stepPin, LOW); 459 delay(5); 460 } 461 462 steps=0; // Reset position variable to zero 463 464 digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction 465 for(int x = 0; x < halfDist+425; x++) { 466 digitalWrite(stepPin,HIGH); 467 delayMicroseconds(50); 468 digitalWrite(stepPin,LOW); 469 delayMicroseconds(50); 470 } 471 } 472 473 void setstepdelay() 474 { 475 // display.setContrast(contrast); 476 display.display(); 477 } 478 479 void turnMotorOn() 480 { 481//Left limit to Right Limit 482 digitalWrite(dirPin,HIGH); 483 for(int x = 0; x < fullDist; x++) { 484 digitalWrite(stepPin,HIGH); 485 delayMicroseconds(stepdelay); 486 digitalWrite(stepPin,LOW); 487 delayMicroseconds(stepdelay); 488 } 489//Right limit to Left 490 digitalWrite(dirPin,LOW); 491 for(int x = 0; x < fullDist; x++) { 492 digitalWrite(stepPin,HIGH); 493 delayMicroseconds(stepdelay); 494 digitalWrite(stepPin,LOW); 495 delayMicroseconds(stepdelay); 496 } 497 } 498 499 void turnMotorOff() 500 { 501 digitalWrite(7,HIGH); 502 } 503 504 void timerIsr() { 505 encoder->service(); 506} 507 508void displayIntMenuPage(String menuItem, int value) 509{ 510 display.setTextSize(1); 511 display.clearDisplay(); 512 display.setTextColor(WHITE, BLACK); 513 display.setCursor(10, 0); 514 display.print(menuItem); 515 display.drawFastHLine(0,10,80,WHITE); 516 display.setCursor(5, 15); 517 display.print("Value"); 518 display.setTextSize(2); 519 display.setCursor(80, 10); 520 display.print(value); 521 display.setTextSize(2); 522 display.display(); 523} 524 525void displayStringMenuPage(String menuItem, String value) 526{ 527 display.setTextSize(2); 528 display.clearDisplay(); 529 display.setTextColor(WHITE, BLACK); 530 display.setCursor(0, 0); 531 display.print(menuItem); 532 display.setCursor(50, 15); 533 display.print(value); 534 display.setTextSize(2); 535 display.display(); 536} 537 538void displayMenuItem(String item, int position, boolean selected) 539{ 540 if(selected) 541 { 542 display.setTextColor(BLACK, WHITE); 543 }else 544 { 545 display.setTextColor(WHITE, BLACK); 546 } 547 display.setCursor(0, position); 548 display.print(">"+item); 549} 550 551void readRotaryEncoder() 552{ 553 value += encoder->getValue(); 554 555 if (value/2 > last) { 556 last = value/2; 557 down = true; 558 delay(150); 559 }else if (value/2 < last) { 560 last = value/2; 561 up = true; 562 delay(150); 563 } 564}
Processing Software Code
processing
Change the float threshold = __; to adjust when the computer sends a signal to the Arduino through the COM port on line 18.
1// Import the libraries and dependencies 2import oscP5.*; 3import java.awt.*; 4import processing.serial.*; 5 6Serial myPort; 7String myText=""; 8 9OscP5 oscP5; 10Robot pong; 11float currentAttention; 12float threshold = 70; 13 14// The setup function runs once when you start your application 15void setup(){ 16 17 size(300,300); 18 myPort = new Serial(this, "COM6", 57600); 19 myPort.bufferUntil('n'); 20 21 oscP5 = new OscP5(this, 7771); // Start listening for incoming messages at port 7771 22 23 try { // Try and create a new robot named bob 24 pong = new Robot(); 25 } 26 catch (AWTException e) { // If there is an error, print it out to the console 27 e.printStackTrace(); 28 29 } 30} 31 32void serialEvent (Serial myPort) { 33 myText = myPort.readStringUntil('n'); 34} 35 36// The draw function runs over and over again until you close the application 37void draw(){ 38 39 background(0,0,0); 40 text (myText, 120, 120); 41 myText=""; 42 43 if (currentAttention > threshold) { 44 //bob.keyPress(java.awt.event.KeyEvent.VK_ENTER); 45 myPort.write("on"); 46 delay(7000); 47 48 } 49 // else { 50 //bob.keyRelease(java.awt.event.KeyEvent.VK_ENTER); 51 //} 52 53} 54 55void oscEvent(OscMessage theMessage) { 56 // Print the address and typetag of the message to the console 57 // println("OSC Message received! The address pattern is " + theMessage.addrPattern() + ". The typetag is: " + theMessage.typetag()); 58 59 // Check for Attention messages only 60 if (theMessage.checkAddrPattern("/attention") == true) { 61 currentAttention = theMessage.get(0).floatValue(); 62 println("Your attention is at: " + currentAttention); 63 } 64} 65 66
Updated Arduino Code
c_cpp
This is the code with added serial port monitoring, when the Arduino receives "on" through the serial port, it runs the cups back and forth at defined speed.
1/* 2 * Code by Ty Palowski for Automated Beerpong Game V2 3 * https://youtube.com/c/typalowski 4 */ 5 6 7#include <Adafruit_GFX.h> 8#include <Adafruit_SSD1306.h> 9#include <ClickEncoder.h> 10#include <TimerOne.h> 11 12#define SCREEN_WIDTH 128 // OLED display width, in pixels 13#define SCREEN_HEIGHT 32 // OLED display height, in pixels 14 15// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) 16#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) 17 18Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 19 20// defines pins numbers 21const int dirPin = 2; 22const int stepPin = 4; 23const int enPin = 5; 24 25int menuitem = 1; 26int frame = 1; 27int page = 1; 28int lastMenuItem = 1; 29 30String menuItem1 = "Motor: OFF"; 31String menuItem2 = "Difficulty"; 32String menuItem3 = "Mode"; 33String menuItem4 = "Reset"; 34 35boolean motor = true; 36int stepdelay; 37 38int maxDelay = 240; 39int diffDelta = 23; 40 41String difficulty[10] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; 42int selectedDifficulty = 9; 43 44String mode[2] = { "EASY", "HARD"}; 45int selectedMode = 1; 46 47boolean up = false; 48boolean down = false; 49boolean middle = false; 50 51ClickEncoder *encoder; 52int16_t last, value; 53 54// '85062033-beer-pong-or-beirut-drinking-game-with-cups-with-ball-line-art-vector-icon-for-apps-and-websites-', 128x32px 55const unsigned char myBitmap [] PROGMEM = { 56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0x83, 0x83, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0x38, 0x38, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xc3, 0xc3, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x83, 0x83, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xff, 0xff, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x98, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x9c, 0x71, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x9f, 0xf1, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x90, 0x13, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x98, 0x13, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc8, 0x23, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 88}; 89 90#define home_switch 9 // Pin 9 connected to Home Switch (MicroSwitch) 91 92int direction; // Variable to set Rotation (CW-CCW) of the motor 93int steps; // Used to set HOME position after Homing is completed 94 95int fullDist = 32766; 96int halfDist = fullDist/2; 97 98 99void setup() { 100 Serial.begin(57600); 101 102 103 // Sets the two pins as Outputs 104 pinMode(stepPin,OUTPUT); 105 pinMode(dirPin,OUTPUT); 106 107 pinMode(enPin,OUTPUT); 108 digitalWrite(enPin,LOW); 109 110 111 pinMode(7,OUTPUT); 112 113 114 encoder = new ClickEncoder(A1, A0, A2); 115 encoder->setAccelerationEnabled(false); 116 117 display.begin(); 118 display.clearDisplay(); 119 120 Timer1.initialize(1000); 121 Timer1.attachInterrupt(timerIsr); 122 123 last = encoder->getValue(); 124 125 display.setRotation (2); 126 127 display.drawBitmap(0, 0, myBitmap, 128, 64, WHITE); // display.drawBitmap(x position, y position, bitmap data, bitmap width, bitmap height, color) 128 129 // Show the display buffer on the screen. 130 display.display(); 131 132 133// Start Homing procedure of Stepper Motor at startup 134Serial.println("Homing..."); 135 while (digitalRead(home_switch)) { // Do this until the switch is activated 136 digitalWrite(dirPin, HIGH); // (HIGH = anti-clockwise / LOW = clockwise) 137 digitalWrite(stepPin, HIGH); 138 delayMicroseconds(75); // Delay to slow down speed of Stepper 139 digitalWrite(stepPin, LOW); 140 delayMicroseconds(75); 141} 142 143 while (!digitalRead(home_switch)) { // Do this until the switch is not activated 144 digitalWrite(dirPin, LOW); 145 digitalWrite(stepPin, HIGH); 146 delay(5); // More delay to slow even more while moving away from switch 147 digitalWrite(stepPin, LOW); 148 delay(5); 149 } 150 151 steps=0; // Reset position variable to zero 152 153 digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction 154 for(int x = 0; x < halfDist+425; x++) { 155 digitalWrite(stepPin,HIGH); 156 delayMicroseconds(50); 157 digitalWrite(stepPin,LOW); 158 delayMicroseconds(50); 159 } 160 Serial.println("Ready!"); 161 delay(1000); 162 163} 164 165void loop() { 166 167String readString; 168String Q; 169 170while (Serial.available()){ 171 delay(1); 172 if(Serial.available()>0){ 173 char c = Serial.read(); 174 if (isControl(c)){ 175 break; 176 } 177 readString += c; 178 } 179} 180 181Q = readString; 182if (Q=="on"){ 183 Serial.println("on"); 184 //Center to Left Limit 185 digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction 186 for(int x = 0; x < halfDist; x++) { 187 digitalWrite(stepPin,HIGH); 188 delayMicroseconds(stepdelay); 189 digitalWrite(stepPin,LOW); 190 delayMicroseconds(stepdelay); 191 } 192 //Left Limit to Right Limit 193 digitalWrite(dirPin,LOW); 194 for(int x = 0; x < fullDist; x++) { 195 digitalWrite(stepPin,HIGH); 196 delayMicroseconds(stepdelay); 197 digitalWrite(stepPin,LOW); 198 delayMicroseconds(stepdelay); 199 } 200//Right limit to Center 201 digitalWrite(dirPin,HIGH); 202 for(int x = 0; x < halfDist; x++) { 203 digitalWrite(stepPin,HIGH); 204 delayMicroseconds(stepdelay); 205 digitalWrite(stepPin,LOW); 206 delayMicroseconds(stepdelay); 207 } 208 } 209 210 211stepdelay = maxDelay - selectedDifficulty*diffDelta; 212 213 if (motor == true) 214 { 215 turnMotorOff(); 216 } 217 else 218 { 219 turnMotorOn(); 220 } 221 222 drawMenu(); 223 224 readRotaryEncoder(); 225 226 ClickEncoder::Button b = encoder->getButton(); 227 if (b != ClickEncoder::Open) { 228 switch (b) { 229 case ClickEncoder::Clicked: 230 middle=true; 231 break; 232 } 233 } 234 235 if (up && page == 1 ) //We have turned the Rotary Encoder CounterClockwise 236 { 237 up = false; 238 if(menuitem==1 && frame ==2) 239 { 240 frame--; 241 } 242 if(menuitem==2 && frame ==3) 243 { 244 frame--; 245 } 246 if(menuitem==3 && frame ==4) 247 { 248 frame--; 249 } 250 251 lastMenuItem = menuitem; 252 menuitem--; 253 if (menuitem==0) 254 { 255 menuitem=1; 256 } 257 } 258 else if (up && page == 2 && menuitem==2 ) 259 { 260 up = false; 261 selectedDifficulty--; 262 if(selectedDifficulty == -1) 263 { 264 selectedDifficulty = 9; 265 } 266 } 267 else if (up && page == 2 && menuitem==4 ) { 268 up = false; 269 } 270 else if (up && page == 2 && menuitem==3 ) { 271 up = false; 272 selectedMode--; 273 if(selectedMode == -1) 274 { 275 selectedMode = 1; 276 } 277 } 278 279 if (down && page == 1) //We have turned the Rotary Encoder Clockwise 280 { 281 282 down = false; 283 if(menuitem==2 && lastMenuItem == 1) 284 { 285 frame ++; 286 } 287 else if(menuitem==3 && lastMenuItem == 2) 288 { 289 frame ++; 290 } 291 else if(menuitem==4 && lastMenuItem == 3 && frame!=3) 292 { 293 frame ++; 294 } 295 lastMenuItem = menuitem; 296 menuitem++; 297 if (menuitem==5) 298 { 299 menuitem--; 300 } 301 } 302 else if (down && page == 2 && menuitem==2 ) { 303 down = false; 304 selectedDifficulty++; 305 if(selectedDifficulty == 10) 306 { 307 selectedDifficulty = 0; 308 } 309 } 310 else if (down && page == 2 && menuitem==3 ) { 311 down = false; 312 selectedMode++; 313 if(selectedMode == 2) 314 { 315 selectedMode = 0; 316 } 317 } 318 319 if (middle) //Middle Button is Pressed 320 { 321 middle = false; 322 323 if (page == 1 && menuitem==1) // Motor Control 324 { 325 if (motor) 326 { 327 menuItem1 = "Motor: ON"; 328 motor = false; 329 turnMotorOff(); 330 //Left to Center 331 digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction 332 for(int x = 0; x < halfDist; x++) { 333 digitalWrite(stepPin,HIGH); 334 delayMicroseconds(stepdelay); 335 digitalWrite(stepPin,LOW); 336 delayMicroseconds(stepdelay); 337 } 338 } 339 else 340 { 341 menuItem1 = "Motor: OFF"; 342 motor = true; 343 turnMotorOn(); 344 //Center to Right 345 digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction 346 for(int x = 0; x < halfDist; x++) { 347 digitalWrite(stepPin,HIGH); 348 delayMicroseconds(stepdelay); 349 digitalWrite(stepPin,LOW); 350 delayMicroseconds(stepdelay); 351 } 352 } 353 } 354 355 if(page == 1 && menuitem ==4)// Reset 356 { 357 resetDefaults(); 358 } 359 else if (page == 1 && menuitem==2) { 360 page=2; 361 } 362 else if (page == 1 && menuitem==3) { 363 page=2; 364 } 365 else if (page == 2) 366 { 367 page=1; 368 } 369 } 370 } 371 372 void drawMenu() 373 { 374 375 if (page==1) 376 { 377 display.setTextSize(1); 378 display.clearDisplay(); 379 display.setTextColor(WHITE, BLACK); 380 display.setCursor(15, 0); 381 display.print("MAIN MENU"); 382 display.drawFastHLine(0,10,128,WHITE); 383 384 if(menuitem==1 && frame ==1) 385 { 386 displayMenuItem(menuItem1, 15,true); //FRAME 1 387 displayMenuItem(menuItem2, 25,false); 388 } 389 else if(menuitem == 2 && frame == 1) 390 { 391 displayMenuItem(menuItem1, 15,false); 392 displayMenuItem(menuItem2, 25,true); 393 } 394 else if(menuitem == 3 && frame == 2) 395 { 396 displayMenuItem(menuItem2, 15,false); //FRAME 2 397 displayMenuItem(menuItem3, 25,true); 398 } 399 400 else if(menuitem == 2 && frame == 2) 401 { 402 displayMenuItem(menuItem2, 15,true); 403 displayMenuItem(menuItem3, 25,false); 404 } 405 else if(menuitem == 4 && frame == 3) 406 { 407 displayMenuItem(menuItem3, 15,false); //FRAME 3 408 displayMenuItem(menuItem4, 25,true); 409 } 410 411 else if(menuitem == 3 && frame == 3) 412 { 413 displayMenuItem(menuItem3, 15,true); 414 displayMenuItem(menuItem4, 25,false); 415 } 416 else if(menuitem == 2 && frame == 3) 417 { 418 displayMenuItem(menuItem2, 15,true); //FRAME 2 419 displayMenuItem(menuItem3, 25,false); 420 } 421 else if(menuitem == 1 && frame == 2) 422 { 423 displayMenuItem(menuItem1, 15,true); //FRAME 1 424 displayMenuItem(menuItem2, 25,false); 425 } 426 display.display(); 427 } 428 else if (page==2 && menuitem == 2) 429 { 430 displayStringMenuPage(menuItem2, difficulty[selectedDifficulty]); 431 } 432 else if (page==2 && menuitem == 3) 433 { 434 displayStringMenuPage(menuItem3, mode[selectedMode]); 435 } 436 } 437 438 439 void resetDefaults() 440 { 441 selectedDifficulty = 0; 442 selectedMode = 0; 443 motor = true; 444 menuItem1 = "Motor: OFF";// Start Homing procedure of Stepper Motor at startup 445 446 while (digitalRead(home_switch)) { // Do this until the switch is activated 447 digitalWrite(dirPin, HIGH); // (HIGH = anti-clockwise / LOW = clockwise) 448 digitalWrite(stepPin, HIGH); 449 delayMicroseconds(75); // Delay to slow down speed of Stepper 450 digitalWrite(stepPin, LOW); 451 delayMicroseconds(75); 452} 453 454 while (!digitalRead(home_switch)) { // Do this until the switch is not activated 455 digitalWrite(dirPin, LOW); 456 digitalWrite(stepPin, HIGH); 457 delay(5); // More delay to slow even more while moving away from switch 458 digitalWrite(stepPin, LOW); 459 delay(5); 460 } 461 462 steps=0; // Reset position variable to zero 463 464 digitalWrite(dirPin,LOW); // Enables the motor to move in a particular direction 465 for(int x = 0; x < halfDist+425; x++) { 466 digitalWrite(stepPin,HIGH); 467 delayMicroseconds(50); 468 digitalWrite(stepPin,LOW); 469 delayMicroseconds(50); 470 } 471 } 472 473 void setstepdelay() 474 { 475 // display.setContrast(contrast); 476 display.display(); 477 } 478 479 void turnMotorOn() 480 { 481//Left limit to Right Limit 482 digitalWrite(dirPin,HIGH); 483 for(int x = 0; x < fullDist; x++) { 484 digitalWrite(stepPin,HIGH); 485 delayMicroseconds(stepdelay); 486 digitalWrite(stepPin,LOW); 487 delayMicroseconds(stepdelay); 488 } 489//Right limit to Left 490 digitalWrite(dirPin,LOW); 491 for(int x = 0; x < fullDist; x++) { 492 digitalWrite(stepPin,HIGH); 493 delayMicroseconds(stepdelay); 494 digitalWrite(stepPin,LOW); 495 delayMicroseconds(stepdelay); 496 } 497 } 498 499 void turnMotorOff() 500 { 501 digitalWrite(7,HIGH); 502 } 503 504 void timerIsr() { 505 encoder->service(); 506} 507 508void displayIntMenuPage(String menuItem, int value) 509{ 510 display.setTextSize(1); 511 display.clearDisplay(); 512 display.setTextColor(WHITE, BLACK); 513 display.setCursor(10, 0); 514 display.print(menuItem); 515 display.drawFastHLine(0,10,80,WHITE); 516 display.setCursor(5, 15); 517 display.print("Value"); 518 display.setTextSize(2); 519 display.setCursor(80, 10); 520 display.print(value); 521 display.setTextSize(2); 522 display.display(); 523} 524 525void displayStringMenuPage(String menuItem, String value) 526{ 527 display.setTextSize(2); 528 display.clearDisplay(); 529 display.setTextColor(WHITE, BLACK); 530 display.setCursor(0, 0); 531 display.print(menuItem); 532 display.setCursor(50, 15); 533 display.print(value); 534 display.setTextSize(2); 535 display.display(); 536} 537 538void displayMenuItem(String item, int position, boolean selected) 539{ 540 if(selected) 541 { 542 display.setTextColor(BLACK, WHITE); 543 }else 544 { 545 display.setTextColor(WHITE, BLACK); 546 } 547 display.setCursor(0, position); 548 display.print(">"+item); 549} 550 551void readRotaryEncoder() 552{ 553 value += encoder->getValue(); 554 555 if (value/2 > last) { 556 last = value/2; 557 down = true; 558 delay(150); 559 }else if (value/2 < last) { 560 last = value/2; 561 up = true; 562 delay(150); 563 } 564}
Downloadable files
Original wiring diagram for the automated table.
Wiring schedule/diagram.
Original wiring diagram for the automated table.
Original wiring diagram for the automated table.
Wiring schedule/diagram.
Original wiring diagram for the automated table.
Comments
Only logged in users can leave comments