Arduino ESP32 y su sistema de interrupciones.

@cosmefulanito04 : he probado por polling y va perfecto, ni rebotes ni filtros ni falsos nada. Cuenta 100, alguna vez 101 y alguna 99 pero una de cada bastantes. Va mejor que el mejor filtrado de las interrupciones.

Supongo que si waitTime tiene un valor bajo, digamos 1, podría darse que al llegar al estado SET_LOW_TRC_STATE, el DPC_PIN siga en alto y generes un falso disparo. Se podría agregar un estado más que verifique que el DPC_PIN vuelva al estado bajo, pero esto puede traer problemas si el waitTime es grande, digamos que 99/100. Probaría con esto:

C:
...
#define IDLE_STATE                            0
#define DPC_FIRST_CHECK_STATE                1
#define SET_HIGH_TRC_STATE                    2
#define SET_LOW_TRC_STATE                    3
#define WAIT_STATE                            4
 
#define DPC_PIN DO
#define TRC_PIN D1

#define MAX_WAIT_TIME                        50

void timer(){
 
    switch(stateVar)
    {
        case DPC_FIRST_CHECK_STATE:
            if(digitalRead(D0) > 0)
            {
                // First check pass after 100uS later
                stateVar = SET_HIGH_TRC_STATE;
            }
            else
            {
                // Bounce or noise
                stateVar = IDLE_STATE;
                FlexiTimer2::stop();
            }
            break;

        case SET_HIGH_TRC_STATE:
            if(digitalRead(DPC_PIN) > 0)
            {
                // Second check pass after 200uS later
                stateVar = SET_LOW_TRC_STATE;
            
                digitalWrite(TRC_PIN, HIGH);
                FlexiTimer2::stop();
                FlexiTimer2::set(waitTime, 1.0/10000, timer); // Set waitTime*100uS "tick"
                FlexiTimer2::start();
            }
            else
            {
                // Bounce or noise
                stateVar = IDLE_STATE;
                FlexiTimer2::stop();
            }
            break;

        case SET_LOW_TRC_STATE:
            // Clear TRC PIN  after waitTime*100uS later
            stateVar = WAIT_STATE;
        
            digitalWrite(TRC_PIN, LOW);
            FlexiTimer2::stop();
            FlexiTimer2::set(1, 1.0/10000, timer); // Set 100uS "tick"
            FlexiTimer2::start();
            break;

        case WAIT_STATE:
            if((waitTime > MAX_WAIT_TIME) || (digitalRead(DPC_PIN) < 1))
            {
                stateVar = IDLE_STATE;
                FlexiTimer2::stop();
            }
            break;

        default:
            // Wrong state!
            stateVar = IDLE_STATE;
            FlexiTimer2::stop();
    }
}
...

Con MAX_WAIT_TIME, se define que si waitTime es menor (o igual) a 5mS (50), se habilite la espera en el estado "WAIT_STATE" hasta que el puerto DPC_PIN vuelva a 0. Si waitTime tiene un valor alto (más de 5mS), ya no hay necesidad de esperar que el puerto DPC_PIN vuelva a 0.

De todas formas habría que ver que pasa cuando waitTime sea 100 o cercano (10mS), si se pierde un pulso o no. Para evitar eso, se podría quitar el doble chequeo inicial "DPC_FIRST_CHECK_STATE", pasando directamente del estado "IDLE_STATE" al estado "SET_HIGH_TRC_STATE" y reducir la escala waitTime hasta 98 o 99.
 
Última edición:
Acá les dejo el código fuente de gestión de los GPIO. Tiene las funciones mapeadas a los nombres que usa Arduino, pero internamente son bastante mas complicadas aunque el código se entiende fácil. Esto es de la ultima versión de Espressif que está en git-hub.

@Scooter , que versión tenés instalada (en el IDE Arduino) de la biblioteca de los ESP32 ?? Por que me resulta extremadamente rebuscado meter una máquina de estados mas un timer para zafar de interrupciones repetidas. Me inclino mas por algún problema con versiones de software o compatibilidad de micros, pero no por un hardware fallado de fábrica...
 

Adjuntos

  • fuentes.zip
    4.1 KB · Visitas: 4
Para el caso el mismo efecto tiene.
Si expressive hace mal el hardware o el software el caso es que funciona mal.

Al final lo voy a dejar así que parece el justiprecio a este follón:
C:
/*
Esp32 detección de paso por cero
*/

#define entrada D0
#define salida D2

static unsigned long hora=0;
static unsigned int ISRs=0;
static int pCero = 0;    //Cuenta de pasos por cero

void IRAM_ATTR interr(){
disableInterrupt(entrada);
 if (micros()-hora>70){
    digitalWrite(salida,HIGH);
    pCero++;
    digitalWrite(salida,LOW);
    hora = micros();
  }
ISRs++;
enableInterrupt(entrada);

}

void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Detección de paso por cero");
pinMode(entrada,INPUT_PULLUP);
pinMode(salida,OUTPUT);
attachInterrupt(D0,interr,RISING);    // En el ESP32 hagas lo que hagas solo va HIGH

}

void loop() {
  // put your main code here, to run repeatedly:
Serial.print("Pasos por cero :   ");
Serial.print(pCero);
pCero = 0;
Serial.print("     ISRs realizadas =");
Serial.println(ISRs);
ISRs=0;
delay(1000);
}

Esto está dando este resultado que sin ser una joya es aceptable:
Código:
Detección de paso por cero
Pasos por cero :   0     ISRs realizadas =0     <<<Aquí está sin enchufar a la red
Pasos por cero :   0     ISRs realizadas =0
Pasos por cero :   0     ISRs realizadas =0
Pasos por cero :   0     ISRs realizadas =0
Pasos por cero :   0     ISRs realizadas =0
Pasos por cero :   193     ISRs realizadas =239  <<<Se enchufa en este momento; chisporroteos
Pasos por cero :   202     ISRs realizadas =207  <<< Tiene que dar 200 porque lee los pulsos de subida y bajada
Pasos por cero :   200     ISRs realizadas =211
Pasos por cero :   200     ISRs realizadas =206
Pasos por cero :   200     ISRs realizadas =214
Pasos por cero :   202     ISRs realizadas =205
Pasos por cero :   200     ISRs realizadas =206
Pasos por cero :   202     ISRs realizadas =206
Pasos por cero :   200     ISRs realizadas =208
Pasos por cero :   200     ISRs realizadas =205
Pasos por cero :   200     ISRs realizadas =207
Pasos por cero :   202     ISRs realizadas =211
Pasos por cero :   200     ISRs realizadas =204
Pasos por cero :   201     ISRs realizadas =207
Pasos por cero :   201     ISRs realizadas =207
Pasos por cero :   200     ISRs realizadas =204
Pasos por cero :   200     ISRs realizadas =209
Pasos por cero :   202     ISRs realizadas =208
Pasos por cero :   200     ISRs realizadas =205
Pasos por cero :   200     ISRs realizadas =211

Para obtener 200 se hacen 206~211 interrupciones que no es una exageración.
201 o 202 puede ser válido porque en 1s entran 100 ciclos pero podría coincidir 101 transiciones, podría ser que el bucle tarde un poco mas de 1000ms, no me parece fantástico pero si aceptable.

Sin el enable y disable interrupt saca como 3000 ISRs realizadas
 
Sin el enable y disable interrupt saca como 3000 ISRs realizadas
Si, eso se vé en el código fuente que subí. En ninguna parte toca un registro de interrupciones ni las deshabilita...
El alguna parte del datasheet del C3 dice que se puede activar una especie filtrado por hardware para eliminar pulsos parásitos en la línea de entrada y sincronizarla con el reloj del micro....cosa raaaara....
 
Scooter, solo por asegurar: has probado a que las variables de la interrupción sean volátiles?
Me acabé liando y las declaré static en lugar de volatile. Las he puesto volátiles pero es indiferente el resultado.
Te confirmo que el resultado es el mismo:
C:
/*
Esp32 detección de paso por cero
*/

#define entrada D0
#define salida D2

volatile unsigned long hora=0;
volatile unsigned int ISRs=0;
volatile unsigned int pCero = 0;    //Cuenta de pasos por cero

void IRAM_ATTR interr(){
disableInterrupt(entrada);
 if (micros()-hora>70){
    digitalWrite(salida,HIGH);
    pCero++;
    digitalWrite(salida,LOW);
    hora = micros();
  }
ISRs++;
enableInterrupt(entrada);
}

void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Detección de paso por cero");
pinMode(entrada,INPUT_PULLUP);
pinMode(salida,OUTPUT);
attachInterrupt(D0,interr,RISING);    // En el ESP32 hagas lo que hagas va CHANGE
}

void loop() {
  // put your main code here, to run repeatedly:
Serial.print("Pasos por cero :   ");
Serial.print(pCero);
pCero = 0;
Serial.print("     ISRs realizadas =");
Serial.println(ISRs);
ISRs=0;
delay(1000);
}
Resultado:
Código:
Pasos por cero :   202     ISRs realizadas =205
Pasos por cero :   200     ISRs realizadas =214
Pasos por cero :   200     ISRs realizadas =205
Pasos por cero :   200     ISRs realizadas =201
Pasos por cero :   202     ISRs realizadas =220
Pasos por cero :   200     ISRs realizadas =200
Pasos por cero :   200     ISRs realizadas =206
Pasos por cero :   200     ISRs realizadas =206
Pasos por cero :   202     ISRs realizadas =211
Pasos por cero :   200     ISRs realizadas =201
Pasos por cero :   202     ISRs realizadas =209
Pasos por cero :   200     ISRs realizadas =205
Pasos por cero :   200     ISRs realizadas =201
Pasos por cero :   200     ISRs realizadas =209
Pasos por cero :   202     ISRs realizadas =209
Pasos por cero :   200     ISRs realizadas =206
Pasos por cero :   200     ISRs realizadas =203

No obstante las dejo volatile que es "como debería de ser". Static en variables globales no tiene mucho sentido.
 
Última edición:
Con el esquema del primer post un PC814 y una resistencia de 150k.
Lo tengo montado en varias placas y en varias "posturas", en todas hace lo mismo.

He actualizado el código del dimmer en el hilo del dimmer.
Al final he añadido unos matices mas.
Funciona razonablemente , aunque no fino del todo en ángulos de disparo muy grandes, probablemente necesite mas anchura de pulso de disparo pero no he querido hacerlo muy grande.
 
Atrás
Arriba