In Italiano: Sistemi Automatici (Parte 1)

ASTRATTO: Gli appunti di seguito riportati traggono origine dalle lezioni tenute dall’autore, raccolte da un volume pubblicato negli anni 90, insieme agli altri due che completavano il corso di “SISTEMI e AUTOMAZIONE per ITI MECCANICI” Purtroppo il volume era datato: veniva trattato estesamente il sistema operativo MS DOS, sviluppato il programma TURBO-PASCAL ecc. Tolte le parti che non interessano più, ed effettuati alcuni ritocchi, il “tipo” di cui sopra l’autore ha deciso di aggiungere gli appunti così modificati a quelli del suo sito. La parte di elettrotecnica generale non è datata e quindi può essere utilizzata.

Introduzione

Obiettivi

  1. Far sì che le macchine possano svolgere in autonomia lavori ripetitivi;
  2. Sviluppare macchine che possano compiere operazioni che un operatore umano non potrebbe compiere perché richiedono troppa potenza, precisione o velocità;
  3. Sviluppare macchine che possono lavorare in ambienti che sono ostili o pericolosi per l’uomo.

Sistemi di Numerazione

Sistemi di numerazione per calcolatori

  1. Numeri, interi, frazionari e reali;
  2. Lettere, conservate tramite opportuni codici che associano a ogni lettera un numero;
  3. Istruzioni di programmazione, codificate mediante numeri di riferimento, affinché il calcolatore, letto il numero dell’istruzione, possa rintracciare nei suoi circuiti il blocco di sequenze operative adatto a eseguire l’istruzione;
  4. Informazioni grafiche delle figure rappresentate a video (posizione e colori dei pixel che compongono l’immagine), codificate numericamente;
  5. Brani audio, clip video, codificati come sequenze estese di numeri.

Sistema di numerazione binario

Sistema di numerazione esadecimale

Sistema di numerazione BCD

Algoritmi

Algoritmi e diagrammi di flusso

  1. Mettere acqua e caffè nella caffettiera;
  2. Chiudere la caffettiera;
  3. Accendere il gas;
  4. Attendere la bollitura;
  5. Chiudere il gas;
  6. Versare il caffè nella tazza;
  7. Riporre la caffettiera su un materiale non combustibile.
  1. accetta un insieme di dati di ingresso;
  2. Li elabora;
  3. Restituisce un insieme di dati di uscita.
  1. Finitezza: l’algoritmo deve essere composto da un numero finito di passi elementari; in teoria non si pone limite né di tempo né di memoria impegnati per ogni passo, basta siano finiti. Nello sviluppo di un algoritmo è assolutamente necessario curare che non si verifichino cicli infiniti, ovvero ripetizioni con condizioni mai soddisfatte di uscita dal ciclo. Naturalmente è preferibile un algoritmo che spreca poche risorse, ma questo è un problema pratico di efficienza, che esula dalla finitezza.
  2. Non Ambiguità: l’algoritmo deve essere interpretabile in modo univoco da un qualsiasi esecutore. Il risultato deve essere deterministico, ovvero non deve portare a risultati diversi nel tempo, salvo il caso in cui il comportamento differenziato sia prestabilito. Il linguaggio utilizzato deve essere chiaro e attento, perciò viene utilizzato un formalismo rigoroso che non si ritrova nel linguaggio umano, spesso troppo approssimativo o viceversa appesantito da dettagli ininfluenti.
  3. Realizzabilità: l’algoritmo deve essere realizzabile con le risorse a disposizione del linguaggio.
  1. Elaborazione: istruzione esecutiva;
  2. Inizializzazione: impostazione di valori iniziali alle variabili di input;
  3. Input/output: operazioni di lettura e scrittura;
  4. Condizione: test; 5. inizio: inizio algoritmo;
  5. Fine: fine algoritmo.
  1. Sequenza semplice;
  2. Selezione semplice o multipla;
  3. Iterazione postcondizionale, precondizionale, ciclo iterativo.
  • Elaborazione di dati mediante calcoli aritmetico-logici;
  • Copia di valori entro variabili o scambio del contenuto di variabili.
  • Se la condizione è TRUE il programma percorre il ramo etichettato come VERO e incontra il blocco delle “istruzioni condizione vera”;
  • Se la condizione è FALSE il programma percorre il ramo etichettato come FALSO e incontra il blocco delle “istruzioni condizione falsa”.
  • Cicli postcondizionali;
  • Cicli precondizionali.
  • La condizione è controllata dopo l’esecuzione della sequenza di istruzioni;
  • Pertanto la sequenza istruzioni viene eseguita almeno una volta.
  • Quando il risultato della condizione dipende da istruzioni che devono precederla;
  • In particolare nella prima iterazione, la mancata esecuzione delle istruzioni potrebbe condurre a una condizione indeterminata.
  • La condizione è controllata prima della sequenza di istruzioni;
  • Pertanto non è sempre garantita l’esecuzione della sequenza di istruzioni, perché se la condizione è subito falsa il ciclo non viene mai eseguito.
  1. I viene inizializzata a 0;
  2. Viene verificata subito la condizione I< MAX;
  3. Se la condizione è vera viene eseguita la “sequenza istruzioni”;
  4. . I viene incrementata: I = I + 1;
  5. Viene ripetuto il test.
  1. Sequenza;
  2. Selezione;
  3. Iterazione.
  1. Partire da una formulazione generica delle sezioni principali dell’algoritmo;
  2. Espandere l’algoritmo per raffinamenti successivi;
  3. Esplicitare ogni passo mediante una struttura di controllo fondamentale.
  1. Spazio di memoria occupato o più in generale risorse impegnate;
  2. Tempo di esecuzione.
  1. Numero di passi risolutivi;
  2. Tempo speso per ogni passo.
  1. Numeri;
  2. Caratteri.
  1. Il codice ASCII standard a 7 bit, che associa a ogni carattere un numero, compreso tra 0 e 127, e comprende le lettere dell’alfabeto minuscole e maiuscole e i vari segni di punteggiatura;
  2. Il codice ASCII esteso a 8 bit, che include anche i numeri compresi tra 128 e 255, per la codifica di alcuni simboli specifici delle diverse località geografiche. La tabella seguente è uno stralcio della tavola completa, facilmente reperibile in Internet. Vi sono elencate le codifiche esadecimale, decimale, binaria dei numeri dallo 0 al 9 e di alcuni caratteri.
  1. Tipi interi e char;
  2. Tipi reali.
  1. Con n bit si possono codificare 2n numeri interi;
  2. Un numero intero può essere con segno (signed) e senza segno (unsigned);
  3. A parità di numero di bit, un signed può registrare numeri più piccoli di un unsigned, perché l’insieme dei valori esprimibili deve essere condiviso dai positivi e negativi;
  4. A partire dai tipi base, si possono applicare i modificatori short e long, che permettono rispettivamente di contrarre o espandere la dimensione.

Variabili e Costanti

  1. Contenere lettere, numeri, simbolo underscore; non sono permessi spazi e punti;
  2. Iniziare con una lettera;
  3. Non coincidere con una parola riservata del linguaggio.

Operatori ed espressioni

  1. Di assegnamento;
  2. Aritmetici;
  3. Relazionali;
  4. Logici;
  5. Orientati al bit.
  1. printf;
  2. scanf.
    Il C++ mette a disposizione:
  3. cout;
  4. cin.
  1. “prenotare” la posizione che le variabili devono occupare all’interno del messaggio, per mezzo di specificatori di formato. Il messaggio, in questo caso, prende il nome di stringa di formattazione, appunto perché definisce le caratteristiche del formato del messaggio;
  2. far seguire il messaggio dall’elenco delle variabili, separate da virgole. Lo specificatore di formato è un simbolo, preceduto da %, associato al tipo di variabile da rappresentare. La tabella sotto a sinistra riporta i vari specificatori di formato. Quella a destra riporta i modificatori di tipo, che servono a specificare un ulteriore attributo al tipo.
  1. Il primo lo spazio a disposizione per la stampa, con giustificazione a destra;
  2. Il secondo il numero di decimali visualizzati.
  1. Su singola riga con il simbolo //;
  2. Su più righe racchiudendo la frase di commento entro i simboli /* e */.

La struttura condizionale

  1. IF-ELSE;
  2. IF;
  3. IF-ELSE nidificati;
  4. SWITCH.
  1. Se l’espressione logica è TRUE il programma percorre il ramo etichettato come VERO e incontra il blocco delle “istruzioni da eseguire se espressione logica vera”.
  2. Se l’espressione logica è FALSE il programma percorre il ramo etichettato come FALSO e incontra il blocco delle “istruzioni da eseguire se espressione logica falsa”.

I cicli

  1. CICLO FOR;
  2. CICLI FOR NIDIFICATI;
  3. CICLI DO-WHILE e WHILE.
  1. La condizione è controllata dopo l’esecuzione della sequenza di istruzioni (post condizionale), pertanto la sequenza istruzioni viene eseguita almeno una volta;
  2. Questa modalità è impiegata quando il risultato della condizione dipende da istruzioni che devono precederla. In particolare nella prima iterazione la mancata esecuzione delle istruzioni potrebbe condurre a una condizione indeterminata. Nel WHILE:
    1. La condizione è controllata prima della sequenza di istruzioni (precondizionale), pertanto non è garantita sempre l’esecuzione della sequenza di istruzioni, perché se la condizione è subito falsa il ciclo non viene mai eseguito;
    2. questa modalità è utile quando l’esecuzione o meno della sequenza di istruzioni deve essere subordinata a un controllo a priori;

Vettori e matrici

  1. Le caselle sono numerate da 0 a 7;
  2. La sesta casella è individuata da INDICE = 5;
  3. Il contenuto della casella di indice 5 è 2.
  1. Il tipo della variabile;
  2. Il nome della variabile;
  3. La estensione, cioè il numero di caselle.
  1. Un indice i per l’identificazione della riga;
  2. Un indice j per l’identificazione della colonna.

Funzioni

  1. Il programma chiamante passa dei dati in ingresso alla funzione, detti parametri o argomenti di input;
  2. La funzione li elabora e restituisce al programma chiamante il risultato, detto valore di ritorno o valore restituito.
  1. Prevedere un insieme di scelte alternative;
  2. Consentire la scelta della funzione e attivare la sua esecuzione;
  3. Consentire di proseguire o terminare il programma.
  1. Leggibilità:
    • ogni funzione ha un nome che richiama i suoi compiti,
    • si individuano facilmente le parti funzionali nel programma chiamante,
    • si intuisce la struttura logica del programma chiamante;
  2. Sviluppo:
    • si possono utilizzare funzioni sviluppate da terze parti,
    • i programmatori possono lavorare in team sullo stesso progetto con compiti diversi;
  3. Manutenzione:
    • si possono aggiornare solo i moduli che richiedono una revisione,
    • si possono individuare direttamente i moduli che contengono dei bug;
  4. Efficienza:
    • la medesima funzione può essere riutilizzata nello stesso o in altri programmi,
    • la medesima funzione può operare a ogni chiamata su insiemi di dati diversi.

Funzioni predefinite

  1. La funzione che svolgono;
  2. Con quali modalità chiamarle;
  3. Quali parametri di input passare;
  4. Quale valore di ritorno ricevere.
  1. Calcola la radice quadrata di un numero;
  2. Accetta come parametro di input il radicando di tipo float;
  3. Restituisce un valore di ritorno di tipo float.
  1. Il nome della funzione;
  2. Il tipo dei parametri di input e il nome (opzionale);
  3. Il tipo del valore di ritorno.
  1. Disporre tra parentesi la serie dei parametri di input separati da virgole;
  2. Assegnare la funzione a una variabile, tramite l’operatore di assegnamento =.

Funzioni utente

  1. Le dichiarazioni dei parametri di input A, B;
  2. Il tipo dei parametri di input, in questo int;
  3. La dichiarazione di una variabile interna MAX;
  4. Le istruzioni di elaborazione;
  5. La parola chiave return, che fissa il parametro di output.
  1. Chiamarla con il suo nome;
  2. Disporre tra parentesi la serie dei parametri di input separati da virgole;
  3. Assegnare la funzione a una variabile, tramite l’operatore di assegnamento =.
  1. I parametri dell’istruzione chiamante, nell’esempio NUM1 e NUM2, sono detti parametri attuali, perché mutano di volta in volta.
  2. I parametri della funzione, nell’esempio A, B, sono detti parametri formali.

Variabili locali e globali

  1. Un primo livello esterno al main;
  2. Un secondo livello, il main, che è esso stesso una funzione, la funzione principale;
  3. Un terzo livello delle funzioni utente.
  1. Si definisce variabile globale una funzione dichiarata nel livello esterno;
  2. Si definisce variabile locale una variabile dichiarata in un sottolivello, per esempio una funzione.
  1. Una variabile globale è visibile a tutti i livelli;
  2. Una variabile locale è visibile solo nel livello nel quale è dichiarata.
  1. Migliore leggibilità
    ➞ perché chi legge il programma rintraccia le variabili nell’ambiente dove sono utilizzate;
  2. Portabilità delle funzioni
    ➞ perché ogni funzione reca con sé le proprie variabili quindi può essere riutilizzata in altri programmi senza pesanti modifiche;
  3. Minore possibilità di errore
    ➞ perché altrimenti diverse funzioni potrebbero accedere erroneamente alla stessa variabile globale, con scopi diversi;
  4. Minore occupazione di memoria
    ➞ perché vengono allocate in memoria solo all’inizio dell’esecuzione della funzione.

Stringhe

  1. Delimitare la fine della stringa in tutte le situazioni, senza alcuna ambiguità;
  2. Dichiarare una sola volta la stringa con una lunghezza prestabilita, ma memorizzare sequenze di caratteri più corte della effettiva lunghezza della stringa. La stringa, come il vettore, può essere rappresentata visivamente da un insieme di caselle, numerate a partire da 0. In figura è rappresentata una stringa di 8 caselle così caratterizzata:
    1. le caselle sono numerate da 0 a 7;
    2. ogni casella è identificata da un indice, un numero che esprime la sua posizione d’ordine;
    3. per esempio la terza casella è individuata da INDICE = 2; il suo contenuto è la lettera ‘A’;
    4. la stringa è conclusa dal carattere terminatore;
    5. le caselle 5, 6, 7 sono vuote oppure, se hanno un contenuto, questo è ininfluente.
  1. Il tipo della variabile, che è un char;
  2. Il nome della variabile;
  3. La estensione, cioè il numero di caselle.

Modalità di lettura/scrittura

  1. Lettura/scrittura di ogni singola casella;
  2. Lettura/scrittura dell’intera stringa.
  • ponendo i caratteri delle caselle tra parentesi graffe, racchiusi da apici e separati da virgole;
  • specificando l’intera stringa tra virgolette.

Programmazione delle stringhe

  1. Funzione strlen (STRINGA) Calcola la lunghezza di una stringa, ovvero il numero dei caratteri costituenti. Il termine strlen è la contrazione di string length = lunghezza stringa. La funzione accetta tra parentesi il nome della stringa e restituisce il numero di caratteri.
  2. Funzione strcat (STRINGA1, STRINGA2) Concatena due stringhe. La stringa risultante viene caricata in STRINGA1. Il termine strcat è la contrazione di string concatenation = concatenazione stringa. La funzione accetta due stringhe tra parentesi, le concatena e restituisce il risultato dell’operazione nella stringa a sinistra, che risulta pertanto sovrascritta.
  3. Funzione strcpy (STRINGA1, STRINGA2) Copia una stringa sorgente STRINGA 2 entro una stringa destinazione STRINGA1. Il termine strcpy è la contrazione di string copy = copia stringa. La funzione copia una stringa sorgente a destra nella stringa destinazione a sinistra.
  4. Funzione strcmp Confronta il contenuto di due stringhe. La funzione restituisce valore: 0 se STRINGA1 = STRINGA2 ovvero se le due stringhe sono uguali. > 0 se STRINGA1 > STRINGA2 ovvero se STRINGA1 segue STRINGA2 in ordine alfabetico.

Elenchi

  1. Ogni riga è una stringa.
  2. Ogni stringa è un insieme di caratteri.
  1. Numero di righe pari al numero di stringhe;
  2. Numero di colonne pari al numero dei caratteri.
  1. Il tipo della variabile, che è un char;
  2. Il nome della variabile;
  3. La estensione, intesa come numero di righe (parole) e colonne (caratteri per parola).

Modalità di lettura/scrittura

  1. Lettura/scrittura di ogni singola casella;
  2. Lettura/scrittura di una intera riga;
  3. Lettura/scrittura dell’intero elenco.

Programmazione degli elenchi

Struttura

  1. COGNOME di tipo stringa ➞ memorizza il cognome dell’alunno;
  2. MATRICOLA di tipo stringa ➞ memorizza il suo codice alfanumerico di matricola;
  3. MEDIA di tipo int ➞ memorizza la media complessiva delle materie di studio.
  1. Il NOME della struttura, preceduto dalla clausola struct;
  2. Tra parentesi graffe i campi, nella modalità consueta di dichiarazione di variabile.

Vettore di struttura

  1. Il tipo della struttura; 2. il nome della variabile; 3. la estensione, intesa come numero di CELLE del vettore.
  1. Il nome della variabile vettore di struttura;
  2. Seguito dal numero della cella tra parentesi quadre;
  3. Seguito da un punto;
  4. Seguito dal nome del campo che interessa.

File binari e file di testo

  1. File binari;
  2. File di testo.

File binari

  1. Dichiarazione di una variabile di tipo puntatore a file;
  2. Apertura del file;
  3. Lettura e/o scrittura del file;
  4. Chiusura del file.
  • la parola chiave FILE definisce il tipo della variabile gestorefile;
  • l’asterisco specifica che tale variabile è un puntatore (indirizzo) alle informazioni contenute nel file.
  • nomefile è il nome fisico del file, che deve essere preceduto dal percorso di individuazione, nel caso il file si trovi in una directory diversa da quella di esecuzione corrente;
  • tipo operazione può essere: rb, wb, r+ per l’apertura del file binario rispettivamente in modalità lettura, scrittura e lettura/scrittura;
  • l’istruzione fopen restituisce NULL se l’apertura non va a buon fine.
  • fread (puntatore variabile dati, dimensione singolo dato, numero dati, gestorefile) fwrite (puntatore variabile dati, dimensione singolo dato, numero dati, gestorefile)
  • puntatore variabile dati è l’indirizzo di memoria della variabile:
    — che contiene i dati da scrivere su file nel caso di fwrite,
    — di destinazione dei dati nel caso di lettura fread;
  • dimensione dato è la dimensione in byte di ciascun dato elementare, calcolata per mezzo dell’istruzione sizeof (). Per dato elementare si intende la frazione minima nella quale i dati possono essere partizionati;
  • numero dati è il numero di dati elementari da leggere/scrivere;
  • gestorefile è il puntatore al file in oggetto.
  • chiude il file liberando le risorse impegnate del sistema operativo;
  • rende permanenti le modifiche operate sul file
  1. Variabile monodimensionale;
  2. Variabile pluridimensionale.
  1. fseek;
  2. ftell;
  3. feof.
  1. offset indica di quanti byte saltare in avanti rispetto alla posizione di origine dell’indicatore di posizione;
  2. Origine permette di impostare la posizione di origine dell’indicatore di posizione.
    In particolare:
    • SEEK_SET = inizio del file;
    • SEEK_END = fine del file;
    • SEEK_CUR = posizione corrente.
  • leggere l’intero file in un’unica soluzione e applicare la ricerca alla variabile letta;
  • oppure leggere un record alla volta. In questo secondo caso si deve:
  • posizionare l’indicatore di posizione all’inizio del file;
  • scandire uno dopo l’altro i record alla ricerca del dato;
  • il tutto entro un ciclo while che termina se il dato è stato trovato oppure se è stata raggiunta la fine del file.

File di testo

  1. Dichiarazione di una variabile di tipo puntatore a file;
  2. Apertura del file;
  3. Lettura e/o scrittura del file;
  4. Chiusura file.
  1. fprintf;
  2. fscanf.
  1. Gestore file è il puntatore alle informazioni contenute nel file;
  2. Specificatori di formato è l’insieme, racchiuso tra virgolette, degli specificatori di formato delle variabili da salvare;
  3. Elenco variabili è l’insieme delle variabili da salvare. fscanf (gestorefile, specificatori di formato, elenco variabili) 1. è analoga a fprintf.

Teoria dei sistemi

  1. Trascura le grandezze che hanno una influenza debole nell’economia del sistema;
  2. Elegge le grandezze più rappresentative in relazione agli obiettivi del problema;
  3. Prende in considerazione un modello matematico ideale semplificato del sistema.
  1. le variabili;
  2. I parametri;
  3. Il modello matematico;
  4. Il modello schematico.

I parametri

Il modello matematico

Modello matematico e schema a blocchi

  1. Variabile di ingresso: numero di pedalate/secondo = NP;
  2. Variabile di uscita: velocità della bicicletta = V. Il modello matematico è la relazione che intercorre tra NP e V, come descritto in figura.
  1. Giricorona = numero di giri al secondo sviluppati dalla corona ovvero dai pedali = NP;
  2. Girirocchetto = numero di giri sviluppati al secondo dal rocchetto ovvero dalla ruota posteriore;
  3. R = raggio delle ruote in metri;
  4. Rapporto = (numero di denti della corona) / (numero di denti del rocchetto).

Il dominio del tempo

  1. Notazione delle variabili;
  2. Grafici cartesiani;
  3. Transitori e regime;
  4. Transitori di oscillazione;
  5. Condizioni iniziali e al contorno.

Valore nominale

  1. Tempo di assestamento ST (settling time);
  2. Sovraelongazione (overshoot).

Tempo di assestamento (ST)

Sovraelongazione

Variabili di stato

Classificazione dei sistemi

Classificazione dettata dalle proprietà delle variabili

Classificazione dettata dalle proprietà del modello matematico

Studio e simulazione dei sistemi nel dominio del tempo

  1. Scrivere le formule matematiche discrete che governano un processo;
  2. Simulare il processo implementando le formule con un linguaggio di programmazione.
  1. Le variazioni o differenze finite;
  2. Il rapporto incrementale.

Differenze Finite

Rapporto incrementale

Le equazioni alle differenze finite

  1. L’incognita è una funzione y(x);
  2. L’incognita compare entro un rapporto incrementale.

Gli infinitesimi e la derivata

Sistemi elettrici

Configurazioni circuitali fondamentali

  1. La VC(t) tende al valore di regime E per t tendente a infinito;
  2. La velocità di crescita della VC(t) è strettamente dipendente dalla costante di tempo. Se la t è piccola la carica ha luogo rapidamente e viceversa.

SISTEMI MECCANICI

Equazione del moto nei sistemi meccanici

  1. Scrittura dell’equazione del moto;
  2. Risoluzione numerica dell’equazione del moto;
  3. Simulazione numerica.

Risoluzione numerica dell’equazione del moto

  1. Massa inizialmente ferma, quindi v(0) = 0;
  2. Massa trascinata verso il basso di 1 metro e rilasciata, quindi: x(0) = 1 m.
  1. Colonna v(t): D4 = D3–100 * E3 * $H$19
  2. Colonna x(t): E4 = E3 + D3 * $H$19

Analogie tra processi elettrici e meccanici

  1. Individuazione numero e posizione nodi;
  2. Tracciamento rete meccanica;
  3. Conversione in rete elettrica.

Individuazione numero e posizione nodi

Tracciamento rete meccanica

Conversione in rete elettrica

Sistemi Idraulici

Differenza di altezza

Portata

  1. La resistenza idraulica;
  2. La capacità idraulica.

Resistenza idraulica

Capacità idraulica

Equazioni dei sistemi idraulici

Sistema idraulico con foro di afflusso a portata costante

Svuotamento serbatoio

Equazioni dei sistemi termici

Raffreddamento di un corpo

Microcontrollori e Microprocessori

  • ogni funzione operativa richiede una propria struttura circuitale, di conseguenza il progetto risulta poco flessibile e dispendioso;
  • nel caso di sistemi complessi la struttura hardware diventa imponente, di conseguenza è alto il rischio di errori nel progetto e nell’assemblaggio dei componenti e si hanno alti costi di progettazione e di produzione. Per logica programmata si intende un approccio progettuale ibrido hardware-software, nel quale:
    • è presente uno strato hardware strutturato in modo permanente;
    • allo strato hardware si sovrappone uno strato software;
    • lo strato software non è rigidamente determinato come quello hardware, ma può essere adattato alle specifiche del progetto.
  • la funzionalità operativa è dettata dal software, quindi per apportare modifiche al progetto basta modificare il software, senza alterare l’hardware;
  • agendo sul software è semplice correggere il progetto in fase di sviluppo, nonché tenerlo aggiornato;
  • il progettista non deve preoccuparsi dei dettagli costruttivi dello strato hardware. Nella logica programmata i moduli hardware vengono realizzati mediante sistemi LSI e VLSI (LSI = Large Scale Integration; VLSI = Very Large Scale Integration) detti microprocessori e microcontrollori. Un microprocessore è un dispositivo complesso che integra funzionalità sia hardware sia software:
    • dal punto di vista hardware è dotato di circuiti organizzati per le funzionalità interne e per l’interfacciamento con dispositivi esterni;
    • dal punto di vista software è dotato di capacità di calcolo di base logiche e aritmetiche, ma soprattutto può leggere ed eseguire programmi.
  • legato al mondo dei computer, molto potenti ma anche ingombranti e appesantiti da una serie di sovrastrutture (schermo, tastiera) che ne rallentano il funzionamento;
  • adatto ad applicazioni di uso generale (general purpose), come internet e pacchetti applicativi, dove sono necessarie ampie risorse visuali ma non particolari livelli di miniaturizzazione. Il microcontrollore invece:
  • è specializzato, cioè spesso destinato a una sola funzione nel suo ciclo di vita; nella sua memoria interna viene infatti inciso un programma permanente che attraverso i pin svolge funzioni di controllo dei sistemi con i quali è interfacciato;
  • può essere direttamente incorporato (embedded) entro schede elettroniche di tutti i generi, da sistemi robotici a sistemi per la gestione del traffico a giochi, essendo progettato per la massima autosufficienza funzionale;
  • proprio perché incorporato in schede di gestione di processi è progettato per lavorare in tempo reale (real-time), ovvero interagire alla massima velocità con il processo.
  1. CPU;
  2. sezioni di memoria (RAM, ROM….);
  3. sezioni di input-output.
  1. La CPU=Central Processing Unit = Unità Centrale di Elaborazione, è il cuore e l’intelligenza del microcontrollore. Essa:
    • interpreta ed esegue il programma;
    • gestisce l’UnitàAritmetico-Logica (ALU=ArithmeticLogicUnit) per l’esecuzione delle istruzioni di programma;
    • attiva e sincronizza i dispositivi che cooperano all’esecuzione del programma.
  2. Le sezioni di memoria sono destinate al mantenimento del programma che la CPU ha in carico e dei dati sui quali la CPU opera. In particolare si distinguono:
    • memoria ROM dove sono incisi dati strutturali dell’elaboratore;
    • memoria RAM dove è memorizzato il programma che la CPU deve eseguire e i dati sui quali deve operare.
  3. Le sezioni di input-output fungono da interfaccia tra la CPU e le unità esterne al microprocessore. In particolare si distinguono:
    • porte di INPUT, per esempio per la lettura dello stato di interruttori;
    • porte di OUTPUT, per esempio per il comando di led e relè.2.2
  • semplifica il collegamento riducendo drasticamente il numero di collegamenti;
  • permette in teoria una espansione illimitata, senza bisogno di cablare nuove interconnessioni. Per impedire che si verifichino sovrapposizioni di segnali in una medesima linea è necessario che un solo dispositivo alla volta sia abilitato al colloquio con la CPU. Per questo la CPU deve svolgere compiti di arbitrato e definire il dispositivo abilitato al colloquio. In linea di principio, facendo riferimento all’architettura di base, le informazioni sono canalizzate entro tre distinti bus:
    1. bus dati;
    2. bus indirizzi;
    3. bus controlli.
  • le istruzioni sono dirette dalla memoria alla CPU;
  • i dati sono diretti dalla memoria alla CPU se letti e viceversa se salvati.
  1. La CPU pone l’indirizzo della locazione di memoria da leggere (ad esempio 101 = 5) sul bus indirizzi;
  2. La CPU invia il segnale di read alla memoria attraverso il bus controlli;
  3. La locazione viene letta e il suo contenuto 01010101 viene posto sul bus dati. Da qui la CPU lo legge e lo ingloba al suo interno.
  • se CS = 0 la logica three state all’uscita viene posta in condizione buffer con circuito aperto, pertanto le uscite risultano virtualmente scollegate;
  • se CS = 1 le uscite sono libere di porre i valori digitali 0 o 1 sui terminali che fanno capo al bus.

Linguaggio macchina e assembler

  • è dotato di capacità di calcolo e logiche;
  • svolge attività di governo delle varie periferiche e apparati a esso connessi.
  • contiene istruzioni che il microprocessore deve eseguire;
  • fa riferimento a dati che il microprocessore deve manipolare.
  • una sequenza di parole di memoria con i codici delle istruzioni;
  • la specifica dell’indirizzo a lato di ogni parola di memoria.
  • è difficile digitare delle sequenze numeriche senza compiere errori di battitura;
  • il codice numerico non è facile da memorizzare;
  • il codice numerico non fornisce alcuna indicazione sul significato dell’istruzione.
  • il nome simbolico richiama, con una dizione vicina all’inglese, il significato dell’istruzione;
  • il nome simbolico è facile da ricordare, per questo il codice assemblatore, in inglese assembler, è detto anche codice mnemonico. In assembler anche l’indirizzo di una istruzione è codificato con un nome simbolico, detto etichetta o label. Una istruzione in assembler solitamente è formata da due campi: il campo codice operativo e il campo operando. Di questi il codice operativo specifica una azione e l’operando specifica il dato al quale è riferita l’azione. A una sola istruzione in codice assembler possono corrispondere in codice macchina:
    • istruzioni a un solo byte;
    • istruzioni a due o più byte.
  • entro il primo byte il codice operativo, che specifica l’operazione da compiere;
  • entro il secondo byte l’operando, che di volta in volta varia, oppure l’indirizzo dell’operando. Le istruzioni a tre byte tipicamente sono istruzioni di salto nelle quali, nel caso del set 8051:
    • il primo byte è il codice operativo dell’istruzione;
    • il secondo byte è la parte alta (8 bit) dell’indirizzo di salto a 16 bit (linee A15 ÷ A8 del bus indirizzi);
    • il terzo byte è la parte bassa (8 bit) dell’indirizzo di salto a 16 bit (linee A7 ÷ A0del bus indirizzi).
  1. Le etichette degli indirizzi;
  2. Le istruzioni in assembler;
  3. Gli indirizzi delle istruzioni;
  4. Il codice esadecimale delle istruzioni;
  5. Il codice binario delle istruzioni.
  • basso livello significa linguaggio vicino alla struttura hardware della macchina e alla sua logica operativa;
  • alto livello significa linguaggio vicino al livello della lingua parlata e compresa dall’uomo. Procedendo nella direzione dei linguaggi dal basso verso l’alto livello troviamo:
    • linguaggio macchina: costituito da codice binario;
    • linguaggio assemblatore: sostituisce il codice mnemonico al codice binario;
    • linguaggi di alto livello come C e Basic.
  • il programma per tradurre il linguaggio assembler in linguaggio macchina si chiama assemblatore;
  • il programma per tradurre il linguaggio di alto livello in linguaggio macchina si chiama compilatore;
  • semplificare la scrittura del programma;
  • applicare modifiche al programma in modo agevole;
  • sistemi che lavorano in tempo reale, nei quali è richiesta la massima prontezza;
  • l’ambito didattico, perché permette di studiare a fondo il microprocessore.

Architettura interna della CPU

  1. Registri deputati al prelievo delle istruzioni: program counter e stack pointer, che servono a individuare la posizione dell’istruzione nella memoria;
  2. Registri e dispositivi deputati al riconoscimento delle istruzioni: registro istruzioni, decodifica istruzioni, controllo, temporizzazione che servono a interpretare l’istruzione e diramare gli ordini agli apparati esecutivi;
  3. Registri e dispositivi deputati all’esecuzione delle istruzioni: accumulatore, registri, ALU, flag, che servono a mettere in atto fattivamente le operazioni comandate dall’istruzione.
  1. Registri deputati al prelievo delle istruzioni. Program counter PC: indica a quale indirizzo di memoria prelevare l’istruzione ancora da eseguire. Una volta eseguita l’istruzione, accade che:
    • il PC viene incrementato, per puntare alla successiva istruzione;
    • nel caso si debba eseguire un salto, il PC viene forzato al nuovo indirizzo cui saltare.
    Stack pointer: in esso la CPU deposita l’indirizzo di ritorno, nel caso di salti causati da chiamate a sottoprogrammi. In particolare:
    • l’indirizzo dell’istruzione corrente viene caricato dal PC entro lo SP;
    • al ritorno dalla chiamata a sottoprogramma SP ripristina l’indirizzo in PC;
    • in caso di chiamate nidificate, gli indirizzi vengono accatastati (stack significa appunto catasta);
    • la modalità di salvataggio e ripescaggio degli indirizzi accatastati è del tipo LIFO (Last In First Out = ultimo a entrare, primo a uscire).
  2. Registri e dispositivi deputati al riconoscimento delle istruzioni
    Registro istruzioni: in esso viene depositato il codice operativo dell’istruzione da eseguire. Decodifica istruzioni: qui la CPU compara l’istruzione con una lista interna che contiene il set di istruzioni, ovvero l’insieme delle istruzioni che la CPU riconosce. Nella lista, per ogni istruzione, è registrato un microprogramma di implementazione, che viene eseguito. Controllo: in questa sezione vengono generati i segnali destinati al bus controlli, necessari per completare la lettura dell’istruzione. Temporizzazione: questa sezione genera sequenze predefinite di impulsi, con un ritmo dettato dal segnale di clock, per comandare elettronicamente i dispositivi coinvolti nell’istruzione. Clock: è un segnale a onda quadra che ritma l’operato del microcontrollore.
  3. Registri e dispositivi deputati alla esecuzione delle istruzioni Accumulatore: è il principale registro di memoria, innervato con tutti gli altri registri, infatti:
    • quasi tutte le istruzioni lo utilizzano come registro per i dati in ingresso;
    • quasi tutte le istruzioni depositano in esso il risultato. Flag: è un registro che segnala (flag = bandiera) mediante ogni singolo bit delle particolari condizioni; per esempio:
    • il flag di zero è un bit che segnala, mediante il suo stato 1 o 0, se una operazione ha dato risultato uguale o diverso da zero;
    • il flag di carry è un bit che registra il valore del riporto generato da una somma. ALU Arithmetic Logic Unit = Unità Aritmetico Logica: esegue operazioni aritmetiche e logiche.
    Registri: sono registri di memoria utilizzati per depositare dati in modo temporaneo, nel corso dell’esecuzione delle operazioni.

Fasi di Fetch ed Execute

  • fase di fetch: in essa la CPU acquisisce dalla memoria l’istruzione (fetch = ricerca);
  • fase di execute: in essa la CPU esegue l’istruzione.
  1. Nel Program Counter viene impostato l’indirizzo dell’istruzione da reperire in memoria. In particolare dopo il reset il PC vale solitamente 0000h, cioè punta alla cima della memoria.
  2. Il contenuto del PC viene inviato sul bus indirizzi, diretto a selezionare la locazione di memoria.
  3. La CPU attiva il controllo Read per comandare un’operazione di lettura in memoria.
  4. La CPU legge la parola di memoria attraverso il bus dati e la deposita nel Registro Istruzioni.
  5. L’unità di decodifica riconosce il codice operativo presente nel Registro Istruzioni. Supponiamo che l’istruzione sia ADD A, B che significa “somma l’accumulatore A al registro temporaneo B”. In tal caso la fase di execute contempla i seguenti passi successivi.
  6. La CPU trasferisce il contenuto dell’accumulatore nella ALU.
  7. La CPU trasferisce il contenuto del registro temporaneo B nella ALU.
  8. La CPU comanda alla ALU di effettuare la somma.
  9. La CPU comanda il trasferimento del risultato nell’accumulatore; il dato precedente è soprascritto.

Interfacciamento Microprocessori

  1. La CPU presenta un byte sul bus dati;
  2. La CPU comanda una operazione di scrittura sul terminale write del latch, tramite il bus controlli;
  3. I livelli logici presenti sugli ingressi D7 D6 D5 D4 D3 D2 D1 D0 vengono trasferiti e memorizzati sulle uscite Q7 Q6 Q5 Q4 Q3 Q2 Q1 Q0;
  4. La sezione di decodifica indirizzi tramite il terminale enable abilita il latch, che abbandona lo stato di alta impedenza;
  5. I livelli logici rimangono impressi sui dispositivi collegati alle uscite, nel caso dell’immagine sottostante caso 8 led.
  1. La CPU comanda un’operazione di lettura sul terminale write del latch, tramite il bus controlli;
  2. I livelli logici D7 D6 D5 D4 D3 D2 D1 D0 presenti sugli ingressi, che in questo caso sono degli interruttori, vengono trasferiti e memorizzati sulle uscite Q7 Q6 Q5 Q4 Q3 Q2 Q1 Q0 dove rimangono a disposizione della CPU;
  3. La CPU tramite il terminale enable abilita il latch, che abbandona lo stato di alta impedenza;
  4. Le uscite Q7 Q6 Q5 Q4 Q3 Q2 Q1 Q0 si presentano sulle corrispondenti linee del bus dati;
  5. La CPU incorpora gli 8 bit dei dati.

Interfacciamento Microcontrollori

  • scrivere i dati sul latch di uscita mediante una operazione software di output;
  • salvare i dati nel latch di ingresso mediante una operazione software di input.
  • un latch di uscita di nome Data Latch per il salvataggio del bit in uscita;
  • un latch di ingresso rivolto in senso opposto per il salvataggio del bit in ingresso;
  • il pin I/O pin, che supporta sia bit di input sia bit di output;
  • un TTL Input Buffer.
  • un latch di nome TRIS Latch, che serve a selezionare o la lettura o la scrittura;
  • una porta AND e una OR; un FET tipo P e uno tipo N;
  • un buffer di input.
  • Q TRIS Latch = 0 output
  • Q TRIS Latch = 1 input
  • regione OUT: elementi adibiti a operazioni di scrittura;
  • regione IN: elementi adibiti a operazioni di lettura.

Scrittura (OUT)

Lettura (IN)

Microcontrollori PIC

  • Memorie — memoria flash RAM, ROM, EPROM.
  • Periferiche — dispositivi che integrano le funzionalità della CPU quali Timer e conv. ADC.
  • Interfacce — soluzioni per il dialogo con apparati esterni come porte di ingresso/uscita, interfaccia seriale e parallela.
  • comunica con la memoria programma tramite il bus programma;
  • comunica con la memoria dati tramite il bus dati.
  1. La RAM contiene i File Registers (registri archivio) che conservano l’“impronta” del sistema. Se la CPU è il cervello del sistema, i file register ne sono il cuore.
  2. Sulla EEPROM possono essere salvati dati da conservare. Non esiste un vero e proprio bus indirizzi, in quanto gli indirizzi delle istruzioni sono diramati in modi distinti:
  • la memoria dati RAM e in parte la EPROM ricevono l’indirizzo della locazione da leggere/scrivere attraverso il bus dati;
  • la memoria programma Flash riceve l’indirizzo dell’istruzione da eseguire dal Program Counter PC, a sua volta collegato al bus dati. Come tradizione la CPU gestisce l’istruzione di programma in due fasi: la fase di fetch e la fase di execute:
    — nella fase di fetch avviene il prelievo dell’istruzione dalla memoria (fetch = ricerca);
    — nella fase di execute ha luogo l’esecuzione vera e propria del comando impartito dall’istruzione.
  • mentre è ancora in corso l’esecuzione di una istruzione, con il coinvolgimento del bus dati.
  • la CPU può iniziare la lettura dell’istruzione successiva attraverso il bus programma.
Architettura del PIC16F84A

Struttura della memoria

  • La memoria di programma nei dispositivi di ultima generazione è di tipo flash, una memoria non volatile programmabile e cancellabile elettricamente fino a 100000 volte.
  • All’indirizzo 0000h è collocato il vettore di reset. A questa locazione si dispone il PC al momento del reset; da qui inizia l’esecuzione del programma.
  • Uno o più indirizzi sono riservati ai vettori di interrupt.
  • Sono presenti alcuni livelli di stack (catasta) entro i quali il programma salva (push) l’indirizzo di ritorno da sottoprogramma e lo ripristina (pop) all’uscita dal sottoprogramma.
  1. Registri uso generale GPR (General Purpose Registers) a disposizione per la registrazione dei dati manipolati dal programma, normalmente noti come “variabili”.
  2. Registri funzione speciale SFR (Special Function Registers) impiegati dalla CPU per controllare il comportamento dei dispositivi del microcontrollore, come il Timer e le porte di I/O. Una ulteriore suddivisione riguarda i registri SFR:
    • tipo “core”: contengono informazioni che disciplinano il comportamento del sistema nel suo insieme;
    • tipo “periferica”: mantengono memorizzate le informazioni di configurazione delle periferiche interne.

Progetto e simulazione di automi

Ingressi, Uscite e stati

  • insieme variabili di ingresso: I(t);
  • insieme variabili di uscita: U(t);
  • insieme variabili di stato: X(t).
  • sezione di memoria: memorizza lo stato attuale;
  • sezione logica: prepara lo stato futuro;
  • sezione di temporizzazione (clock): sincronizza l’evoluzione.

Definizione e rappresentazione schematica formale

  • variabili di ingresso, appartenenti all’insieme I(t): sono le sollecitazioni esterne, che non sono prodotte dal sistema ma ne condizionano il funzionamento;
  • variabili di uscita, appartenenti all’insieme U(t): sono le grandezze interne del sistema che interessa osservare e utilizzare;
  • variabili di stato, appartenenti all’insieme X(t): sono le grandezze che descrivono le varie tappe dell’evoluzione del sistema.
  • automa di Moore: le uscite all’istante t dipendono solo dallo stato all’istante t (sistema proprio);
  • automa di Mealy: le uscite all’istante t dipendono dallo stato all’istante t e anche dagli ingressi all’istante t (linea tratteggiata, sistema improprio). Possiamo definire un livello maggiore di dettaglio, evidenziando la molteplicità di ingressi, uscite e stati, come nello schema espanso qui riportato.

Automazione Industriale

  • Binari (o linee) di potenza (power rail);
  • Contatti elettrici NA o NC;
  • Bobine di uscita (chiamate anche “relè” o “coil”);
  • Relè “interni” e “speciali”.
  • Contatori;
  • Temporizzatori;
  • Funzioni matematiche, logiche, di trattamento dati ecc. (le tipologie dipendono largamente dal modello di PLC utilizzato).

Struttura base di un programma LADDER

  • Ogni rung inizia obbligatoriamente dal binario di potenza sinistro, mentre il collegamento col binario di potenza di destra è spesso facoltativo (generalmente i software di programmazione effettuano di default questa connessione laddove è richiesta);
  • Ciascun rung può contenere contatti, bobine di uscita, blocchi funzione, relè di uscita interni o speciali ecc…

Contatti

  • Contatto NA: la corrente circola quando il contatto viene azionato (a riposo essa non circola);
  • Contatto NC: la corrente circola con il contatto in posizione di riposo (a contatto azionato essa non circola);

Bobine di uscita

  • uscite fisiche del PLC: in questo caso determinano lo stato del dispositivo di uscita corrispondente, attraverso il quale viene comandato il relativo attuatore;
  • Relè o aree di memoria interne al PLC: in questo caso hanno la funzione di memorizzare il risultato dell’elaborazione di un determinato rung di programma da utilizzare successivamente.
  • In ogni rung (che, ricordiamo, inizia sempre dal binario di potenza sinistro) può essere inserito un numero teoricamente illimitato di contatti, che possono essere connessi tra loro in modo da ottenere le funzioni logiche AND e OR:
  • Due o più contatti connessi in serie realizzano la funzione logica AND;
  • Due o più contatti connessi in parallelo realizzano la funzione logica OR.
  • Ogni rung termina generalmente con una sola bobina di uscita connessa al binario di potenza destro; le bobine non possono essere collegate tra loro in serie, ma si possono inserire più bobine di uscita in parallelo in modo che il rung le possa comandare contemporaneamente.
Esempio (dal manuale di programmazione del PLC Omron CP1L)

Contatori a decremento

  • Count input: viene connesso al dispositivo che manda gli impulsi al contatore (p. es. la fotocellula che rileva il passaggio di una persona attraverso una porta); ad ogni impulso presente sull’ingresso il contatore decrementa di 1 il valore corrente;
  • Reset input: viene connesso al comando che permette di resettare il contatore al valore iniziale (p. es. un pulsante).
  • Il numero del contatore al quale si fa riferimento (da 0 a 4095 per il CP1L);
  • Il valore iniziale di settaggio del contatore (da 0 a 9999).
  • Un impulso sull’ingresso reset input pone PV = S (PV: valore corrente del contatore);
  • Ad ogni impulso presente su count input PV viene decrementato di 1;
  • Quando PV = 0 il contatore si attiva, eccitando in questo modo la bobina ad esso collegata;
  • Il contatore può essere resettato in qualunque momento portando alto l’ingresso reset input.;
  • Se reset input viene mantenuto alto il conteggio è bloccato.

Contatori reversibili (Up/Down)

  • Increment input: conteggio in avanti (UP);
  • Decrement input: conteggio all’indietro (DOWN);
  • Reset input: reset del contatore al valore iniziale (SV);
  • (1) — Il valore corrente del contatore (PV) può “fluttuare” tra 0 ed il valore di settaggio (SV);
  • (2) — Nel conteggio UP il contatore incrementa di 1 ad ogni impulso: raggiunto il valore di settaggio si ha l’attivazione del contatore al successivo impulso che ne determina l’azzeramento;
  • (3) — Nel conteggio DOWN il funzionamento è del tutto simile a quanto detto sopra, con la differenza che il contatore decrementa di 1 ad ogni impulso.

Temporizzatori (Timer)

  • Il numero del timer N (da 0 a 4095);
  • Il valore di settaggio S, che determina il ritardo all’eccitazione.
  • (1) — Quando il segnale di input viene portato alto il valore corrente del timer inizia a decrementare partendo da S: quando PV raggiunge il valore 0 il timer si attiva e rimane in questo stato fino a che l’ingresso ritorna basso;
  • (2) — Se l’ingresso viene riportato basso prima dell’azzeramento di PV il timer viene resettato al valore iniziale senza che si abbia alcuna eccitazione.

Temporizzatori veloci (High Speed Timer)

Schemi Industriali cablati e con PLC

Cenni sul motore Asincrono Trifase

  • hanno uguale valore efficace e frequenza;
  • sono sfasate di 120° tra loro.

Struttura di principio

Funzionamento

Campo magnetico rotante

  • un campo HO con velocità di rotazione costante w e direzione oraria;
  • un campo HA con la medesima velocità di rotazione w ma direzione antioraria. Il legame tra la lunghezza del vettore risultante H e quella dei vettori componenti è:

Azionamento del motore asincrono trifase

  • contattore KM1 per la marcia avanti provvisto di:
    • tre contatti di potenza.
    • Un contatto ausiliario;
  • pulsante di marcia PM e pulsante di arresto PA.
    Gli elementi utilizzati nel circuito di potenza sono:
    • gruppo contatti KM1;
    • fusibili di protezione F1.
  1. Premendo il pulsante PM normalmente aperto viene alimentata la bobina di KM1.
  2. Il contatto ausiliario di KM1 posto in parallelo a PM mantiene la bobina alimentata, nonostante il rilascio di PM.
  3. La conseguente chiusura dei tre contatti di KM1 determina l’allacciamento della rete ai morsetti del motore e il conseguente avvio.
  4. L’interruzione dell’alimentazione può essere comandata tramite l’intervento su PA.
  • allo spunto mentre il motore è ancora fermo il campo magnetico rotante ruota già alla frequenza di alimentazione; questo scostamento elevato determina una elevata corrente di avviamento, fino a 10 volte quella nominale;
  • la coppia di spunto essendo di molto superiore alla coppia resistente determina un avvio rapido del motore ma non dolce;
  • le elevate punte di corrente sollecitano molto gli avvolgimenti, pertanto questo tipo di inserzione è utilizzato per potenze ridotte, dell’ordine di qualche kW.
  • teleruttore KM1: U = L1; V = L2; W = L3 rotazione in un senso;
  • teleruttore KM2: U = L3; V = L2; W = L1 rotazione in un senso opposto.
  • un secondo contatto ausiliario NC KM2 è posto in serie alla bobina KM1;
  • un secondo contatto ausiliario NC KM1 è posto in serie alla bobina KM2.

Trasformata e antitrasformata di laplace

  1. Si trasferisce il problema nel dominio delle trasformate;
  2. Lo si manipola applicando le diverse regole computazionali e lo si risolve;
  3. Si antitrasforma la soluzione restituendo la soluzione nel dominio del tempo
  • tabella minima delle principali trasformate e dimostrazioni;
  • teoremi della trasformata.

Ricavare nuove Trasformate dalla tabella minima e dai Teoremi

Applicazione della trasformata alla risoluzione di equazioni differenziali

Antitrasformata di Laplace

Metodo di scomposizione mediante sistema

  1. Si esprime la funzione come somma di frazioni; ciascuna frazione è costituita al denominatore da uno dei termini di primo grado del denominatore della U(s), mentre al numeratore presenta un valore costante. Il problema è la determinazione delle costanti che rendono equivalenti le due forme prima e dopo l’uguale: