se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Progetti Arduino
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

Buongiorno a tutti ho necessità di comandare due uscite partendo da un ingresso.
l'ingresso è azionato da un relè di un modulo temporizzatore che mi funge da interruttore, se attivo il timer il relè si eccita e rimane eccitato per il tempo prestabilito diseccitandosi allo scadere del tempo, ora con questo ingresso ho bisogno di comandare due uscite distinte e cioè, all'attivazione del relè del temporizzatore mi manda alto la prima uscita per 100mS per poi andare basso, allo scadere del tempo il relè si diseccita mandandomi alto la seconda uscita per 100mS per poi andare basso.
Con la porzione di sketch che posto me lo fa ma mi blocca tutto il resto dello sketch eppure le istruzioni sono chiare!!

Codice: Seleziona tutto

#define timerPin 34 //
#define ledPinTIMERON 35 //
#define ledPinTIMEROFF 36 //

void setup() {
  
  pinMode (timerPin, INPUT);
  pinMode (ledPinTIMERON, OUTPUT);
  pinMode (ledPinTIMEROFF, OUTPUT);

  digitalWrite (ledPinTIMERON, LOW);
  digitalWrite (ledPinTIMEROFF, LOW);

}

void loop() {
 
 if (digitalRead (timerPin) == HIGH) {
    digitalWrite (ledPinTIMERON, HIGH);
    digitalWrite (ledPinTIMEROFF, LOW);
    delay (100);
    digitalWrite (ledPinTIMERON, LOW);
    digitalWrite (ledPinTIMEROFF, LOW);
    while (digitalRead (timerPin) == HIGH);
    delay (100); 
  } else {
    digitalWrite (ledPinTIMEROFF, HIGH);
    digitalWrite (ledPinTIMERON, LOW);
    delay (100);
    digitalWrite (ledPinTIMEROFF, LOW);
    digitalWrite (ledPinTIMERON, LOW);
    while (digitalRead (timerPin) == LOW);
    delay (100);
  }

}
So perfettamente che la funzione delay è bloccante ma passati i 100mS si sblocca invece qua non si sblocca niente, secondo voi cosa non va?
Alessio67
Messaggi: 489
Iscritto il: lun 19 mar 2018, 14:26

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da Alessio67 »

io lo faccio con un S7 200
TheOrdinarySuperhero
Messaggi: 1032
Iscritto il: mar 2 ott 2018, 15:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da TheOrdinarySuperhero »

A te serve che il modulo funzioni quando si preme il bottone e tutto sia a off quando non è premuto?
Inoltre devi mettere alta la timeroff nella seconda parte
In metacodice sarebbe
Se bottone premuto
TimerON alto e timer OFF basso
Aspetta 100
TimerON basso timeroff ALTO (tu hai messo basso)
Finché bottone premuto
Aspetta 100

ELSE
(dunque se io bottone non è premuto)
Timer on e timer OFF bassi.

Io aggiungerei un piccolo ritardo tra gli on e gli off per essere dare il tempo al relay di attaccare e staccare
Avatar utente
pgv
Messaggi: 484
Iscritto il: gio 17 set 2020, 13:16
Località: Ginevra

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da pgv »

Domanda (pedante): ma lo sketch e' tutto li' o c'e' dell'altro in seguito?
Perche' se c'e' dell'altro codice che segue l'if/else, allora l'istruzione che blocca e' la

while (digitalRead (timerPin) == LOW);

che resta li' fino a che timerPin not riprende il valore di HIGH.
Avatar utente
Maxvarese
Messaggi: 1954
Iscritto il: mar 9 apr 2019, 23:53

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da Maxvarese »

Come si fa a postare i programmi così nel forum?
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

ovviamente non è tutto li il codice, sostanzialmente a me serve che quando timerPin è alto è rimane alto mi manda alto l'uscita ledPinTIMERON per 100mS, quando timerPin è basso è rimane basso mi manda alto ledPinTIMEROFF per 100mS. Praticamente l'ingresso timerPin viene gestito da un relè che, se attivo il temporizzatore chiude semplicemente un relè, con questo io piloto l'ingresso. In seguito avendo nel resto dello sketch due pulsanti di abilitazione e disabilitazione al posto di avere due uscite separate (ledPinTIMERON e ledPinTIMEROFF), pilotare i due pulsanti ma vorrei vederlo in seguito, adesso mi preme capire la funzione separata.
Comunque si la funzione while è bloccante perchè non ho un pulsante ma un interruttore, come faccio adesso?
Ultima modifica di RoccoCostruzioni il ven 25 set 2020, 20:10, modificato 1 volta in totale.
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

In risposta a Maxvarese basta semplicemente cliccare sul riquadro dove trovi </> e ti appare nel messaggio che stai scrivendo [ code ] [ /code ], fatto ciò ti basta inserire tra i due code il tuo codice
Avatar utente
pgv
Messaggi: 484
Iscritto il: gio 17 set 2020, 13:16
Località: Ginevra

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da pgv »

Come si fa per non bloccare? Una opzione e' di attaccarsi ad un interrupt (e NON al tram...). Fondamentalmente, si scrive una funzione che gestisce i cambiamenti di un dato pin (non si puo' fare con un pin qualsiasi, dipende dal modello di Arduino, per esempio sul Nano (che e' il mio cavallo di battaglia ogni volta che comincio un progetto, salvo derapare se le risorse sono inadeguate al compito) sono gestiti solamente i pin (digitali) 2 e 3. Il Mega e il Mega2560 gestiscono interrupt dai pin (digitali) 2, 3, 18, 19, 20, 21. I nuovi Arduino (carissimi!) anche da tutti i pin. La funzione NON la chiami tu da dentro loop(), ma la "dichiari" al sistema con la chiamata

attachInterrupt(digitalPinToInterrupt(pinCheVuoiUsare), nomeDellaFunzione, rispondiA);

dove
- digitalPinToInterrupt(pinCheVuoiUsare) e' il modo raccomandato di passare il numero del pin che vuoi usare per il segnale di ingresso;
- nomeDellaFunzione e' il nome della funzione che deve essere eseguita in risposta ad un interrupt;
- rispondiA permette di selezionare a quale tipo di "evento" deve rispondere la tua funzione, e puo' assumere i valori seguenti:
- LOW se la funzione deve essere eseguita ogniqualvolta il pin e' LOW (occhio...);
- CHANGE se la funzione deve essere eseguita ogniqualvolta il pin cambia livello, ossia se passa da LOW a HIGH o da HIGH a LOW;
- RISING se la funzione deve essere eseguita ogniqualvolta il pin passa da LOW a HIGH;
- FALLING se la funzione deve essere eseguita ogniqualvolta il pin passa da HIGH a LOW.

La chiamata a attachInterrupt restituisce un valore int che corrisponde al numero del vettore di interrupt se tutto va bene, oppure -1 se la richiesta si riferiva a un interrupt non esistente.

A questo punto sappiamo come fare perche' una certa funzione venga eseguita allorche' avviene "qualcosa" in ingresso ad un determinato pin. Ora nasce il (rognoso) problema di come fare per generare un impulso di una lunghezza precisa in risposta al nostro "evento". Chiaramente, mettere una bella sequenza

digitalWrite(pinDiUscita, HIGH);
delay(100);
digitalWrite(pinDiUscita, LOW);

purtroppo semplicemente NON funziona, perche' delay() fa affidamento su un'altra routine di interrupt e durante l'esecuzione di una le altre sono disabilitate. Se l'Arduino puo' permettersi di sprecare 100 millisecondi senza fare niente altro mentre genera i segnali, in teoria si potrebbe usare ripetutamente delayMicroseconds() con un ritardo in microsecondi inferiore a 500 (altrimenti possono succedere cose fastidiose). PERO', ed e' un grosso pero', durante questo tempo l'Arduino diventa "sordo" a mondo esterno e si perde eventuali caratteri o pacchetti in arrivo su porte seriali, WiFi o Ethernet (a meno che l'hardware non abbia dei bufferoni belli grossi). Come rimediare?

Soluzione 1. "throw money at the problem" - gettare soldi al problema, ossia aggiungere un pochino di hardware esterno che generi un impulso della lunghezza desiderata a partire dal momento in cui l'Arduino invia il comando, per esempio con un 74LS123 che ha pure due canali...(https://www.ti.com/lit/an/sdla006a/sdla006a.pdf). In questo caso, un breve impulso all'uscita fara' partire il monostabile per un tempo fissato da due componenti esterne. Ma a questo punto, a meno che per l'Arduino non sia importante sapere che cosa sta facendo o ha fatto il Timer esterno, perche' non pilotare direttamente il 74LS123 con l'uscita del Timer esterno stesso? Volendo proseguire nella stessa direzione, perche' non utilizzare addirittura un ATTINY85 come "coprocessore" per l'Arduino principale? Un pin per il segnale del Timer esterno, due pin per le uscite e altri due per comunicare all'Arduino principale lo "stato" del sistema, codificato su un massimo di 4 valori... L'ATTINY davvero eseguirebbe solo il tuo doppio loop (con in aggiunta il pilotaggio delle due uscite di comunicazione con l'Arduino master). Lo ho visto fare. Non e' elegantissima la soluzione, ma risolve.

Soluzione 2. "elbow oil" ossia olio di gomito... Niente compoenti extra, piu' lavoro, Occorre utilizzare un altro interrupt dell'Arduino, e qui ci gettiamo in un vespaio perche' gli interrupt da Timer sono delicatissimi (in quanto servono anche all'Arduino per cosucce da nulla come tenere conto del tempo o gestire le uscite pseudo-analogiche in PWM).
L'ottimo Nick Gammon ha una pagina molto completa (ma in inglese) sugli interrupt all'indirizzo http://gammon.com.au/interrupts che spiega che cosa si puo' e che cosa non si puo' fare con e in un routine di servizio di un interrupt.

Credo di aver presentato (senza entrare nel dettaglio implementativo) due opzioni possibili, di cui la prima comprende due sotto-opzioni. Se vuoi, possiamo sceglierne una ed entrare nel dettaglio.
RoccoCostruzioni
Messaggi: 51
Iscritto il: mer 9 set 2020, 21:16

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da RoccoCostruzioni »

Grazie dell'esaustiva risposta PGV, opterei per la soluzione software quindi la soluzione 2 però come tu dici ci gettiamo in un vespaio non indifferente, se è una cosa che non ti arreca danni e non ti porta via molto tempo e vorresti aiutarmi allora andiamo avanti altrimenti lasciamo stare da buon if else :lol: :lol: :lol:
Avatar utente
pgv
Messaggi: 484
Iscritto il: gio 17 set 2020, 13:16
Località: Ginevra

Re: se interruttore alto attiva un uscita altrimenti me ne attivi un'altra

Messaggio da pgv »

Cominciamo con una analisi del problema:

a.1) situazione commerciale, oggetto da vendere su larga scala quindi minimizzare il costo del prodotto finale e' importante. Se pero' introducendo una componente esterna posso ridurre i requirements sul tipo di processore, per esempio invece di un ATMEGA256 che da sito Microchip costa $8.61 (in pezzature da 5000) posso metterci un ATMEGA328PB che e' prezzato a $1.46 (sempre in pezzature da 5000) aggiungendo un ATTINY13 dal costo di $0.68 per gestire il timer esterno ho realizzato una riduzione netta di $6.47 a pezzo venduto...
a.2) prototipo singolo commerciale per dimostrare la fattibilita'. Di solito (leggi, nella mia esperienza personale, SEMPRE) il cliente vuole il primo prototipo sul tavolo ieri. I suoi commerciali probabilmente anche la settimana prima... Anche senza rispariare sui componenti anzi con un rincaro (leggero) hai buone probabilita' di produrre un prototipo piu' affidabile (una volta programmato il "coprocessore" puoi fregartene, lui continuera' a fare quel che gli hai detto di fare indipendentemente da quello che programmi nel processore principale. Non sarebbe la prima volta che "giusto una modifica estetica, cambiami le scritte (o fammi lampeggiare un LED, o che so io)" introduce cambiamenti che interagiscono negativamente con il resto del programma, e andare a caccia di un problema mentre stai gestendo interruzioni da ingressi e da timer... Per citare un film mito:

Devi fare a te stesso una domanda: "Mi sento fortunato?" Eh, pivello? [Frase originale: You've got to ask yourself one question: "Do I feel lucky?" Well, do ya, punk?]

Io ho smesso di sentirmi fortunato decenni fa...

b.1) situazione amatoriale, non te ne frega niente se costa un po' di meno tanto ne fai uno solo, per te, con quello che hai nel cassetto, e una volta che funziona lo copri di colla a caldo e lo lasci li' per sempre. In piu', grazie al COVID, sei confinato e hai tempo libero sulle mani da non sapere piu' che fare, hai consumato tre testine di lettori BlueRay e sei stufo di film, e hai voglia di imparare qualcosa di nuovo e cimentarti con un problema difficile. Interrupt! Interrupt! Ovviamente interrupt! Impari, ti distrai, ti tieni occupato e risolvi il problema in maniera elegante.
b.2) situazione amatoriale, MA (come me) sei un po' smanettone e non riesci a seguire l'Undicesimo Comandamento ("Se funziona quanto basta, non toccarlo che si guasta"). Allora ti riconduci (salvo per la nota spese che non puoi mandare all'Azienda) al caso a.2 piu' sopra. Magari senza la pressione del cliente ("E' pronto? I miei commerciali vogliono fare un breve spot da trasmettere"), ma con tutti i problemi che possono comparire andando a "ritoccare" un programma complicato.

Detto questo, io sono disponibile a condividere quel po' di esperienza (e i ricordi dolorosi) che mi sono fatto...

<== ATTENZIONE! SEGUONO AFFERMAZIONI ERETICHE. NASCONDETE DONNE, BAMBINI E BESTIAME ==>
In realta' probabilmente invece di un ATTINY per gestire gli impulsi da produrre basterebbe un PIC12F508 (BOOM! Fulmine sul blasfemo!) che e' ancora piu' cost-effective. Non dimentichiamoci che i microcontrollori sono "logica programmabile" dopo tutto. Ed ora che sono andato fuori argomento, mi stupisco (anche al lume dei video che non ci sia un canale PIC o magari "Altri Micro" nel Forum.
Rispondi