/*
*
* Dispositivo di conteggio punti per un biliardo all'italiana.
* Il dispositivo presenta un tastiera di 16 pulsanti con numeri simboli e lettere
* due display a 7 segmenti TM1637 a 4 cifre uno per ogni biglia(gialla e bianca)
* il tutto gira su un arduino nano ed un alimentatore con uscite a 12v per
* la scheda arduino e 5v per i due display.
* La Tastiera permette:
* la scelta della biglia gialla tramite il simbolo '*' o bianca tramite il simbolo '#';
* l'aggiunta di un valore di massimo 2 cifre ad una biglia tramite i numeri;
* la sottrazione di un valore tramite il simbolo 'B' e i numeri;
* la cancellazione di un operazione tramite il simbolo 'C'
* la scelta di un tipo di partita tramite il simbolo 'A' la conferma di questa scelta tramite 'D'.
*
* La Tastiera è collegata ai pin 9,8,7,6 per le righe e 5,4,3,2 per le colonne
* i display sono collegati rispettivamente clock (CLK) A5 e dati (DIO) A4 per il giallo
* clock (CLK) 11 e dati (DIO) 12 per il bianco.
*
*/
#include <Keypad.h> //libreria per uso tastiera
#include <Arduino.h> //libreria per uso tipi arduino
#include <TM1637TinyDisplay.h> //libreria per uso display 7 segmenti tipo TM1637
#define CLKg A5 //pin clock display giallo
#define DIOg A4 //pin dati display giallo
#define CLKb 11 //pin clock display bianco
#define DIOb 12 //pin dati display bianco
#define Time 3000 //tempo in millisecondi per inserire un valore
#define Npartite 6 //quantità dei tipi di partite/match
const byte ROWS=4; //quantità righe tastiera
const byte COLS=4; //quantità colonne tastiera
//array per i singoli segmenti
const uint8_t SEG_VALORI[]{
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, // 0
SEG_B | SEG_C, // 1
SEG_A | SEG_B | SEG_D | SEG_E | SEG_G, // 2
SEG_A | SEG_B | SEG_C | SEG_D | SEG_G, // 3
SEG_B | SEG_C | SEG_F | SEG_G, // 4
SEG_A | SEG_C | SEG_D | SEG_F | SEG_G, // 5
SEG_A | SEG_C | SEG_D |SEG_E | SEG_F | SEG_G, // 6
SEG_A | SEG_B | SEG_C, // 7
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,// 8
SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G, // 9
SEG_G, // -
SEG_D, // _
0x00, // empty
0xff // full
};
const uint8_t SEG_PLAY[] = {
SEG_A | SEG_B | SEG_E | SEG_F | SEG_G, // P
SEG_D | SEG_E | SEG_F, // L
SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G, // A
SEG_B | SEG_C | SEG_D | SEG_F | SEG_G // Y
};
const uint8_t SEG_LOSS[] = {
SEG_D | SEG_E | SEG_F, //L
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, //O
SEG_A | SEG_C | SEG_D | SEG_F | SEG_G, //S
SEG_A | SEG_C | SEG_D | SEG_F | SEG_G //S
};
const uint8_t SEG_WIN[] = {
SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, //V
SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, //V
SEG_B | SEG_C, //i
SEG_A | SEG_B | SEG_C | SEG_E | SEG_F //n
};
char keys[ROWS][COLS]={ //matrice della tastiera
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
/*
* Tipi di partite/match disponibili
* il primo valore indica da quanti game è composta la partita
* il secondo valore indica la durata in punti del singolo game
* l'ultima coppia di valori è simbolica per permette l'inserimento di una partita personalizzata
*/
uint16_t partite [Npartite][2]{
{1,60},
{3,60},
{5,60},
{1,100},
{3,100},
{9999,9999}
};
byte rowPins[ROWS]={9,8,7,6}; //pin righe tastiera
byte colPins[COLS]={5,4,3,2}; //pin colonne tastiera
Keypad keypad = Keypad(makeKeymap(keys),rowPins,colPins,ROWS,COLS); //creazione oggetto tastiera
TM1637TinyDisplay displayg(CLKg, DIOg); //display biglia gialla
TM1637TinyDisplay displayb(CLKb, DIOb); //display biglia bianca
uint16_t cnt,gialla,bianca; //contatori dei punti delle biglie
uint8_t winG,winB,n; //winG e winB contatori game, n indice tipo partita/match
boolean match; //valore controllo partita/match in corso default true
boolean less; //valore controllo sottrazione default false
boolean stG=false,stB=false; //valori di selezione biglia
unsigned long t1; //Tempo di esecuzione per uso timer aggiunta valore
//funzione inserimento valore da aggiungere o sottrarre ad una biglia
void somma(boolean &st,uint16_t &ball,uint8_t win,TM1637TinyDisplay &disp);
//funzione formazione valore da aggiungere o sottrrare ad una biglia
void conta(char key,boolean &st,uint16_t &ball,uint8_t win,TM1637TinyDisplay &disp,unsigned long &t);
//funzione inserimento valori durata partita personalizzata
uint16_t inserisci(TM1637TinyDisplay &disp);
//funzione visuallizzazione valori game sul display
void show(TM1637TinyDisplay &disp,uint16_t c0,uint16_t c1,uint16_t c2,uint16_t c3);
//funzione animazione display attesa inserimento valori
void animation(TM1637TinyDisplay &disp,uint8_t x0,uint8_t x1,uint8_t x2,uint8_t x3,unsigned int t);
//funzione animazione dei display fine partita
void animation2(TM1637TinyDisplay &disp1,TM1637TinyDisplay &disp2,uint8_t seg1[],uint8_t seg2[],uint16_t b1,uint16_t b2,unsigned int t);
//funzione di controllo raggiungimento soglia punti vittoria
void controllo(uint16_t &ball1,uint16_t &ball2,uint8_t &win,TM1637TinyDisplay &disp1,TM1637TinyDisplay &disp2);
void setup() {
Serial.begin(9600);
gialla=0;
bianca=0;
cnt=0;
n=0;
winG=0;
winB=0;
match=true;
less=false;
displayg.setBrightness(5);
show(displayg,13,13,13,13);
displayb.clear();
displayb.setBrightness(5);
show(displayb,13,13,13,13);
delay(500);
displayg.setSegments(SEG_PLAY);
show(displayb,1,10,6,0);
delay(1000);
displayg.clear();
show(displayg,winG,11,(gialla/10)%10,gialla%10);;
displayb.clear();
show(displayb,winB,11,(bianca/10)%10,bianca%10);
Serial.println("Inizio nuova partita");
Serial.print("gialla = ");
Serial.print(gialla);
Serial.print(" bianca = ");
Serial.println(bianca);
}
void loop() {
char key=keypad.getKey();
static uint8_t i=-1;
if(!(n==(Npartite-1)&&(partite[n][0]==0))){
controllo(gialla,bianca,winG,displayg,displayb);
controllo(bianca,gialla,winB,displayb,displayg);
}
if(key){
Serial.print("Key pressed: ");
Serial.println(key);
} if(key=='A'){
match=false;
stG=false;
stB=false;
i=((++i) % Npartite);
displayg.showNumberDec(partite[i][0]);
displayb.showNumberDec(partite[i][1]);
}
if(match){
if(key=='*'){ //selezione biglia gialla
if(cnt!=0)somma(stB,bianca,winB,displayb);
t1=millis();
stG=true;
stB=false;
less=false;
cnt=0;
displayg.clear();
animation(displayg,0x00,0x00,0x08,0x08,30);
if(n==(Npartite-1)&&(partite[n][0]==0)) displayb.showNumberDec(bianca);
else if(bianca<100) show(displayb,winB,11,(bianca/10)%10,bianca%10);
else show(displayb,winB,(bianca/100)%10,(bianca/10)%10,bianca%10);
}
if(key=='#'){ //selezione biglia bianca
if(cnt!=0)somma(stG,gialla,winG,displayg);
t1=millis();
stB=true;
stG=false;
less=false;
cnt=0;
displayb.clear();
animation(displayb,0x00,0x00,0x08,0x08,30);
if(n==(Npartite-1)&&(partite[n][0]==0)) displayg.showNumberDec(gialla);
else if(gialla<100) show(displayg,winG,11,(gialla/10)%10,gialla%10);
else show(displayg,winG,(gialla/100)%10,(gialla/10)%10,gialla%10);
}
if(stG){
conta(key,stG,gialla,winG,displayg,t1);
}
if(stB){
conta(key,stB,bianca,winB,displayb,t1);
}
}else if(key=='D'){
n=i;
i=-1;
winG=0;
winB=0;
if(n==(Npartite-1)){
partite[n][0]=inserisci(displayg);
if(partite[n][0]>9) {
partite[n][0]=9;
displayg.showNumberDec(partite[n][0]);
}
partite[n][1]=inserisci(displayb);
if(partite[n][1]>999){
partite[n][1]=999;
displayb.showNumberDec(partite[n][1]);
delay(1000);
}
}
displayg.setSegments(SEG_PLAY);
if(partite[n][1]<99) show(displayb,partite[n][0],10,(partite[n][1]/10)%10,partite[n][1]%10);
else show(displayb,partite[n][0],(partite[n][1]/100)%10,(partite[n][1]/10)%10,partite[n][1]%10);
delay(1000);
match=true;
gialla=0;
bianca=0;
if (partite[n][0]==0){
displayg.showNumberDec(gialla);
displayb.showNumberDec(bianca);
}
else {
show(displayg,winG,11,(gialla/10)%10,gialla%10);
show(displayb,winB,11,(bianca/10)%10,bianca%10);
}
cnt=0;
Serial.println("Inizio nuova partita");
Serial.print("gialla = ");
Serial.print(gialla);
Serial.print(" bianca = ");
Serial.println(bianca);
}else if((key=='C')||(key=='*')||(key=='#')){
match=true;
i=-1;
if(gialla<100) show(displayg,winG,11,(gialla/10)%10,gialla%10);
else show(displayg,winG,(gialla/100)%10,(gialla/10)%10,gialla%10);
if(bianca<100) show(displayb,winB,11,(bianca/10)%10,bianca%10);
else show(displayb,winB,(bianca/100)%10,(bianca/10)%10,bianca%10);
}
}
void controllo(uint16_t &ball1,uint16_t &ball2,uint8_t &win,TM1637TinyDisplay &disp1,TM1637TinyDisplay &disp2){
if(ball1>=partite[n][1]) {
win++;
animation2(disp1,disp2,SEG_WIN,SEG_LOSS,ball1,ball2,500);
if (win>(partite[n][0]/2)){
displayg.setSegments(SEG_PLAY);
if(partite[n][1]<99) show(displayb,partite[n][0],10,(partite[n][1]/10)%10,partite[n][1]%10);
else show(displayb,partite[n][0],(partite[n][1]/100)%10,(partite[n][1]/10)%10,partite[n][1]%10);
winG=0;
winB=0;
Serial.println("Inizio nuova partita");
}
match=true;
gialla=0;
show(displayg,winG,11,(gialla/10)%10,gialla%10);
bianca=0;
show(displayb,winB,11,(bianca/10)%10,bianca%10);
cnt=0;
Serial.print("gialla = ");
Serial.print(gialla);
Serial.print(" bianca = ");
Serial.println(bianca);
}
}
void somma(boolean &st,uint16_t &ball,uint8_t win,TM1637TinyDisplay &disp){
st=false;
if(less){
ball-=cnt;
less=false;
}else ball+=cnt;
cnt=0;
if(n==(Npartite-1)&&(partite[n][0]==0)) disp.showNumberDec(ball);
else if (ball<100) show(disp,win,11,(ball/10)%10,ball%10);
else show(disp,win,(ball/100)%10,(ball/10)%10,ball%10);
Serial.print("gialla = ");
Serial.print(gialla);
Serial.print(" bianca = ");
Serial.println(bianca);
}
void conta(char key,boolean &st,uint16_t &ball,uint8_t win,TM1637TinyDisplay &disp,unsigned long &t){
if(millis()>=t+Time)
somma(st,ball,win,disp);
else if(((key-48)>=0)&&((key-48)<10)){
cnt=(cnt*10)+(key-48);
if(cnt>100)cnt=cnt%100;
Serial.print("conta ");
Serial.println(cnt);
if(less)disp.showNumberDec(-cnt);
else disp.showNumberDec(cnt);
}else if(key=='B'){
less=true;
disp.showNumberDec(-cnt);
}
else if(key=='C'){
less=false;
stB=false;
stG=false;
cnt=0;
if(n==(Npartite-1)&&(partite[n][0]==0)) disp.showNumberDec(ball);
else if (ball<100) show(disp,win,11,(ball/10)%10,ball%10);
else show(disp,win,(ball/100)%10,(ball/10)%10,ball%10);
}
}
uint16_t inserisci(TM1637TinyDisplay &disp){
char key='A';
uint16_t val=0;
animation(disp,0x00,0x00,0x08,0x08,50);
while(key!='D'){
key=keypad.getKey();
if(key!='D'){
if(((key-48)>=0)&&((key-48)<10)) {
val=(val*10)+(key-48);
disp.showNumberDec(val);
}
else if(key=='C') {
val=0;
disp.showNumberDec(val);
}
}
}
return val;
}
void show(TM1637TinyDisplay &disp,uint16_t x0,uint16_t x1,uint16_t x2,uint16_t x3){
uint8_t dati[]={SEG_VALORI[x0],SEG_VALORI[x1],SEG_VALORI[x2],SEG_VALORI[x3]};
disp.clear();
disp.setSegments(dati);
}
void animation(TM1637TinyDisplay &disp,uint8_t x0,uint8_t x1,uint8_t x2,uint8_t x3,unsigned int t){
uint8_t dati[]={x0,x1,x2,x3};
for(int i=0;i<7;i++){
if(i%2==0)disp.setSegments(dati);
else disp.clear();
delay(t);
}
}
void animation2(TM1637TinyDisplay &disp1,TM1637TinyDisplay &disp2,uint8_t seg1[],uint8_t seg2[],uint16_t b1,uint16_t b2,unsigned int t){
for(int i=0;i<9;i++){
if(i%2==0){
disp1.setSegments(seg1);
disp2.setSegments(seg2);
}else{
disp1.showNumberDec(b1);
disp2.showNumberDec(b2);
}
delay(t);
}
}