Richiesta di aiuto di un novellino

Salve,
Questo è il mio primo post dopo la presentazione e volevo chiedere ad una buon anima se mi può dare una mano; sto realizzando una gattaiola ( porticina per cani ) motorizzata, come servo motore utilizzo un servo meccanico (utilizzante dei relè), l’apertura o chiusura della basculante viene decisa in base al resoconto di due sensori HC-R04 ( sensori di distanza ad ultrasuoni ).
Il problema in cui incorro, testando il programma sul “campo”, è che arrivati alla prima lettura del primo sensore arduino (UNO Rev 3) da il comando di movimento del motore, ma al posto di passare alla domanda successiva entra in loop il codice dentro il primo if.
Lascio di seguito il codice.
Spero che il codice sia abbastanza chiaro.

porticina.ino (3.51 KB)

Secondo me il tuo problema principale sono i delay, anche se non ho capito benissimo cosa vuoi fare precisamente (flow chart)

Salve io devo fare in modo che la "porticina" si apra quando un entità fisica (in questo caso il mio animale domestico) passi davanti al primo sensore e si richiuda dopo che sia passata davanti al secondo sensore e vice versa, in che modo sarebbe sbagliato il posizionamento dei delay?

Non è sbagliato il posizionamento del delay, è proprio sbagliato optare per il delay per questa applicazione :wink: Dovresti cercare di sostituirlo con millis() e quindi implementare nel tuo codice la funzione nel modo opportuno per ottenere quello che vuoi.
Puoi trovare tantissimi esempi in rete di come si applica quella funzione, magari dacci un'occhiata e scrivi se qualcosa non ti è chiara!
Ciao!

P.S. Ti spiego brevemente il motivo per cui delay non va bene: la funzione delay blocca il codice in quel punto eseguendo il tempo indicato da te tra le parentesi in ms, stando fermo praticamente. In poche parole usando millis questo non avviene, perché millis non blocca il programma, ma è semplicemente uno scorrere del tempo, che usandolo nella maniera che vuoi, con varie variabili, fai in modo che il programma scorra lo stesso fino al verificarsi di un evento e non che si blocchi come avviene nel tuo caso. Insomma dal playground: usare delay è come se per riscaldare la pizza, aspetti che so 5 minuti fermo lì ad aspettare che si scaldi e senza poter fare nient'altro, mentre invece con millis, mentre la pizza si riscalda puoi fare molte altre cose :slight_smile: Ricordati che Arduino non ha la potenza di calcolo necessaria per essere un multitasking come il tuo PC! millis() non è fare più cose contemporaneamente, ma fare altre cose mentre si aspetta e con delay questo non è possibile!

As_Needed ha ragione. Mi sono imbattuto nel tuo stesso problema tempo fa.
Questo l’ho preso dal mio vecchio codice il quale non è altro che un adattamento a cosa trovai su google.
Gestisce un sensore , ma secondo me puoi aggiungerne un altro sfruttando lo stesso principio
http://playground.arduino.cc/Main/PinChangeInterrupt
Ho commentato il più possibile , dovrebbe essere chiaro :slight_smile:

#include <TimerOne.h>

/*
 * genera un trig ogni 100ms e calcola la distanza
 * la lettura dell'echo avviene attraverso l'individuazione di un fronte di salita e discesa ( interrupt on change Pin 2)
 */
#define TRIGGER_PIN 9        //  PIN per il trigger
#define ECHO_PIN 2           //  PIN 2 per l'echo
#define TIMER_US 100000      // 100000us = 100ms - Determina ogni quanto tempo deve leggere e convertire in cm
#define Echo_interrupt_INT 0 // INTERRUPT 0 = DIGITAL PIN 2 
#define Echo_interrupt_Pin 2 // Serve per determinare se il change è sul fronte di discesa o salita


int trig = TRIGGER_PIN;
int echo = ECHO_PIN; 

volatile int sensore1 = 0 ; 
volatile unsigned long Conta_us = 0; 
volatile boolean Edge = false; // Determina l'inizio o la fine dell'impulso di lettura (echo). Ovvero fronte di salita(true) o discesa(false) di un'onda quadra 

void setup() {
Serial.begin(9600); 
Serial.println(" Hello " );

pinMode(trig,OUTPUT);
pinMode(echo,INPUT);

Timer1.initialize(TIMER_US);          
Timer1.attachInterrupt( timerIsr );   
attachInterrupt(Echo_interrupt_INT,misura,CHANGE);   // Genera un interrupt su ogni cambiamento di stato del Pin ( interrupt on change)
}
 
void loop() {

}

/*
 * Ogni 100ms pinga
 */
void timerIsr()
{
if(Edge)  // ok abbiamo una nuova onda, ricaviamo quindi la distanza in cm
 {
   sensore1 =  sensore1/58.0; // conversione in cm
   Serial.println(sensore1);
   Edge = false;      // calcolo terminato , attendiamo un altro 'echo'
 }
                digitalWrite(trig,HIGH);  // e lo richiediamo con un 'trig' (ping)
                delayMicroseconds(10);   // minimo 10us  
                digitalWrite(trig,LOW);
}    
void misura()  // misura la lunghezza del'echo/onda quadra
{
  // 
  if(digitalRead(Echo_interrupt_Pin) == HIGH) // abbiamo un'onda quadra dal Pin echo del sensore !
  {
    Conta_us = micros();  //  prende nota del conteggio attuale
  }
  else
  {
    if(Conta_us && (Edge == false))  // l'onda quadra termina
    {
      sensore1 = (int)(micros() - Conta_us); // quindi ricava per differenza rispetto al valore precedente la lunghezza dell'onda quadra in us
      Conta_us = 0;                          // azzera in attesa di un nuovo conteggio
      Edge = true; // rende falsa ( non false! ) questa 'if' finchè in TimerIsr non ha terminato di convertire la distanza in cm
    }
  }
}

ho letto ora che usi la libreria del servo quindi credo anche il timer1.
provo a modificarlo pe run altro timer

Edit:
Usa la libreria MsTimer2 per il Timer2, quindi dovresti poter usare anche il servo

#include <MsTimer2.h>

/*
 * genera un trig ogni 100ms e calcola la distanza
 * la lettura dell'echo avviene attraverso l'individuazione di un fronte di salita e discesa ( interrupt on change Pin 2)
 */
#define TRIGGER_PIN 9        //  PIN per il trigger
#define ECHO_PIN 2           //  PIN 2 per l'echo
#define TIMER_US 100000      // 100000us = 100ms - Determina ogni quanto tempo deve leggere e convertire in cm
#define Echo_interrupt_INT 0 // INTERRUPT 0 = DIGITAL PIN 2 
#define Echo_interrupt_Pin 2 // Serve per determinare se il change è sul fronte di discesa o salita


int trig = TRIGGER_PIN;
int echo = ECHO_PIN; 

volatile int sensore1 = 0 ; 
volatile unsigned long Conta_us = 0; 
volatile boolean Edge = false; // Determina l'inizio o la fine dell'impulso di lettura (echo). Ovvero fronte di salita(true) o discesa(false) di un'onda quadra 

void setup() {
Serial.begin(9600); 
Serial.println(" Hello " );

pinMode(trig,OUTPUT);
pinMode(echo,INPUT);

MsTimer2::set(100, timerIsr); // 100ms 
MsTimer2::start(); 
attachInterrupt(Echo_interrupt_INT,misura,CHANGE);   // Genera un interrupt su ogni cambiamento di stato del Pin ( interrupt on change)
}
 
void loop() {

}

/*
 * Ogni 100ms pinga
 */
void timerIsr()
{
if(Edge)  // ok abbiamo una nuova onda, ricaviamo quindi la distanza in cm
 {
   sensore1 =  sensore1/58.0; // conversione in cm
   Serial.println(sensore1);
   Edge = false;      // calcolo terminato , attendiamo un altro 'echo'
 }
                digitalWrite(trig,HIGH);  // e lo richiediamo con un 'trig' (ping)
                delayMicroseconds(10);   // minimo 10us  
                digitalWrite(trig,LOW);
}    
void misura()  // misura la lunghezza del'echo/onda quadra
{
  // 
  if(digitalRead(Echo_interrupt_Pin) == HIGH) // abbiamo un'onda quadra dal Pin echo del sensore !
  {
    Conta_us = micros();  //  prende nota del conteggio attuale
  }
  else
  {
    if(Conta_us && (Edge == false))  // l'onda quadra termina
    {
      sensore1 = (int)(micros() - Conta_us); // quindi ricava per differenza rispetto al valore precedente la lunghezza dell'onda quadra in us
      Conta_us = 0;                          // azzera in attesa di un nuovo conteggio
      Edge = true; // rende falsa ( non false! ) questa 'if' finchè in TimerIsr non ha terminato di convertire la distanza in cm
    }
  }
}