I had some more antique hardware laying around so I made a simple scoreboard. If it can Blynk - use it!
It’s very basic, but still useful for my needs:
- Track 2 different scores
- Input 2 player names
- Large numerals (they are 3 lines high)
- Reset and start over
Hardware:
- Arduino UNO R3
- 4x20 LCD with HD44780 compatible controller (mine is actually a SPLC780 from Sunplus)
- ENC28J60 ethernet
Not added yet:
- 5 physical buttons
Pics from app and the LCD itself:
Code:
/*
2018-01-10 00:00:00
A SIMPLE 4x20 LCD SCOREBOARD
Using Arduino UNO, ENC28J60 ethernet, HD44780 compatible controller and custom glyphs for displaying larger numbers.
The very clever way to display BIG numbers with the HD44780 controller was stolen from:
http://woodsgood.ca/projects/2015/01/16/large-numbers-on-small-displays/
ENC28J60 wiring:
CS - Pin 10
SI - Pin 11 (= ST)
SO - Pin 12
SCK - Pin 13
INT - Pin 2 (= LNT)
*/
//============
#include <LiquidCrystal.h>
#include <UIPEthernet.h>
#include <BlynkSimpleUIPEthernet.h>
//============ For splitting numbers to digits
byte num100s;
byte num10s;
byte num1s;
//============ LCD setup and custom glyphs
const int rs = 7, en = 6, d4 = 5, d5 = 4, d6 = 3, d7 = 8; // NOTE! d7 is not the standard pin 2 since UIP needs that for INT.
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
byte x10[8] = {0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07};
byte x11[8] = {0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C};
byte x12[8] = {0x00,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F};
byte x13[8] = {0x07,0x07,0x07,0x07,0x07,0x1F,0x1F,0x1F};
byte x14[8] = {0x1C,0x1C,0x1C,0x1C,0x1C,0x1F,0x1F,0x1F};
byte x15[8] = {0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C};
byte x16[8] = {0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07};
byte x17[8] = {0x00,0x00,0x0E,0x0E,0x0E,0x00,0x00,0x00};
byte row = 0,col = 0;
//============ Network
char auth[] = "";
byte arduino_mac[] = { 0xAE, 0xED, 0xBA, 0xFE, 0xFE, 0xCA };
IPAddress arduino_ip (192, 168, 1, 24);
IPAddress dns_ip (192, 168, 1, 1);
IPAddress gateway_ip (192, 168, 1, 1);
IPAddress subnet_mask(255, 255, 255, 0);
//============ Misc
WidgetTerminal terminal(V0);
byte playerNo = 0;
//============ Setup
void setup() {
Blynk.begin(auth, "", 8442, arduino_ip, dns_ip, gateway_ip, subnet_mask, arduino_mac);
while (Blynk.connect() == false) {
// Wait until connected
}
lcd.begin(20, 4);
lcd.createChar(0, x10);
lcd.createChar(1, x11);
lcd.createChar(2, x12);
lcd.createChar(3, x13);
lcd.createChar(4, x14);
lcd.createChar(5, x15);
lcd.createChar(6, x16);
lcd.createChar(7, x17); // colon
terminal.println(F("Blynk v" BLYNK_VERSION ": Device started"));
terminal.println(F("-------------"));
terminal.println("");
terminal.flush();
newGame();
}
//============ Get player names from terminal
BLYNK_WRITE(V0) {
if (playerNo == 0) {
String playerName = param.asStr();
playerName.remove(9); // Trim the Strings to 9 chars so they won't screw up the numbers on the next row.
lcd.setCursor(0,0);
lcd.print(playerName);
terminal.println("");
terminal.println("Enter player 2's name");
terminal.flush();
playerNo++;
}
else if (playerNo == 1) {
String playerName = param.asStr();
playerName.remove(9);
lcd.setCursor(11,0);
lcd.print(playerName);
terminal.println("");
terminal.println("Rack 'em up!");
terminal.flush();
playerNo++; // Now we ignore input from terminal
}
}
//============ PLAYER 1 score button
BLYNK_WRITE(V1) {
int valP1 = param.asInt();
Blynk.virtualWrite(V11, valP1);
updateNumberP1(valP1);
}
//============ PLAYER 2 score button
BLYNK_WRITE(V2) {
int valP2 = param.asInt();
Blynk.virtualWrite(V12, valP2);
updateNumberP2(valP2);
}
//============ PLAYER 1 dispaly score on LCD
void updateNumberP1(int numP1) {
row = 1;
if (numP1 >= 100) { // Need to split the current score (number) to its individual digits
num100s = numP1 / 100;
num10s = numP1 % 100 / 10;
num1s = numP1 % 10;
doNumber( num100s,row,0);
doNumber( num10s,row,3);
doNumber( num1s,row,6);
}
else if (numP1 >= 10) {
num10s = numP1 / 10;
num1s = numP1 % 10;
doNumber( num10s,row,3);
doNumber( num1s,row,6);
}
else {
doNumber( numP1,row,6);
}
}
//============ PLAYER 2 dispaly score on LCD
void updateNumberP2(int numP2) {
row = 1;
if (numP2 >= 100) {
num100s = numP2 / 100;
num10s = numP2 % 100 / 10;
num1s = numP2 % 10;
doNumber( num100s,row,11);
doNumber( num10s,row,14);
doNumber( num1s,row,17);
}
else if (numP2 >= 10) {
num10s = numP2 / 10;
num1s = numP2 % 10;
doNumber( num10s,row,14);
doNumber( num1s,row,17);
}
else {
doNumber( numP2,row,17);
}
}
//============ Button to start a new game
BLYNK_WRITE(V3) {
if (param.asInt()) {
newGame();
}
}
//============ Start a new game
void newGame() {
playerNo = 0; // Start reading input from terminal again
resetValues();
terminal.println("Enter player 1's name");
terminal.flush();
// Display 0 : 0
row = 1;
doNumber( 0,row,6);
doNumber(11,row,9);
doNumber( 0,row,17);
}
//============ Reset values to 0 in app and clear LCD and terminal
void resetValues() {
for (int i = 0; i <= 24; i++) {
terminal.println(""); // "clear screen" in app.
}
terminal.flush();
lcd.clear();
Blynk.virtualWrite(V1, 0);
Blynk.virtualWrite(V2, 0);
Blynk.virtualWrite(V11, 0);
Blynk.virtualWrite(V12, 0);
}
//*****************************************************************************************//
// doNumber: routine to position number 'num' starting top left at row 'r', column 'c'
//*****************************************************************************************//
void doNumber(byte num, byte r, byte c) {
lcd.setCursor(c,r);
switch(num) {
case 0: lcd.write(byte(2)); lcd.write(byte(2));
lcd.setCursor(c,r+1); lcd.write(byte(5)); lcd.write(byte(6));
lcd.setCursor(c,r+2); lcd.write(byte(4)); lcd.write(byte(3)); break;
case 1: lcd.write(byte(0)); lcd.write(byte(1));
lcd.setCursor(c,r+1); lcd.print(" "); lcd.write(byte(5));
lcd.setCursor(c,r+2); lcd.write(byte(0)); lcd.write(byte(4)); break;
case 2: lcd.write(byte(2)); lcd.write(byte(2));
lcd.setCursor(c,r+1); lcd.write(byte(2)); lcd.write(byte(3));
lcd.setCursor(c,r+2); lcd.write(byte(4)); lcd.write(byte(2)); break;
case 3: lcd.write(byte(2)); lcd.write(byte(2));
lcd.setCursor(c,r+1); lcd.write(byte(0)); lcd.write(byte(3));
lcd.setCursor(c,r+2); lcd.write(byte(2)); lcd.write(byte(3)); break;
case 4: lcd.write(byte(1)); lcd.write(byte(0));
lcd.setCursor(c,r+1); lcd.write(byte(4)); lcd.write(byte(3));
lcd.setCursor(c,r+2); lcd.print(" "); lcd.write(byte(6)); break;
case 5: lcd.write(byte(2)); lcd.write(byte(2));
lcd.setCursor(c,r+1); lcd.write(byte(4)); lcd.write(byte(2));
lcd.setCursor(c,r+2); lcd.write(byte(2)); lcd.write(byte(3)); break;
case 6: lcd.write(byte(1)); lcd.print(" ");
lcd.setCursor(c,r+1); lcd.write(byte(4)); lcd.write(byte(2));
lcd.setCursor(c,r+2); lcd.write(byte(4)); lcd.write(byte(3)); break;
case 7: lcd.write(byte(2)); lcd.write(byte(2));
lcd.setCursor(c,r+1); lcd.print(" "); lcd.write(byte(6));
lcd.setCursor(c,r+2); lcd.print(" "); lcd.write(byte(6)); break;
case 8: lcd.write(byte(2)); lcd.write(byte(2));
lcd.setCursor(c,r+1); lcd.write(byte(4)); lcd.write(byte(3));
lcd.setCursor(c,r+2); lcd.write(byte(4)); lcd.write(byte(3)); break;
case 9: lcd.write(byte(2)); lcd.write(byte(2));
lcd.setCursor(c,r+1); lcd.write(byte(4)); lcd.write(byte(3));
lcd.setCursor(c,r+2); lcd.print(" "); lcd.write(byte(6)); break;
case 11: lcd.setCursor(c,r+1); lcd.write(byte(7)); lcd.setCursor(c,r+2); lcd.write(byte(7)); break;
}
}
//============ Main loop
void loop() {
Blynk.run();
}
Feedback, suggestions, improvements and cookies are most welcome!