giovedì 4 settembre 2025

Orologio Scacchi Nuovo

 

 Orologio scacchi oled

In questo post descrivo il progetto per un nuovo orologio per gioco degli scacchi che utilizza due display oled.



Su questo blog avevo già pubblicato un mio lavoro "Orologio digitale per scacchi".
Purtroppo quel lavoro è stato parzialmente smontato perché non più funzionante, ho quindi deciso di fare un nuovo orologio.




Caratteristiche principali 

Deviatore gioco, centrale che scambia gli orologi.
Funzione SET ( tasto BIANCO) :
Possibilità di regolare (tasto BLU ) il tempo da 5 minuti a 90 minuti ( 1h e 1/2), con step di 5 minuti, singolarmente per ogni orologio.
Pulsante di Start/ Stop  (tasto ROSSO)  per avviare la partita, Stop per interrompere la partita ed iniziarne una nuova.

Questo orologio è del tutto simile al precedente, lo sketch è riutilizzato in gran parte, ho modificato eliminando le parti non necessarie ed aggiungendo librerie e codice per la visualizzazione su "OLED".


Materiale occorrente:

1    Arduino UNO ( è possibile usare anche altre schede compatibili).
2    Display moduli OLED da 0,96 pollici 128x64 I2C.
1    Scheda TCA9548A espansione canali I2C.
    Deviatore una via due posizioni.
3    Pulsanti momentanei.
5    resistenze da 10K.
*************
Nel mio lavoro ho utilizzato anche:
2     led Uno Giallo uno Verde
    resistenze da 180 ohm.

Qui sotto lo schema elettrico.



                    Prova su Bread Board del TCA9548 e dei due display oled.





Montaggio su basetta forata della scheda TCA9548 e collegato con Arduino, pulsanti ed oled.






Orologio in funzione.






Scambio Orologio




Fine tempo orologio, uno degli orologi ha finito il tempo e si ferma su 00.00







Funzionamento ed istruzioni rimangono le stesse del precedente lavoro.

In questa versione utilizzo Arduino uno, al quale collego sia la schedina TCA espansione canali I2C, e due Oled I2C da 0,96 pollici.
L'utilizzo degli oled semplifica molto lo schema, ma per utilizzarli ho usato la libreria U8x8lib.
Nel mio sketch uso molto poco della libreria se interessati guardate il video 355 di Paolo Aliverti, colgo l'occasione per ringraziarlo per tutti i video che fa.

Anche sul mio canale YouTube trovate un video sul funzionamento dell'orologio di scacchi.


Qui sotto lo sketch 






/*
/*

  ScacchiTCA6548.ino
 
   version for U8x8 API

  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)

  Copyright (c) 2016, olikraus@gmail.com
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification,
  are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this list
    of conditions and the following disclaimer.
   
  * Redistributions in binary form must reproduce the above copyright notice, this
    list of conditions and the following disclaimer in the documentation and/or other
    materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  

*/

/*
//--------------------------------------------------------------------------//
//********************************
  Sergio  & Adiano Prenleloup
 *********************************
 ***    OROLOGIO SCACCHI  ********
 ****   **********      **********
 ***    Versione V300825
 ******   30/08/2025  ************
 *********************************
 ***  ADATTAMENTO DEL PROGRAMMA  ***
 ***  CON MODULI OLED I2C     *****
 **********************************
 // Si cambia solo la parte visualizzazione
 // usando display OLED I2C
//--------------------------------------------------------------------------//
// Tasti == START/STOP  -- SET  --- Regola
//------------------------------------------
// In questa versione l'orologio esegue le normali funzioni per giuoco scacchi,
//
// Inizialmente viene proposto il tempo di gioco di default 5 minuti.
// E' possibile con la funzione SET cambiare il tempo ( anche in modo diverso
// per i due orologi) alla pressione del tasto SET si accende led, a questo
// punto si preme il tasto Regola che incrementerà il tempo di 5 minuti ad
// ogni pressione, per regolare il secondo orologio spostare il tasto deviatore
// gioco. Finita la regolazione premere nuovamente SET il led si spenge.
// E' possibile regolare da 5 a 90 minuti, con step di 5 minuti.
// Premendo START / STOP parte l'orologio attivo.
// Il gioco prosegue scambiando gli orologi fino al termine del tempo.
// Quando un orologio è arrivato allo 00.00 si ferma tutto fino alla nuova
// pressione del tasto START. Ed il ciclo ricomincia per nuova partita.
// E' possibile durante il gioco interrompere la partita premendo START/STOP
// Gli orologi si azzerano e premendo ancora START/STOP è possibile effettuare
// altra partita.
// Questo orologio visualizza a sinistra i minuti e sulla destra i secondi.
//
//
// ------------------------------------------------------------------------//
*/
//VERSIONE CON DEVIATORE
// VERSIONE FUNZIONANTE BENE
//  VERSIONE SENZA FISCHER
//
//
//**************************************************************
//****  AGGIUNTE PER OLED
//*************************************************************

#include <Arduino.h>
#include <LibPrintf.h>
#include <U8x8lib.h>
#include <Wire.h>

// Please UNCOMMENT one of the contructor lines below
// U8x8 Contructor List

//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/// U8X8_PIN_NONE);        
U8X8_SSD1306_128X64_ALT0_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);  
 // same as the NONAME variant, but may solve the "every 2nd line skipped" problem
U8X8_SSD1306_128X64_ALT0_HW_I2C u8x8_b(/* reset=*/ U8X8_PIN_NONE);      
 // same as the NONAME variant, but may solve the "every 2nd line skipped" problem

// End of constructor list
#define TCAADDR 0x70

//#include <Adafruit_GFX.h>
//#include <Adafruit_SSD1306.h>



#define SCREEN_ADDRESS 0x3c
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)


//Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


//*************************************************************************

unsigned long tb = 0;
unsigned long tbounce= 50;
// per memorizzare il tempo millis al setup
//----------------------------------------------------------------------

//**************************************************************************
//*************************************************************************
//--------------------------------------------------------------------------//
// gestione pulsanti
//
int ButtonA = 12; // pin pulsante Orologio A
int ButtonB = 11; // pin pulsante Orologio B
int oroA = 10; // accende orologio A
int oroB = 9; // accende orologio B
int statoA = 0;
int statoB = 0;
int statoAP = 0;
int statoBP = 0;
int SET_pin = 8; // pin pulsante SET si entra in SET
int START_pin = 13; // pin pulsante STAERT e STOP  gioco
int Regola_pin = 7; // pin per la regolazione minuti di gioco
int Led_Set = 4;  // se acceso SET attivo
int stato_bottoni[3];    // gestione pulsanti
boolean stato_switch[3]; // gestione pulsanti
//--------------------------------------------------------------------
//  stato_switch[0]  stato del pulsante START/STOP
//  stato_switch[1]  stato del pulsante SET
//  stato_switch[2]  stato del pulsante Regola
//-------------------------------------------------------------------



//-------------------------------------------------------------------
//  gestione orologi e tempi
int lastsec = 0;
int OrologioAttivo = 0; // 0 orologio A,  1 orologio B,
int tempoOrologi[2];  // contiene il tempo degli orologi 0 e 1
int statoOrologi[2];  // indice orologio attivo
int SET_A = 300; // tempo di 5 minuti
int SET_B = 300; // questi tempi si possono cambiare con la
                 // procedura SET
int Tmax = 5400;  // tempo massimo di gioco 90 minuti ( un'ora e mezzo)
//--------------------------------------------------------------------------//

//--------------------------------------------------------------------------//
//long tb = 0;
//long tbounce= 50;
int orologioA;
int orologioB;


void setup()
{

Wire.begin();

 
  tcaselect(0);

  u8x8.begin();
  u8x8.setPowerSave(0);

 tcaselect(1);

    u8x8_b.begin();
  u8x8_b.setPowerSave(0);


tcaselect(0);

  u8x8.setFont(u8x8_font_amstrad_cpc_extended_r);
//u8x8.drawString(0, 0, "Hello World");  
  //u8x8.setFont(u8x8_font_courB24_3x4_r);
  u8x8.drawString(0,5,"V300825");
  delay(1000);
  u8x8.clearDisplay(); // Clear the buffer
 
tcaselect(1);

  u8x8.setFont(u8x8_font_amstrad_cpc_extended_r);
  //u8x8.drawString(0, 0, "Hello World");  
  //u8x8.setFont(u8x8_font_courB24_3x4_r);
  u8x8.drawString(0,6,"START");
  delay (1000);
 u8x8.clearDisplay(); // Clear the buffer



  pinMode (ButtonA,INPUT); // deviatore gioco
  pinMode (ButtonB,INPUT); // deviatore gioco
  pinMode (SET_pin,INPUT); // pulsante SET
  pinMode (START_pin,INPUT); // pulsante START/STOP
  pinMode (Regola_pin,INPUT); // pulsante Regola
  pinMode (oroA, OUTPUT); // orologioAattivo PIN 8
  pinMode (oroB, OUTPUT); // orologioBATTIVO PIN 9
 
  tempoOrologi[0] = SET_A; // tempo di default 5 minuti
  tempoOrologi[1] = SET_B;

 
   tb = millis();
   tbounce= 50;


}
//-----------------------------------------
// fine setup
//-----------------------------------------


 //------------------------------------------------------------//
// Inizio loop principale
//------------------------------------------------------------//
void loop()
{  

 

   // si attende la pressione del tasto START o del tasto SET
    stato_switch[0]  = 0;
    while  (stato_switch[0] == 0) // fino alla pressione di Start
     {
      tempoOrologi[0] = SET_A;
      tempoOrologi[1] = SET_B;
      visualizzaTempo();
      controllaPulsante();
  // con la pressione del tasto SET si entra nella procedura    
            while (stato_switch[1] == 1)
                  {
                    digitalWrite(Led_Set,HIGH);
                    proceduraSET();
                   controllaPulsante();
                  }
          digitalWrite(Led_Set,LOW);          
     }

   
//------------------------------------------------------------
//   Loop ---  G I O C O -------------------------------------
// il deviatore A B scambia gli orologi
// l'orologio che parte è quello con il deviatore alto
// inizia il conto alla rovescia alternando i due
// orologi fino alla fine del tempo di gioco.
//-------------------------------------------------------------


   while (tempoOrologi[OrologioAttivo] > 0)
        {
        Deviatore();
         
          visualizzaTempo();


         
    //----------------------------------------------------------    
          unsigned long secs = millis() / 1000 - lastsec;
          if (secs >= 1)
             {
              lastsec = millis() / 1000;
     
              aggiornaTempoTrascorso(OrologioAttivo, -1);
             
            }
            Deviatore();
   //---------------------------------------------------------
         visualizzaTempo();
         
       
        //------- STOP e Azzera -----------
         stato_switch[0]  = 0;
         controllaPulsante();
          if   (stato_switch[0] == 1)  // stop
                 {
                   tempoOrologi[0] = 0;
                    tempoOrologi[1] = 0;
                  break;
               }                        
       }
//---------------------------------------------------------------
//   fine gioco uno degli orologi è arrivato a 0
//   si visualizzano i tempi con orologi fermi
//   fino alla pressione del tasto START
//---------------------------------------------------------------
  stato_switch[0]  = 0;
 
   while (stato_switch[0] == 0)
      {
        controllaPulsante();
        visualizzaTempo();
   
      }  



}  
 
  //-----------------------------------
  // FINE LOOP
  //-----------------------------------



//========================================
//   FUNZIONI
//========================================

void tcaselect(uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}


void Deviatore() // scambio orologi attivi
{

  if (digitalRead(ButtonA))
    {
      if ((millis()-tb ) > tbounce){
      digitalWrite(oroB,HIGH);digitalWrite(oroA,LOW);
      orologioA = 0; orologioB = 1;
      tb = millis();
      }
    }

 if (digitalRead(ButtonB))
    {
      if ((millis()-tb) > tbounce){
      digitalWrite(oroB,LOW);digitalWrite(oroA,HIGH);
      orologioB = 0; orologioA = 1;
      tb = millis();

      }
    }
//    orologioA = digitalRead(ButtonA);
//    orologioB = digitalRead(ButtonB);

  if (orologioA == 1)
    {
     OrologioAttivo = 0;
 
    }  
 
  if (orologioB == 1)
  {
   OrologioAttivo = 1;

  }  
}




//-----------------------------------------------------------------
// PROCEDURA SET
//    si regola il tempo di gioco ai due orologi anche
//    diverso ( Deviatore) - scatti di 5 minuti fino a 90 minuti
//    poi torna a 5 minuti
//-----------------------------------------------------------------
void proceduraSET() // siamo entrati in SET alla pressione
                    // del tasto SET -- si accende led
                    // per uscire si preme ancora SET
                    // il led si spenge
{
tcaselect(0);

  //u8x8.setFont(u8x8_font_amstrad_cpc_extended_r);
//u8x8.drawString(0, 0, "Hello World");
     u8x8.clearDisplay();
  u8x8.setFont(u8x8_font_courB24_3x4_r);
  u8x8.drawString(0,5,"SET");
  delay(1000);
  u8x8.clearDisplay(); // Clear the buffer


 
    stato_switch[1]  = 0; // azzero tasto SET
    tempoOrologi[0] = SET_A;
    tempoOrologi[1] = SET_B;
    visualizzaTempo();
   
     while (stato_switch[1] == 0) // fino ad pressione del tasto set
     {  
             controllaPulsante();
         
           if (stato_switch[2] == 1) // se premuto tasto Regola
             {
             
                     Deviatore();  // si regola set orologio attivo
                  if (OrologioAttivo == 0)
                     {
                      SET_A = SET_A + 300;
                       if (SET_A > Tmax) // massimo 90 minuti
                          {
                            SET_A = 300;
                          }
                           
                     }
             
                      Deviatore(); // si regola set orologio attivo
                     if (OrologioAttivo == 1)
     
                       {
                        SET_B = SET_B + 300;
                          if (SET_B > Tmax) // massimo 90 minuti
                             {
                               SET_B = 300;
                             }
                       }
                    }
                   
               tempoOrologi[0] = SET_A;
               tempoOrologi[1] = SET_B;
               visualizzaTempo();
               stato_switch[2]  = 0;    
          }
               tempoOrologi[0] = SET_A;
               tempoOrologi[1] = SET_B;
               visualizzaTempo();
               stato_switch[1]  = 0;
     // fine procedura set
       }
     
//-----------------------------------------------------------------
// Si aggiorna il tempo dell'orologio attivo
//-----------------------------------------------------------------
void aggiornaTempoTrascorso(int orologio, int delta)
{
  tempoOrologi[orologio] = tempoOrologi[orologio] +delta;
}

//---------------------------------------------------------------
// tempo in minuti e secondi
//---------------------------------------------------------------
void minutiSecondi(unsigned long t, int& m, int& s)
{
  m = t / 60;
  s = t % 60;
}

//---------------------------------------------------------------
// Si visualizzano i tempi dei due orologi
//---------------------------------------------------------------
void visualizzaTempo()
{
 

  int m1; int s1;
 
  minutiSecondi(tempoOrologi[0], m1, s1);

 // char bufferm1[10];
 // sprintf(bufferm1 ,"%0d",m1);

 // char buffers1[10];
 // sprintf(buffers1 ,"%0d",s1);


  char bufA[6];
  sprintf(bufA ,"%02d:%02d", m1, s1);





  tcaselect(0);
 
  u8x8.setFont(u8x8_font_courB24_3x4_r);
  u8x8.drawString(0,5,bufA);
  //u8x8.drawString(6,5,":");
 // u8x8.drawString(9,5,buffers1);

   
  int m2; int s2;
  minutiSecondi(tempoOrologi[1], m2, s2);

  //char bufferm2[10];
  //sprintf(bufferm2 ,"%0d",m2);

  //char buffers2[10];
  //sprintf(buffers2 ,"%02d",s2);

  char bufB[6];
  sprintf(bufB ,"%02d:%02d", m2, s2);


 tcaselect(1);
 
  u8x8.setFont(u8x8_font_courB24_3x4_r);
  u8x8.drawString(0,5,bufB);
 // u8x8.drawString(6,5,":");
 // u8x8.drawString(9,5,buffers2);

}




//------------------------------------------------------------
// GESTIONE PULSANTI
//------------------------------------------------------------

 void controllaPulsante()
{
    aggiornaStato(START_pin, stato_bottoni[0], stato_switch[0]);
    aggiornaStato(SET_pin, stato_bottoni[1], stato_switch[1]);
    aggiornaStato(Regola_pin, stato_bottoni[2], stato_switch[2]);
}

void aggiornaStato(int bottone, int& statoBottoneVecchio, boolean& statoSwitch)
{
  //Si legge lo stato corrente del bottone (se premuto o no)
  int statoBottoneCorrente = digitalRead (bottone);
 
  //Se lo stato corrente del bottone è cambiato (diverso dal vecchio stato)
  //si deve gestire il nuovo stato
  if (statoBottoneCorrente != statoBottoneVecchio)
  {
      //se stiamo passando da rilasciato a premuto allora gestiamo la
      //logica antirimbalzo e attiviamo/disattiviamo lo swith
     if (statoBottoneCorrente == HIGH)
     {
       delay(10);
       statoSwitch = !statoSwitch;
     }
     //il nuovo stato diventa lo stato corrente
     statoBottoneVecchio = statoBottoneCorrente;
  }
}


//-----------------------------------------------------
//   fine
//-----------------------------------------------------


Grazie per l'attenzione, potete lasciare un commento o domande, cercherò di rispondere a tutti.



Al prossimo post




Nessun commento:

Posta un commento

Vi ringrazio per la lettura e vi invito al prossimo post.
Se il post vi è stato utile, vi è piaciuto oppure no, scrivete un commento.

Un saluto a tutti.
Sergio

Copyright - Condizioni d’uso - Disclaimer
http://avventurarduino.blogspot.it/2012/10/inizia-lavventura-arduino-12-settembre.html