Conflicto con interrupción externa biblioteca stepper con motor paso a pasoa dmega328p

no tengo experiencia con temas de micro controladores admega328p y arduino , tengo un conflicto al utilizar una biblioteca o librera stepper al usar una interrupción externa por un sensor de impacto sencillo de placa metálicas y un contrapeso, su función detener un conteo de 40 segundos durante ese tiempo la compuerta se mantiene abierta ,si es impactada por movimiento ,golpe etc la interrupción externa debe detener el conteo de 40 segundos y regresar la compuerta de cierre de emergencia a su punto de cierre y activar indicador luminoso y sonoro

el conflicto se presenta al activar la interrupción externa el motor no se mueve que da consumiendo corriente y el código se bloquea y no responde

la funciones de abrir y cerrar funcionan bien

código dela compuerta

int abrir = 6; //pin 6 del puerto D como entrada
int cerrar = 7; //pin 7 del puerto D como entrada

int apertura ; //variable del tipo entero para apertura
int cierre ; //variable del tipo entero para cierre

int impacto = 2; // pin 2 del puerto D como entrada

#include <Stepper.h> //Importamos la librería para controlar motores paso a paso
// Ponemos nombre al motor, el número de pasos y los pins de control
Stepper M1(200, 8, 9, 10, 11);

////funcion apagar todas las bobinas
void apagado() // Apaga bobinados del motor
{
digitalWrite (8, LOW);
digitalWrite (9, LOW);
digitalWrite (10, LOW);
digitalWrite (11, LOW);
}


void setup()
{

Serial.begin(9600);
pinMode(abrir, INPUT); //pin 7 declarado como entrada
pinMode(cerrar, INPUT);//pin 6 declarado como entrada
pinMode(impacto, INPUT);//pin 2 pueto D como entrada sensor de impacto censillo
attachInterrupt(digitalPinToInterrupt(impacto), c_emergencia, FALLING); //interrupcion externa por impacto o movimiento para cierre
// Velocidad del motor en RPM
M1.setSpeed(120);
M1.step(120);
delay(500);
apagado();//funcion apagar todas las bobinas
}

void loop()
{

apertura = digitalRead (abrir);

if (apertura == LOW)//pregunta si el pin6 por D tiene un pulso bajo 0V
{
M1.step(-120); //movimiento del motor para abrir la compuerta
apagado();//funcion apagar todas las bobinas
delay(40000);//tiempo que debe permanecer abierta la compuerta
M1.step(120); //cierra la compuerta
apagado();
}

cierre = digitalRead(cerrar);



if (cierre == LOW)//pregunta si el pin7 por D tiene un pulso bajo 0V
{
M1.step(120);//movimiento del motor para cerrar la compuerta
apagado();//funcion apagar todas las bobinas
}
}


void c_emergencia()//interrupion externa pin 2 por D para cerrado de mergencia de la compuerta
{

M1.step(120);//ocaciona el conflicto al resibir la interrupcion externa del pin2 por D
apagado();//funcion apagar todas las bobinas
}

encontré lo que podría ser posiblemente una solución en el código, respondió ala interrupción sin bloquearse,
me quedo un un tiempo de unos 37 segundos variando a cual no responde el código después de cerrar la compuerta por impacto o movimiento ,acción echa por el sensor de impacto no e podido encontrar el porque se demora esos 37 segundos aproximadamente varia
esto fue la modificación que le ice al entrar ala interrupción.

quiero aclarar algo que se me olvido en el momento de la publicación.
al dársele la orden ala compuerta para que habrá se inicia un delay de 40 segundos en el momento de la interrupción por impacto o movimiento interrumpe el conteo cierra la compuerta , regresa al código y continua contando la variación de pende del instante de la interrupción que lleve contando delos 40 segundos

void c_emergencia1()//interrupion externa pin 2 por D para cerrado de mergencia de la compuerta
{
  sei(); // activa las interrupciones
  M1.step(120);//cierra la compuerta  interrupción externa del pin2 por D
  apagado();//función apagar todas las bobinas
  cli(); // desactiva las interrupciones globales
}

El problema de fondo es que utilizas delay() para controlar el tiempo que la compuerta debe estar abierta (40 segundos). Recuerda que delay() bloquea la ejecución de todo lo demás. Es una función muy útil, pero no es para esto.

En tu programa le estás dando la vuelta a ese bloqueo haciendo el trabajo de mover la compuerta dentro de la rutina de interrupción, y este no es el uso adecuado de las interrupciones.

Una rutina de interrupción debe tener una ejecución sumamente breve, y usualmente se usa para cambiar los valores de unas cuantas variables.

Por ejemplo, la interrupción puede modificar una bandera que indique que la compuerta debe cerrarse de emergencia. Esto se detecta en el loop(), que se ejecuta con gran rapidez cuando no usamos delay().

Lo que te conviene hacer aquí es usar millis() para controlar el tiempo de apertura, y estar monitoreando la bandera para activar de inmediato el cierre de la compuerta.

Para empezar, ayúdanos a sacar adelante tu proyecto publicando un diagrama de las conexiones que tienes, para no estar haciendo suposiciones que luego no eran correctas. Puedes hacer un dibujo a mano y publicar una foto.

Y échale un vistazo al ejemplo de "BlinkWithoutDelay" para familiarizarte con el uso de millis() como temporizador de eventos.

1 Like

dado al pedido de mancera1979 de que le subiera una imagen de las conexiones, monte todo en proteus anexo la simulación, el código actual el hex para la simulación.
el simulador no hace girar el motor bien, en el circuito físico el motor gira bien
Compuerta.zip (308,0 KB)
la imagen no se como colocarla en el foro, le pido a un moderador en caso que la imagen quede mal si me puede ayudar a corregirla

A ver si este código funciona. He eliminado todos los llamados a delay() salvo el del setup que no afecta.

int abrir = 6; // pin 6 del puerto D como entrada
int cerrar = 7; // pin 7 del puerto D como entrada
int impacto = 2; // pin 2 del puerto D como entrada

#include <Stepper.h> // Importamos la librería para controlar motores paso a paso
// Ponemos nombre al motor, el número de pasos y los pins de control
Stepper M1(200, 8, 9, 10, 11);

volatile bool emergencia = false; // Variable de bandera para la interrupción

// Función apagar todas las bobinas
void apagado() {
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
}

void setup() {
  Serial.begin(9600);
  pinMode(abrir, INPUT); // Pin 7 declarado como entrada
  pinMode(cerrar, INPUT); // Pin 6 declarado como entrada
  pinMode(impacto, INPUT); // Pin 2 puerto D como entrada sensor de impacto sencillo
  attachInterrupt(digitalPinToInterrupt(impacto), c_emergencia, FALLING); // Interrupción externa por impacto o movimiento para cierre
  // Velocidad del motor en RPM
  M1.setSpeed(120);
  M1.step(120);
  delay(500);
  apagado(); // Función apagar todas las bobinas
}

void loop() {
  static unsigned long startMillis = 0;
  static bool contando = false;

  if (emergencia) {
    M1.step(120);     // Mover motor para cerrar la compuerta
    apagado();          // apagar todas las bobinas
    emergencia = false; // Resetear la bandera de emergencia
  }

  int apertura = digitalRead(abrir);
  if (apertura == LOW && !contando) { // Pregunta si el pin6 por D tiene un pulso bajo 0V
    M1.step(-120); // Movimiento del motor para abrir la compuerta
    apagado(); // Función apagar todas las bobinas
    startMillis = millis(); // Guardar el tiempo de inicio
    contando = true; // Empezar el conteo
  }

  if (contando && (millis() - startMillis >= 40000)) { // Si han pasado 40 segundos
    M1.step(120); // Cierra la compuerta
    apagado(); // Función apagar todas las bobinas
    contando = false; // Resetear el conteo
  }

  int cierre = digitalRead(cerrar);
  if (cierre == LOW) { // Pregunta si el pin7 por D tiene un pulso bajo 0V
    M1.step(120); // Movimiento del motor para cerrar la compuerta
    apagado(); // Función apagar todas las bobinas
  }
}

void c_emergencia() { // Interrupción externa pin 2 por D para cierre de emergencia de la compuerta
  emergencia = true; // Establecer la bandera de emergencia
}

Observa que la rutina de interrupción ahora solo maneja un flag y ese flag corre y activa o no lo que deba en el loop(). La rutina de interrupción entonces trabaja como debe ser, rápida y veloz.

Si hay emergencia o sea si se pone en HIGH (activada la interrupción)
se ejecuta en el loop esto

  if (emergencia) {
    M1.step(120);     // Mover motor para cerrar la compuerta
    apagado();          // apagar todas las bobinas
    emergencia = false; // Resetear la bandera de emergencia
  }

cerramos compuerta, apagamos motor y ponemos en false el flag de nuevo. Listo.
Si hay apertura, entonces activamos contando, disparamos millis() a través de startMillis (la diferencia es la cuenta en segundos transcurridos) y al final lo mismo..cerramos puerta y apagamos motor.

1 Like

Gracias por tomarse el tiempo y con la colaboración.
copie el código que subió lo cargue al arduino , a ensayarlo al accionar cierre de emergencia sigue corriendo el tiempo restante delos 40 segundos antes de dejar hacer otra función.
se podrá detener el conteo de los 40 segundos al accionar cierre de emergencia para que el código siga avanzando después del cierre de emergencia.
otra de talle del código una ves que se accione el cierre de emergencia se tiene que acciona un modulo de doble rele se acciona con 0V (LOW) ,utilizo los pines 12 y 13 para accionar los reles uno para buzzer y el otro para foco o bombillo (con fin de indicador luminoso y audible)
podría hacerme el favor de colaborarme con esas modificaciones

Agrega

contando = false;

al primer if para regresar al estado original.

En cuanto tal encendido del LED y el buzzer,

  1. Se activan cuando hay un paro de emergencia
  2. ¿Cuándo se desactivan?
1 Like

Gracias con la modificación que colocaste ,al recibir el impacto o movimiento cierra la compuerta, borra el conteo y el código sigue respondiendo sin de mora alguna

Dado a que no me explique bien al colocarlo en el primer if por lo novato que soy no me percate en el momento, el conteo de la compuerta de 40 segundos se suspendió, asiendo prueba y error termine colocándolo en el ultimo if.

void c_emergencia() // Interrupción externa pin 2 por D para cierre de emergencia de la compuerta
{
  emergencia = true; // Establecer la bandera de emergencia
  contando = false; // Resetear el conteo
  Serial.println("cierre de emergencia");
 }

funciona todo gracias
ahora sigo con el modulo doble de rele

Moderador:
Por favor, lee las Normas del foro y edita tu código/error usando etiquetas de código.
Ve a edición, luego selecciona todo el código que has publicado, lo cortas y click en (<CODE/>)


No debes usar el puerto serie dentro de una rutina de servicio de interrupción.

eso los use para revisar la rutina si estaba ejecutando ya que tenia un problema y no lo encontraba.
se le agradece la observación

Moderador:
Te pedí que editaras y pasaste de largo la advertencia.
Lee el privado que te envié y por favor.

los códigos que subí los selecciono y le doy al botón
cual es que dices no se si es que no tomo el formato de code

lo busque el código que mencionas, ese código le había como 3 veces al botón code .

lo que note es que escribí if para hacer referencia, será ese mensaje que esta dando dificultades, lo edite borre todo lo que había colocado el botón code lo seleccione todo y le di al botón code de nuevo y le dio formato a todo lo que escribí , toca hacer con todo lo mismo creía que solo tenia que seleccionar el código y darle al botón de code

Hoy se concluyo el proyecto de la compuerta quería subir un video del funcionamiento, el servidor no lo permitió por el tamaño de 17mb solo permitía 8mb.


Les agradezco a todos los que me colaboraron que comparten sus conocimientos ,con los que apenas estamos profundizando con el micro controlador Admega328p y la tarjeta de desarrollo Arduino .
Gracias a todos

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.