Sei sulla pagina 1di 6

/*

Una linea produttiva semiautomatica è costituita da un nastro trasportatore unidirezionale, alimentato tramite un
deposito il cui sgancio automatico deve essere mantenuto per 2 secondi.
Il nastro porta una bottiglia vuota alla volta sotto una postazione di lavoro individuata da un sensore di posizione.
Due erogatori riempiono le bottiglie alternativamente di aranciata oppure di coca-cola, per un totale di 12
bottiglie diverse per confezione, ciascuna bottiglia viene riempita per 23 secondi. Alla fine del nastro un sensore
di posizione individua la bottiglia confezionata.
Quando la produzione ha completato la confezione di 12 bottiglie il ciclo si conclude, se l'operatore non
interviene entro 3 minuti con un pulsante di blocco una cicalina richiama l'attenzione dell'operatore.
Per avviare la produzione di altre 12 bottiglie l'operatore deve ripremere il tasto start.

*/

//1a -----------------------------------------------------------
#include<HMI.h>
//1b -----------------------------------------------------------
#define pinStart 3
#define pinMuto 4
/ define pinPosizione 6
#define pinFine 7
#define pinDeposito 20
#define pinNastro 21
#define pinFanta 22
#define pinCoca 23
#define pinAllarme 24
//1c -----------------------------------------------------------
unsigned long inizioSgancio; // sez 2
int memoriaDeposito;

unsigned char bottiglie; // sez 3


int memoriaFine;

int memoriaPosizione ; // sez 4


int ugelloAttivo;

unsigned long inizioRiempimento; // sez 5


unsigned int inizioCicalina; // sez 6

int memoriaErogazione; // sez 7

void setup() {

//2a -----------------------------------------------------------
Serial.begin(19200 , SERIAL_8E1);

//2b -----------------------------------------------------------
inizioSgancio = 0; // sez 2
memoriaDeposito = 0;
bottiglie = 0 ; // sez 3
memoriaFine = 0;
memoriaPosizione = 0; // sez 4
ugelloAttivo = pinCoca;
inizioRiempimento = 0; // sez 5
inizioCicalina = 0; // sez 6

memoriaErogazione = 0; // sez 7

//2c -----------------------------------------------------------
pinMode(pinStart , INPUT);
pinMode(pinMuto , INPUT);
// pinMode(pinInizio , INPUT);
pinMode(pinFine , INPUT);
pinMode(pinPosizione , INPUT);
pinMode(pinDeposito , OUTPUT);
pinMode(pinNastro , OUTPUT);
pinMode(pinFanta , OUTPUT);
pinMode(pinCoca , OUTPUT);
pinMode(pinAllarme , OUTPUT);
}

void loop() {
synch();

//3a -----------------------------------------------------------
const int start = digitalRead(pinStart);
const int posizione = digitalRead (pinPosizione);
const int fine = digitalRead(pinFine);
const int muto = digitalRead(pinMuto);
int nastro = digitalRead(pinNastro);;
int cicalina = digitalRead(pinAllarme);

//3b -----------------------------------------------------------

// gestisce la ripartenza del ciclo con lo start


if (start == 1)
bottiglie = 0;

//----------------------------- fronte generico P o N ------------------


/*
16/03/2020 DAD
bool trigger;
bool memoria;

// fronte positivo
bool fronteP = false;
if (trigger && !memoria)
fronteP = true;
memoria = trigger;

// fronte negativo
bool fronteN = false;
if (!trigger && memoria)
fronteN = true;
memoria = trigger;
*/
//----------------------------------------------------
/* sezione 2 relativo allo SGANCIO AUTOMATICO
Molti dispositivi, cioè attuatori, hanno bisogno di un'azione che si prolunga nel tempo, ad esempio un pulsante se premuto
troppo brevemente può non portare a l'aggancio del contattore.

Pattern DURATA.
Descrizione: Quando trigger diventa attivo l'azione inizia per concludersi quando è passato il tempo prestabilito:

azione = true; // preset


if (trigger)
inizio = millis(); // tempo iniziale, variabile globale
else // inizio è nullo quando il timer non è mai stato usato
if (!inizio || (millis() - inizio >= durata))
azione = 0;

Miglioramento: se il trigger viene trattenuto, il tempo di durata dell'azione è maggiore di quello stabilito, usando non il
trigger ma il suo fronte positivo, la durata dell'azione è sempre esatta.

azione = 1;
if (frontePtrigger)
inizio = millis();
else
if (!inizio || (millis() - inizio >= durata))
azione = 0;

Nel campo dei PLC o WLC si usa il temporizzatore di tipo TOF: ritardo alla disinserzione, appena abilitato attiva il proprio
bit di temporizzazione e lo disattiva quando è trascorso il tempo impostato. Questo tipo di timer richiede che trigger rimanga
attivo, altrimenti l'uscita si disattiva.

azione = 1;
if (frontePtrigger)
inizio = millis();
else
if (!trigger || !inizio || (millis() - inizio >= tempo))
azione = 0;

*/

// creazione fronte di inizio sgancio


int frontePDep = 0;
if ((start == 1 || (fine == 1 && bottiglie < 12)) && memoriaDeposito == 0)
frontePDep = 1;

memoriaDeposito = start || fine; // non è la somma, vale 1 se lo vale uno dei due
// non si è guardato il valore delle bottiglie perchè si presuppone che la macchina si è fermata

// timer 2 secondi per bottiglia

int deposito = 1; // preset


if (frontePDep == 1)
inizioSgancio = millis();
else // niente fronte
if (inizioSgancio == 0 || (millis() - inizioSgancio >= 2000))
deposito = 0;

//----------------------------------------------------
// sezione 3 relativo al CONTEGGIO DELLE BOTTIGLIE
// ad ogni passaggio per il sensore fine incrementa il conteggio
// il paradigma è quello del tornello
//
// tornello generico
// if (frontePtrigger == 1)
// numero = numero + 1;

int frontePfine = 0;
if (fine == 1 && memoriaFine == 0)
frontePfine = 1;
memoriaFine = fine;

if (frontePfine == 1)
bottiglie = bottiglie + 1;

//----------------------------------------------------
// sezione 4 relativo al RIEMPIMENTO DELLE BOTTIGLIE ISTANTANEO
// in pratica si seleziona alternativamente la bevanda senza tenere conto del tempo
// il paradigma è quello del toggle
//
// toggle generico
// if (frontePtrigger == 1)
// if (uscita == primo)
// uscita = secondo;
// else
// uscita = primo;

// fronte di arrivo nella posizione sottostante agli ugelli


int frontePposizione = 0;
if (posizione == 1 && memoriaPosizione == 0)
frontePposizione = 1;
memoriaPosizione = posizione;

if (frontePposizione == 1) // è arrivata la bottiglia sotto?


if (ugelloAttivo == pinCoca)
ugelloAttivo = pinFanta;
else
ugelloAttivo = pinCoca;

//------------------------------------------------------------
// sezione 5 relativa al RIEMPIMENTO DELLE BOTTIGLIE NON ISTANTANEO
// è lo stesso paradigma dello sgancio delle bottiglie, cioè la luce delle scale
int erogazione = 1; // preset
if (frontePposizione == 1) // ma la bottiglia è arrivata?
inizioRiempimento = millis();
else // niente fronte, cioé niente bottiglia arrivata, ma potrebbe essere già lì da prima
if (inizioRiempimento == 0 || millis() - inizioRiempimento >= 23000)
erogazione = 0;
//-----------------------------------------
/* sezione 6 relativa alla GESTIONE CICALINA

Pattern ATTESA
Descrizione: l’azione inizia non all’attivazione del trigger, ma dopo un certo tempo.

if (trigger) // variabile di ingresso


inizio = millis() // variabile globale
if (inizio && (millis() - inizio >= attesa))
azione = 1;
else
azione = 0;

Miglioramento: se il trigger viene trattenuto, il tempo di attesa è maggiore di quello stabilito, usando non il trigger ma il suo
fronte positivo, l’attesa è sempre esatta.

if (frontePtrigger)
inizio = millis()
if (inizio && (millis() - inizio >= attesa))
azione = 1;
else
azione = 0;

Variante: Quando l'azione è iniziata esiste la possibilità di interromperla.

if (frontePtrigger)
inizio = millis()
if (basta) // variabile di ingresso
inizio = 0;
if (inizio && (millis() - inizio >= attesa))
azione = 1;
else
azione = 0;

Nel campo dei PLC o WLC si usa il temporizzatore di tipo TON: ritardo all’inserzione, attiva il proprio bit dopo che è
trascorso il tempo impostato. Il trigger deve rimanere attivo sia durante l’attesa che durante l’azione.

if (frontePtrigger)
inizio = millis()
if (trigger && inizio && (millis() - inizio >= attesa))
azione = 1;
else
azione = 0;
*/

// 16/3/2020 DAD
if (frontePfine == 1 && bottiglie == 12) // trigger
inizioCicalina = millis();

if (muto == 1) // funziona sia prima che dopo l'allarme


inizioCicalina = 0;
if ((millis() - inizioCicalina >= 180000) && inizioCicalina != 0)
cicalina = 1;
else
cicalina = 0;

//------------------------------------------------
// sezione 7 relativa alla GESTIONE NASTRO
// il nastro parte per due motivi: all'inizio perché è stato
// premuto lo start, riparte alla fine di ogni riempimento,
// resta in movimento per autoritenuta, si ferma quando arriva sotto
// agli ugelli di riempimento, si ferma quando le bottiglie sono 12.
// fronte di arrivo nella posizione sottostante agli ugelli
// paradigma autoritenuta, in generale non occorrono fronti perché
// non sono coinvolte temporizzazioni, ma in particolare questa volta
// il trigger è un fronte di discesa, la fine dell'erogazione.
//
// autoritenuta generica
// if ((trigger == 1 || azione == 1) && fine == 0)
// azione = 1;
// else
// azione = 0;

// fronte di fine erogazione della bevanda


int fronteNerogazione = 0;
if (erogazione == 0)
if (memoriaErogazione == 1)
fronteNerogazione = 1;
memoriaErogazione = erogazione;

if (((start == 1 || fronteNerogazione == 1) || nastro == 1) && (frontePposizione == 0 && bottiglie < 12))


nastro = 1;
else
nastro = 0;

// 3c --------------------------------------------------------------------------------
digitalWrite(pinDeposito , deposito); // esercizio 2
digitalWrite(ugelloAttivo , erogazione); // esercizio 5
digitalWrite(pinAllarme , cicalina); // esercizio 6
digitalWrite(pinNastro , nastro); // esercizio 7
}
[/code]