interrupción con pin Alert del ADS1115 no funciona.

Hola, estoy haciendo un sistema de encendido automático para un generador a gasolina. Consigo encenderlo pero no que se apague. Uso un arduino uno.
Este es mi código:

//para interrupción botón:
volatile int contador = 0;
int n = contador;
long T0 = 0;

//para interrupción parada:
volatile int count = 0;
int a = count;

//Medir corriente y potencia AC
const float FACTOR = 30; //30A/1V
const float multiplier = 0.0625F;
 
uint16_t samples[NUMSAMPLES];

void setup() {
  Serial.begin(9600);
  ads.setGain(GAIN_TWO);        // ±2.048V  1 bit = 0.0625mV
  ads.begin();
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines
  lcd.backlight(); // backlight on
  
  analogReference(EXTERNAL);

  digitalWrite(rele1, HIGH);
  digitalWrite(rele2, HIGH);
  digitalWrite(rele4, HIGH);
  digitalWrite(enablePin, HIGH);

  pinMode(rele1, OUTPUT);
  pinMode(rele2, OUTPUT);
  pinMode(rele4, OUTPUT);
  pinMode(enablePin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(PinTrig, OUTPUT);
  pinMode(PinEcho, INPUT);
  pinMode(interruptPin, INPUT);

  // Activar comparador para 0.01V en canal 0
  // (Donde 13333 = 10 / 0.0625F)
  ads.startComparator_SingleEnded(0, 0); //habrá que comprobar si es necesario

  // Inicializamos el array para el control de nivel de gasolina
  for (int i = 0; i < numLecturas; i++)
  {
    lecturas[i] = 0;
  }

  //attachInterrupt(digitalPinToInterrupt(buttonPin), interruptButton, FALLING);
  enableInterrupt(buttonPin, interruptButton, FALLING);
  disableInterrupt(interruptPin);
}

void button()
{ if (n != contador)
  {
    rutinaBoton();
    n = contador ;
  }
}

void interruptButton()
{
  if (millis() > T0 + 50)
  {
    noInterrupts();
    contador++;
    T0 = millis();
    //attachInterrupt(digitalPinToInterrupt(interruptPin), interruptCount, FALLING);
    //detachInterrupt(digitalPinToInterrupt(buttonPin));
    enableInterrupt(interruptPin, interruptCount, RISING);
    disableInterrupt(buttonPin);
    interrupts();
  }
}

void rutinaBoton()
{
  step(true, 600);
  digitalWrite(rele1, LOW); // activamos rele1: CONEXION GENERADOR-CASA
  for (int z = 0; z < 3; z++)
  {
    digitalWrite(rele4, LOW); // activamos rele4: ENCENDIDO GENERADOR
    delay(3000);
    digitalWrite(rele4, HIGH); // desactivamos rele4
    delay(100);
  }
  step(false, 600);
}

//Método para el motor
void step(boolean dir, int steps) {
  digitalWrite(enablePin, LOW);
  digitalWrite(dirPin, dir);
  for (int k = 0; k < steps; k++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(800);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(800);
  }
  digitalWrite(enablePin, HIGH);
}

void parada()
{
  if (n != count)
  {
    rutinaApagadoGen;
    a = count;
  }
}

void interruptCount()
{
    noInterrupts();
    count++;
    //attachInterrupt(digitalPinToInterrupt(buttonPin), interruptButton, FALLING);
    //detachInterrupt(digitalPinToInterrupt(interruptPin));
    enableInterrupt(buttonPin, interruptButton, FALLING);
    disableInterrupt(interruptPin);
    interrupts();
}

void rutinaApagadoGen()
{
    digitalWrite(rele2, LOW); // activamos rele2 y rele3: APAGAMOS GENERADOR
    delay(100);
    digitalWrite(rele2, HIGH); // desactivamos rele2 y rele3
    digitalWrite(rele1, HIGH); // desactivamos rele1: CORTAMOS CONEXION GENERADOR-CASA
    delay(100);
}

void impresionCorriente()
{
  float currentRMS = getCorriente();
  float power = 230 * currentRMS;

  lcd.setCursor(0, 0);
  printMeasure("Amp:", currentRMS, " ");
  lcd.setCursor(10, 0);
  printMeasure("Wat:", power, "");
}

float getCorriente()
{
  float voltage;
  float corriente;
  float sum = 0;
  long tiempo = millis();
  int counter = 0;

  while (millis() - tiempo < 1000)
  {
    voltage = ads.readADC_Differential_0_1() * multiplier;
    corriente = voltage * FACTOR;
    corriente /= 1000.0;

    sum += sq(corriente);
    counter = counter + 1;
  }

  corriente = sqrt(sum / counter);
  return (corriente);
}


void printMeasure(String prefix, float value, String postfix)
{
  lcd.print(prefix);
  lcd.print(value, 3);
  lcd.print(postfix);
}

void impresionBateria()
{
  lcd.setCursor(0, 2);
  lcd.print("Bat: ");
  lcd.print(voltaje);
  lcd.print(" V. ");
  lcd.setCursor(14, 2);
  lcd.print(porcent);
  lcd.print(" %");
}

void impresionGasolina()
{
  // Solo mostramos si hemos calculado por lo menos una media
  if (primeraMedia)
  {
    float distanciaLleno = distanciaVacio - media;
    float cantidadLiquido = distanciaLleno * 5.755 / distancia55;
    int porcentaje = (int) (distanciaLleno * 139 / distanciaVacio);

    // Mostramos en la pantalla LCD

    // Cantidad de líquido
    lcd.setCursor(0, 3);
    lcd.print("Gas " + String(cantidadLiquido) + " lts");

    // Porcentaje
    lcd.setCursor(15, 3);
    lcd.print(String(porcentaje) + " %");
  }
}

void impresionTemp()
{
  uint8_t i;
  float average;
 
  // take N samples in a row, with a slight delay
  for (i=0; i< NUMSAMPLES; i++) {
   samples[i] = analogRead(THERMISTORPIN);
   delay(10);
  }
 
  // average all the samples out
  average = 0;
  for (i=0; i< NUMSAMPLES; i++) {
     average += samples[i];
  }
  average /= NUMSAMPLES;
 
  Serial.print("Average analog reading "); 
  Serial.println(average);
 
  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  Serial.print("Thermistor resistance "); 
  Serial.println(average);
 
  float steinhart;
  steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                         // convert to C
 
  Serial.print("Temperature "); 
  Serial.print(steinhart);
  Serial.println(" *C");

  lcd.setCursor(0, 1);
  lcd.print("TempGen " + String(steinhart) + " " + ((char)223) + "C");
 
  delay(1000);
}

void refrescoLCD()
{
  tAhora = millis();              // Comprobamos para refrescar el LCD
  if ( tAhora - tAntes >= tEjec)
  { // cada 10 segundos
    tAntes = tAhora; // actualizamos variables
    lcd.clear();     // Refrescamos
  }
}

// The loop function is called in an endless loop
void loop()
{
  //para ver por pantalla la lectura del ads1115.
  int16_t adc0;
  adc0 = ads.getLastConversionResults();
 // lcd.setCursor(17, 1);
  //lcd.print(adc2);
  Serial.println(adc0);

  
  
 
  button();
  gasolina();
  bateria();
  impresionCorriente();
  impresionBateria();
  impresionGasolina();
  impresionTemp();
  refrescoLCD();
  parada();
}

He tenido que recortar el código porque no entraba. espero que sea suficiente
Agradezco cualquier sugerencia.
Gracias
Xosé

Si no entra tu código, simplemente adjúntalo pero cuando supera los 9K sino debe postearse como bien has hecho.
Gracias!!! Estas en el 5% de los que lee las normas antes de postear.

Esto no se hace dentro de una interrupción,

void interruptButton()
{
  if (millis() > T0 + 50)
  {
    noInterrupts();
    contador++;
    T0 = millis();
    //attachInterrupt(digitalPinToInterrupt(interruptPin), interruptCount, FALLING);
    //detachInterrupt(digitalPinToInterrupt(buttonPin));
    enableInterrupt(interruptPin, interruptCount, RISING);
    disableInterrupt(buttonPin);
    interrupts();
  }
}

y por esa razón no puedes apagarlo.

Ademas lo que siempre digo, para que usar interrupciones para leer el estado de un interruptor? No tiene sentido vigilar con interrupciones algo tan lento como un generador que se acciona ahora y lo apagas en 1 min

Ese no es el sentido de las interrupciones.

Ahora veré como modificar tu código para mejorar esa parte.

EDITO1: veo varios errores como este

void refrescoLCD() {
  tAhora = millis();              // Comprobamos para refrescar el LCD
  if ( tAhora - tAntes >= tEjec)

donde defines el tipo de variable para tAhora? En ningún sitio. Debe ser si o si unsigned long.
Y lo mismo donde le dices a tAntes lo mismo.. ademas de que debería se static unsigned long para preservar el valor anterior.
Esa rutina de refrezco no funciona como crees y vive borrando el LCD.

Todo esto debería ser una sola rutina

 impresionCorriente();
  impresionBateria();
  impresionGasolina();
  impresionTemp();
  refrescoLCD();

muchos delay() en boton lo que totalizan 9.3 segundos en que tu código solo responde a una interrupción. Eso es mala programación desde mi punto de vista. El recurso del uso de la interrupción se justifica jsutamente por usar delay de esta forma cuando en otra parte del código usas millis() entonces decide, usas millis() o delay()?

Te mostraré como se hace solo con millis() y sin interrupciones.

EDITO2: He visto que el código tiene un gran abuso de delay() y debe rehacerse de nuevo según mi enfoque por eso te explico como reemplazar el boton SIN INTERRUPCIONES y tu ve como se comporta

en las globales

unsigned long T0;

enum TipoEstadoGenerador {
    ARRANQUE,
    PARADA      
}

TipoEstadoGenerador estadoGenerador = PARADA;

En el loop en lugar de boton()

  // esto reemplaza la interrupción
  estadoBoton = digitalRead(buttonPin);
  if (!estadoBoton && buttonPinAnt)  // falling del boton
       estadoGenerador = !estadoGenerador; // cada presion en el boton cambia el estado
  estadoBotonAnt = estadoBoton;

Tienes delay() por todos lados.
Y veo errores x todos lados. Grandes consumos de tiempo como while() captura de datos y uso de funciones que demoran mucho mas tiempo como

sum += sq(corriente);

Seguro desconoces la librería Emonlib que hace todo eso. Te aconsejo la uses y no malgastes uso del procesador como lo estas haciendo. No esta mal, funciona, pero no es eficiente.

Todos los comentarios que te hago apuntan a eso.. MAL no estan, funcionan, pero solo no son adecuados o eficientes.

Lo siento, ya pongo que tuve que cortar el código porque no entraba en el post.
En la primera parte de tu respuesta pones una parte de mi código que es mi enésima modificación...ya no se como ponerlo

Entiendo que meto mucho delay(), pero no he podido -de momento- hacerlo de otra manera.
Entiendo también la posibilidad de los diferentes estados del botón y aquí mi problema:
El botón, cuando el generador está apagado cierra un circuito a 12 V de CC, pero cuando el generador se enciende al pulsar el botón (interruptor de la luz en casa), el circuito ya tiene corriente alterna a 220 V, con lo que no puede usarse en el arduino (que yo sepa) por eso la "interrupción" de parada, que se generaría cuando por el circuito de alterna no pase corriente, a través de un SCT-013-030 y el pin Alert de un ADS1115

Yo reveería toda la programación evitando el uso de delay. Pero en algunos casos hay que hacer grandes cambios.

Tu error es este:

void interruptButton()
{
  if (millis() > T0 + 50)
  {
    noInterrupts();
    contador++;
    T0 = millis();
    //attachInterrupt(digitalPinToInterrupt(interruptPin), interruptCount, FALLING);
    //detachInterrupt(digitalPinToInterrupt(buttonPin));
    enableInterrupt(interruptPin, interruptCount, RISING);
    disableInterrupt(buttonPin);
    interrupts();
  }
}

Dentro de una interrupción no puedes habilitar una interrupción para comenzar ni desahabilitar interrupciones.
Ambas son contrasentidos.
Lo que se hace es habilitar un flag y en el loop se activa/desactiva las interrupciones.

postearé hoy solo el código que enciende y apaga el generador (esto último no consigo que se haga) y intentaré poner un dibujo para que se entienda el circuito.
gracias, surbyte

Vamos a ello:
El código

//LIBRERIAS
#include <I2C.h>
#include <LiquidCrystal_I2C.h>
#include <DRV8825.h>
#include <Stepper.h>
#include <Adafruit_ADS1015.h>
#include <EnableInterrupt.h>

//CONSTANTES
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
Adafruit_ADS1115 ads(0x48);

// defines pins numbers
const int rele1 = 11; //relé1 (conmutador AC-DC casa: activa reles Fase y Neutro de acometida de corriente)
const int rele2 = 10; //relés 2 y 3 (contacto en posición Marcha)
const int rele4 = 9; //relé 4 (encendido generador)
const int dirPin = 8; //dirección motor pasos
const int stepPin = 7; //motor pasos
const int enablePin = 6; //motor pasos
const int PinTrig = 5; //sensor distancia
const int PinEcho = 4; //sensor distancia
const int interruptPin = 3; //lectura Alerta ads1115
const int buttonPin = 2; //interruptor, enchufe,..(cierre circuito casa en DC...genera interrupción)
const int pinV = A0; //para leer voltaje batería

//para interrupción botón:
volatile int contador = 0;
int n = contador;
long T0 = 0;

//para interrupción parada:
volatile int count = 0;
int a = count;

//Medir corriente y potencia AC
const float FACTOR = 30; //30A/1V
const float multiplier = 0.0625F;

// para el refresco de pantalla
unsigned long tAntes = 0;
unsigned long tAhora = 0;
unsigned long tEjec = 10000;

void setup() {
  Serial.begin(9600);
  ads.setGain(GAIN_TWO);        // ±2.048V  1 bit = 0.0625mV
  ads.begin();
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines
  lcd.backlight(); // backlight on
  
  analogReference(EXTERNAL);

  digitalWrite(rele1, HIGH);
  digitalWrite(rele2, HIGH);
  digitalWrite(rele4, HIGH);
  digitalWrite(enablePin, HIGH);

  pinMode(rele1, OUTPUT);
  pinMode(rele2, OUTPUT);
  pinMode(rele4, OUTPUT);
  pinMode(enablePin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(PinTrig, OUTPUT);
  pinMode(PinEcho, INPUT);
  pinMode(interruptPin, INPUT);

  // Activar comparador para 0.01V en canal 0
  ads.startComparator_SingleEnded(0, 0); //¿? no se si sirve para algo

  enableInterrupt(buttonPin, interruptButton, FALLING);
  disableInterrupt(interruptPin);
}

void button()
{ if (n != contador)
  {
    rutinaBoton();
    n = contador ; 
  }
}

void interruptButton()
{
  if (millis() > T0 + 50)
  {
    contador++;
    T0 = millis();
    enableInterrupt(interruptPin, interruptCount, RISING);
    disableInterrupt(buttonPin);
  }
}

void rutinaBoton()
{
  step(true, 600);
  digitalWrite(rele1, LOW); // activamos rele1: CONEXION GENERADOR-CASA
  for (int z = 0; z < 3; z++)
  {
    digitalWrite(rele4, LOW); // activamos rele4: ENCENDIDO GENERADOR
    delay(3000);
    digitalWrite(rele4, HIGH); // desactivamos rele4
    delay(100);
  }
  step(false, 600);
}

//Método para el motor
void step(boolean dir, int steps) {
  digitalWrite(enablePin, LOW);
  digitalWrite(dirPin, dir);
  for (int k = 0; k < steps; k++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(800);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(800);
  }
  digitalWrite(enablePin, HIGH);
}

void parada()
{
  if (n != count)
  {
    rutinaApagadoGen;
    a = count;
  }
}

void interruptCount()
{
    count++;
    enableInterrupt(buttonPin, interruptButton, FALLING);
    disableInterrupt(interruptPin);
}

void rutinaApagadoGen()
{
    digitalWrite(rele2, LOW); // activamos rele2 y rele3: APAGAMOS GENERADOR
    delay(100);
    digitalWrite(rele2, HIGH); // desactivamos rele2 y rele3
    digitalWrite(rele1, HIGH); // desactivamos rele1: CORTAMOS CONEXION GENERADOR-CASA
    delay(100);
}

void impresionCorriente()
{
  float currentRMS = getCorriente();
  float power = 230 * currentRMS;

  lcd.setCursor(0, 0);
  printMeasure("Amp:", currentRMS, " ");
  lcd.setCursor(10, 0);
  printMeasure("Wat:", power, "");
}

float getCorriente()
{
  float voltage;
  float corriente;
  float sum = 0;
  long tiempo = millis();
  int counter = 0;

  while (millis() - tiempo < 1000)
  {
    voltage = ads.readADC_Differential_0_1() * multiplier;
    corriente = voltage * FACTOR;
    corriente /= 1000.0;

    sum += sq(corriente);
    counter = counter + 1;
  }

  corriente = sqrt(sum / counter);
  return (corriente);
}

void printMeasure(String prefix, float value, String postfix)
{
  lcd.print(prefix);
  lcd.print(value, 3);
  lcd.print(postfix);
}

void refrescoLCD()
{
  tAhora = millis();              // Comprobamos para refrescar el LCD
  if ( tAhora - tAntes >= tEjec)
  { // cada 10 segundos
    tAntes = tAhora; // actualizamos variables
    lcd.clear();     // Refrescamos
  }
}

// The loop function is called in an endless loop
void loop()
{
  button(); 
  impresionCorriente(); 
  refrescoLCD();
  parada();
}

adjunto un archivo con el circuito. Lo importante es que arduino y la corriente alterna no se llevan bien y para ello a la hora de apagar el generador debo leer si hay corriente en el circuito y si no hay corriente (todas las luces están apagadas) generar una interrupción con el ADS1115 en el pin 3 de arduino que active active o desactive los relés correspondiente para apagar el generador

grilo te envié las normas del foro!!
Las imágenes deben verse, no simplemente ponerlas para que alguien las descargue. Yo no las descargo hasta verlas. Asi que no se que pusiste ahi y menos te responderé.

El ADS1115 es un AD de 16 bits 8 canales y usas su salida ALERT/RDY como disparador de una interrupción, de modo que es posible que dicho comparador no este trabajando como pretendes.

La hoja de datos dice:

9.3.7 Digital Comparator (ADS1114 and ADS1115 Only)
The ADS1115 and ADS1114 feature a programmable digital comparator that can issue an alert on the
ALERT/RDY pin. The COMP_MODE bit in the Config register configures the comparator as either a traditional
comparator or a window comparator. In traditional comparator mode, the ALERT/RDY pin asserts (active low by
default) when conversion data exceeds the limit set in the high-threshold register (Hi_thresh). The comparator
then deasserts only when the conversion data falls below the limit set in the low-threshold register (Lo_thresh). In
window comparator mode, the ALERT/RDY pin asserts when the conversion data exceed the Hi_thresh register
or fall below the Lo_thresh register value

En la página 29 y 30 tienes como se programa el COMPARDOR y el valor de umbral (16 bits) prefijado.

Debes revisar mas detalladamente lo que has hecho.

Ante todo pedir perdón por no haber leído todas las normas del foro
Espero que ahora la imagen se vea.

gracias surbyte por tu rápida respuesta.
ciertamente el problema está en el Alert del ADC1115 pero a pesar de leer el dataset no he conseguido ver como hacer. releeré y veré como puedo hacer.

En mi opinión el problema está en este trozo de código:

  // Activar comparador para 0.01V en canal 0
  ads.startComparator_SingleEnded(0, 0); //¿? no se si sirve para algo

Pero no se como hacer -y he leído el datasheet detenidamente- para que de la alerta desde el canal 0, cuando no exista voltaje en la red.
El STC-013-030 debería enviar una señal al ADS1115 y este al pin3 del arduino, cuando en la red no circule corriente.

Tengo que reconocer que no tengo idea de como solucionar esto

sigo agradeciendo cualquier comentario al respecto

Bien, después de releer repetidamente la hoja de datos del ads1115 llego a la conclusión de que no consigo un cambio de estado en el pin3 cuando la corriente es 0 amp.
Eliminado el ads1115 del circuito se me planteó otro problema: para pequeñas cargas, la lectura que da el stc-013-030 se aproximadamente la misma que cuando la carga es 0. en ambos casos la lectura en de 0.3 a 0.5 Amp.
No es posible de este modo cambiar el estado de nada.
Buscando otras posibilidades encontré un post que habla de los ortoacopladores, en concreto del hcpl-3700. tendré que comprarme uno y rehacer el código.
Gracias

un post que habla de los ortoacopladores

Son OPTO acopladores.

Quieres detectar que hay o no 220VAC no? Si es asi en tutoriales o documentación hay un buen post al respecto.