Relè e interruzione

Salve, mi sto cimentando nella realizzazione di un modulo per l'automazione delle tapparelle;
Premesso che sono riuscito a pilotare un relè dando in input il tempo per cui deve essere accesso, il mio problema nasca dal fatto che se io volessi interrompere per sicurezza la salita e la discesa, non so come fare (utilizzerò un sensore pir) nel senso che una volta partito il delay, non posso più interromperlo; avete qualche suggerimento in merito? Vi ringrazio

Il delay() è modo veramente basilare per realizzare ritardi. Anch'io lo uso, ma solo quando veramente devo fermare tutto per un po', ad es. se visualizzo la versione all'accensione.

In generale, i ritardi andrebbero realizzati mediante la lettura della variabile millis(). Se memorizzi il tempo in una variabile long e di volta in volta confronti il tempo corrente con quello memorizzato puoi rilevare quando è trascorso il tempo desiderato.

Ah ok, grazie per la spiegazione! Sono veterano in c# lato web, quindi devo macinare un po' ed imparare questo pseudo c/c++.
Domani proverò a fare delle verifiche, speriamo vadano bene!
Grazie ancora

Devi studiarti come si usa la millis() prima QUI, poi QUI ed infine leggi anche QUI e QUI ... vedrai che ti sarà tutto più chiaro :wink:

Guglielmo

P.S.: Non si tratta di pseudo C/C++ ... È C/C++ e quelle di cui stai parlano sono delle semplici funzioni.

fabio7586:
Salve, mi sto cimentando nella realizzazione di un modulo per l'automazione delle tapparelle;
Premesso che sono riuscito a pilotare un relè dando in input il tempo per cui deve essere accesso, il mio problema nasca dal fatto che se io volessi interrompere per sicurezza la salita e la discesa, non so come fare (utilizzerò un sensore pir) nel senso che una volta partito il delay, non posso più interromperlo; avete qualche suggerimento in merito? Vi ringrazio

Da elettricista la prima cosa che farei sarebbe predisporre comunque un arresto di emergenza,penso basterebbe verificare la condizione di un ingresso da te scelto e fin quanto lo stesso si trova in condizione di High il programma può girare altrimenti no....

Beh... C'è sempre il pin di reset che domina su tutto... :slight_smile:

seti81:
Da elettricista la prima cosa che farei sarebbe predisporre comunque un arresto di emergenza,penso basterebbe verificare la condizione di un ingresso da te scelto e fin quanto lo stesso si trova in condizione di High il programma può girare altrimenti no....

Sisi, ma quello che sto facendo sono test di codice con led(ho comunque testato anche lampada a 220v) a cui vorrei aggiungere il sensore pir, che blocca il movimento nel caso di presenza in prossimità, ma finché non ho stabilità sul codice, non passo al test diretto, per cui sorgeva il dubbio su come fare una sorta di multitasking con arduino sempre in ascolto affinché se sopraggiungesse una qualsiasi condizione di blocco quest'ultimo si bloccasse! Ora sto studiando il comportamento di millis () e la sua implementazione!

Allora, sto solo perdendo tempo, non riesco a capire la logica dietro millis()

#include <LiquidCrystal.h>
char com;
float tempo=0.00;
float del;
float tim=1000.0;
int incomingValue;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
unsigned long tem;
unsigned long Chiusura;
int value=1;
/*-----( Declare objects )-----*/
/*-----( Declare Variables )-----*/
#define Relay_1  6  // Arduino Digital I/O pin number
#define Relay_2  7
#define Relay_3  8
#define Relay_4  9
#define interval 0 
void setup() {
  digitalWrite(Relay_1, value);
  digitalWrite(Relay_2, value);
  digitalWrite(Relay_3, value);
  digitalWrite(Relay_4, value);  
  
  
//---( THEN set pins as outputs )----  
  pinMode(Relay_1, OUTPUT);   
  pinMode(Relay_2, OUTPUT);  
  pinMode(Relay_3, OUTPUT);  
  pinMode(Relay_4, OUTPUT);    
  delay(4000); //Check that all relays are inactive at Reset
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Salve mondo!");
Serial.begin(9600); // inizializzazione seriale
}
 
void loop() {
if( Serial.available() )
{
char buffer[] = {' ',' ',' ',' ',' ',' ',' '}; // Receive up to 7 bytes

 Serial.readBytesUntil('n', buffer, 7);
incomingValue = atoi(buffer);
 Serial.println(incomingValue);
  } //controllo input da seriale

tem=millis();

if(tem-Chiusura> incomingValue && incomingValue!=0)
  {
  
    if(value==HIGH)
{
  value=LOW;
  }
    else{
      value=HIGH;
      }
    digitalWrite(Relay_1, value);

  Chiusura=millis();

    incomingValue=0;
  }

//se riceve 'H' eccita il relè

 lcd.setCursor(0, 1);  
  // stampa il numero di secondi dall'ultimo reset  
  lcd.print(millis()/1000); 
}

Premesso che c’è un po di confusione nel codice, che poi provvederò ad eliminare, qualcuno mi sa aiutare? Ho visto l’esempio dei led con millis() ma parrebbe funzionare soltanto come blink, anche aggiungendo una doppia condizione al millis();
devo imputare da seriale tot secondi (espressi in millisecondi) e si deve accendere il led che poi si spegnerà.
boh??
Chiedo scusa, non chiedo codice, ma almeno uno spunto su cui partire. Non trovo nulla anche in inglese su google…

Per un uso prolungato, la variabile per memorizzare il tempo deve essere unsigned long.
Float tempo è inutile! Già il tempo è conteggiato in millisecondi!

Così è un po’ più leggibile :slight_smile:

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

char com;
float tempo=0.00;
float del;
float tim=1000.0;
int incomingValue;

unsigned long tem;
unsigned long Chiusura;
int value=1;

#define Relay_1  6  // Arduino Digital I/O pin number
#define Relay_2  7
#define Relay_3  8
#define Relay_4  9
#define interval 0

void setup()
{
  digitalWrite(Relay_1, value);
  digitalWrite(Relay_2, value);
  digitalWrite(Relay_3, value);
  digitalWrite(Relay_4, value); 
 
 
//---( THEN set pins as outputs )---- 
  pinMode(Relay_1, OUTPUT);   
  pinMode(Relay_2, OUTPUT); 
  pinMode(Relay_3, OUTPUT); 
  pinMode(Relay_4, OUTPUT);   
  delay(4000); //Check that all relays are inactive at Reset

  lcd.begin(16, 2);
  lcd.print("Salve mondo!");   // Print a message to the LCD.

Serial.begin(9600); // inizializzazione seriale
}
 
void loop()
{
if( Serial.available() )
  {
  char buffer[] = {' ',' ',' ',' ',' ',' ',' '}; // Receive up to 7 bytes

  Serial.readBytesUntil('n', buffer, 7);
  incomingValue = atoi(buffer);
  Serial.println(incomingValue);
  } //controllo input da seriale

tem=millis();

if(tem-Chiusura> incomingValue && incomingValue!=0)
  {
  if(value==HIGH) {value=LOW;}
  else{value=HIGH;}

  digitalWrite(Relay_1, value); //se riceve 'H' eccita il relè
  Chiusura=millis();
  incomingValue=0;
  }

lcd.setCursor(0, 1); 
lcd.print(millis()/1000); // stampa il numero di secondi dall'ultimo reset
}

Questo:

if(value==HIGH) {value=LOW;}
else{value=HIGH;}

E’ semplificabile in:

value=!value

ma, se value può valere solo 0 o 1, puoi anche scrivere:

value=1-value.

Datman:
Per un uso prolungato, la variabile per memorizzare il tempo deve essere unsigned long.
Float tempo è inutile! Già il tempo è conteggiato in millisecondi!

Si, in loop non la utilizzo, stanno lì perché avevo fatto diverse prove; quella che utilizzo è tem che è unsigned long.

Devo fare questo genere di passaggio:
Se in input do 30 secondi, devo fare in modo che il relè rimanga acceso per quei secondi li senza spegnersi, e poi solo dopo spegnersi;
Non riesco a uscirne...vi prego aiutatemi

fabio7586:
Devo fare questo genere di passaggio:
Se in input do 30 secondi, devo fare in modo che il relè rimanga acceso per quei secondi li senza spegnersi, e poi solo dopo spegnersi;
Non riesco a uscirne...vi prego aiutatemi

Non so se ti può essere utile...io ho usato questo sistema per tenere eccitato un relè per un certo
tempo (in questo caso 250 ms) anche dopo aver rilasciato un pulsante, e non uso il delay.

if (!digitalRead(pin_alza) == 1) {
timer1 = millis();
digitalWrite(pin_rele1, HIGH);
}
if (millis() - timer1 >= 250) {
digitalWrite(pin_rele1, LOW);
}

Spdking:
Non so se ti può essere utile…io ho usato questo sistema per tenere eccitato un relè per un certo
tempo (in questo caso 250 ms) anche dopo aver rilasciato un pulsante, e non uso il delay.

if (!digitalRead(pin_alza) == 1) {
timer1 = millis();
digitalWrite(pin_rele1, HIGH);
}
if (millis() - timer1 >= 250) {
digitalWrite(pin_rele1, LOW);
}

Ti ringrazio, ma il mio problema è proprio quel tempo che tu hai fisso; il mio è variabile imputato da seriale; quando li inputo, il primo loop mi attiva il relé ma poi non si spegne più perché ovviamente il valore che ho imputato rimane sempre; così ho provato a fare questa operazione: valoreinput-currentvalue-lastvalue
Dove currentvalue è millis () e lastvalue è il tempo registrato nell’if; tutto ciò per azzerare la variabile; ma quella differenza mi restituisce un valore sui 4 miliardi, probabilmente per colpa di qualche cast che non ho fatto; non capisco perché, le operazioni di confronto riescono, ma eventuali operazioni matematiche di base no. Non lo so…

non puoi mettere all'interno del loop un'altra istruzione if con l'evento emergenza e con
l'istruzione di diseccitare il relè? potresti anche provare a concatenare con operatori logici.
Io ad esempio ho due relè e due pulsanti, ognuno eccita il suo relè e diseccita l'altro, anche se è
all'interno del ciclo di attesa, quindi effettivamente lo fermo quando premo l'altro pulsante (anche il mio è un sistema alza - abbassa)
poi puoi sempre modificare il tempo con una variabile

pensavo a qualcosa del genere:

void loop() {

if (!digitalRead(pin_alza) == 1) {
timer1 = millis();
digitalWrite(pin_rele1, HIGH);
}
if (millis() - timer1 >= 5000) {
digitalWrite(pin_rele1, LOW);
}
if (eventoemergenza == 1 ) {
digitalWrite(pin_rele1, LOW);
}
}

Spdking:
non puoi mettere all'interno del loop un'altra istruzione if con l'evento emergenza e con
l'istruzione di diseccitare il relè? potresti anche provare a concatenare con operatori logici.
Io ad esempio ho due relè e due pulsanti, ognuno eccita il suo relè e diseccita l'altro, anche se è
all'interno del ciclo di attesa, quindi effettivamente lo fermo quando premo l'altro pulsante (anche il mio è un sistema alza - abbassa)
poi puoi sempre modificare il tempo con una variabile

pensavo a qualcosa del genere:

void loop() {

if (!digitalRead(pin_alza) == 1) {
timer1 = millis();
digitalWrite(pin_rele1, HIGH);
}
if (millis() - timer1 >= 5000) {
digitalWrite(pin_rele1, LOW);
}
if (eventoemergenza == 1 ) {
digitalWrite(pin_rele1, LOW);
}
}

Allora ho riscritto il codice secondo come mi hai suggerito:
dopo mezza giornata di analisi del codice (porca paletta) sono giunto alla conclusione che il mio problema era ultimovalore=valoreattuale; all'interno dell'if, perchè ogni volta che entrava nell'if, aggiornava ultimo valore e quindi valoreattuel-ultimovalore, era sempre più piccolo del valore inserito;
così ho inserito ultimovalore=valoreattuale; nel serial.available così imposto un tempo statico e riesco a gestire l'accensione.

Alleluia!

Grazie a tutti!

Eccomi di nuovo qua :frowning:

il codice:

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

unsigned int ValoreLetturaSeriale = 0;
unsigned long inizio;
unsigned long lastmillis = 0;
 int count=0;
 int segnal  = 13;
 int ledGreen = 9;
int ledYellow = 10;
String lett;
int rele;
char ultimobit;
#define Relay_OFF 1
#define Relay_ON 0

#define Relay_1  6 
#define Relay_2  7
#define Relay_3  8
#define Relay_4  9
#define interval 0

void setup()
{
  digitalWrite(Relay_1, Relay_OFF);
  digitalWrite(Relay_2, Relay_OFF);
  digitalWrite(Relay_3, Relay_OFF);
  digitalWrite(Relay_4, Relay_OFF);

pinMode(ledYellow, OUTPUT);
pinMode(ledGreen, OUTPUT);
  pinMode(Relay_1, OUTPUT);
  pinMode(Relay_2, OUTPUT);
  pinMode(Relay_3, OUTPUT);
  pinMode(Relay_4, OUTPUT);
  delay(4000); 

  lcd.begin(16, 2);
  lcd.print("Salve mondo!");   

  Serial.begin(9600); 
}
void loop()
{
  
  int pirSegnal = digitalRead( segnal );
  inizio=millis();
  if (Serial.available())
  {
    char buffer[] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; // Receive up to 15 bytes

    Serial.readBytesUntil('n', buffer, 15);
    ValoreLetturaSeriale = atoi(buffer);

    


   lett=(String(buffer));
   lett.trim();
   int lunghezza=lett.length();
   ultimobit=lett.charAt(lunghezza-1);
    
    Serial.print("Valore Lettura: ");
    Serial.println(ValoreLetturaSeriale);
    ValoreLetturaSeriale=(unsigned int)ValoreLetturaSeriale;
    lastmillis=inizio;
    Serial.print("Valore rele: ");
    Serial.println(rele);
    
  } //controllo input da seriale
 ;
if (pirSegnal == LOW  ) 
    {
  digitalWrite( ledGreen, 0 );
  digitalWrite( ledYellow, 1 );

    }else
    digitalWrite( ledGreen, 1 );
  digitalWrite( ledYellow, 0 );

 if (inizio - lastmillis>= ValoreLetturaSeriale) 
 {
  if(ultimobit=='A')
  {
   digitalWrite(Relay_1, Relay_OFF);
   lcd.setCursor(0, 0);
   lcd.print("Rele 1 Spento   ");
  }
  if(ultimobit=='B')
  {
   digitalWrite(Relay_2, Relay_OFF);
   lcd.setCursor(0, 0);
   lcd.print("Rele 2 Spento   ");
  }
  if(ultimobit=='C')
  {
   digitalWrite(Relay_3, Relay_OFF);
   lcd.setCursor(0, 0);
   lcd.print("Rele 3 Spento   ");
  }
 }
 else
 {
  if(ultimobit=='A')
  {
  digitalWrite(Relay_1, Relay_ON);
  lcd.setCursor(0, 0);
  lcd.print("Rele in discesa ");
  }
  if(ultimobit=='B')
  {
  digitalWrite(Relay_2, Relay_ON);
  lcd.setCursor(0, 0);
  lcd.print("Rele in salita  ");
  }
  if(ultimobit=='C')
  {
  digitalWrite(Relay_3, Relay_ON);
  lcd.setCursor(0, 0);
  lcd.print("Rele3 acceso");
  }
 }
 if (pirSegnal == HIGH )
 {
  if(ultimobit=='A')
  {

  digitalWrite(Relay_1, Relay_OFF);

  ValoreLetturaSeriale=0;
  }
  if(ultimobit=='B')
  {
   digitalWrite(Relay_2, Relay_OFF);
  }
 }
 if (pirSegnal == LOW  ) 
    {
  digitalWrite( ledGreen, 0 );
  digitalWrite( ledYellow, 1 );

    }

 
  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000); // stampa il numero di secondi dall'ultimo reset
}

Ho attaccato le tapparelle; il modulo relè ha due alimentazioni separate, una per gli optoisolatori che è fornita da arduino, e l’altra (per i relè) da un alimentatore esterno; arduino ha l’usb per il momento (faccio uso della seriale per i valori da imputare); i problemi sono due:

l’lcd sfarfalla continuamente ed in serie all’alimentazione dei relè ho messo due led che mi indicano lo stato del sensore pir; quando il relè parte, il led perde la metà della sua luminosità (a vista);
come li risolvo questi problemi?

Vi ringrazio