[RISOLTO] MC14490 (hardware debounce)

Buongiorno,
per curiosità ho preso qualche MC14490P per il debounce hardware (datasheet)

Per non sbagliare, ho cercato in rete, ma ho trovato solo questo schema, quindi vi chiedo, è corretto?

inoltre, che condensatore (C1) posso usare?

Per quanto riguarda l'alimentazione, il datasheet riporta Vdd: –0.5 to +18.0, quindi posso tranquillamente usare i 5V. Corretto?

TIA
Federico

Prova a leggere qui:
https://forum.arduino.cc/index.php?topic=352537.0

(ho corretto il link)

nid69ita:
Prova a leggere qui:
MC14490 e tempi di debounce - Hardware - Arduino Forum

oops, mi era sfuggito perchè ho cercato MC14490P!

Grazie
Federico

PS
Nel link (sorgente) che hai messo c'è qualche carattere di troppo :slight_smile:

Dopo aver smaltito enne ripetizioni di "brodo natalizio" (chiamarlo brodo è riduttivo), ho finalmente deciso di testare il chip in oggetto.
Tanto per complicarmi il test ho deciso di provare a gestire vari stati del pulsante, in particolare:

JUST_PRESSED  //Appena premuto
PRESSED       //Tenuto premuto
LONG_PRESSED  //Tenuto premuto per più di n secondi
JUST_RELEASED //Appena rilasciato

questo lo schema dei collegamenti per i pulsanti

e qui il codice di test

/*
  Hardware debounce con MC14490 - Test
  Version:  1.0 - Dec 2019
  Author:   Federico Luciani (Federico66)
*/

//Decommentare per il debounce software
//#define DEBOUNCE_SOFTWARE

#ifdef DEBOUNCE_SOFTWARE
#define DEBOUNCE_DELAY  60
#endif

//Numero totale dei pulsanti
#define MAX_BTN 4

//Tempo limite per la definizione di pressione prolungata
#define LONG_PRESSED_TIME 1500

//Enumerazione degli stati del pulsante
enum BTN_STATE {
  BTN_NONE          = 0,
  BTN_JUST_PRESSED  = 1,  //Appena premuto
  BTN_PRESSED       = 2,  //Tenuto premuto
  BTN_LONG_PRESSED  = 3,  //Tenuto premuto per più di n secondi
  BTN_JUST_RELEASED = 4   //Appena rilasciato
};

//Pin utilizzati dai pulsanti
uint8_t btn_pin[MAX_BTN] = {3, 4, 5, 6};

//Pin utilizzati dai led
uint8_t led_pin[MAX_BTN] = {9, 10, 11, 12};

//Stato iniziale dei pulsanti virtuali
uint8_t btn_state[MAX_BTN] = {BTN_NONE, BTN_NONE, BTN_NONE, BTN_NONE};

//Stato iniziale dei pulsanti fisici
bool btn_prev_state[MAX_BTN] = {HIGH, HIGH, HIGH, HIGH};

//Stato iniziale dei led
bool led_state[MAX_BTN] = {LOW, LOW, LOW, LOW};

//Tempo iniziale di pressione per calcolo della pressione prolungata
uint32_t start_pressed = 0;

//Se software debounce, tempo ultima lettura
#ifdef DEBOUNCE_SOFTWARE
uint32_t last_time;
#endif

void setup() {
  Serial.begin(9600);

  for (uint8_t i = 0; i < MAX_BTN; i++) {
#ifdef DEBOUNCE_SOFTWARE
    pinMode(btn_pin[i], INPUT_PULLUP);
#else
    pinMode(btn_pin[i], INPUT);
#endif
    pinMode(led_pin[i], OUTPUT);
    digitalWrite(led_pin[i], LOW);
  }
}

void loop() {
  checkButtons();

  //Il primo led si accende/spegne alla pressione del primo pulsante
  if (btn_state[0] == BTN_JUST_PRESSED) {
    Serial.println("Just Pressed");
    led_state[0] = !led_state[0];
    digitalWrite(led_pin[0], led_state[0]);
  }

  //Il secondo led si accende/spegne al rilascio del secondo pulsante
  if (btn_state[1] == BTN_JUST_RELEASED) {
    Serial.println("Just Released");
    led_state[1] = !led_state[1];
    digitalWrite(led_pin[1], led_state[1]);
  }

  //Il terzo led si accende dopo pressione prolungata del terzo pulsante
  //e si spegne al suo rilascio
  if (btn_state[2] == BTN_LONG_PRESSED && !led_state[2]) {
    Serial.println("Long Pressed");
    led_state[2] = HIGH;
    digitalWrite(led_pin[2], led_state[2]);
  } else if (btn_state[2] == BTN_JUST_RELEASED && led_state[2]) {
    Serial.println("Just Released");
    led_state[2] = LOW;
    digitalWrite(led_pin[2], led_state[2]);
  }

  //Il quarto led si accende alla pressione del quarto pulsante,
  //lampeggia dopo pressione prolungata e si spegne al suo rilascio
  if (btn_state[3] == BTN_JUST_PRESSED) {
    Serial.println("Just Pressed");
    led_state[3] = HIGH;
    digitalWrite(led_pin[3], led_state[3]);
  } else if (btn_state[3] == BTN_LONG_PRESSED) {
    Serial.println("Long Released");
    led_state[3] = !led_state[3];
    digitalWrite(led_pin[3], led_state[3]);
    delay(100);
  } else if (btn_state[3] == BTN_JUST_RELEASED) {
    Serial.println("Just Released");
    led_state[3] = LOW;
    digitalWrite(led_pin[3], led_state[3]);
  }
  
}

void checkButtons() {

#ifdef DEBOUNCE_SOFTWARE
  if ((last_time + DEBOUNCE_DELAY) > millis())
    return;
  last_time = millis();
#endif

  for (uint8_t i = 0; i < MAX_BTN; i++) {
    bool btn_cur_state = digitalRead(btn_pin[i]);
    if (btn_cur_state != btn_prev_state[i]) {
      if (btn_cur_state == LOW) {
        //Just pressed
        start_pressed = millis();
        btn_state[i] = BTN_JUST_PRESSED;
      } else {
        //Just released
        btn_state[i] = BTN_JUST_RELEASED;
      }
    } else {
      if (btn_cur_state == LOW) {
        uint32_t timeHold = millis() - start_pressed;
        if (timeHold >= LONG_PRESSED_TIME) {
          //Long Pressed
          btn_state[i] = BTN_LONG_PRESSED;
        } else {
          //Pressed
          btn_state[i] = BTN_PRESSED;
        }
      } else {
        //None
        btn_state[i] = BTN_NONE;
      }
    }
    btn_prev_state[i] = btn_cur_state;
  }
  
}

Il risultato mi sembra buono, quindi io son contento :wink:
Come al solito, ogni critica o proposta di miglioramento è ben accetta.

Se non avete il chip, ma volete testare il codice, vi basta decommentare la define DEBOUNCE_SOFTWARE; questa abilita un semplice debounce software.
A tal proposito, ho notato che il tempo di debounce, nel mio caso, deve essere di almeno 60 ms, altrimenti lo stato JUST_RELEASED non viene intercettato! Onestamente non ho indagato se è migliorabile, non era lo scopo del test.

Buon divertimento
Federico

Quante complicazioni per un anti rimbalzo! :slight_smile:

Datman:
Quante complicazioni per un anti rimbalzo! :slight_smile:

Perchè complicazioni?

L'obiettivo (raggiunto) era solo testare il chip, poi mi sono lasciato prendere la mano :wink:

Federico

Federico66:
Buongiorno,
per curiosità ho preso qualche MC14490P per il debounce hardware (datasheet)

Per non sbagliare, ho cercato in rete, ma ho trovato solo questo schema, quindi vi chiedo, è corretto?

inoltre, che condensatore (C1) posso usare?

Per quanto riguarda l'alimentazione, il datasheet riporta Vdd: –0.5 to +18.0, quindi posso tranquillamente usare i 5V. Corretto?

TIA
Federico

Perché non prendi le informazioni contenute nel Datasheet che hai linkato?
Collegamento pulsante figura 4 a pagina 4

uwefed:
Perché non prendi le informazioni contenute nel Datasheet che hai linkato?
Collegamento pulsante figura 4 a pagina 4

Ho letto il datasheet, ma vista la poca fiducia che ho nelle mie capacità di lettura di un datasheet, cerco sempre conferme :wink:

Federico

Almeno uno schema di utilizzo é contenuto nel datasheet.
Scegliere la frequenza e percui la capacitá da usare non é facile.
Ciao Uwe

Con i valori usati l'scillatore lavora a circa 150 Hz.
VDD = 5V e Cext = 10nF.

Per lavorare il rimbalzo deve avvenire entro i primi 4 cicli di clock. 1/150 = ~6.6ms x 4 ~ 26ms.
Con Cext = 0.022uF (22nF) il periodo è ~ 0,015s (15ms) x 4 = 60ms.

Un valore di cext molto alto può danneggiare il circuito nel caso il power down avvenga molto rapidamente, cioè ad esempio staccando proprio l'alimentazione da VDD. Per scongiurare un possibile guasto in figura 2 viene suggerito il circuito con i due diodi che scaricano Cext su VDD.

Non ho approfondito circa il funzionamento ma sembra replicabile con codice C.

Ciao.

Premessa: qualche tempo fa ho relizzato un orologio con timer che usa, tra l'altro, quattro pulsanti. Ho usato il debounce software e il tutto funziona egregiamente, ma visto che è ancora su breadboard, e avendo letto di questi chip, ho pensato di provarli.
Cosciente del fatto che non sarei stato in grado di calcolare il tipo di condensatore da utilizzare e dopo averne provato qualcuno a caso, ho chiesto qui.

Sempre per curiosità e voglia di capire, dopo che mi è stato consigliato il 10nF, ho ripreso il datasheet e ho fatto qualche calcolo.

Frequenza oscillatore per i 5V, fosc = 1,5/0,01uF = 150Hz, che è quindi inferiore alla frequenza Max del clock (1,4MHz), sempre con 5V; anche se non capisco perchè il valore "Typ" (2.8MHz) è più alto del Max (1,4MHz)! (Pagina 4)

Sempre sul datasheet, c'è scritto di stare attenti al Power down con valori di Cest molto alti, e quindi di verificare che lo spegnimento non sia più veloce di t = (VDD – VSS)Cext/(10 mA). Nel mio caso t = 5V0,01uF/10mA = 0,005ms, che mi è sembrato un valore molto basso da superare, considerando anche che nell'esempio del datasheet dice che per valori vicino 1,5ms non ci sono problemi e che solitamente gli alimentatori non raggiungono queste velocità.

Qui finiscono le mie deduzioni, quindi ho collegato il tutto e verificato che funzionasse :slight_smile:
Visto che funzionava, per esercizio, ho deciso di gestire i pulsanti "a stati" ed il risultato è il codice nel post #3.

In merito alla questione

Maurotec:
Per lavorare il rimbalzo deve avvenire entro i primi 4 cicli di clock. 1/150 = ~6.6ms x 4 ~ 26ms.
Con Cext = 0.022uF (22nF) il periodo è ~ 0,015s (15ms) x 4 = 60ms.

non conoscendo il tempo di rimbalzo dei pulsanti, ma ipotizzando che sia intorno a 10ms (nel debounce software si usa circa 20ms), grazie al tuo calcolo, direi che anche questo torna, 10ms < 26ms :wink:

Se ho detto castronate, vi prego di correggermi.

Grazie
Federico