Hacer ejemplos detector cruce por cero

Hola:

Quiero hacer ejemplos sobre un circuito, detector de cruce por cero. Tengo un esquema que hice muy simple, como en Proteus 8.5 SP0 no incluye el optoacoplador H11AA1, uso el 4N25 con su diodo correspondiente.

Mirando este esquema.

Hice este esquema.

Ver zoom.

Antes que me lleguen los materiales, necesito un guía, :wink:

Mientras...

Hago pruebas de todo tipo en el Proteus, por ejemplo, hacer un circuito eléctrico mejor que se adapte a lo que busco. Cuando lo tenga, hacer pruebas de todo tipo si me detecta la entrada digital. Empezar hacer varios programas en Arduino de prueba. Tengo Arduino UNO r3 y el LCD, en shield key pad 16x2. Para ver los resultados si hace falta. :wink:

Una vez que me detecte los pulsos, por ejemplo que me muestre resultados en pantalla, o en el monitor serie si lo desean, hay que ver resultados de lo que hace la entrada.

Quiero hacer pruebas de todo tipo, pequeños y grandes. Por ejemplo:

Programa 1:
Contador de pulsos.
Solo se muestra en el monitor serie o LCD o los dos a la vez, la cantidad de pulsos que está detectando en la entrada del optoacoplador. Este ejemplo puede servir, lo adaptaré a mi manera y lo pongo aquí cuando acabe.

const int inputPin = 2;
 
int value = 0;
 
void setup() {
  Serial.begin(9600);
  pinMode(inputPin, INPUT);
}
 
void loop(){
  value = digitalRead(inputPin);  //lectura digital de pin
 
  //mandar mensaje a puerto serie en función del valor leido
  if (value == HIGH) {
      Serial.println("Encendido");
  }
  else {
      Serial.println("Apagado");
  }
  delay(1000);
}

Programa 2:
Lo que se nos ocurra. Iremos poco a poco.
Medir la frecuencia con interrupción.

// period of pulse accumulation and serial output, milliseconds
const int MainPeriod = 100;
long previousMillis = 0; // will store last time of the cycle end
 
volatile unsigned long previousMicros=0;
volatile unsigned long duration=0; // accumulates pulse width
volatile unsigned int pulsecount=0;
 
// interrupt handler
void freqCounterCallback()
{
  unsigned long currentMicros = micros();
  duration += currentMicros - previousMicros;
  previousMicros = currentMicros;
  pulsecount++;
}
 
void reportFrequency()
{
    float freq = 1e6 / float(duration) * (float)pulsecount;
    Serial.print("Frec:");
    Serial.print(freq);
    Serial.println(" Hz");
 
     // clear counters
    duration = 0;
    pulsecount = 0;
}
 
void setup()
{
  Serial.begin(19200);
  attachInterrupt(0, freqCounterCallback, RISING);
}
 
void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= MainPeriod)
  {
    previousMillis = currentMillis;   
    reportFrequency();
  }
}

Programa 3:
Al detectar los pulsos de entrada y sabiendo gracias arriba los resultados cuanto cuenta por cada cierto tiempo, pues haremos algo como esto.

int pulsos = 0;

if (pulsos => 0)
{
    // Mostrar mensaje:
    // Motor detenido.
}

if (pulsos => 200)
{
    // Motor en marcha.
}

if (pulsos =< 700)
{
    // Motor detenido.
}

if (pulsos => 1023)
{
    // Como sobre pasa el valor.
    // Motor trabajando en vacío porque
    // se rompió o se soltó la correa del
    // tambor.
    // Se detiene el motor.
}

¿Alguna sugerencia, comentarios e ideas?

Dejo claro que la entrada del optoacoplador tiene como máximo 35 Vac. Es regulable de 0Vac hasta los 35Vac.

Saludos.

Para que sirve R2 ?

Que esperas obtener en pin D2 ?

Hola:

El pin D2 obtiene los pulsos de cruce por cero.

Tengo un taco generador que en su velocidad máxima del motor, proporciona 35 Vac.

Arduino tiene que saber cuantos pulsos obtiene y mostrarlo en el LCD o serial monitor para saber cuanto pulsos me entra en esos 35 Vac, que puedo variarlo de 0Vac a 35 Vac.

Que muestre los RPM del motor, y Hz.

El R2 está a masa, que puede ir también a 5V, solo es para asegurar que está a 0V cuando en la salida del optoacoplador no hay nada, solo 0V.

Saludos.

Pon el Emisor a GND y en el Colector ademas de ir al pin 2 de Arduino a una pata de la resistencia de 10K, la otra pata la pones a +5V.

Hola:

Por lo que interpreto, te refieres justo esto.

Si es así com oindica arriba. Ahora toca programar algo que cuente los cruce por cero y Arduino los detecte y muestre.

Otro programa que muestre los Hz.

¿Hay algún problema hacerlo como indica abajo?

Saludos.

Sugerencia: reiniciar contadores que se incrementan en una ISR puede provocar condición de carrera, deberías hacerlo llamando una función como esta:

void resetCounters() {
  detachInterrupt(0);
  duration = 0;
  pulsecount = 0;
  attachInterrupt(0, freqCounterCallback, RISING);
}

Se supone que para la obtención de los valores la historia es la misma; mira que millis() también hace algo así.

Recuerda que la CPU es de 8 bits, así que incluso copiar variables de 32 bits toma al menos 4 instrucciones máquina (y en medio de alguna de ellas puede entrar la interrupción); lo cual hace estas operaciones sean "moleculares" (no "atómicas").
Dicho en otras palabras: cuando el programa principal y una interrupción intentan acceder a la misma variable al mismo tiempo, el valor resultante es indeterminado (para la lógica del código, termina siendo "incorrecto").

Para este caso puntual, dos fallos pueden ocurrir (recordando que unsigned int se compone de 2 bytes):

Al leer la variable: si antes de copiar el último byte se dispara la interrupción, y en esta ocurre un acarreo en el incremento/suma (más de un byte se tiene que modificar); el valor recuperado en ese instante podría estar por encima de lo que debería.
Por ejemplo: el contador está en 255 (0x00FF), según código se necesita recuperar el valor de dicho contador; se lee el primer byte pero luego se dispara la interrupción la cual incrementará el contador. 255 definitivamente va a causar acarreo (a nivel binario), incrementando también el segundo byte (¡el programa principal aún no lo ha leído por culpa de la interrupción!). Después de 255 sigue 256 (0x0100), entonces el programa principal al reanudarse lee el segundo byte de la variable, en cuál ahora tiene el valor de 1.
Si me sigues la idea, sabrás qué acaba de ocurrir: al copiar el primer byte antes de la interrupción (0xFF), y el segundo ya después (0x01); el valor recuperado es 0x01FF o 511. Definitivamente 511 no está después de 255, ¿o me equivoco?

Al reiniciar la variable: no es problema cuando la interrupción solo incrementa (excepto cuando un desbordamiento o cambio de signo tenía que suceder); pero cuando es una suma con otro valor que no sea 0 ni 1, podría acabar en algo diferente de cero aunque (según programa principal) debería ser cero.
De nuevo, el procesamiento sigue siendo de byte en byte, con la posibilidad de ser interrumpido "en el camino".

Para los que tienen experiencia programando para PC, es la misma problemática de la concurrencia (también conocido como programación multitarea, multihilo o paralela). Aunque la interrupción no es paralelismo verdadero, el concepto es el mismo debido a que estamos hablando de un cambio súbdito en el flujo del programa; el cuál no es deterministico (es impredecible).

La probabilidad de ocurrencia de semejante fallo es muy pequeña, pero sigue siendo posible; he ahí el detalle.

Dato curioso: si la CPU es de 8 bits, eso quiere decir que las operaciones (básicas) con variables de ese tamaño (o menor), es imposible que sean interrumpidas. Las banderas de interrupción son revisadas cada ciclo de instrucción, no en cada ciclo de reloj.

PD 1: todo lo que acabo de mencionar aplica sólo para variables globales volatile; para las que no lo son es todavía más complicado de explicar su comportamiento (a menos que se estudie el código binario resultante), ya que el compilador suele permitir que hayan copias de las más usadas en los registros de propósito general, haciendo que rara vez hayan valores actualizados en RAM. Con volatile, el compilador está obligado a que la copia en RAM siempre esté actualizada.

PD 2: si alguien pretende refutar mi sugerencia, entonces que me demuestre que el compilador siempre deshabilita (temporalmente) las interrupciones cuando se opera con 16 bits o más; aunque esto empeore el rendimiento al insertar 3 instrucciones máquina adicionales por cada operación.

Amigo lo que no puedes hacer es invertir la polaridad del transistor de salida del acoplador.

Adjunto la corrección:

Buenas:

Gracias por las explicaciones.

Aquí un esquema de como lo hace algunos.

Zoom.

¿Es necesario tantos diodos?

Saludos

Metaconta:
¿Es necesario tantos diodos?

Bueno, es eso o un "schmitt trigger" con muy baja histérisis, o un optoacoplador detector de cruces en cero.

Hola muy buenas. Buscando encontre este tema que es muy importante. Detertac el cruce por cero y con esto saber la frecuencia. De la red. Ahora lo que quisiera saber es como seria para disparar un triac y manejar la luminucidad de un foco. Por favor ayudenme.

Todos los temas son importantes, tmb lo es respetar una advertencia que te dice que el hilo tiene mas de 120 dias sin movimientos.
Aún asi has respondido para consultar algo.
Ahora lee las normas del foro y crea un hilo con esta consulta nuevamente.
Hilo cerrado.