Orologio digitale

Buongiorno a tutti, in questo periodo di forzata inattività ho fatto, .. e rifatto, … e rifatto per la terza volta un orologio digitale che funziona (fatto salvo due pulsanti che riesco a far funzionare solo definendoli OUTPUT e non come INPUT) …. per un paio d'ore, poi i numeri che compaiono sui display a 7 segmenti impazziscono.

In un primo tempo pensavo si trattasse di un problema di programma per cui avevo chiesto indicazioni nella sezione soft, ma ora ritengo sia dovuto alla scarsità (di energia???) dell'arduino utilizzato (un Pro mini AT mega 328 a 5V e 16 mHz) anche in quanto scollegando i display a video compaiono i dati corretti.

Qualcuno può darmi indicazioni? allego programma e schema del circuito.

#include <stdio.h>
#include <DS1302.h>

int orario;
int data;

// Pin RTC
const int kCePin   = 2;  // Chip Enable
const int kIoPin   = 3;  // Input/Output
const int kSclkPin = 4;  // Serial Clock

#define led1 8

// Pin integrati
#define DATA_PIN 7
#define LATCH_PIN 5
#define CLOCK_PIN 6

// Pin pulsanti visualizzazione/set
#define PulsDisplay 9
#define PulsSet 8

int StatoDisplay = 0;   // visualizza ora o data
int StatoSet = 0;

// Variabili scelta correzioni
int Set_Ore;
int Set_Min;
int Set_Gg;
int Set_Mesi;

// Variabili corrette
int corOre = 0;
int corMinuti = 0;
int corData = 0;
int corMese = 0;

// Variabili correzioni
int modOre = 0;
int modMinuti = 0;
int modData = 0;
int modMese = 0;

long t_debounce = 0;
long debounce_delay = 500;

// Variabili display
unsigned long a;
unsigned long b;
unsigned long c;
unsigned long d;

// Variabili comandi display
unsigned long e;
unsigned long f;
unsigned long g;
unsigned long h;

unsigned long values[] = {
  //gfedcba
  0x7E, // 0
  0xC,  // 1
  0xB6, // 2
  0x9F, // 3
  0xCD, // 4
  0xDA, // 5
  0xFA, // 6
  0xE,  // 7
  0xFE, // 8
  0xDE, // 9
  0x0,  // tutto spento
};

DS1302 rtc(kCePin, kIoPin, kSclkPin);

void printTime() {
  Time t = rtc.time();

  // Array temporaneo inserimento valori data/ora
  char buf[50];

  Set_Ore = t.hr;
  Set_Min = t.min;
  Set_Gg = t.date;
  Set_Mesi = t.mon;

  corOre = t.hr + modOre;
  corMinuti = t.min + modMinuti ;
  corData = t.date + modData;
  corMese = t.mon + modMese;

  snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d",
           t.yr, corMese, corData,
           corOre, corMinuti, t.sec);

  // Controllo a video
  Serial.println(buf);

  orario = (corOre * 100) + corMinuti;
  data = (corData * 100) + corMese;
}

void setup() {
  Serial.begin(9600);
  Serial.println("Versione caricata 13");
  pinMode(DATA_PIN, OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);

  pinMode(led1, OUTPUT);
  pinMode(PulsDisplay, OUTPUT);
  pinMode(PulsSet, OUTPUT);

  // Initializzazione data/ora
  //rtc.writeProtect(false);
  //rtc.halt(false);

  // Sunday, April 26, 2020 at 15:19:00.
  //Time t(2020, 04, 26, 15, 19, 00, Time::kSunday);

  // Memorizzazione valori inseriti
  //rtc.time(t);
}

void loop() {
  // Lampeggio Led
  if (digitalRead(led1) == HIGH)  {
    digitalWrite(led1, LOW);
  } else {
    digitalWrite(led1, HIGH);
  }

  //Visualizzazione ora/data
  if ((digitalRead(PulsDisplay)) && (StatoSet == 0)) {
    if ( (millis() - t_debounce) > debounce_delay) {
      StatoDisplay = !StatoDisplay;
      t_debounce = millis();
    }
  }
  printTime();
  nuovoSet();
  modValori();
  vis_dati();

  delay(1000);
}

void writeRegister(unsigned long value) {
  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, value >> 24);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, value >> 16);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, value >> 8);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, value);
  digitalWrite(LATCH_PIN, HIGH);
}

void vis_dati() {
  a = values[h];
  b = values[g];
  d = values[f];
  c = values[e];

  unsigned long dati = d;
  dati = (dati << 8) | c;
  dati = (dati << 8) | b;
  dati = (dati << 8) | a;

  writeRegister(dati << 0);
}

void ora() {
  e = (orario / 1000);
  f = (orario - (e * 1000)) / 100;
  g = (orario - (e * 1000) - (f * 100)) / 10;
  h = (orario - (e * 1000) - (f * 100) - (g * 10));
}

void DispData() {
  e = (data / 1000);
  f = (data - (e * 1000)) / 100;
  g = (data - (e * 1000) - (f * 100)) / 10;
  h = (data - (e * 1000) - (f * 100) - (g * 10));
}

void ModificaOra() {
  g = ((corOre ) / 10);
  h = ((corOre ) - (g * 10));
  e = 10;
  f = 10;
}

void ModificaMin() {
  g = ((corMinuti  ) / 10);
  h = ((corMinuti  ) - (g * 10));
  e = 10;
  f = 10;
}

void ModificaData() {
  g = ((corData ) / 10);
  h = ((corData ) - (g * 10));
  e = 10;
  f = 10;
}

void ModificaMese() {
  g = (corMese  / 10);
  h = corMese - (g * 10);
  e = 10;
  f = 10;
}

void  modValori() {
  switch (StatoSet) {
    case (0): // fine delle modifiche
      if (StatoDisplay == 1) {
        DispData();
      } else {
        ora();
      }
      break;

    case (1): // incrementa il valore delle ore
      while (StatoSet == 1) {
        nuovoSet();
        ModificaOra(); // visualizzo su disply le ore
        vis_dati();

        //incremento le ore premendo PulsDisplay
        if (digitalRead(PulsDisplay)) {
          if ( (millis() - t_debounce) > debounce_delay) {
            if (corOre == 23) {
              modOre = 24 - (Set_Ore + 24);
            } else {
              modOre = modOre + 1;
            }
            corOre = Set_Ore + modOre;
          }
          t_debounce = millis();
        }
      }
      break;

    case (2): // incrementa il valore dei minuti
      while (StatoSet == 2) {
        nuovoSet();
        ModificaMin(); // visualizzo su disply i minuti
        vis_dati();
        //incremento i minuti premendo PulsDisplay
        if (digitalRead(PulsDisplay)) {
          if ( (millis() - t_debounce) > debounce_delay) {
            if (corMinuti == 59) {
              modMinuti = 60 - (Set_Min + 60);
            } else {
              modMinuti = modMinuti + 1;
            }
            corMinuti = Set_Min + modMinuti;
          }
          t_debounce = millis();
        }
      }
      break;

    case (3): // incrementa il valore della data
      while (StatoSet == 3) {
        nuovoSet();       
        ModificaData(); // visualizzo su disply la data
        vis_dati();
        //incremento la data premendo PulsDisplay
        if (digitalRead(PulsDisplay)) {
          if ( (millis() - t_debounce) > debounce_delay) {
            if (corData == 31) {
              modData = 31 - (Set_Gg + 30);
            } else {
              modData = modData + 1;
            }
            corData = Set_Gg + modData;
          }
          t_debounce = millis();
        }
      }
      break;

    case (4): // incrementa il valore dei mesi
      while (StatoSet == 4) {
        nuovoSet();
        ModificaMese();// visualizzo su disply il mese
        vis_dati();
        //incremento i mesi premendo PulsDisplay
        if (digitalRead(PulsDisplay)) {
          if ( (millis() - t_debounce) > debounce_delay) {
            if (corMese == 12) {
              modMese = 12 - (Set_Mesi + 11);
            } else {
              modMese = modMese + 1;
            }
            corMese = Set_Mesi + modMese;
          }
          t_debounce = millis();
        }
      }
      break;
  }
}

void nuovoSet()
{
  if (digitalRead(PulsSet)) {
    if ( (millis() - t_debounce) > debounce_delay) {
      StatoSet = StatoSet + 1;
      if (StatoSet > 4) {
        StatoSet = 0;
      }
      t_debounce = millis();
    }
  }
}

//******************************FINE*****************************************

Enrico

Orologio_schem.pdf (1.91 MB)

Hm, curiosità: forse mi sfugge qualcosa, ma come alimenti il tutto? Ossia in quello schema dov'è l'alimentatore? Non alimenterai mica i display con i 5V di Arduino, spero...

Hm, curiosità: forse mi sfugge qualcosa, ma come alimenti il tutto? Ossia in quello schema dov'è l'alimentatore? Non alimenterai mica i display con i 5V di Arduino, spero...

….. speri male, pensavo bastassero i 5V di arduino, o i 9 erogarti da un normale alimentatore per telefoni sempre attraverso il RAW di arduino.

Immagino di aver fatto una "cazzata"!!

Ciao
Enrico

Primo problema: i 74LVC138, pur tollerando livelli logici in ingresso fino a 5V, possono essere alimentati solo da 2,7 a 3,3V!

  1. I pin 1, 2, 3 sono gli ingressi A, B, C dei demux "3 a 8": come fa a funzionare???... Forse è sbagliato lo schema...

  2. Quei demux attivano un'uscita per volta, secondo il codice applicato in ingresso: sarebbe stato molto più semplice usando dei decoder appositi per display a 7 segmenti, dotati anche di uscite regolate in corrente, senza dover mettere tante resistenze in serie ai segmenti. Ad esempio c'è il vecchio, classico M5450, che ha un pin apposito per la regolazione della luminosità, ma trovi a pochi euro schedine a 4 o 6 o 8 display con comando I2C o simile con decoder:

7 segment serial display
.

enrico24:
, ma ora ritengo sia dovuto alla scarsità (di energia???) dell'arduino utilizzato (un Pro mini AT mega 328 a 5V e 16 mHz) .

La scarsità di energia, è da leggere come somma del consumo di ampere (corrente) dei tuoi dispositivi, rispetto a quanta corrente viene fornita sul pin 5V, che probabilmente è insufficiente.
Ora spero di non scrivere cavolate:
Il pin 5V esce dal regolatore di corrente sul pcb, vedi schema (in alto a sx) di solito un MIC5205, max current output 150mA
Su una Uno il regolatore (altro chip) mi pare invece eroga max 400mA

Primo problema: i 74LVC138, pur tollerando livelli logici in ingresso fino a 5V, possono essere alimentati solo da 2,7 a 3,3V!

Sto cospargendomi il capo di cenere!!!! Non mi sono accorto di aver sbagliato integrato!! Sono, ovviamente, dei 74HC595!! GRAZIE.

I punti 2 e 3 ritengo si riferiscono all'errore di etichettatura di quello che io chiamo (probabilmente sbagliando) integrato - non conoscevo il termine "demux".

In generale, e non è una critica, ho voluto costruire l'orologio complicandomi la vita e spendendo, sicuramente, più tempo e denaro per avere un oggetto meno "elegante" di quanto avrei potuto fare acquistandolo, per a) "passare" il tempo e b) per imparare qualcosa di nuovo.

Grazie comunque dell'attenzione dedicatami e dei suggerimenti che potrei dover applicare in altri progetti.

saluti

Enrico

Qualche condensatore elettrolitico sull'alimentazione (uno o due da 47uF), ma anche dei ceramici da 100nF (100000pF) vicino a ciascun integrato) potrebbero essere di grande aiuto, perché gli assorbimenti a impulsi, se la corrente fa un giro non studiato bene, possono andare a interferire con il funzionamento del microcontrollore.

Il piedino di reset non è collegato a nulla?... Anche quello è un problema. Deve essere collegato al positivo, direttamente o attraverso una resistenza da 10kOhm se vuoi mettere un pulsante di reset.

Integrato è un termine generico, sempre appropriato; multiplexer o mux è specifico.

enrico24:
….. speri male, pensavo bastassero i 5V di arduino, o i 9 erogarti da un normale alimentatore per telefoni sempre attraverso il RAW di arduino.

Non so se ho quindi capito bene: tu attualmente alimenti a 9V Arduino (da jack quindi immagino),e da questo pensavi di prendere i 5V da mandare ai display ed integrati, esatto? Per i 5V ok, ma il problema, come temo e mi pare ti abbiano già detto, è la corrente massima che può uscire da Arduino.

Per cui io ti consiglierei di usare alimentazione diversa per i led e integrati: o prendendo l'alimentazione non dal pin 5V ma in "parallelo" sullo stesso alimentatore di Arduino se usi un alimentatore a 5V (che va su Vin), oppure un secondo alimentatore a 5V (con GND in comune all'altro e ad Arduino ovviamente).

Ho modificato lo schema (v. allegato).

x Docdoc: l'alimentazione (modificata) viene fatta con un adattatore AC/DC che eroga 9v a 1A, ridotta a 5,5V con questo; ho separato l'alimentazione ad Arduino/7Segmenti così non dovrei più avere problemi di tensione (come suggerito da nid69ita). In questa maniera dovrei aver superato anche la necessità dei condensatori (v. Datman).

Il piedino di reset non è collegato a nulla?... Anche quello è un problema. Deve essere collegato al positivo, direttamente o attraverso una resistenza da 10kOhm se vuoi mettere un pulsante di reset

Non penso di utilizzarlo, per questo non ho fatto il collegamento (complicarmi la vita si, ...ma non troppo; non sono un provetto saldatore e lo spazio non è molto!)

Integrato è un termine generico, sempre appropriato; multiplexer o mux è specifico.

Grazie, non lo sapervo.

Ancora grazie a tutti per i suggerimenti.

Enrico

Allegato

Orologio_02_schem.zip (1.3 MB)

enrico24:
Non penso di utilizzarlo, per questo non ho fatto il collegamento (complicarmi la vita si, ...ma non troppo; non sono un provetto saldatore e lo spazio non è molto!)

Che tu lo utilizzi o meno NON cambia il fatto che il pin di reset DEVE essere tenuto a livello HIGH, quindi ... metti una resistenza da un 10K tra il pin di reset e il Vcc.

Guglielmo

Che tu lo utilizzi o meno NON cambia il fatto che il pin di reset DEVE essere tenuto a livello HIGH, quindi ... metti una resistenza da un 10K tra il pin di reset e il Vcc.

OBBEDISCO! (Scusa, ma non ho resistito).

Questo è valido per tutti gli Arduino/programmi? In quanto in nessun tutorial è evidenziato.

Saluti

Enrico

enrico24:
OBBEDISCO! (Scusa, ma non ho resistito).

... si risponde SIGNOR' SI SIGNORE !!! (... manco io ho resitito :smiley:)

enrico24:
Questo è valido per tutti gli Arduino/programmi? In quanto in nessun tutorial è evidenziato.

Dipende dalla MCU e da quanto c'è scritto nel suo datasheet. Per gli AVR è normalmente sempre meglio forzare il livello HIGH anche se, all'interno, c'è già una pull-up.

Inoltre, in realtà, sarebbe sempre bene NON lasciare MAI scollegato alcun pin di INPUT di una MCU, dato che essi possono sempre essere fonte di possibili disturbi e ...
... averli sul pin di "reset" ... non è esattamente il massimo della vita :smiley:

Guglielmo

enrico24:
...così non dovrei più avere problemi di tensione (come suggerito da nid69ita).

Solo per precisione, i problemi erano di corrente (ampere), non di tensione (volt). :slight_smile:

... si risponde SIGNOR' SI SIGNORE !!!

Si, ma il mio secondo nome è Garibaldi!

.. scherzi a parte grazie per il consiglio.

Solo per precisione, i problemi erano di corrente (ampere), non di tensione (volt).

Grazie, sembra sottinteso che utilizzare 1A dovrebbe essere sufficiente anche senza condensatori …

Enrico

enrico24:
. . . sembra sottinteso che utilizzare 1A dovrebbe essere sufficiente anche senza condensatori …

Può darsi.

Ma il giorno che non capirai per quale motivo un tuo progetto fa strane cose, e le fa in maniera del tutto casuale, e il cablaggio è perfetto, e il software provato a pezzi funziona, ma tutto insieme non sempre, e tu senti impellente il bisogno di un muro in cui sbattere la testa . . . :smiley:
. . . verifica prima se i condensatori li hai messi E SE HAI ANCORATO A Vcc IL PIN DI RESET.

Ciao,
P.

...e se un giorno volessi programmare un attiny85, se non ci metti un condensatore sull'alimentazione è come voler programmare un mattone! :smiley:

Evviva i condensatori!!

Li sto mettendo.

Grazie ancora a tutti.

Enrico

PS: ovviamente provvedo anche ad ancorare il reset!

Ecco lo schema corretto secondo le vs. ultime indicazioni.

Non posso ancora essere soddisfatto in quanto penso vi sia un contatto anomalo, in quanto accanto al piedino 9 del micro pro lampeggia, se collegato al riduttore di corrente, velocemente una lucetta; ciò non avviene se alimentato via PC.

Inoltre non riesco a far comparire sui 7 segmenti l'ora (mentre a video questa è corretta).

Ho pertanto deciso di rifare integralmente il progetto con nuovi componenti.

Saluti

enrico

Ecco l'allegato.