Debouce hardwere per interrupt su ESP32

Salve a tutti,
ho collegato un pluviometro a bascula ad un ESP32 (in PULLUP hardwere con R da 10K) al GPIO 13 e programmato sotto interrupt; come ci si aspetta da un contatto di quel tipo i rimbalzi che fa sono parecchi.... Per controllare ho comunque collegato un oscilloscopio, ecco i risultati (immagine1).
HO poi collegato in parallelo al contatto un condensatore ceramico da 100nF ed il risultato è questo (immagine2); il problema è che a livello di software non migliora nulla, anzi al contrario peggiora!!
Ho allegato anche una foto dello schema.

Foto disponibili qui: Forum - Google Drive

Qualcuno può aiutarmi?

Grazie in anticipo

Alan Masutti

Prova con lo schema allegato e vedi come va ...

Debouncing-pin.png
Guglielmo

Debouncing-pin.png

Grazie della risposta Guglielmo,
purtroppo continua lo stesso a farlo...

Alan

A me l'immagine 2, a parte l'overshooting negativo, sembra abbastanza pulita.
Sicuro che il problema non sia a livello software?

cotestatnt:
Sicuro che il problema non sia a livello software?

Sicuro al 90%: ho cambiato il GPIO dal 13 allo 0 (FLASH button) e il problema non si verifica!

Ma hai solo il pluviometro di collegato al ESP32 ?

nid69ita:
Ma hai solo il pluviometro di collegato al ESP32 ?

si, il GPIO 0 non è disponibile nei piedini, ho usato il Pulsante on-board....

La cosa strana e’ che i pluviometri usano dei reed, che di solito hanno meno rimbalzi dei comuni switch meccanici (non ne sono totalmente esenti, tranne i reed a contatto “bagnato” in mercurio che pero’ sono difficili da trovare, ma dovrebbero essere comunque molto meno) … per di piu se usando lo schema proposto da Guglielmo ti da lo stesso problema … inizierei a sospettare di qualcos’altro …

>alanmasutti: prova a scrivere proprio due righe di codice che fanno solo la gestione del interrupt e magari incrementano un contatore che visualizzi su monitor seriale ... se il problma non appare, allora sai che è da qualche altra parte nel programma, se appare ancora ... posta il piccolo codice di test che diamo un'occhiata ... ::slight_smile:

Guglielmo

gpb01:
>alanmasutti: prova a scrivere proprio due righe di codice che fanno solo la gestione del interrupt e magari incrementano un contatore che visualizzi su monitor seriale ... se il problma non appare, allora sai che è da qualche altra parte nel programma, se appare ancora ... posta il piccolo codice di test che diamo un'occhiata ... ::slight_smile:

Guglielmo

void setup() {
  // put your setup code here, to run once:
  initPluviometro();
  Serial.begin(115200);
  pinMode(0,INPUT);
}
volatile int cont1;

void IRAM_ATTR pluviometroISR1() {
  noInterrupts();
  cont1++;
  interrupts();
}

void initPluviometro() {
  pinMode(13, INPUT);
  attachInterrupt(13, pluviometroISR1, FALLING);
  interrupts();
}

void loop() {
  Serial.println(cont1);
  delay(500);  
  if(!digitalRead(0)){
    cont1 =0;
  }
}

I contatori arrivano anche ad 70 volte per cambio di stato...

Ciao,
Dalle ultime prove, risulta che con il condensatore fa ancora peggio.... il contatore senza condensatore non supera 10, con il condensatore arriva anche a 80 senza problemi....
non mi spiego il perché!...

Alan

Fare l'antirimbalzo con un condensatore e' un metodo che funziona solo se l'ingresso usato e' a trigger di schmitt e con una isteresi sufficente, altrimenti il condensatore peggiora la situazione.
E' comunque un metodo che presenta una scarsa ripetibilita' a causa della tolleranza dei componenti.
Ti propongo una soluzione software che pero', non avendo un ESP32, ho testato su di una UNO.

#define DEBOUNCE_TIME 50                          // tempo di antirimbalzo in mS                  

#define WAIT_FOR_INTERRUPT 0
#define WAIT_FOR_DEBOUNCE 1

uint16_t Conta;
uint32_t StartDebounceTime;
uint8_t State;
volatile bool IntFlag = false;

//------------------------------------------------------------------------
void setup() 
{
  Serial.begin(115200);

  Conta = 0;
  State = WAIT_FOR_INTERRUPT;                        
  pinMode(2,INPUT_PULLUP); 
  attachInterrupt(digitalPinToInterrupt(2), pluviometroISR1, FALLING);
  interrupts();
}

//------------------------------------------------------------------------
void loop() 
{
  switch (State)
  {
    case WAIT_FOR_INTERRUPT:                      // stiamo aspettando un interrupt
    
      if (IntFlag)                                // e' arrivato un interrupt             
      {
        Conta++;                                  // incrementa il contatore
        Serial.println(Conta);                    // e stampalo
        StartDebounceTime = millis();             // inizializza il tempo di antirimbalzo
        IntFlag = false;                          // resetta il flag di interrupt
        State = WAIT_FOR_DEBOUNCE;                // cambia stato
      }
      break;

    case WAIT_FOR_DEBOUNCE:                       // stiamo aspettando che scada il tempo di antirimbalzo
    
      if( (millis() - StartDebounceTime) > DEBOUNCE_TIME)
      {                                           // il tempo e' scaduto
        EIFR = 0x01;                              // resetta eventuali interrupt pendenti
                                                  // perche' il core di Arduino non lo fa prima di abilitare un interrupt
                                                  // (secondo me e' un baco anche se c'e' chi sostiene che sia una scelta)
                                                  
        attachInterrupt(digitalPinToInterrupt(2), pluviometroISR1, FALLING); // riabilita l'interrupt
        State = WAIT_FOR_INTERRUPT;               // cambia stato
      }
      break;
    }
    // qui si fanno le altre cose che deve fare il programma
    // ...
    // ...
}

//------------------------------------------------------------------------
void pluviometroISR1()                            // servizio interrupt
{
  detachInterrupt(digitalPinToInterrupt(2));      // disabilita l'interrupt
  IntFlag = true;                                 // setta il flag per il main
}

Purtroppo a causa di un baco del core di Arduino (o secondo alcuni di una scelta) quando si abilita un interrupt quelli eventualmente pendenti non vengono prima resettati e quindi bisogna farlo con un accesso diretto al registro di flag.
Quindi se per caso fossi interessato ad implementare la mia soluzione devi cercare come si fa questo sull'ESP32.

Marco

Sulimarco:
Fare l'antirimbalzo con un condensatore e' un metodo che funziona solo se l'ingresso usato e' a trigger di schmitt e con una isteresi sufficente, altrimenti il condensatore peggiora la situazione.

Quello che non capisco è: come mai con il pulsante sul GPIO 0 (non credo abbia il Trigger di Schmitt) funziona senza alcun problema...?

... non so la ESP32, ma la MCU di Arduino i trigger sugli ingressi li ha ...

Sulimarco:
Fare l'antirimbalzo con un condensatore e' un metodo che funziona solo se l'ingresso usato e' a trigger di schmitt e con una isteresi sufficente, altrimenti il condensatore peggiora la situazione.
...

... questa mi giunge nuova ...

Etemenanki:
... questa mi giunge nuova ...

Beh, è abbastanza probabile ...
... se non hai un "trigger di schmitt" sull'ingresso, il condensatore tiene il pin in una situazione "indeterminata" più a lungo, tempo dato dalla curva di carica ... ::slight_smile:

Guglielmo

Se intendi i vecchi ingressi senza alcuna tolleranza sono daccordo anch'io ... ma ormai a parte le porte logiche elementari, credo non li trovi piu su alcuna MCU ... almeno, io ho sempre utilizzato i debounce RC un po dappertutto, e fin'ora problemi simili a quelli dell'OP non ne ho mai avuto nemmeno uno ...

Etemenanki:
Se intendi i vecchi ingressi senza alcuna tolleranza sono daccordo anch’io …

… si, ovviamnete intendo ingressi senza alcuna soglia … non ho idea di come siano i pin di ingresso degli ESP32, ma mi sembra strano che non abbiano un trigger in ingresso, anche perché, da datasheet:

VIH (High-level input voltage): da 0.75×VDD1 a VDD1+0.3 V
VIL (Low-level input voltage) : da –0.3 a 0.25×VDD1 V

Guglielmo

... però pare che NON lo abbiano ... interessante discussione su un problema simile a quello del OP ... QUI ... ::slight_smile:

Guglielmo

... vedo che per sicurezza molti li mettono esternamente:

  • 1 Schmitt Buffer = 74LVC1G17
  • 2 Schmitt Buffers = 74LVC2G17
  • 3 Schmitt Buffers = 74LVC3G17
  • 1.65V to 5.5V VCC, logic inputs are tolerant up to 5.5V, ESD protection
  • If you need an inverter, then change the 17 to 14.

Guglielmo

VIH (High-level input voltage): da 0.75×VDD1 a VDD1+0.3 V
VIL (Low-level input voltage) : da -0.3 a 0.25×VDD1 V

Queste non sono le specifiche di un ingresso a trigger di schmitt.
Qui si dice che da un certo valore in su viene letto sicuramente un 1 e che da un certo valore in giu’ viene letto sicuramente uno 0. Nella fascia intermedia non e’ garantito un risultato noto.
Questo e’ un ingresso normale.

Un ingresso a trigger di schmitt deve avere specificati:
VT+ Positive-Going Threshold Voltage

VT− Negative-Going Threshold Voltage

VT+ −VT− Hysteresis