L'ambiente di sviluppo QVIEW (QMOVE Viewer), il linguaggio QCL (QEM Control Language) e il linguaggio LADDER (logica contatto), sono gli strumenti necessari per lo sviluppo, il debug e la modifica dei progetti per il sistema QMOVE. La potenzialità di questa combinazione di hardware e software permette di sviluppare controlli per l'automazione industriale, con particolare riguardo alla gestione della movimentazione (elettrica, idraulica, CNC o ON / OFF).
Come ogni linguaggio strutturato e compilato, anche il QCL ed il Ladder necessita di un editor per digitare le righe di codice e di un compilatore che le traduca in linguaggio macchina controllandone la sintassi; QVIEW è l’ambiente di sviluppo che, oltre a supportare il linguaggio QCL ed il linguaggio Ladder, permette di trasferire il programma nella CPU del sistema QMOVE, di monitorare e modificare tutte le variabili ed i parametri del programma ed eventualmente interromperne l’esecuzione per comprendere e correggere eventuali funzionamenti non desiderati (DEBUG).
Il QCL è un linguaggio di tipo strutturato la cui sintassi e i cui comandi risulteranno familiari a chi si occupa già di programmazione o che comunque ha avuto modo di fare esperienza con un linguaggio ad alto livello. Chi invece si addentra per la prima volta nel mondo dei linguaggi strutturati potrà trovare in questo manuale un valido supporto di apprendimento.
Il Ladder è un linguaggio a contatti logici il cui uso sarà familiare a chi si occupa di programmazione PLC. Chi invece si addentra per la prima volta nel mondo ladder dovrà provvedere ad integrare il presente manuale con un corso PLC generico.
I device sono delle funzionalità messe a disposizione del programmatore. Essi svolgono le funzioni tipiche dell’automazione industriale, dalla lettura di un ingresso analogico, alla lettura di un segnale proveniente da un traduttore di posizione, fino ad eseguire dei veri e propri posizionamenti di assi. Ogni device è dotato di un manuale specifico, si rimanda perciò alla documentazione relativa.
Una applicazione di prodotti QEM in una automazione industriale può aver bisogno sia di un progetto sviluppato in Qview (per il controllo e l'automazione) e sia di un progetto per tutto quello che riguarda l'interfaccia con l'operatore. QPaint è l'ambiente per lo sviluppo dell'interfaccia grafica per i terminali operatore QEM. I due progetti sono legati tra di loro perché fanno riferimento alla stessa struttura dati (variabili, array, ecc.).
In questa sezione verrà introdotto l’ambiente di sviluppo (QVIEW) presentando un semplice esempio. L'esempio è un supporto alla sperimentazione pratica durante l’apprendimento.
Le fasi fondamentali che verranno sviluppate possono essere riassunte in:
QVIEW 6.0 è uno dei software del pacchetto QWorkbench. Una volta installato e avviato il QVIEW 6.0, la schermata iniziale appare come in Figura 1.
Figura 1: Primo avvio |
Per creare un nuovo progetto devi selezionare:
e scrivere il nome del progetto come “FirstApp”. Viene visualizzata la finestra per avere alcune informazioni sul progetto. Per ora è possibile lasciare perdere. Sarà possibile compilare questo modulo in un secondo momento. Ora è possibile salvare il progetto per creare il file di progetto. Seleziona:
e scegliere una directory dove vuoi salvare il progetto. Ora bisogna creare le due units fondamentali per creare un progetto minimale che possa essere compilato. Selezionare:
lasciare il Unit Name come CONFIG e premere OK. Come si vede una nuova unit è apparsa nell'area bianca e una finestra di editor è apparsa nella Work Area. In questa nuova finestra sarà possibile vedere le linee di codice che compongono la unit. Andiamo ora a modificare questa unit. La Configuration Unit è unica nel progetto (non ne possono essere aggiunte altre di questo tipo) ed è utilizzata per dichiarare le variabili o le strutture dati del progetto, per dichiarare quali device si vogliono usare e per dichiarare per quale tipo di hardware si sta sviluppando il progetto.
In questo momento è necessario sapere che la unit di configurazione è dove:
Ora é necessario inserire alcuni cambiamenti della unit di configurazione. Cercare la parola chiave SYSTEM nella unit (è possibile usare lo strumento di ricerca con CTRL+F). Verrà trovato questo codice:
;------------------------------------------------------------------- ; SYSTEM variables definitions ;------------------------------------------------------------------- SYSTEM
cambiare nel modo seguente:
;------------------------------------------------------------------- ; SYSTEM variables definitions ;------------------------------------------------------------------- SYSTEM count L ;This is a variable use as a counter
Con questa sintassi è stata dichiarata la variabile count, il suo tipo è L (Long) e essa appartiene al gruppo SYSTEM.
Tutte le linee di codice che iniziano con “;” sono commenti del programmatore. Esse non hanno effetto esecutivo sul progetto. |
---|
Un'altra operazione è l'indicazione della composizione del QMOVE sistema. Prima di tutto bisogna cercare la parola chiave BUS.
;------------------------------------------------------------------- ; BUS configuration ;------------------------------------------------------------------- BUS
Cambiare come segue:
;------------------------------------------------------------------- ; BUS configuration ;------------------------------------------------------------------- BUS 1 1P51 30 2 . . 3 1MG8F . 4 . .
Queste righe di codice dipendono dal tipo di hardware per cui sta sviluppando il progetto. Nella documentazione di installazione del controllo qmove in uso, è possibile ottenere le informazioni relative alla configurazione della sezione BUS.
Aggiungere una nuova unit al progetto. Seleziona:
lasciare il nome della unit a UNIT1 e premere OK. Otterremo una seconda unit con il seguente codice già scritto:
MAIN: WAIT 1 JUMP MAIN END
cambiare in questo modo:
MAIN: count = count + 1 WAIT 1 JUMP MAIN END
Le unit di questo tipo possono essere più di una in un progetto. Il codice compreso tra l'etichetta MAIN e l'istruzione JUMP MAIN è ripetuto continuamente come in un ciclo infinito. La linea di codice count = count + 1 incrementa di 1 il valore della variabile count ad ogni ciclo.
Prima di trasferire il progetto nella CPU, bisogna sempre compilarlo. E' possibile avviare la compilazione dal menù:
Alla fine della compilazione, alcuni messaggi ti informeranno dei risultati ottenuti. Nell'esempio che abbiamo appena creato il risultato non dovrebbe avere errori e quindi otterremo Project compiling OK!.
Prima di poter aprire il collegamento è necessario che sia attivo il gestore delle risorse QRM (Qem Resurces Manager). Si trova tra le icone in basso a sinistra della barra degli strumenti di Windows. La sua icona è . Se questa icona è presente significa che il QRM è attivo. Altrimenti sarà necessario avviarlo trovandolo nel pacchetto QWorkbench.
La connessione può avvenire sia via seriale tramite il convertitore IQ009 convertitore IQ009, sia tramite il collegamento tra la porta Ethernet del PC e la porta Ethernet del Qmove (per i modelli che ne sono provvisti).
Per poter trasferire il progetto compilato alla CPU bisogna connettere il PC al sistema QMOVE. Selezionare:
Appare la finestra “Connection Resources”. Cliccare con il tasto destro su Serial Com e selezionare Edit Resource Property….
Per un semplice collegamento seriale è necessario solo assicurarsi che il numero della porta COM sia corretto. Per quanto riguarda la velocità di comunicazione, lasciare per ora AUTODETECT.
Per un collegamento Ethernet invece è necessario selezionare TCP/IP e specificare il TCP/IP Host & Port con il suo indirizzo IP e il numero della porta a 5001. Per configurare il QMOVE con uno specifico indirizzo IP si deve usare una delle utility installate nel QWorkbench: QConfigurator-1 oppure QConfigurator-2.
Ora fare un doppio click sulla risorsa da usare per il collegamento e il messaggio No connection sulla barra in basso dovrebbe cambiare in Connected with… seguito dal codice del modello hardware utilizzato.
In questo momento si è pronti per trasferire il progetto compilato nella CPU. Selezionare:
e il progetto verrà trasferito. Durante il trasferimento una finestra informa sullo stato del trasferimento.
Il sistema ora è pronto per mettere in esecuzione l’applicativo appena scaricato. Seleziona:
Appare la finestra
si noti che la finestra presenta il messaggio Mode READY.
Selezionando il comando
l’applicativo scaricato viene messo in esecuzione; lo stato della CPU diventa RUN. Cliccare ora sul tasto e inserire un nuovo Watches Panel con il nome Counter Monitor (oppure un nome a scelta del programmatore). Nella prima riga del Watches Panel inserire il nome dell'unica variabile del nostro progetto count.
Quando la CPU è in RUN vedremo il valore della variabile che si incrementa.
Le dichiarazioni possibili in un progetto per QMOVE possono essere le seguenti:
Queste dichiarazioni possono avvenire
I simboli sono i nomi assegnati alle variabili, array, datagroup, costanti, input o output.
Per distinguere tra loro le varie dichiarazioni si utilizzano delle parole chiavi poste prima di ogni gruppo di dichiarazioni. Le parole chiavi sono:
La unit di configurazione è una componente di un progetto per QMOVE; c'é un'unica unit di configurazione in un progetto.
La unit di configurazione serve come contenitore di dichiarazioni di alcune variabili e di alcune le costanti utilizzate nell’applicativo; inoltre viene anche definita la composizione hardware del sistema QMOVE adottato, specificando il tipo di scheda CPU e il modello delle schede presenti.
Le variabili, array, datagroup, device e costanti dichiarati nella unit di configurazione sono disponibili per tutto il progetto. Possono essere visibili (e quindi leggibili e scrivibili) da tutte le altre unit che compongono il progetto.
Le altre unit che compongono un progetto per QMOVE possono essere più di una e hanno lo scopo di contenere il codice operativo che determina la logica di funzionamento del progetto stesso. Inoltre all'inizio di queste unit è possibile fare lo stesso tipo di dichiarazioni che si possono fare nella unit di configurazione (tranne la dichiarazione della composizione dell'hardware e la dichiarazione degli ingressi e uscite digitali).
Le variabili, array, datagroup dichiarate nelle unit operative possono essere dotate di una proprietà di accessibilità aggiuntiva. Normalmente quando si dichiara una variabile in una unit operativa essa può essere utilizzata solamente in quella unit. In fase di dichiarazione è possibile, però, assegnare ad essa una proprietà aggiuntiva:
In seguito descriveremo tutte le informazioni che è necessario conoscere per poter dichiarare le variabili.
Nella descrizione della sintassi le parti tra <…> sono obbligatorie. Le parti tra […] sono opzionali, mentre le parti separate da “/” sono da considerarsi “usare uno di questi”. |
---|
Il carattere punto e virgola (“;”) ha lo scopo di identificare una riga di commento. Tutto il testo inserito dopo questo carattere non verrà considerato. Il carattere punto e virgola vale solo per la linea in cui è inserito. |
QCL prevede cinque tipi principali di dato:
Il dato di tipo FLAG è utilizzato per la definizione di variabili booleane che hanno un range di valori interi compreso tra 0 e 1. L’occupazione della memoria da parte delle variabili di questo tipo dipende dal loro numero.
La sintassi per la definizione di una variabile di tipo FLAG è la seguente:
<variable name> F [OUT/IN/INOUT] [;comment]
Il dato di tipo BYTE è utilizzato per la definizione di variabili che hanno un range di valori interi compreso tra -128 e +127; ogni variabile occupa un byte di memoria.
La sintassi per la definizione di una variabile BYTE è la seguente:
<variable name> B [OUT/IN/INOUT] [;comment]
Il dato di tipo WORD è utilizzato per la definizione di variabili che hanno un range di valori interi compreso tra -32768 e +32767; ogni variabile occupa due byte di memoria.
La sintassi per la definizione di una variabile WORD è la seguente:
<variable name> W [OUT/IN/INOUT] [;comment]
Il dato di tipo LONG è utilizzato per la definizione di variabili che hanno un range di valori interi compreso tra -2147483648 e +2147483647; ogni variabile occupa quattro byte di memoria. La sintassi per la definizione di una variabile LONG è la seguente:
<variable name> L [OUT/IN/INOUT] [;comment]
Il dato di tipo SINGLE è un valore a virgola mobile come definito dalla specifica IEEE 754 single precision.
La sintassi per la definizione di una variabile SINGLE è la seguente:
<variable name> S [OUT/IN/INOUT] [;comment]
Il dato di tipo DOUBLE è un valore a virgola mobile come definito dalla specifica IEEE 754 double precision.
La sintassi per la definizione di una variabile DOUBLE è la seguente:
<variable name> D [OUT/IN/INOUT] [;comment]
Assegnando ad una variabile un valore esterno al range consentito si verifica la condizione di overflow. |
---|
Tipo dato | Codice | Spazio occupato memoria (Bit) | Intervallo |
FLAG | F | 1 | 0 ÷ 1 |
BYTE | B | 8 | -128 ÷ 127 |
WORD | W | 16 | -32768 ÷ 32767 |
LONG | L | 32 | -2147483648 ÷ 2147483647 |
SINGLE | S | 32 | Vedi specifica IEEE 754 single precision |
DOUBLE | D | 64 | Vedi specifica IEEE 754 double precision |
Gli identificatori sono dei nomi tramite i quali è possibile fare dei riferimenti ad oggetti o ad etichette. Ogni identificatore è formato da uno o più caratteri alfanumerici tenendo presente che il primo deve essere una lettera. I caratteri alfanumerici possono essere riassunti in:
- dalla “A” alla “Z”
- dalla “a” alla “z”
- da “0” a “9”
- “_”
I nomi vengono usati per agevolare l'identificazione di un oggetto all'interno del sistema QMOVE. Per oggetto si intende qualsiasi entità gestibile a livello di linguaggio e provvista di caratteristiche fisiche proprie come ad esempio: variabili, ingressi, uscite e devices. In Qview 6.0 i nomi sono limitati ad una lunghezza massima di 64 caratteri.
Una costante è un carattere o una stringa di caratteri utilizzabile come valore in un progetto. Le costanti vengono dichiarate in seguito alla parola chiave CONST. Viene riportata la sintassi per la definizione di costanti:
CONST <nome costante> <valore> [OUT] [;comment]
dove:
CONST | Parola chiave che indica la definizione delle costanti. |
<nome costante> | Nome della costante. |
<valore> | valore associato alla costante. |
[OUT] | Si può usare in una dichiarazione all'interno di una unit operativa quando si vuole rendere accessibile in lettura la costante anche alle altre unit operative. |
[;comment] | Il commento non è obbligatorio ma consigliato per una miglior lettura del software |
Un esempio di dichiarazione di alcune costanti è:
CONST TM_SECOND 1000 OUT ;These are the number of milliseconds in a second. DIM_ARRAY 7 OUT ;Used as array dimension. DIM_PROG 10 ;Used as number of recipe. DIM_STEP 5 ;Used as number of step for each recipe.
Le variabili SYSTEM mantengono il loro valore anche allo spegnimento del sistema. |
---|
Con il nome SYSTEM vengono raggruppate tutte le variabili ritentive; possono essere di tipo FLAG, BYTE, WORD, LONG o SINGLE. Devono essere poste in seguito alla parola chiave SYSTEM. La sintassi per la definizione di variabili SYSTEM.
SYSTEM <nome variabile> <F/B/W/L/S> [OUT/IN/INOUT] [;comment]
dove:
SYSTEM | Parola chiave che indica la definizione di variabili SYSTEM. |
<nome variabile> | Nome della variabile SYSTEM. |
<F/B/W/L/S> | Tipo della variabile e può essere. |
[OUT/IN/INOUT] | Tipo di accessibilità. |
[;comment] | Il commento è consigliato per una miglior lettura del software. |
Esempio:
SYSTEM count L ;This is used as a counter. sbSeconds B OUT ;Seconds sbMinutes B OUT ;Minutes swHours W ;Hours
Le variabili GLOBAL hanno la caratteristica di venire azzerate ad ogni accensione del sistema |
---|
Con il nome GLOBAL vengono raggruppate tutte le variabili non ritentive; possono essere di tipo FLAG, BYTE, WORD, LONG e SINGLE. Vengono dichiarate in seguito alla parola chiave GLOBAL. Viene riportata la sintassi per la definizione di variabili GLOBAL.
GLOBAL <nome variabile> <F/B/W/L/S> [OUT/IN/INOUT] [;comment]
dove:
GLOBAL | Parola chiave che indica per la definizione di variabili GLOBAL. |
<nome variabile> | Nome della variabile GLOBAL. |
<F/B/W/L/S> | Tipo della variabile. |
[OUT/IN/INOUT] | Tipo di accessibilità. |
[;comment] | Il commento è consigliato per una miglior lettura del software. |
Esempio:
GLOBAL gfMyFlag F OUT ;Non retentive flag variable gbYourByte B IN ;Non retentive byte variable gwHisWord W INOUT ;Non retentive word variable glYourLong L IN ;Non retentive long variable gsTheirSingle S OUT ;Non retentive single precision variable
Una variabile Array System è un insieme di variabili ritentive dello stesso tipo. Esse hanno la stessa dimensione ed è possibile accedere ad esse tramite un nome comune e riferendosi ad uno specifico elemento tramite un indice. Non sono previsti array di variabili tipo FLAG.
Come le SYSTEM sono variabili ritentive e devono essere dichiarate di seguito alla parola chiave ARRSYS.
Viene riportata la sintassi per la definizione di variabili ARRAY SYSTEM.
ARRSYS <nome variabile> <B/W/L/S> <numero_elementi> [OUT/IN/INOUT] [;comment]
dove:
GLOBAL | Parola chiave che per la definizione di variabili ARRAY SYSTEM. |
<nome variabile> | Nome della variabile ARRAY SYSTEM. |
<B/W/L/S> | Tipo della variabile e può essere |
<numero_elementi> | Numero di elementi che compongono la variabile. |
[OUT/IN/INOUT] | Tipo di accessibilità. |
[;comment] | Il commento è consigliato per una miglior lettura del software. |
Il numero massimo di elementi consentiti in un array è di 65535. Non si possono indicare dimensioni negative o dimensioni con parte decimale. Come dimensione dell’array è possibile usare delle costanti già definite nella sezione CONST; se questa avesse valore decimale verrà troncato: ad esempio il valore 200.34 viene forzato a 200.
Esempio:
ARRSYS asbMyArray B 10 INOUT ;Array system declaration of 10 bytes in size. aslYourArray L DIM_ARRAY IN ;Array system declaration of DIM_ARRAY bytes in size.
Si osservi che nel secondo array si è usata una costante per la dichiarazione della dimensione.
Una variabile Array Global è un insieme di variabili non ritentive dello stesso tipo. Esse hanno la stessa dimensione ed è possibile accedere ad esse tramite un nome comune, riferendosi ad uno specifico elemento tramite un indice. Non sono previsti array di variabili tipo FLAG.
Come le GLOBAL sono variabili non ritentive e devono essere dichiarate di seguito alla parola chiave “ARRGBL”.
Viene riportata la sintassi per la definizione di variabili ARRAY GLOBAL:
ARRGBL <nome variabile> <B/W/L/S> <numero_elementi> [OUT/IN/INOUT] [;comment]
dove:
ARRGBL | Parola chiave per la definizione di variabili ARRAY GLOBAL. |
<nome variabile> | Nome della variabile ARRAY GLOBAL. |
<B/W/L/S> | Tipo della variabile e può essere. |
<numero_elementi> | Numero di elementi che compongono la variabile. |
[OUT/IN/INOUT] | Tipo di accessibilità. |
[;comment] | Il commento è consigliato per una miglior lettura del software. |
Esempio:
ARRGBL arwMyArray W 15 OUT ;Array global declaration of byte of 15 dimension.
Sono variabili utilizzate per realizzare temporizzazioni alle quali può essere assegnato un valore intero (espresso in ms) che rappresenta il tempo che deve trascorrere (dal momento dell’assegnazione); in lettura è disponibile lo stato di “temporizzazione terminata” (1) o “temporizzazione in corso” (0).
Le variabili timer vengono dichiarate in seguito alla parola chiave “TIMER”.
La sintassi per la definizione di variabili TIMER è:
TIMER <timer name> [OUT/IN/INOUT] [;comments]
dove:
TIMER | Parola chiave per la definizione di variabili TIMER. |
<timer name> | Nome della variabile TIMER. |
[OUT/IN/INOUT] | Tipo di accessibilità. |
[;comment] | Il commento è consigliato per una miglior lettura del software. |
Esempio:
TIMER tTimer1 INOUT ;First timer. tTimer2 OUT ;Second timer. tSeconds OUT ;3rd timer. tDelay INOUT ;4th timer.
Quando la variabile timer si trova a sinistra dell’assegnazione si definisce il caricamento di un valore sul timer (valore espresso in millisecondi):
tMyTimer = 1000 ;Set timer tMyTimer to 1 second.
Quando la variabile timer si trova a destra dell’assegnazione o all’interno di una espressione ne viene letto lo stato (0 = Temporizzazione in corso, 1 = Temporizzazione terminata):
gfIsTimerEnd = tMyTimer ;Assign to gfIsTimerEnd variable the timer state.
oppure
IF(tMyTimer) ;If timer tMyTimer has passed exec the code ;Put here the code ..... ENDIF
È, inoltre, possibile leggere il valore del tempo rimanente prima dello scadere del timer (il valore restituito è espresso in millisecondi):
< Timer Name >.remain
Esempio:
glRemainTime = tMyTimer.remain
Sono tutte le variabili che fanno riferimento ad ingressi od uscite digitali. La loro dichiarazione deve essere posta in seguito alle parole chiave INPUT per gli ingressi o OUTPUT per le uscite.
Gli ingressi e uscite digitali possono essere dichiarati solamente nella unit di configurazione. |
---|
La sintassi per la definizione di variabili INPUT ed OUTPUT è:
INPUT <variable name> <F/B/W> <io address> OUTPUT <variable name> <F/B/W> <io address>
Gli I/O address sono disponibili sulle schede tecniche hardware delle schede utilizzate. |
---|
dove:
INPUT | Parola chiave per la definizione di variabili INPUT. |
OUTPUT | Parola chiave per la definizione di variabili OUTPUT. |
<variable name> | Nome della variabile, cioè il simbolo associato all'ingresso o uscita. |
<F/B/W> | Tipo della variabile |
<io address> | Indirizzo dell’INPUT o OUTPUT così composto: Slot number.name: Slot number è il numero dello slot nel quale è posta la scheda con la risorsa hardware. name: è il nome che fa riferimento all’indirizzo fisico dell’I/O (definito nei riferimenti hardware). |
Un’applicazione interessante degli ingressi e delle uscite digitali è quello del raggruppamento degli stessi in un unico identificatore. Questo identificatore è analogo ad una variabile di otto o sedici bit dove ogni ingresso o uscita digitale rappresenta un bit.
Esempio:
INPUT ibInput B 3.INPB ;8 digital input grupped in a single byte
OUTPUT obOutput B 3.OUTB ;8 digital output grupped in a single byte
Se si dispone di schede con più di otto ingressi o uscite digitali Esempio:
INPUT ibInput1 B 3.INPB1 ;First 8 digital input grupped in a byte (1÷8). ibInput2 B 3.INPB2 ;Second 8 digital input grupped in a byte (9÷16). iwInput W 3.INPW ;A word of 16 digital input grupped in a word (1÷16).
OUTPUT obOutput1 B 3.OUTB1 ;First 8 digital output grupped in a byte 8 (1÷8). obOutput2 B 3.OUTB2 ;Second 8 digital output grupped in a byte 8 (9÷16). owOutput B 3.OUTW ;A word of 16 digital output grupped in a word (1÷16).
Le variabili Datagroup sono una particolare struttura di dati, memorizzate in una zona ritentiva. Esse vengono dichiarate nella unit di configurazione e sono idonee per rappresentare un archivio di ricette.
Le variabili Datagroup contengono due tipologie di variabili:
DATAGROUP <DataGroup Name> DATAPROGRAM <number of recipes> ;Static variables declaration <variable name> <F/B/W/L/S> <variable name> <F/B/W/L/S> <variable name> <F/B/W/L/S>
Le variabili statiche risiedono nel sottosettore di DATAGROUP nominato come DATAPROGRAM. Il primo valore di questo settore è un numero o una costante intera, e indica il numero di ricette dell'archivio. Le variabili statiche sono da considerarsi come contenitori di un determinato valore per ogni ricetta, e sono accessibili come un array, dove l'indice è il numero di ricetta desiderata. Esempio:
DATAGROUP Name DATAPROGRAM 100 ;Static variables declaration Variable1 L Variable2 S Variable3 F
Per far riferimento alla variabile Variable3 della ricetta 5, viene usato il codice:
Variable3[5]
Possiamo immaginare la struttura della memoria di una variabile DATAGROUP, nel nostro esempio con variabili statiche, come la seguente tabella:
Variable1 | Variable2 | Variable3 | |
---|---|---|---|
Ricetta 1 | |||
Ricetta 2 | |||
Ricetta 3 | |||
… | |||
Ricetta 100 |
DATAGROUP <DataGroup Name> DATAPROGRAM <number of recipes> STEP <number of steps> ;Indexed variables declaration <variable name> <F/B/W/L/S> <variable name> <F/B/W/L/S> <variable name> <F/B/W/L/S>
Le variabili indicizzate risiedono nel sottosettore di DATAGROUP nominato come STEP. La loro funzione è quella di introdurre per ogni ricetta, il concetto di passo. Il primo valore di questo settore è un numero o una costante intera, e indica il numero di passi per ogni ricetta dell'archivio. Le variabili indicizzate sono da considerarsi come contenitori di una lista di valori per ogni ricetta, e sono accessibili come un array a 2 dimensioni, dove il primo valore è il numero di ricetta, il secondo il passo desiserato. Esempio:
DATAGROUP Name DATAPROGRAM 100 ;Static variables declaration Variable1 L Variable2 S Variable3 F STEP 10 ;Indexed variables declaration Variable4 W Variable5 B
Per far riferimento alla variabile Variable4 della ricetta 5 al passo 9, viene usato il codice:
Variable4[5, 9]
Possiamo immaginare la struttura della memoria di una variabile DATAGROUP, nel nostro esempio con variabili statiche e indicizzate, come la seguente tabella:
Variable1 | Variable2 | Variable3 | Variable4 | Variable5 | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Ricetta 1 | |||||||||||||
Ricetta 2 | |||||||||||||
Ricetta 3 | |||||||||||||
… | |||||||||||||
Ricetta 100 | |||||||||||||
Altre informazioni:
La sezione BUS nell’unità di configurazione è indispensabile per dichiarare quale modello hardware di QMOVE il programmatore ha a disposizione.
In base al modello hardware dichiarato è possibile anche avere a disposizione le sue risorse hardware come per esempio il numero di ingressi e uscite digitali, il numero di ingressi e di uscite analogiche oppure il numero di ingressi di conteggio. Il QMOVE può inoltre essere dotato anche di altre risorse come interfacce seriali o lettori di memoria removibile.
La dichiarazione da inserire nella sezione BUS si suddivide in slot.
Nello slot 1 si indica quale è la CPU utilizzata mentre negli slot successivi servono per dichiarare quali schede elettroniche sono installate nel modello. Ogni scheda è individuata da una parola chiave che ne identifica tipologia di hardware. Le parole chiavi sono reperibili nei manuali installazione e manutenzione dell’hardware utilizzato.
La sintassi da utilizzare è:
BUS 1 <ID_CPU> <FW> [2 <ID_CARD> .] [3 <ID_CARD> .] [4 <ID_CARD> .]
Esempio:
BUS 1 1P51F 30 ;QMOVE J1-P51F with firmware 30 2 . . ;No card is installed in this slot 3 1MG8F . ;This card has 32 digital input, 32 digital output, 6 analog output, ecc.
L'argomento relativo alla visibilità dei simboli dichiarati all'interno del progetto è molto importante. Vale la pena di riprenderlo con cura in questo capitolo dedicato ad esso.
Come abbiamo detto in precedenza, è possibile dichiarare i seguenti gruppi
CONST SYSTEM GLOBAL ARRSYS ARRGBL TIMER INPUT OUTPUT INTDEVICE
sia nella unit di configurazione che nelle altre unit che compongono il progetto. Gli altri gruppi di dichiarazioni
BUS REFERENCES
Possono essere presenti solamente nella unit di configurazione.
Come vedete è apparsa la parola chiave REFERENCES che merita una spiegazione approfondita alla fine di questo capitolo. |
---|
Nella seguente figura è rappresentato schematicamente dove è possibile trovare i vari gruppi di dichiarazione in un progetto.
I simboli dichiarati nella unit di configurazione hanno una visibilità estesa a tutte le unit del progetto. Facciamo l'esempio di dichiarare una variabile del gruppo SYSTEM:
SYSTEM ConfigurationVariable L ;This variable is declared in the configuration unit
Questa variabile potrà essere utilizzata in qualsiasi altra unit presente nel progetto sia per assegnare ad essa un valore (scrittura) sia per essere usata come valore all'interno di una espressione (lettura).
ConfigurationVariable = 5 ;Assign the value 5 to the variable Unit1Variable = ConfigurationVariable * 2 ;Assign twice variable value to another variable
In realtà la notazione completa per riferirsi alla variabile ConfigurationVariable è la seguente:
APPLICATION.ConfigurationVariable
La radice APPLICATION. può essere omessa e spiegheremo in seguito quando usarla.
I simboli che vengono dichiarati all'interno delle unit che contengono il codice operativo, prima della parola chiave BEGIN, hanno una visibilità diversa. Per esempio la seguente variabile:
GLOBAL local_variable W ;This variable is declared in a unit BEGIN ... ;Here are the code lines
è visibile solamente all'interno della unit in cui viene dichiarata. Nessuna altra unit potrà accedere a questa variabile né in lettura né in scrittura. Essa è considerata una variabile locale nel senso che viene dichiarata per scopi che si esauriscono nella stessa unit. E' possibile che un'altra unit contenga una dichiarazione di una variabile con lo stesso nome. Non sarà possibile infatti incorrere in equivoci perché quando si usa il simbolo local_variable in una unit, è chiaro che ci si riferisce sempre alla variabile locale e non a quella di un'altra unit.
Aggiungendo dei particolari attributi alla dichiarazione di una variabile, è possibile creare un'interfaccia verso l'esterno della unit in cui è dichiarata. Questi attributi sono
Se per esempio ampliamo il precedente esempio:
GLOBAL InputVariable L IN ;This variable is like an input OutputVariable L OUT ;This variable is like an output InOutVariable L INOUT ;This variable is both an input and an output local_variable W ;This variable is declared in a unit BEGIN ... ;Here are the lines code
otteniamo una interfaccia della unit verso le altre unit.
La variabile InputVariable viene vista dalla unit come un input e quindi essa non potrà essere modificata internamente ma solamente utilizzata per il suo valore. In pratica è una variabile in sola lettura per la unit che la dichiara.
Come si vede dalla figura, le altre unit (Unit2) possono accedere ad essa se specificano quale è la unit a cui la variabile appartiene:
Unit1.InputVariable = 1
In questo modo ci potranno essere unit che hanno la stessa o le stesse variabili con proprietà IN. Non potranno esserci equivoci perché ogni variabile appartiene a unit con nomi differenti.
La variabile OutputVariable è un output per la unit che la dichiara. Essa quindi è il risultato di una elaborazione interna alla unit ed è usata per fornire alle altre unit questo risultato. La variabile dichiarata con questa proprietà è in sola lettura per tutte le altre unit.
Come si vede dalla figura, le altre unit (Unit2) possono utilizzare il valore della variabile OutputVariable solo se specificano prima il nome della unit a cui la variabile appartiene:
IF Unit1.OutputVariable ... ENDIF
La variabile InOutVariable è sia un IN che un OUT. Tale variabile può essere modificata sia dalla unit che la dichiara sia dalle altre unit.
Anche in questo caso le altre unit (Unit2) possono utilizzare la variabile della Unit1 specificando prima del suo nome anche il nome della unit a cui appartiene:
IF Unit1.OutputVariable EQ 0 Unit1.OutputVariable = 1 ... ENDIF
Abbiamo già detto che la notazione completa per identificare le variabili dichiarate nella unit di configurazione è
APPLICATION.<variable name>
E' necessario usare la radice APPLICATION. prima del nome della variabile quando ci possono essere fonti di equivoco. Infatti se venisse dichiarata la variabile HomePosition nella unit di configurazione e un'altra variabile con lo stesso nome in Unit1, ciò sarebbe fonte di equivoco.
Per questo motivo quindi si deve usare la notazione
APPLICATION.HomePosition
e
Unit1.HomePosition
a seconda di chi ci si riferisce.
Un diverso attributo che può essere assegnato ad un simbolo al momento della dichiarazione è il REFERENCE. In questo caso il simbolo che viene dichiarato come REFERENCE è semplicemente un riferimento ad una variabile dichiarata in un altro punto (tipicamente nella unit di configurazione). La dichiarazione di questi speciali simboli sarà composta di due fasi
Per esempio:
Nella Unit1
GLOBAL MachineState B REFERENCE
Nella unit di configurazione
GLOBAL GeneralState B ... REFERENCES Unit1.MachineState = GeneralState
La variabile GeneralState è un simbolo generico che viene associato alla variabile dichiarata localmente in Unit1 e chiamata MachineState. I riferimenti devono essere sempre stabiliti tra simboli dello stesso tipo. E' possibile creare dei riferimenti per tutti i tipi di dichiarazioni (SYSTEM, GLOBAL, ARRSYS, ARRGBL, INPUT, OUTPUT, INTDEVICE, TIMER).
La dichiarazione di INTDEVICE, INPUT, OUTPUT può avvenire solamente come REFERENCE.
Anche le costanti possono essere dichiarate nelle unit che contengono il codice operativo. Se la dichiarazione avviene in questo modo nella Unit1 per esempio:
CONST MAX_PROGRAM_NUMBER 100 ;local constant ... BEGIN ...
la costante MAX_PROGRAM_NUMBER potrà solamente essere usata internamente alla unit che la dichiara. Se invece la dichiarazione è come la seguente:
CONST MAX_PROGRAM_NUMBER 100 OUT ;Output constant ... BEGIN ...
allora la costante MAX_PROGRAM_NUMBER sarà visibile anche dalle altre unit. Vale sempre e comunque la regola che le altre unit potranno accedere a questa costante in questo modo:
Unit1.MAX_PROGRAM_NUMBER
Il QCL (QEM Control Language) è un linguaggio nato appositamente per la programmazione del sistema QMOVE. Le caratteristiche principali del QCL sono la semplicità (poche ma potenti istruzioni), la facilità d’uso (somiglianza con il linguaggio BASIC) e l’orientamento verso l’automazione industriale grazie alle istruzioni appositamente studiate per il controllo assi.
Nel linguaggio QCL vengono messi a disposizione tutti gli operatori elementari per la manipolazione dei dati.
L'operatore di assegnamento può essere utilizzato all'interno di una qualunque espressione e può agire su tutte le variabili, sia elementari che appartenenti a DataGroup o a parametri Device. La forma generica di un'istruzione di assegnamento è la seguente:
<variable name> = <expression>
Se la dimensione della variabile variable name è inferiore alla dimensione del risultato dell'espressione il valore viene troncato, secondo le regole della conversione di tipo (vedi appendice dedicata).
Gli operatori aritmetici sono
Questi operatori agiscono su tutti i tipi di dato e sulle loro combinazioni (compresi i bit).
Esempio:
sbVar01 = slVar02 + swVar03 slVarxy = glVarA * glVarB sl01 = ss02 % ss03
Gli operatori logici (AND, OR e NOT) possono agire su tutte le variabili tranne quelle a singola precisione. La loro funzione è riassunta dalla seguente tabella.
Negli esempi il valore 1 indica semplicemente che la variabile è diversa da 0. |
---|
a b | a AND b | a OR b | NOT a |
0 0 | 0 | 0 | 1 |
0 1 | 0 | 1 | 1 |
1 0 | 0 | 1 | 0 |
1 1 | 1 | 1 | 0 |
Esempi
glBit01 = glBit02 AND gfBit03 glBitA = NOT glBitB
Gli operatori binari
agiscono su tutti i tipi di variabili compresi i SINGLE (previa conversione automatica in intero). Questi operatori realizzano la stessa tabella di verità che regola le equivalenti operazioni logiche, con la differenza che agiscono sui singoli bit.
(a)10 | (b)10 | (a)2 | (b)2 | a ANDB b | a ORB b | NOTB a | a XORB b |
3 | 2 | 011 | 010 | 010 | 011 | 100 | 001 |
7 | 5 | 111 | 101 | 101 | 111 | 000 | 010 |
Esempio
swVar01 = gwVar02 ANDB gwVar03
Permettono di valutare le relazioni che intercorrono tra i valori. Il linguaggio QCL definisce cinque operatori relazionali.
EQ | uguale a (equal) |
NEQ | non uguale a (not equal) |
LT | minore di (lower than) |
LE | minore o uguale a (lower equal) |
GT | maggiore di (greater than) |
GE | maggiore o uguale a (greater equal) |
Esempio
gfBit01 = glCont GE glAsse01
Sono le parentesi rotonde “()” che permettono di modificare il livello di precedenza degli operatori
sopradescritti.
Esempio
AA = [(A + B)/C] - (D x E)
gwVarAA = ((gwVarA + gwVarB) / glVarC) - (swVarD * glVarE)
Il livello di priorità degli operatori QCL ricalca quello di tutti i linguaggi di programmazione. Le priorità sono le seguenti:
Priorità massima |
---|
( ) |
Funzioni matematiche e Funzioni trigonometriche |
NEG NOT NOTB |
* / % |
+ - |
LT GT LE GE |
EQ |
AND ANDB |
OR ORB XORB |
= |
Priorità minima |
Sono tutte quelle istruzioni che permettono di modificare il flusso di esecuzione.
È la tipica istruzione condizionale; se la <expression> è vera, valore booleano 1, viene eseguito il blocco istruzioni
altrimenti viene eseguito il blocco istruzioni <code lines 2>. Un blocco istruzioni può essere costituito da un insieme di istruzioni ma anche da un'istruzione sola; inoltre la sezione ELSE è opzionale. La sintassi è: <code QCL> IF <expression> <code lines 1> [ELSE <code lines 2>] ENDIF
Esempio:
MAIN: IF tTime ;If timer has expired tTime = TM_SECOND ;reload the timer and count = count + 1 ;increase by 1 the variable count ENDIF WAIT 1 JUMP MAIN END
Esempio di ciclo IF nidificato.
Modifichiamo l’esempio appena introdotto nel modo seguente:
MAIN: IF tSeconds ;If the timer has expired tSeconds = TM_SECONDO ;reload the timer. IF sbSeconds LT 59 ;If the sbSeconds variable is less than 59 sbSeconds = sbSeconds + 1 ;increase the seconds counter ELSE ;else (if the seconds are greater than 59) sbSecondi = 0 ;reset the seconds IF sbMinutes LT 59 ;If the sbMinutes variable is less than 59 sbMinutes = sbMinutes + 1 ;increase the minutes counter ELSE ;else (if the minutes are greater than 59) sbMinuti = 0 ;reset the minutes IF swHours LT 167 ;If the swHours variable is less than 167 swHours = swHours + 1 ;increase the hours ELSE ;else (if the hours is greater than 167) swHours = 0 ;reset the hours, because a week has passed. ENDIF ENDIF ENDIF ENDIF WAIT 1 JUMP MAIN END
Abbiamo realizzato così un orologio di sistema con tre variabili system: una per i secondi, una per i minuti e una per le ore. Si è utilizzata una variabile di tipo Byte per i secondi e per i minuti dato che il valore che esse assumono non esce mai dal range [-128, 127], mentre per la variabile swHours si è utilizzato una variabile di tipo Word dato che può arrivare fino al valore 167, all’interno del range [-32768, 32767], che è il numero di ore in una settimana.
È un ciclo iterativo che serve normalmente per eseguire un certo numero di volte una o un blocco di istruzioni. È possibile uscire dal ciclo FOR-NEXT prima che diventi falsa la condizione di ciclo tramite l'istruzione BREAK; quando quest'ultima viene incontrata viene eseguito un salto alla prima istruzione successiva al NEXT. La sintassi è:
FOR (<initialization>, <test>, <increment>) < code lines > NEXT
dove:
<initialization> | è una espressione eseguita all'avvio del ciclo e quindi una sola volta |
<test> | è una espressione condizionale che, se falsa, determina la fine del ciclo FOR |
<increment> | è un valore numerico che viene sommato all'indice al termine di ogni esecuzione del < code lines > |
Esempio:
MAIN: FOR(gbYourByte = 1, gbYourByte LE 10, 1) ;For gbYourByte from 1 to 10 arwMyArray[gbYourByte] = POW(3, gbYourByte) ;the element arwMyArray[gbYourByte] gets the value 3^gbYourByte, dswStat2[gbYourByte] = 1 ;assign the value 1 to the static variable, ddbDin1[gbYourByte,1] = 2 ;assign the value 2 to the indexed variable if the 1st step. NEXT WAIT 1 JUMP MAIN END
Con il ciclo FOR-NEXT visto si riempie l’array global arwMyArray delle prime 10 potenze di 3.
È un ciclo iterativo che serve per eseguire una o un blocco di istruzioni finché una condizione si verifica.
È possibile uscire dal ciclo WHILE-ENDWHILE prima che diventi falsa la condizione di ciclo tramite l'istruzione BREAK; quando quest'ultima viene incontrata viene eseguito un salto alla prima istruzione successiva al ENDWHILE. La sintassi è:
WHILE (<condition>) < code lines > ENDWHILE
dove:
<condition> | è una espressione condizionale che deve dare un risultato booleano. Quando la condizione è vera vengono eseguite continuamente le < code lines >. Quando la condizione è falsa si passa ad eseguire il codice successivo a ENDWHILE. |
Esempio:
Questi due cicli hanno lo scopo di poter impostare il valore delle variabili sbMinutes e swHours tenendo attivati due diversi ingressi ifSetUpMinutes e ifSetUpHours, rispettivamente. Si osservi che all’interno di ogni WHILE è stato inserito un timer di ritardo, tDelay, per fare in modo che l’incremento della variabile sia più lento per dare modo all’utente di disattivare l’ingresso quando la variabile assume il valore voluto. Naturalmente il valore da assegnare ai minuti o alle ore è limitato e quindi viene aggiunto un IF all’interno del while per controllare questo limite. La spiegazione dell'istruzione WAIT 1 viene rimandata in seguito. |
---|
MAIN: WHILE (ifSetUpHours) ;While the input is actived: IF tDelay ;if the timer is expired tDelay = 500 ;reload the timer, swHours = swHours + 1 ;increase the hours counter. IF swHours GE 168 ;If the hours are more than 167 (great equal than 168) swHours = 0 ;reset the hours counter. ENDIF ENDIF WAIT 1 ENDWHILE WHILE (ifSetUpMinutes) ;While the input is actived: IF tDelay ;if the timer is expired tDelay = 500 ;reload the timer, sbMinutes = sbMinutes + 1 ;increase the minutes counter. IF sbMinutes GE 60 ;If the minutes are more than 59 (great equal than 60) sbMinutes = 0 ;reset the minutes counter. ENDIF ENDIF WAIT 1 ENDWHILE WAIT 1 JUMP MAIN END
Nel QView 6 è stata introdotta la istruzione SWITCH. Questa istruzione permette di analizzare una certa espressione e eseguire delle righe di codice diverse a seconda del risultato di questa espressione. La sintassi è:
SWITCH(<expression>) CASE <value 1> < code lines for value 1> [;comments] CASE <value 2>..<value 3> < code lines for values between value 2 and value 3> [;comments] CASE <value 4>, <value 5>..<value 6> < code lines for value 4 and for values between value 5 and value 6> [;comments] [DEFAULT < code lines for default>] [;comments] ENDSWITCH
Un esempio banale di un controllo della temperatura rilevata da un sensore che scrive il suo valore nella variabile Temperature.
SWITCH(Temperature) CASE 0 CloseDoor = 1 WarmUp = 100 IceAlarm = 1 OutOfRange = 0 CASE 1..10 CloseDoor = 1 WarmUp = 50 IceAlarm = 0 OutOfRange = 0 CASE 11..15 CloseDoor = 1 WarmUp = 15 IceAlarm = 0 OutOfRange = 0 CASE 16..25 CloseDoor = 0 WarmUp = 0 IceAlarm = 0 OutOfRange = 0 DEFAULT OutOfRange = 1 ENDSWITCH
Attende il verificarsi di una condizione o di un evento. L'istruzione WAIT è una istruzione molto importante poichè quando viene eseguita e la <condizione> è falsa, l'esecuzione delle istruzioni passa al task successivo. È comunque necessario fare una precisazione in questo contesto; infatti l'esecuzione dell'istruzione WAIT comporta comunque la cessione del controllo al task successivo quando viene incontrata la prima volta, senza che la condizione sia controllata. Quando il controllo del flusso istruzioni ritorna al task in questione viene rieseguita l'istruzione WAIT e quindi controllata la condizione. Per maggiori informazioni fare riferimento al capitolo dedicato al multitasking. La sintassi è:
WAIT <condizione>
Esegue un salto incondizionato all'istruzione locata all'etichetta specificata. La sintassi è:
JUMP <etichetta>
Esempio
L’esempio classico per l’istruzione JUMP è quello che viene ripetuto in ogni task per saltare dalla
fine del codice all’inizio, cioè all’etichetta MAIN. Questa istruzione per il controllo di flusso può
essere utilizzata anche in altri punti del task. JUMP è un salto incondizionato, si può renderlo
condizionato in combinazione con un IF con lo scopo di deviare il flusso di codice in base al
verificarsi di particolari condizioni.
Tramite le etichette è possibile localizzare determinati punti nella sequenza delle istruzioni
dell'applicativo. Vengono utilizzate per modificare il flusso di esecuzione delle istruzioni (comando
JUMP del QCL). Quando viene inserita un'etichetta nelle istruzioni è necessario che sia
seguita dai due punti “:”, mentre se si fa riferimento all'etichetta stessa si deve scrivere il nome
senza i due punti.
Esempio jump incondizionato
Label1: ;labeled line < code line > < code line > ;................... JUMP Label1 ;Jump to the label instruction
Esempio jump condizionato
Label1: ;labeled line < code line > IF <condition> ;If the condition is true JUMP Label1 ;Jump to the label instruction ENDIF
Quando, all'interno di una stessa unit, vi è una parte di codice ripetuta più volte è utile
definire una subroutine. L'esecuzione del codice in essa contenuto avverrà ogni qualvolta viene
incontrata una istruzione di chiamata a subroutine (CALL). La subroutine viene identificata da
un nome preceduto dalla parola chiave SUB e deve terminare con la parola chiave ENDSUB. Vedi
anche istruzione CALL.
Per interrompere una subroutine prima del termine della stessa inserire la parola chiave RETURN.
Call to Subroutine: esegue un salto incondizionato alla prima istruzione della subroutine identificata dal nome. Al termine della subroutine (identificata da ENDSUB) il flusso del programma continua dalla istruzione successiva alla CALL.
CALL <nome_subroutine>
Queste righe di codice vanno poste oltre la parola chiave END, cioè oltre la fine della unit operativa. |
---|
Introduciamo una subroutine per calcolare la lunghezza di una diagonale di un quadrato data la lunghezza di un lato.
L’esempio a seguire illustra il richiamo della subroutine:
MAIN: glOurLong = 4 ;This is the square edge CALL CALC_DIAG ;Subroutine call WAIT 1 JUMP MAIN END ;-------------This subroutione calcs the square diagonal----------------- SUB CALC_DIAG gsYourSing = SQRT(2 * POW(glOurlong,2)) ENDSUB
No operation; questa istruzione non ha nessun effetto sul programma e può essere utilizzata per introdurre dei ritardi.
Sono le istruzioni che permettono di attivare o disattivare un’uscita digitale. L'attivazione e la disattivazione possono essere eseguite anche tramite l'operatore di assegnamento (<nome uscita> = 1) ma le istruzioni dedicate sono più veloci.
Attiva una uscita digitale. La sintassi è la seguente:
SETOUT <nome uscita>
Disattiva una uscita digitale. La sintassi è la seguente:
RESOUT <nome uscita>
L’uscita ofOutput1 viene attivata con il comando SETOUT quando la variabile sbSeconds assume il valore 20 solo se l’ingresso ifEnableO1 e attivo. Tale uscita viene poi resettata quando sbSecondi assume il valore 40. |
---|
Introduciamo un esempio in cui vengono cambiate di stato un’uscita a seconda del valore di una variabile:
MAIN: IF (sbSeconds EQ 20) AND ifEnableO1 ;If sbSeconds is equal to 20 and the input si actived SETOUT ofOutput1 ;set the output ENDIF IF sbSecondi EQ 40 ;When the sbSeconds is equal to 40 RESOUT ofOutput1 ;reset the output ENDIF WAIT 1 JUMP MAIN END
Sono le istruzioni che permettono il controllo dell'esecuzione delle unit (unità contenenti il codice QCL o LADDER) del programma utente. Tali istruzioni saranno più comprensibili quando sarà spiegato il sistema di multitasking adottato.
Esegue la sospensione dell'esecuzione della unit di programma specificato.
Tale istruzione può essere utilizzata da una unit per bloccare l'esecuzione di un altra unit oppure per bloccare l'esecuzione di se stessa. In questo caso bisogna ricordare che la unit in questione, essendo sospesa, non può più riattivarsi ma tale operazione deve essere eseguita da una delle altre unit in esecuzione. La sintassi dell'istruzione SUSPEND è:
<unit name>.SUSPEND
Esegue il ripristino dell'esecuzione delle istruzioni di una unit sospesa.
Tale istruzione fa riprendere l'esecuzione di una unit sospesa dall'istruzione successiva a quella eseguita al momento della sospensione. La sintassi è:
<unit name>.RESUME
RESUME produce degli effetti solamente se la unit <unit name> era sospesa.
Esegue una “ripartenza” dell'esecuzione di una unit di programma dalla prima istruzione. Tale istruzione non altera lo stato di sospensione della unit in questione; ciò significa che se viene eseguito un RESTART di una unit sospesa, quest'ultima si predispone per l'esecuzione della prima istruzione ma rimane tuttavia sospesa fino alla sua attivazione con l'istruzione RESUME. La sintassi è:
<nome_task>.RESTART
Per comprendere meglio il significato di queste istruzioni di sistema si veda il capitolo “Multitasking”.
Il sistema QMOVE mette a disposizione delle variabili legate al sistema operativo interno di sola lettura; i nomi di queste variabili sono predefiniti, non possono cioè essere cambiati dall'utente.
Fornisce lo stato di una unit:
La sintassi è:
<unit name>.is_suspended
Il Watchdog task indica che il tempo di esecuzione di una unit del progetto ha superato i 200 ms. È la stessa informazione che compare nel pannello Monitor - CPU alla voce Watchdog Task. La sintassi è:
QMOVE.watchdog
Indica che una unit a tempo del progetto ha perso un evento. È la stessa informazione che compare nel pannello Monitor - CPU alla voce Time task Lost. Una unit a tempo deve essere eseguita con tempistiche deterministiche. Questi tempi potrebbero non venire rispettati a causa del grosso impegno nell'eseguire il codice inserito nella stessa unit. Se questo succede si parla di Time task lost avvenuto.
La sintassi è:
QMOVE.time_task_lost
Indica che la batteria ha un livello di carica basso. Il led BATT lampeggia. Questa informazione ha senso solamente nei modelli di QMOVE forniti di batteria tampone per la memoria RAM.
La sintassi è:
QMOVE.battery_low
Indica che la batteria è scarica. Il led BATT è acceso. Questa informazione ha senso solamente per i modelli di QMOVE che sono dotati di batteria tampone per la memoria RAM.
La sintassi è:
QMOVE.battery_down
Esistono altre variabili di sistema che dipendono dal firmware della CPU utilizzata. Per accedere
a queste variabili si utilizza la sintassi:
QMOVE.sys001 QMOVE.sys002 ;... QMOVE.sys016
Il significato di queste variabili deve essere ricercato nella documentazione firmware della CPU.
Esegue l'elevamento alla potenza della base. La sintassi è:
POW(<base>, <exponent>)
Esempio: gsMaxVal = 2gwNbit
gsMaxVal = POW(2,gwNbit)
Calcola la radice quadrata dell'argomento dato. La sintassi è:
SQRT(<radicand>)
Esempio: gsIpot = v(gsL12 + gsL22)
gsIpot = SQRT(POW(gsL1,2)+POW(gsL2,2))
Calcola il logaritmo naturale dell'argomento dato. La sintassi è:
LN(<val>)
Esempio: gsValue = ln gsMaximum
gsValue = LN(gsMaximun)
Esegue l'elevamento a potenza del numero di Nepero. La sintassi è:
EXP(<exponent>)
Esempio: gsA = e2
gsA =EXP(2)
Ritorna il valore assoluto dell'argomento. La sintassi è:
ABS(<variable>)
Esempio: glModule = I glValue I
glModule = ABS(glValue)
Esegue una operazione di shift a sinistra di n bit sull'argomento.
Lo shift è da intendersi indifferentemente sia logico che aritmetico, ossia:
- I bit che escono dalla sequenza a sinistra vengono perduti.
- I bit che entrano nella sequenza a destra sono degli 0.
Dal punto di vista matematico si tratta della moltiplicazione dell'argomento per la potenza 2^n.
La sintassi è:
SHLL(<variable>,<bits>)
Esempio:
glNewValue = SHLL(glValue, 1) ; Se glValue = &B00001100 (12) allora glNewValue = &B00011000 (24)
Esegue una operazione di shift a destra di n bit sull'argomento.
Lo shift è da intendersi aritmetico (non logico), ossia:
- I bit che escono dalla sequenza a destra vengono perduti.
- I bit che entrano nella sequenza a sinistra sono delle copie del bit più significativo (ossia di quello più a sinistra).
Dal punto di vista matematico si tratta della divisione dell'argomento per la potenza 2^n. Questa interpretazione continua a valere anche per i numeri negativi scritti in complemento a 2.
La sintassi è:
SHLR(<variable>,<bits>)
Esempio:
glValue = SHLR(glValue, 1) ; Se glValue = &B00001100 (12) allora glNewValue = &B00000110 (6) ; Se glValue = &B11110011 (-12) allora glNewValue = &B11111001 (-6)
Esegue una moltiplicazione di valori interi a 32 bit con risultato a 64 bit e una successiva divisione per valore intero a 32 bit. Il risultato è un valore di 32 bit.
N.B. Se viene eseguita una divisione per zero, la CPU andrà in stato “Division by zero error”.
La sintassi è:
MULDIV(<factor1>,<factor2>,<divisor>)
Esempio: glValue = a * b / c
glValue = MULDIV(a, b, c)
Esegue una moltiplicazione di valori interi a 32 bit con risultato a 64 bit e una successiva divisione per valore intero a 32 bit. Il risultato è il resto della divisione.
N.B. Se viene eseguita una divisione per zero, la CPU andrà in stato “Division by zero error”.
La sintassi è:
RMULDIV(<factor1>,<factor2>,<divisor>)
Esempio: glValue = a * b % c
glValue = RMULDIV(a, b, c)
ROUND | Esegue un arrotondamento di un valore in floating point all'intero più vicino. |
TRUNC | Esegue un arrotondamento di un valore in floating point all'intero più vicino non maggiore di grandezza rispetto al valore dato. |
FLOOR | Esegue un arrotondamento di un valore in floating point all'intero più vicino non superiore al valore dato. |
CEIL | Esegue un arrotondamento di un valore in floating point all'intero più vicino non inferiore al valore dato. |
La sintassi è:
ROUND(<variable>) TRUNC(<variable>) FLOOR(<variable>) CEIL(<variable>)
Esempio:
gsValue = ROUND(2.7) ;risulta 3.0 gsValue = ROUND(-2.7) ;risulta -3.0 gsValue = TRUNC(2.7) ;risulta 2.0 gsValue = TRUNC(-2.7) ;risulta -2.0 gsValue = FLOOR(2.7) ;risulta 2.0 gsValue = FLOOR(-2.7) ;risulta -3.0 gsValue = CEIL(2.7) ;risulta 3.0 gsValue = CEIL(-2.7) ;risulta -2.0
ISFINITE | Controlla se il numero dato ha valore finito. |
ISINF | Controlla se il numero dato ha valore infinito. |
ISNAN | Controlla se il numero dato ha valore NaN. |
ISNORMAL | Controlla se il numero dato ha valore normale. |
La sintassi è:
ISFINITE(<variable>) ISINF(<variable>) ISNAN(<variable>) ISNORMAL(<variable>)
Esempio:
gfValue = ISFINITE(gsValue) ;risulta 1 se gsValue è un valore finito, altrimenti 0 gfValue = ISINF(gsValue) ;risulta 1 se gsValue è un valore infinito, altrimenti 0 gfValue = ISNAN(gsValue) ;risulta 1 se gsValue è un NaN (Not a Number), altrimenti 0 gfValue = ISNORMAL(gsValue) ;risulta 1 se gsValue è un valore normale (non zero, non infinito, non NaN), altrimenti 0
Calcola il seno di un angolo espresso in radianti. La sintassi è:
SIN(<angle>)
Esempio: gsYPos = ssRadius x SIN gsalpha
gsYPos = ssRadius * SIN(gsalpha)
Calcola il coseno di un angolo espresso in radianti. La sintassi è:
COS(<angle>)
Esempio: gsXPos = ssRadius x COS gsalpha
gsXPos = ssRadius * COS(gsalpha)
Calcola la tangente di un angolo espresso in radianti. La sintassi è:
TAN(<angle>)
Esempio: gsMyVal = TAN gsalpha
gsMyVal = TAN(gsalpha)
Calcola la cotangente di un angolo espresso in radianti. La sintassi è:
COT(<angle>)
Esempio: gsMyVal = COT gsalpha
gsMyVal = COTG(gsalpha)
Calcola l'angolo, espresso in radianti, il cui seno è uguale all'argomento. La sintassi è:
ASIN(<arc>)
Esempio: gsAngolo = ASIN Arc
gsAngolo = ASIN(Arc)
Calcola l'angolo, espresso in radianti, il cui coseno è uguale all'argomento. La sintassi è:
ACOS(<arc>)
Esempio: gsAngolo = ACOS Arc
gsAngolo = ACOS(Arc)
Calcola l'angolo, esresso in radianti, la cui tangente è uguale all'argomento. La sintassi è:
ATAN(arc)
Esempio: gsMyVal = ATAN Arc
gsMyVal = ATAN(Arc)
In generale, nelle funzioni trigonometriche, gli angoli vengono espressi in radianti. Essendo p un numero irrazionale (non finito) e potendolo rappresentare con una precisione di 7 cifre dopo il punto decimale, si introduce una approssimazione nei calcoli trigonometrici.
Altro limite è dato dai calcoli trigonometrici che danno come risultato un numero infinito, che non può sicuramente essere rappresentato con un numero floating point a singola precisione (7 cifre). Per esempio il risultato della tangente di p/2 è un numero molto grande in modulo con segno negativo, risultato che evidentemente si allontana da +infinito (risultato corretto).
ESEMPIO:
tang p/2 = tang 1.570796371 = -22877332 ;
arctg -22877332 = -1.570796371 = - p/2 (!!)
Non è possibile calcolare la tangente di p/2 con la formula:
tang p/2 = (sen p/2) / (cos p/2)
in quanto viene eseguita una divisione per zero.
L'applicazione che vogliamo sviluppare ha lo scopo di applicare le informazioni finora introdotte.
Il progetto che andremo a realizzare avrà:
Crea un nuovo progetto con
inserisci il Project Name come MyApplication.
Seleziona
e chiamala CONFIG. La unit verrà già precompilata con tutte le parole chiavi che distinguono i vari gruppi di variabili. Nella unit di configurazione è fondamentale, per ora, dichiarare quale hardware si vuole utilizzare.
In questo esempio abbiamo usato
... BUS 1 1P51F 30 2 . . 3 1MG8F .
Per ora non dichiariamo niente altro nella unit di configurazione.
Seleziona
e chiamala MANAGER. Lascia la proprietà Task Mode come Normal. La unit aggiunta presenta il seguente codice pre-inserito:
MAIN: WAIT 1 JUMP MAIN END
Questa unit MANAGER dovrà gestire una macchina a stati rappresentata nel seguente schema:
Il software della unit MANAGER dovrà gestire le transizioni di stato e dovrà fornire alcune informazioni (per esempio quale è lo stato attuale).
Dichiara le seguenti variabili e costanti nella unit MANAGER:
CONST ALARM_STATE 0 OUT MANUAL_STATE 1 OUT AUTOMATIC_STATE 2 OUT GLOBAL NewState B IN ;New state requested State B OUT ;Actual state BEGIN MAIN: WAIT 1 JUMP MAIN END
Ora aggiungi il seguente codice:
CONST ALARM_STATE 0 OUT MANUAL_STATE 1 OUT AUTOMATIC_STATE 2 OUT GLOBAL NewState B IN ;New state requested State B OUT ;Actual state BEGIN MAIN: SWITCH State CASE ALARM_STATE ;Put here the code to do when the state is ALARM CASE MANUAL_STATE ;Put here the code to do when the state is MANUAL CASE AUTOMATIC_STATE ;Put here the code to do when the state is AUTOMATIC ENDSWITCH WAIT 1 JUMP MAIN END
La variabile State è considerata un OUT per questa unit. Se un'altra unit vuole far cambiare lo stato alla macchina non può agire direttamente su State perché solo la unit MANAGER la può modificare. Viene quindi predisposta una variabile NewState che viene usata da MANAGER come un IN nel seguente modo
CONST ALARM_STATE 0 OUT MANUAL_STATE 1 OUT AUTOMATIC_STATE 2 OUT GLOBAL NewState B IN ;New state requested State B OUT ;Actual state BEGIN MAIN: SWITCH State CASE ALARM_STATE ;Put here the code to do when the state is ALARM CASE MANUAL_STATE ;Put here the code to do when the state is MANUAL CASE AUTOMATIC_STATE ;Put here the code to do when the state is AUTOMATIC ENDSWITCH ;Check if there is a change state request IF State NEQ NewState SWITCH NewState CASE ALARM_STATE SWITCH State CASE MANUAL_STATE ;Put here the code for MANUAL to ALARM trasition CASE AUTOMATIC_STATE ;Put here the code for AUTO to ALARM trasition ENDSWITCH CASE MANUAL_STATE SWITCH State CASE ALARM_STATE ;Put here the code for ALARM to MANUAL trasition CASE AUTOMATIC_STATE ;Put here the code for AUTO to MANUAL trasition ENDSWITCH CASE AUTOMATIC_STATE SWITCH State CASE MANUAL_STATE ;Put here the code for MANUAL to AUTO trasition ENDSWITCH ENDSWITCH State = NewState ;The trasition is done ENDIF WAIT 1 JUMP MAIN END
Come puoi osservare, quando la NewState è diversa da State viene eseguito uno dei possibili codici associati ad una delle 5 possibili transizioni. Alla fine della transizione lo stato della macchina viene definitivamente impostato al nuovo stato richiesto.
Una unit che volesse utilizzare la unit MANAGER dovrà quindi usare un codice di questo tipo:
MANAGER.NewState = MANAGER.AUTOMATIC_STATE WAIT MANAGER.State EQ MANAGER.NewState
Per esempio per comandare il cambio di stato in automatico.
Aggiungi un'altra unit con la stessa proprietà di MANAGER e chiamala SEQUENC. Per ottenere una sequenza devi scrivere un codice come questo:
GLOBAL Start F IN ;Start sequence input Sequence W OUT ;This is the step of the sequence start_rise_up F ;Local variable to check the rise edge of Start input BEGIN MAIN: IF Start IF start_rise_up start_rise_up = 0 Sequence = 10 ;Start the sequence ENDIF ELSE start_rise_up = 1 Sequence = 0 ;Reset the sequence ENDIF WAIT 1 JUMP MAIN END
Come puoi osservare quando la variabile Start vale 0 (FALSE) la variabile Sequence viene azzerata (questo serve per impedire alla sequenza di funzionare). Quando la variabile Start vale 1 (TRUE) la variabile Sequence viene impostata al valore 10 solo la prima volta perché poi la variabile start_rise_up viene impostata a 0.
Ora aggiungi il codice per usare la variabile Sequence.
CONST OFF 0 OUT ON 1 OUT GLOBAL Start F IN ;Start sequence input Force F IN ;Force the signal output to ON Sequence W OUT ;This is the step of the sequence Signal F OUT ;This is an output signal start_rise_up F ;Local variable to check the rise edge of Start input TIMER time_on time_off BEGIN MAIN: IF Start IF start_rise_up start_rise_up = 0 Sequence = 10 ;Start the sequence ENDIF ELSE start_rise_up = 1 Sequence = 0 ;Reset the sequence Signal = Force ;Force the signal ENDIF ;This is the sequence management IF Sequence EQ 10 ;First step Signal = OFF ;Reset signal time_off = 1000 ;1000 ms = 1 s Sequence = 20 ENDIF IF Sequence EQ 20 ;Second step IF time_off ;Wait time expired Sequence = 30 ENDIF ENDIF IF Sequence EQ 30 ;3rd step Signal = ON ;Set signal time_on = 500 ;500 ms = 0.5 s Sequence = 40 ENDIF IF Sequence EQ 40 ;4th step IF time_on ;wait time expired Sequence = 50 ENDIF ENDIF IF Sequence EQ 50 ;5th step Sequence = 10 ENDIF WAIT 1 JUMP MAIN END
Quando la variabile Sequence è impostata a 10, viene eseguito il codice contenuto in
IF Sequence EQ 10 ...
che la fa diventare 20 e via così eseguendo passo dopo passo la sequenza. La sequenza consiste nell'impostare a OFF la variabile Signal per 1s e quindi impostare ad ON per 0.5s e quindi ripetere la sequenza all'infinito (finché Start vale TRUE).
Inoltre è stato aggiunto anche l'input Force che, quando la sequenza non è attiva, serve per forzare Signal a ON .
Aggiungi la unit COMMAND e inserisci il seguente codice:
GLOBAL ForceOutput F OUT INPUT Selector F REFERENCE Enable F REFERENCE ManualButton F REFERENCE BEGIN MAIN: WAIT 1 JUMP MAIN END
In questa unit dichiariamo tre REFERENCE ad tre ingressi digitali. Poi vedremo come assegnare questi REFERENCE a tre ingressi digitali veri e propri che andremo ad aggiungere nella unit di configurazione. Ora aggiungi il seguente codice:
GLOBAL ForceOutput F OUT INPUT Selector F REFERENCE Enable F REFERENCE ManualButton F REFERENCE BEGIN MAIN: IF Enable ;If enable input is on IF Selector ;If selector in on automatic position ;Go to automatic state MANAGER.NewState = MANAGER.AUTOMATIC_STATE WAIT MANAGER.State EQ MANAGER.AUTOMATIC_STATE ELSE ;Go to manual state MANAGER.NewState = MANAGER.MANUAL_STATE WAIT MANAGER.State EQ MANAGER.MANUAL_STATE ENDIF ELSE ;Go to alarm state MANAGER.NewState = MANAGER.ALARM_STATE WAIT MANAGER.State EQ MANAGER.ALARM_STATE ENDIF ForceOutput = ManualButton ;Replay the input value to an output variable WAIT 1 JUMP MAIN END
Questo codice serve per decidere quando eseguire le transizioni di stato. Ora è importante completare il codice scritto in MANAGER in questo modo:
CONST ALARM_STATE 0 OUT MANUAL_STATE 1 OUT AUTOMATIC_STATE 2 OUT GLOBAL NewState B IN ;New state requested State B OUT ;Actual state BEGIN MAIN: SWITCH State CASE ALARM_STATE ;Put here the code to do when the state is ALARM SEQUENC.Start = SEQUENC.OFF SEQUENC.Force = SEQUENC.OFF CASE MANUAL_STATE ;Put here the code to do when the state is MANUAL SEQUENC.Force = COMMAND.ForceOutput CASE AUTOMATIC_STATE ;Put here the code to do when the state is AUTOMATIC SEQUENC.Start = SEQUENC.ON ENDSWITCH ;Check if there is a change state request IF State NEQ NewState SWITCH NewState CASE ALARM_STATE SWITCH State CASE MANUAL_STATE ;Put here the code for MANUAL to ALARM trasition SEQUENC.Start = SEQUENC.OFF SEQUENC.Force = SEQUENC.OFF CASE AUTOMATIC_STATE ;Put here the code for AUTO to ALARM trasition SEQUENC.Start = SEQUENC.OFF SEQUENC.Force = SEQUENC.OFF ENDSWITCH CASE MANUAL_STATE SWITCH State CASE ALARM_STATE ;Put here the code for ALARM to MANUAL trasition SEQUENC.Start = SEQUENC.OFF SEQUENC.Force = SEQUENC.OFF CASE AUTOMATIC_STATE ;Put here the code for AUTO to MANUAL trasition SEQUENC.Start = SEQUENC.OFF SEQUENC.Force = SEQUENC.OFF ENDSWITCH CASE AUTOMATIC_STATE SWITCH State CASE MANUAL_STATE ;Put here the code for MANUAL to AUTO trasition SEQUENC.Start = SEQUENC.OFF SEQUENC.Force = SEQUENC.OFF ENDSWITCH ENDSWITCH State = NewState ;The trasition is done ENDIF WAIT 1 JUMP MAIN END
Come si vede, in questo semplice esempio, le operazioni che vengono eseguite durante le transizioni di stato sono tutte uguali e servono per bloccare qualsiasi operazione sulla variabile Signal. Poi si vede che quando lo stato è in manuale l'attivazione di Signal è affidata a COMMAND.ForceOutput che a sua volta ha lo stesso valore di un ingresso digitale. Nello stato automatico invece viene attivata la seguenza gestita nella unit SEQUENC.
Ora facciamo l'ultima aggiunta alla unit di configurazione CONFIG in questo modo:
INPUT ManAuto F 3.INP01 PowerOn F 3.INP02 Push F 3.INP03 REFERENCES COMMAND.Selector = ManAuto COMMAND.Enable = PowerOn COMMAND.ManualButton = Push
In questo modo i simboli della unit COMMAND: Selector, Enable, ManualButton sono dei riferimenti associati agli ingressi dichiarati come: ManAuto, PowerOn, Push rispettivamente. E' evidente che la funzionalità dei REFERENCE in questo esempio è poco utile. Infatti al posto del simbolo Selector avrei potuto usare direttamente ManAuto. Si apprezza la potenzialità dei REFERENCE se si vuole riutilizzare il codice scritto per la unit COMMAND. Infatti potrei aggiungere una nuova unit chiamata COMMAN2 contenente lo stesso indentico codice QCL di COMMAND ma con i REFERENCE riferiti ad altri input. Ottengo in questo modo un codice perfettamente riutilizzabile.
Una funzione QCL è una parte di codice che permette di risolvere particolari problemi, di eseguire elaborazioni dati, di fornire specifiche funzionalità ad un progetto per QMOVE. Per poter utilizzare una funzione QCL nel codice di una unit è sufficiente richiamarla passandole gli argomenti necessari, come si trova descritto in seguito.
Questo modo di procedere comporta alcuni vantaggi:
La lista delle funzioni QCL disponibili e la relativa modalità di utilizzo è disponibile nel menù Help > Functions info, richiamabile in qualsiasi momento dall’ambiente di sviluppo.
Se indichiamo con FuncQCL01 una qualsiasi funzione della libreria, la sintassi corretta per richiamarla è la seguente:
FuncQcl01(<arguments list>)
Non restituendo valori, le funzioni non possono essere utilizzate a destra di un assegnazione o come parte di un'espressione in un istruzione IF, FOR o WHILE.
slType01 = FuncQCL01(...) !COMPILING ERROR! IF (FuncQCl01(...) AND ...) !COMPILING ERROR! FOR (sInt01 = 1, sInt01 LT FuncQCL01(...), ...) !COMPILING ERROR! WHILE (FuncQCL01(...) LT 24) !COMPILING ERROR!
Anche se una funzione QCL non restituisce alcun valore, è tuttavia possibile che una funzione QCL imposti dei valori a dei parametri passati come argomento e quindi in pratica è come se si avessero piú valori di ritorno.
Vediamo alcuni semplici esempi:
AC10AvergArr (MyArray, average_value, ok_calc)
La funzione calcola il valore medio di un array passato come argomento. In questo caso MyArray è un parametro di ingresso e si vuol calcolarne il valore medio.
average_value e ok_calc sono parametri di uscita e sono rispettivamente il valore medio calcolato dalla funzione e un flag indicante il calcolo completato. Quando ok_calc assume valore 1 significa che la funzione ha terminato i suoi calcoli e quindi è possibile recuperare tale valore leggendo la variabile average_value.
Per ciascuna funzione è poi indicato in quale parte dell’unità chiamarla; infatti vi sono funzioni, che proprio per le operazioni che devono svolgere, vanno chiamate in una parte ciclica del codice, mentre alcune altre possono essere chiamate anche in una parte non ciclica del codice. Con parte ciclica si intende la parte del codice QCL che viene eseguita ad ogni scansione del programma.
Con parte non ciclica si intende la parte di codice che non viene eseguita ciclicamente perchè mancano determinate condizioni (per esempio se il codice è contenuto in una istruzione IF la cui condizione non è vera).
L’indicazione sul “dove” richiamare una funzione è riportato nella descrizione di ciascuna funzione (Help > Functions info).
Un’altra caratteristica da tenere presente per alcune funzioni è il fatto che, quando sono necessarie operazioni che impiegano molto tempo, la funzione stessa si preoccupa di eseguire un’istruzione di WAIT al suo interno, ogni 180 millisecondi. Questo per impedire il “blocco” dell’esecuzione della unit dovuto a compiti particolarmente gravosi. Solitamente in funzioni di questo tipo è presente un argomento di tipo flag che puó essere monitorato per verificare quando la funzione ha terminato il suo compito.
Nell’help della funzione utilizzata viene indicato chiaramente il tipo degli argomenti che la funzione si aspetta. Se questo tipo non viene rispettato dal programmatore viene generato un errore in fase di compilazione del progetto.
Supponiamo di utilizzare la funzione di calcolo della media aritmetica dei valori contenuti in un array (AC10AvergArr):
GLOBAL glAverage L ; This is used as the result variable gfDone F ; This flag is used to result variable ARRSYS aslMyArray 10 L ; Array System BEGIN MAIN: IF NOT gfDone AC10AvergArr(aslMyArray, glAverage, gfDone) ENDIF WAIT 1 JUMP MAIN END
Il Ladder (logica a contatti) è un linguaggio nato per la programmazione dei PLC, per cui è molto
performante per la gestione di ingressi uscite e piccole sequenze.
Si dà per scontato che l’utilizzatore conosca il linguaggio Ladder IEC1131; in caso contrario si
consiglia di integrare il presente manuale con un corso PLC generico.
Nel linguaggio LADDER bisogna tener presente che i vari elementi sono analizzati, all’interno del rung, partendo dall’angolo in alto a sinistra e spostandosi dall’alto in basso e da sinistra a destra (Figura 1).
Figura 1: esecuzione del rung. |
Nel caso si inserisca un elemento che occupa più celle (ad esempio un contatore), la cella che fa
da riferimento per lo svolgimento del rung è quella in alto a sinistra.
Il nome delle variabili per il programma Ladder sono dichiarate nella unità di configurazione e
vanno dichiarate come descritto nella sezione QCL. Le stesse variabili possono essere utilizzate
sia in Ladder che in QCL anche contemporaneamente.
In seguito si guida l’utente all’inserimento di un elemento nella rete LADDER utilizzando le voci
del menù predisposte.
Spieghiamo con un esempio come inserire un elemento in una rete LADDER. Innanzitutto si deve inserire una nuova unità LADDER selezionando File > Add unit > Ladder unit. Comparirà la finestra di Figura 2.
Figura 2: inserimento di nuova unità LADDER. |
Una volta confermato con Ok una nuova unità verrà ad aggiungersi nella finestra UNIT MANAGER. Con un doppio click su questa nuova unità LADDER si aprirà l’editor LADDER. A questo punto è possibile inserire il primo elemento della nostra rete LADDER utilizzando la “libreria degli elementi LADDER” come mostrato in figura 3.
Figura 3: Libreria dei blocchi LADDER |
A questo punto è possibile scegliere tra i vari elementi messi a disposizione e posizionarli sulla
griglia dell’editor. L’operazione si può fare sia trascinando l’elemento sulla posizione voluta, sia
facendo un doppio click sull’elemento stesso. In questo caso l’elemento viene posizionato nella
casella dell’editor evidenziata in quel momento.
E’ possibile selezionare l’elemento ladder da inserire scegliendolo anche dalla lista degli “ultimi
elementi inseriti”.
L’elemento ladder deve essere inserito in una rete esistente. Se la rete non esiste bisogna crearla
inserendo un nuovo “rung”. Per inserire un nuovo “rung” selezionare il menù Edit > New
Rung.
Se supponiamo di voler inserire il contatto normalmente aperto si deve selezionare Normally
Open Contact e sull’editor appare il simbolo del contatto (Figura 4).
Figura 4: contatto normalmente aperto inserito in una rete LADDER. |
La libreria degli elementi LADDER è formata da una serie di categorie in cui sono suddivisi i vari
elementi disponibili per comporre la rete LADDER. Nel seguito faremo una veloce carrellata su
queste categorie. Il programmatore tenga presente che la maggior parte degli elementi sono
elementi di tipo standard (IEC1131) e tutti sono dotati di un help in linea richiamabile direttamente
da Qview (selezionando l’elemento e premendo F1).
L’elemento inserito nella figura 4 non ha associata nessuna variabile. Per associare una variabile
all’elemento inserito si deve evidenziare l’elemento e selezionare il menù Edit > Element
Properties. Apparirà la finestra di figura 5.
Figura 5: proprietà del blocco. |
Il campo “Note” serve per associare all’elemento delle notazioni utili per il programmatore. Una volta compilata la finestra come in figura 5, la rete LADDER appare come in figura 6.
Figura 6: proprietà del blocco. |
La finestra delle proprietà dell’elemento permette di inserire tutte le variabili di cui l’elemento necessita. Alcune variabili però non sono obbligatorie. Per esempio in figura 7 si osserva che alcuni parametri dell’elemento TON (On Delay) non sono obbligatori e questo è indicato dal fatto che non presentato i “???” (tre punti interrogativi).
Figura 7: TON: parametri obbligatori e non. |
Le categorie degli elementi LADDER disponibili per comporre la rete LADDER sono:
Contact Elements: | elementi di contatto; |
Coil Elements: | elementi con bobine di contatto; |
Comparison Function: | confronto tra variabili; |
Device Functions: | funzioni relative ai device; |
Counter Functions: | elementi contatori; |
Timer Functions: | temporizzatori; |
Table functions: | funzioni su array; |
Bitwise Functions: | operatori sul singolo bit; |
Boolean Functions - Bitwise: | operatori binari a bit; |
Boolean Functions - Logical: | operatori binari su variabili; |
Math Functions: | operatori matematici; |
Trigonometric Functions: | operatori trigonometrici; |
Edge Functions: | Funzioni di trigger; |
Bistable Functions: | Funzioni di set/reset; |
Selection Functions: | selettori, multiplexer, limitatori. |
Nella rete LADDER è possibile utilizzare una riga di caselle per poter inserire dei commenti.
Per inserire un commento si deve selezionare del menù la voce Edit > New Element > Comment.
Ogni commento può essere composto da un titolo e da un testo.
Nella struttura Ladder è prevista la possibilità di saltare ad una label in modo che il programma possa saltare delle parti gravose di programma quando non è neccessario eseguirle. Per inserire l’elemento di jump si deve selezionare dal menù la voce Edit > New Element > Jump. Le proprietà di questo elemento consistono nel specificare l’etichetta associata al rung a cui saltare. Per inserire l’etichetta a cui saltare si deve agire al solito modo selezionando dal menù la voce Edit > New Element > Label. Naturalmente non ci possono essere etichette (label) con lo stesso nome nella stessa unità (Figura 8).
Figura 8: Elemento di salto (JUMP) alla etichetta (LABEL) ETIC. |
E’ possibile inserire anche l’elemento “Jump end” per saltare alla fine dell’unià direttamente senza bisogno di etichette (Figura 9).
Figura 9: Elemento di salto alla fine (JUMP END). |
Nella struttura Ladder è prevista la possibilità di muovere parti di programma verso l’alto e
verso il basso, in modo da consentire al programmatore di inserire linee di programma non
previste. Per muovere una linea si deve selezionare un rung presente e selezionare tramite le
voci del menù Edit > Move Rows Up o Edit > Move Rows Down.
Una volta terminato il task ladder, esiste la possibilità di compattare le linee di programma in
modo di non lasciare spazi vuoti con il comando di Edit > Compact Rows.
Dalla parola stessa si intuisce che il comando serve a trascinare (drag) e posizionare (drop) uno o piú elementi ladder tramite mouse dopo averli opportunamente selezionati. Selezionando uno o piú elementi ladder e tenendo premuto il pulsante di sinistra del mouse sulla selezione, la selezione cambia colore ed il cursore del mouse cambia forma. È possibile in queste condizioni spostare la selezione. Durante lo spostamento della selezione, compare, nella status bar in basso a sinistra il messaggio: “Placing mode for drag and drop action”. Come per il comando Paste si possono presentare le seguenti situazioni:
- Drag & Drop eseguito in un'area libera da altri elementi ladder:
Una volta piazzato il riquadro, se si rilascia il pulsante del mouse, il riquadro colorato sparisce
e l'elemento o gli elementi selezionati vengono inseriti in editor.
- Drag & Drop eseguito sopra o nell'area di altri elementi ladder:
come precedentemente descritto, una volta piazzato il riquadro, se si rilascia il pulsante del
mouse, il riquadro colorato sparisce e viene visualizzato un box di messaggio che chiede di
confermare o annullare l'operazione. Confermando l'operazione l'elemento o gli elementi vengono
inseriti nella rete sottostante operando automaticamente tutti i collegamenti necessari
per permettere una corretta compilazione del risultato finale.
Gli “Obsolete elements”, sono elementi ladder utilizzati dai programmatori, ma che sono stati successivamente dichiarati obsoleti da QEM in qualità di fornitore e manutentore della libreria degli elementi ladder.
Generalmente, un elemento ladder puó venire marcato come obsoleto se è stato sostituito da un'equivalente elemento piú aggiornato, al quale per esempio, è stata aumentata l'efficienza del codice interno.
L'elemento obsoleto è sempre rimpiazzabile da un'equivalente elemento della libreria ladder in uso. In un progetto che utilizza degli elementi LADDER obsoleti essi sono riconoscibili dal fatto che vengono visualizzato con un colore di backgroud giallo (per default). La presenza di elementi obsoleti nel programma è facilemente constatabile dalla presenza della voce Edit > New Elements > Obsolete Elements e dalla cartella “Obsolete Elements” nella libreria degli elelenti (Figura 10).
Figura 10: Cartella “Obslete Elements” |
Nelle impostazioni Options > Program Setup… > Ladder Editor è possibile modificare le impostazioni di default relative agli elementi ladder obsoleti.
La funzionalità di sostituzione degli elementi obsoleti (Sobstitute Obsolete element) è stata
inserita per operare la sostituzione di un elemento obsoleto inserito nella rete ladder, con un
corrispondente elemento sostitutivo.
La funzionalità è attivata dalla voce di menù Edit > Sobstitute Obsolete Element. Questa
funzione è attivata se il cursore dell’editor ladder è posizionato sopra un'elemento obsoleto
sostituibile.
Una volta sostituiti, gli ex elementi obsoleti cambiano il loro colore di background uniformandosi
con gli elementi non obsoleti.
Utilizzando la voce di menù Edit > Sobstitute All Obsolete Elements si ha la possibilità, in una
sola passata, di sostituire su tutto il progetto (tutte le unità ladder) di tutti gli elementi ladder
obsoleti. Una volta avviata questa procedura si ricercano inizialmente gli elementi ladder obsoleti,
appare il messaggio:
Searches for obsolete elements in progress…
Questo messaggio viene seguito da:
No obsolete elements to substitute
se non ci sono elementi obsoleti, oppure
There are obsolete ladder elements…
A questo punto è possibile scegliere di avviare la sostituzione completa o di abbandonare l’operazione. Una volta completata la sostituzione appare il messaggio:
All obsolete elements are substituted!
Il multitasking è la capacità di un sistema di gestire l’esecuzione contemporanea di diversi compiti.
Un progetto realizzato in QCL e ladder è formato da un insieme di unit o tasks (in italiano compiti, appunto). Il multitasking implementato nel sistema QMOVE è chiamato di tipo cooperativo, nel senso che l’esecuzione delle istruzioni passa da un task ad un altro solamente quando, nel task in esecuzione, viene incontrata una particolare istruzione
WAIT < condizione >.
Questo è vero per i task scritti in codice QCL, mentre per i task sviluppati in ladder il passaggio al task successivo avviene dopo l'ultima istruzione.
La CPU smette di eseguire il codice di un task quando il task stesso viene messo in attesa tramite la istruzione WAIT.
Si schematizza il cosiddetto ciclo di tasks nella figura 1. Ogni task del progetto deve quindi poter cooperare con gli altri task mettendosi in uno stato di attesa del verificarsi di una condizione e quindi nel frattempo passare ad eseguire gli altri task. Per esempio, un task che ha il compito di eseguire un posizionamento di un asse deve aspettare che l'asse arrivi alla quota target prima di continuare con altre operazioni. Nel frattempo, quindi, la CPU potrà eseguire altre istruzioni prgrammate in altre unit.
Al momento dell’accensione l’ordine con cui vengono eseguiti le unit presenti è quello dichiarato nella finestra UNIT MANAGER in QVIEW solo che il primo task eseguito è il secondo in lista poi si procede fino all’ultimo e quindi si esegue per ultimo il primo in lista.
Figura 1: esecuzione task (condizione iniziale). |
Figura 2: esecuzione task (flusso operativo). |
Oltre all’esecuzione del codice, la CPU si occupa di eseguire contemporaneamente i device. La trattazione dei device è rimandata al relativo capitolo; in breve, sono degli strumenti che forniscono delle funzionalità, richiamabili dal codice QCL o Ladder, per realizzare le operazioni più comuni che si incontrano nel campo dell’automazione industriale.
Ogni task inizia la sua esecuzione dalla prima riga di codice. Il controllo poi passa al task successivo quando si incontra nel codice un’istruzione WAIT (Figura 3).
Figura 3: flusso del programma (condizioni iniziali). |
Quando il controllo ritorna al task in questione esso riprende l’esecuzione del codice dal punto in cui l’aveva interrotta solo se la condizione posta subito a destra della parola chiave WAIT è vera altrimenti esegue nuovamente un cambio task, come è schematizzato nella figura 4.
Figura 4: flusso del programma (condizione di cambio task). |
Può succedere quindi che se in un task esiste un WAIT la cui condizione non è mai verificata il codice successivo a tale WAIT non venga mai eseguito.
In ogni unità il codice QCL viene eseguito fino alla fine. Per fare in modo che questo codice venga ripetuto continuamente si deve inserire un salto incondizionato dalla fine all’inizio del modulo. Ogni task, normalmente, ha una dotazione minima di codice QCL del tipo:
[< declaration code > BEGIN] [< initialization code >] MAIN: < operative code > WAIT 1 JUMP MAIN END
Il codice di inizializzazione presente prima del MAIN viene eseguito una sola volta in fase di accensione, mentre tutto quello che sta tra MAIN e JUMP MAIN viene eseguito ciclicamente. Se in un qualsiasi task non fosse presente l’istruzione JUMP MAIN, il task arriverebbe alla fine - END - paralizzando l’intero ciclo di multitasking. La CPU evidenzia che il ciclo è bloccato perennemente in un task attraverso il segnale di Watchdog Active (in QVIEW Monitor > CPU).
L’istruzione WAIT 1 è necessaria per assicurare il cambio di task.
Se si inserisce nel task3 questa istruzione
Task2.SUSPEND
il task2 viene sospeso e non verrà più eseguito.
Se, per esempio, nel task4 la CPU esegue l'istruzione
task2.RESUME
la unit task2 viene riammessa nel ciclo di multitasking e il codice contenuto in essa riprende a funzionare.
L'istruzione RESTART applicata ad una unit fa ripartire l'esecuzione del codice dalla prima istruzione della unit stessa. Per esempio l'ordine di esecuzione delle istruzioni contenute in un task sono schematizzate nella figura seguente:
Se nello stesso task o in un altro presente nel progetto la CPU esegue l'istruzione
task1.RESTART
la prossima esecuzione del codice contenuto nella unti task1 riprende come se fosse la prima esecuzione (first execution).
Può succedere che nella stesura di un programma si debbano gestire eventi a scadenza di tempo fissa e ripetibile. Essendo che il sistema multitasking cooperativo non ha un tempo di ciclo ripetibile, sono state inserite le unit a tempo che sono attivabili selezionando l’apposita casella nella unit property e dichiarando la base tempi da utilizzare.
Figura 1: dichiarazione di una unit a tempo |
Le unit a tempo sono prioritarie rispetto alle unit normali. Si deve porre attenzione al fatto che il codice inserito in una unità a tempo (QCL o LADDER che sia) non impieghi più tempo per essere eseguito del tempo di ripetizione impostato.
Nel caso questo succeda alcune ripetizioni del codice vengono “perse” (cioè non eseguite) e
la CPU segnala tale evento con una stato di “Time task lost”. Questo si può vedere nella finestra CPU Monitor.
Altra particolarità di questo tipo di unità è che non possono essere inserite le istruzioni di WAIT, per cui il codice contenuto deve essere eseguito in un solo ciclo.
Ci possono essere al massimo 7 unità a tempo per ogni progetto.
Può succedere che nella stesura di un programma si debbano gestire eventi provenienti da un ingresso in interruzione (tipicamente fotocellule o sensori di prossimità). Per assolvere a questa funzione sono state inserite le unità in interrupt che sono attivabili selezionando l’apposita casella nella unit property e dichiarando la linea di interruput ed il fronte di attivazione.
Figura 2: dichiarazione di un task in interruzione |
Le unità in interruzione sono prioritarie rispetto alle unità normali e rispetto alle unità a tempo,
e non possono essere inserite le istruzioni di WAIT, per cui il codice contenuto deve essere
eseguito in un solo ciclo. Per non sovraccaricare la CPU con le interruzioni è stato inserito il
controllo che se prima non si è completata l’esecuzione del codice di interruzione, il sistema
non abilita la linea di interrupt, per cui in nessun caso si possono accodare più interruzioni
provenienti dalla stessa linea.
Le unità in interrupt possono essere scritti sia in QCL che in Ladder.
Ci possono essere al massimo 3 unità in interruzione per progetto.
Il termine “device” identifica una categoria di dispositivi software atti a svolgere attività di supporto o controllo (più o meno complesse), semplificando operazioni e procedure proprie dell’automazione industriale.
Per esempio, un device può gestire un posizionatore di tipo CNC con uscita analogica +/-10V, rendendo disponibili tutte le funzioni, i comandi ed i parametri necessari alla corretta gestione dei posizionamenti (ricerca di home, comandi per la movimentazione manuale, parametri di velocità, tempo di inversione, …).
I device dispongono di proprie funzioni, variabili, comandi e parametri; l’utente ha la possibilità di configurarli ed inserirli all’interno del proprio progetto, in modo che uno o più device diventino parte integrante dell’applicativo sviluppato.
I parametri sono delle variabili che permettono di configurare il funzionamento del device (ad esempio la velocità di posizionamento, il conteggio, ecc.):
<device name>.<parameter device>
I comandi fanno eseguire al device determinate funzioni (ad esempio START, STOP, ecc.):
<device name>.<command name>
La lista dei device interni disponibili in un certo modello di QMOVE è inserita nei manuali d’installazione e manutenzione relativi alla CPU utilizzata.
La sintassi per la dichiarazione dei device viene trattata approfonditamente nella documentazione dei device. |
---|
L’utilizzo di un device deve essere dichiarato all’interno del file di configurazione oppure nella parte riservata alle dichiarazioni di ogni unit. La sintassi della dichiarazione varia a seconda del device (interno o esterno).
Per la dichiarazione del device interno, nel file di configurazione deve essere inserita la parola
chiave INTDEVICE.
Per ulteriori informazioni fare riferimento alla documentazione relativa ai device interni.
In questo capitolo si daranno delle informazioni preliminari per un corretto utilizzo dei devices interni. È indispensabile comunque completare ciò che segue con la documentazione specifica fornita per ognuno dei devices.
Come abbiamo già detto, nel capitolo dedicato al multitasking, una delle caratteristiche peculiari dei devices è il tempo di campionamento (Tc) che stabilisce ogni quanto tempo viene eseguita la gestione del device da parte della CPU.
Vediamo quali sono i criteri generici nella scelta dei tempi di campionamento. Solitamente un tempo piccolo permette al device di venire eseguito molto frequentemente e quindi di poter reagire velocemente alle azioni esterne (es.: miglior regolazione degli assi). Durante l’esecuzione del codice QCL un accesso in scrittura al device o un comando viene processato dopo un tempo massimo pari al tempo di campionamento. Questo fa sì che più piccolo è Tc, minore è il ritardo di esecuzione del device. Nel grafico di figura 1 si dà una esemplificazione di quanto detto.
Figura 1: ritardo aggiornamento device. |
La scelta dei tempi di campionamento per i device utilizzati nel progetto che si sta realizzando deve essere fatta con le opportune attenzioni. Una domanda che il lettore si sarà posto è la seguente: “Perchè non posso scegliere come tempi di campionamento il valore minimo consentito per ognuno dei device?”. In effetti in tal modo le prestazioni sarebbero le massime. Questa scelta però non è sempre possibile.
La CPU riserva una parte della sua risorsa di calcolo per la gestione dei devices utilizzati nel progetto. Ogni device ad ogni campionamento impegna una parte di questa risorsa. Per determinare e stimare l’utilizzo della risorsa consideriamo che la CPU ad ogni millisecondo mette a disposizione una risorsa pari a 100. Nella documentazione relativa ai firmware si puo’ trovare la percentuale di risorse che ogni device utilizza in un istante di campionamento. La CPU può
gestire nello stesso campionamento più devices e la risorsa occupata complessivamente è la somma delle percentuali relative ad ogni devices. Nella scelta dei tempi bisogna evitare che in qualche campionamento la risorsa complessiva superi il valore 100%. Automaticamente la CPU sfasa l’esecuzione dei device per evitare di superare il limite massimo della risorsa di calcolo disponibile.
Il grafico di figura 2 dà una esemplificazione di quanto detto. Nell’esempio sono stati installati:
Figura 2: impegno risorse CPU per gestione device interni. |
Un comando ad un device non viene elaborato subito dalla CPU ma al successivo tempo di
campionamento, senza per questo che la sequenza delle successive istruzioni QCL venga interrotta.
Per questo motivo il device potrà trovarsi a processare nello stesso istante di campionamento
più comandi, ed in questo caso la gestione del device non terrà conto della sequenza con
cui tali comandi sono stati dati ma li processerà secondo un ordine interno di priorità. Tale
priorita è specificata nella documentazione relativa ad ogni device.
Quando si vuole assicurare la sequenza con cui i comandi sono stati inseriti nella stesura del
codice QCL, bisogna porre delle istruzioni di WAIT e come condizione uno stato del device. In tal
modo l’istruzione WAIT attende l’esecuzione del comando prima di eseguire l’istruzione successiva.
Esistono dei comandi che sono tra loro complementari e cioè che producono ognuno l’effetto inverso dell’altro. Se ad un campionamento il device si trova ad eseguire alcuni comandi fra loro complementari, risulta avere effetto solamente l’ultimo della sequenza. Anche in questo caso per assicurare l’esecuzione dei due comandi fare riferimento al paragrafo “Comandi consecutivi e loro proprietà”.
Nella sezione INTDEVICE è possibile definire un gruppo di device attraverso le parole chiavi DEVGROUP e ENDDEVGROUP. Esempio:
DEVGROUP Assi X ANPOS2 4 3.CNT01 1 3.INP19 X.X 3.AN01 Y ANPOS2 4 3.CNT02 2 3.INP18 X.X 3.AN02 ENDDEVGROUP
I device all'interno di un gruppo sono sottoposti a due vincoli:
La definizione di un gruppo permette di garantire l'esecuzione di tutti i device che ne fanno parte nello stesso istante di campionamento. E' una funzionalità riservata per particolari applicazioni di motion control.
In questo capitolo verranno descritti i vari menu e comandi di QVIEW. Per l’approfondimento di alcune funzionalità proprie dell’ambiente Windows (Apri, Salva, …) si rimanda alla documentazione del sistema operativo.
La barra degli strumenti è composta da una serie di icone che ripropongono le funzionalità dei
comandi principali (o di uso frequente).
La barra di stato è composta da quattro sezioni distinte.
La prima sezione a sinistra è dedicata alla visualizzazione del valore della variabile selezionata. E' sufficiente cliccare sul tasto destro di una variabile o di un parametro di un device per leggere il suo valore in questa sezione (naturalmente bisogna che il collegamento seriale sia attivo).
La seconda sezione da sinistra visualizza la posizione del cursore (riga e colonna) e la modalità di scrittura (INS = inserimento di testo e OVR = sovrascrittura testo) (Figura 1).
La terza sezione da sinistra visualizza lo stato della porta seriale di comunicazione tra PC e CPU:
stato della porta (No connection o Connected with:…), protocollo di comunicazione in uso e velocità di trasmissione (Figura 2).
La quarta sezione più a destra visualizza i messaggi “Match OK” o “No Match” quando la comunicazione seriale e attiva e il progetto aperto è lo stesso di quello presente nella CPU oppure e diverso, rispettivamente.
Figura 1: seconda sezione da sinistra: posizione cursore. |
Figura 2: terza sezione da sinistra: stato e parametri porta di comunicazione seriale. |
Contiene i comandi per la gestione dei progetti e dei files che li compongono.
Permette di creare un nuovo progetto. Inizialmente viene richiesto il nome da assegnare al
progetto (Figura 1).
Viene quindi aperta automaticamente la finestra “Project Information” (Figura 2) per inserire i
dati del progetto che si intende realizzare. Questa tabella ha lo scopo di raccogliere una serie di
informazioni, essa può essere compilata anche in un secondo momento (in ogni caso non è
obbligatorio compilarla).
Figura 1: inserimento del nome del progetto. |
Figura 2: finestra con le informazioni di progetto. |
Permette di aprire un progetto esistente (Figura 3).
Figura 3: apertura di un progetto. |
E’ possibile aprire i progetti realizzati con versioni precedenti di Qview selezionando le diverse estensioni da “Tipo file”.
Permette di salvare le modifiche apportate al progetto in uso.
Permette di salvare una copia del progetto in uso (comprese le eventuali modifiche apportate) (Figura 4).
Figura 4: salvataggio di un progetto con un altro nome. |
Permette di chiudere il progetto in uso.
Permette di aggiungere una nuova unità al progetto in uso.
Le nuove unità possono essere:
Questa nuova unit verrà aggiunta in coda alla lista delle unit già presenti.
Permette di inserire una nuova unit al progetto in uso.
Le nuove unità possono essere le stesse elencate per il comando Add Unit.
Questa nuova unit verrà inserita nella lista appena sopra alla unit selezionata.
Ogni volta che viene creato una nuova unit di configurazione con i comandi “Add unit” o “Insert unit”, appare la finestra “Unit property” (Figura 5).
Figura 5: intestazione dell’unit di configurazione. |
In questa finestra è possibile assegnare un nome all’unit e una breve descrizione della unit. Una volta confermato con Ok, la unit di configurazione viene aggiunta alla lista delle unit e viene aperta la finestra di editor per iniziare a modificarla.
In un progetto deve esistere una sola unit di configurazione.
Ogni volta che viene creato una nuova unit QCL o LADDER con i comandi “Add unit” o “Insert unit”, appare la finestra “Unit property” (Figura 6, 7).
Figura 6: intestazione dell unità QCL. |
Figura 7: intestazione delle unit LADDER. |
In questa finestra è possibile assegnare un nome alla unit e una breve descrizione della unit.
Una volta confermato con Ok, la unit QCL o LADDER viene aggiunta alla lista delle unit e viene aperta la finestra di editor per iniziare a modificarla.
Nelle finestre “Unit property” è possibile specificare se la unit (QCL o LADDER) è una unit
Le unit di documentazione sono utilizzate dal programmatore per scrivere appunti, note, particolari di funzionamento. E’ possibile utilizzare queste unit solamente in modalità di testo.
Permette di rimuovere la unit selezionata.
Figura 8: selezione della unit da rimuovere. |
Prima dell’eliminazione della unit, il programma chiede se si vuole esportare la unit prima di rimuoverla; in caso contrario, la unit verrà persa.
Figura 9: richiesta di esportazione unit. |
Permette di importare una unit precedentemente esportata anche da un altro progetto (Figura 10).
Figura 10: Importazione di una unit. |
E’ possibile selezionare l’alternativa “Add unit…” o “Insert unit…” per importare la unit in coda alla lista o sopra la unit selezionata in quel momento.
Permette di esportare una copia della unit di progetto selezionata, per poterla trasferire ad un altro progetto. La copia originale rimarrà nel progetto stesso. La unit verrà esportata nella stessa directory del progetto aperto. La unit verrà esportata come un file con estensione unt.
Figura 11: Conferma di esportazione. |
Permette di esportare una copia dell unit di progetto selezionata rinominando la unit. La copia originale rimarrà nel progetto stesso.
Figura 12: richiesta di esportazione unit con rinomina del nome. |
Permette di modificare le proprietà della unit selezionata. In particolare è possibile impostare il comportamento Runtime della unit in questione, cioè la modalità di esecuzione della unit una volta che verrà trasferita nella CPU del Qmove. Le unit possono avere i seguenti comportamenti:
Normal
Fino al limite massimo consentito (totale massimo di unit: 65535).
Conferisce alla unit un comportamento Runtime ciclico (vedere il capitolo relativo al multitasking).
Interrupt
Massimo tre unit per progetto.
Conferisce alla unit un comportamento Runtime determinato da eventi esterni all'apparecchiatura (linee di interrupt hardware). Si puó determinare se l'esecuzione della unit sarà attivata sul fronte di salita o discesa del segnale entrante ed il numero della linea hardware ad essa collegata, impostabile da 1 a 8.
Time
Massimo sette unit per progetto.
Conferisce alla unit un comportamento Runtime determinato dallo scadere di un tempo prefissato, interno all'apparecchiatura.
Il predetto tempo è regolabile in un range da 1 a 999 millisecondi. Nell' inserimento di una nuova unit a tempo, il tempo proposto è di 100ms.
Figura 13: modifica delle proprietà di una unit. |
Aprendo la finestra “Unit property” (Figura 13) è possibile rinominare un unità precedentemente introdotta cambiando il suo Unit Name.
Permette di importare una unit realizzata con le vecchie versioni di Qview (*.mod). E’ possibile aggiungere la unit in coda alla lista (Add Module as unit) oppure inserirla in una posizione intermedia sopra a quella selezionata (Insert Module as unit).
Permette di esportare una o più unità in un formato compatibile con le precedenti versioni del Qview (moduli per Qview 2.x e Qview 3.x). Una volta selezionata questa funzione viene visualizzata la finestra di figura 14 dove è possibile selezionare quali unità esportare (vengono elencate solo le unità non LADDER).
Figura 14: esportazione delle unità come moduli. |
Per selezionare l’unità da esportare bisogna eseguire un doppio-click sull’unità stella.
Permette di esportare il file simboli dal progetto per poter riallineare i simboli nel terminale.
Figura 15: esportazione simboli. |
Permette di esportare il file simboli dal progetto, rinominandoli, per poter riallineare i simboli nel terminale.
Figura 16: esportazione simboli con rinomina. |
Questa funzionalità è disponibile se la compilazione del progetto è andata a buon fine. Esso permette di esportare il file binario (risultato della compilazione) utile per poter eseguire il download dell’applicativo nella CPU senza l’utilizo della comunicazione seriale (per esempio trasferendolo alla CPU attraverso una Multi Media Card). E’ possibile esportare il file binario con lo stesso nome del progetto (Export Binary File) oppure cambiando il suo nome (Export Binary File As…).
Permette di visualizzare una finestra (Figura 20) per l’inserimento delle informazioni specifiche del progetto.
Figura 17: visualizzazione informazioni sul progetto in uso. |
In questa finestra sono presenti delle cartelle che suddividono le informazioni di progetto per argomento. Alcune informazioni sono contrassegnate con un asterisco per indicare che sono obbligatorie per una completa informazione sul progetto. Se alcune di queste informazioni obbligatorie non vengono inserite, periodicamente appariranno dei messaggi che avviseranno il programmatore di questa mancanza (per disabilitare questi avvisi si veda Menu Options - Program Setup). In questa finestra esiste il tasto “Checksums” che inserisce in tabella i codici checksum del progetto automaticamente.
Il comando è disponibili solo selezionando una finestra di editor. |
---|
Permette di accedere ad un finestra “Print Manager” tramite la quale è possibile stampare una parte o tutto il progetto con alcune possibilità di configurazione della stampa stessa. In figura 18 viene mostrata questa finestra dove nel riquadro basso appare la lista delle unit che compongono il progetto. Selezionando queste unità con il mouse è possibile decidere quali stampare. Nel riquadro in alto a sinistra si possono impostare dei settaggi generici sulla dimensione del
font e sul numero di copie da eseguire.
Nel riquadro in alto a destra è possibile configurare la stampa dei task LADDER dove si può specificare:
Inoltre in alto a sinistra è possibile selezionare la stampa solo della parte dell unit evidenziata.
Figura 18: selezione modalità di stampa. |
È possibile richiamare direttamente gli ultimi 4 file aperti (Figura 19).
Figura 19: apertura progetti recenti. |
Chiude QVIEW chiedendo il salvataggio delle eventuali modifiche apportate al progetto in uso.
I comandi a seguire sono disponibili solamente quando è visualizzata un’unità con l’apposito editor. |
---|
Permette di inserire un nuovo elemento nella rete Ladder (deve essere visualizzata un’unità LADDER).
Permette di inserire un nuovo rung nella rete Ladder (deve essere visualizzata un’unità LADDER).
Permette di eliminare il rung selezionato nella rete Ladder (deve essere visualizzata un’unità LADDER).
Permette di collegare in verticale due elementi ladder. Il collegamento viene fatto sempre verso il basso e nella parte sinistra della cella selezionata (deve essere visualizzata un’unità LADDER).
Permette di sostituire l’elemento o tutti gli elementi obsoleti. Per una descrizione più completa si veda il capitolo “Editor LADDER - Elementi LADDER obsoleti” (deve essere visualizzata un’unità LADDER).
Permette di modificare le variabili utilizzate all’interno dell’elemento LADDER selezionato (deve essere visualizzata un’unità LADDER).
Permette di cancellare l’ultima modifica fatta.
Permette di annullare il comando di Undo e reinserire la modifica eliminata.
Per tagliare, copiare, incollare ed eliminare del testo o degli elementi.
Permette di selezionare tutto il testo o gli elementi contenuti in una finestra di editor.
Permette di compattare le righe di codice Ladder nel minor numero di celle possibili eliminando le righe vuote (deve essere visualizzata un’unità LADDER).
Permette di spostare in alto una riga di codice ladder (deve essere visualizzata un’unità LADDER).
Permette di muovere in basso una linea di codice Ladder (deve essere visualizzata un’unità LADDER).
Ricerca la parola inserita in funzione dei criteri di ricerca selezionati (Figura 20).
Criteri di ricerca
Figura 20: finestra inserimento criteri di ricerca. |
Una volta trovato un termine (comando Find), permette di continuare la ricerca dello stesso termine sul resto del documento (o sulle altre unità), mantenendo inalterati i criteri di ricerca.
Ricerca la parola inserita (Find What) con i criteri di ricerca impostati e la sostituisce con la
nuova parola (Replace With)(Figura 21).
Criteri di ricerca
Criteri di sostituzione
Figura 21: finestra inserimento criteri per ricerca e sostituzione. |
Sposta il cursore al numero di riga inserito (Figura 22).
Figura 22: inserimento numero di riga per spostamento cursore. |
Dal momento in cui l’esecuzione del progetto viene interrotta (per esempio per l’inserimento di un breakpoint), questo comando visualizza la riga di programma alla quale si è verificata l’interruzione. In figura 23, il comando Go to PC visualizza l’interruzione per l’inserimento di un breakpoint.
Figura 23: esecuzione programma interrotta da breakpoint. |
Permette di spostarsi tra le unit del progetto.
Quando fosse necessario spostarsi tra alcune unit del progetto ignorandone alcuni altri, selezionare uno per volta le unit da visualizzare e premere la barra spaziatrice. A fianco delle unit selezionate compare un punto rosso (Figura 24).
Con i comandi Next e Previous Selected Unit è possibile scorrere in avanti ed indietro solamente tra le unit selezionate.
Per rimuovere la marcatura, selezionare la unit e ripremere la barra spaziatrice; il punto rosso scompare.
Figura 24: selezione unit da analizzare. |
Contiene i comandi la gestione dei progetti e dei dati contenuti nella CPU.
Converte il progetto in uso in un formato interpretabile dalla CPU. Il progetto potrà essere scaricato nella CPU solo se la compilazione si è conclusa senza errori (Figura 25).
Figura 25: finestra compilazione progetto. |
Nel caso di compilazione del progetto conclusa con errori, è possibile visualizzare sull’editor la riga di codice contenente l’errore facendo un doppio click con il mouse sul messaggio fornita dalla finestra di compilazione.
La funzionalità ha lo scopo di indurre la compilazione forzata di tutto il progetto indipendentemente che esso sia già stato compilato o meno.
Permette eseguire un check della rete Ladder. Sul desktop appare la finestra del risultato della compilazione eseguita (Figura 26).
Figura 26: finestra compilazione rete ladder. |
Visualizza o nasconde la finestra del risultato dell'ultima compilazione (Figura 24).
Questo comando è disponibile solo dopo l’attivazione della comunicazione seriale PC - QMOVE. |
---|
Permette di scaricare nella CPU il progetto compilato. Le varie fasi del download vengono visualizzate in una finestra dedicata (Figura 27).
Figura 27: esito download. |
Questo comando è disponibile solo dopo aver eseguito il download dell’applicativo. |
---|
L’applicativo che l’utente trasferisce nella CPU è costituito da informazioni non mutabili ed informazioni mutabili.
Informazioni non mutabili
Sono le informazioni dell’applicativo che non subiscono variazioni, quali istruzioni QCL, simboli utilizzati nel progetto, titolo applicativo, …
Informazioni mutabili Sono le informazioni che indicano situazioni di funzionamento dell’applicativo quali aree dati per devices interni, valore variabili, array system, contenuto datagroup e dati il cui valore viene modificato durante il funzionamento (tutti i dati applicativo).
Il backup è un comando che consente di creare una copia di sicurezza di tutti i dati mutabili, registrandola all’interno della memoria interna non-volatile. L’utilità di questa operazione deve essere vista nella possibilità di ripristinare tutta la parametrizzazione esistente in un determinato momento. Poichè i valori vengono copiati in una memoria non-volatile, esiste la massima sicurezza nel dispositivo di memorizzazione (Figura 28).
Condizioni che permettono l’esecuzione del comando di backup:
Se il backup, eseguito da terminale operatore, impiega un tempo maggiore del timeout del terminale, interviene l’errore di timeout error nella comunicazione seriale tra CPU e terminale.
Figura 28: richiesta conferma procedura di backup. |
Questo comando è disponibile solo dopo aver eseguito il download dell’applicativo. |
---|
L’applicativo che l’utente richiama dalla CPU è costituito da informazioni non mutabili ed informazioni mutabili.
Informazioni non mutabili
Sono le informazioni dell’applicativo che non subiscono variazioni, quali istruzioni QCL, simboli
utilizzati nel progetto, titolo applicativo, …
Questi dati sono memorizzati in flash memory.
Informazioni mutabili
Sono le informazioni che indicano situazioni di funzionamento dell’applicativo quali aree
dati per devices interni, valore variabili, array system, contenuto datagroup e dati il cui
valore viene modificato durante il funzionamento (tutti i dati applicativo).
Questi dati sono memorizzati in memoria tamponata.
Il comando restore consente di ripristinare tutte le informazioni mutabili con quelle presenti
al momento del backup (Figura 29).
Il contenuto del backup viene cancellato durante la procedura di download; infatti non ha
alcun senso copiare i valori dei dati mutabili di un applicativo su un applicativo diverso.
Condizioni che permettono l’esecuzione del comando di restore:
Figura 29: richiesta conferma procedura di restore. |
Questo comando è disponibile solo dopo aver eseguito il download dell’applicativo. |
---|
Salva i dati presenti nella CPU (valori delle variabili ritentive) in un file .DAT; è possibile definire la directory di destinazione del file (Figura 30).
Figura 30: salvataggio dati CPU su file. |
Questo comando è disponibile solo dopo aver eseguito il download dell’applicativo. |
---|
Sostituisce i valori delle variabili ritentive presenti nella CPU con i valori delle stesse variabili archiviate in un file .DAT (Figura 31). La sostituzione interessa solamente le variabili in comune all’applicativo ed al file .DAT; se, per esempio, nella CPU sono state aggiunte delle variabili successivamente all’archiviazione dei dati, queste non saranno interessate dalla sostituzione.
Figura 31: sostituzione dati CPU con file .DAT |
Questo comando è sempre disponibile. |
---|
Converte il file .DAT selezionato in un file di testo (.TXT) contenente il nome delle variabili ed il relativo valore. Il file di testo viene generato all’interno della directory che contiene il file .DAT e gli viene assegnato lo stesso nome del file .DAT (Figura 32).
Figura 32: conversione file dati. |
Questo comando è disponibile dopo l’apertura di un progetto. |
---|
Confronta i checksums del progetto in uso con quelli dell’applicativo scaricato nella CPU (Figura 33), se sono gli stessi vuol dire che la CPU contiene il progetto su cui sto lavorando. Le eventuali diversità vengono segnalate con i valori di checksum in rosso. Vengono confrontati i seguenti tipi di dati:
ATTENZIONE! La compilazione dello stesso progetto con due Qview di build diverse garantisce le stesse funzionalità, ma non viene garantito che i codici checksum si mantengano uguali.
Figura 33: riepilogo e confronto checksum. |
La colonna CPU visualizza i valori presenti in CPU e rappresentanti il suo applicativo.
La colonna Project viene aggiornata all’apertura del progetto (se precedentemente compilato) e dopo ogni compilazione.
Questo comando è disponibile solo dopo l’attivazione della comunicazione seriale PC - QMOVE. |
---|
Visualizza il nome assegnato al progetto. Questo nome è stato definito nella finestra Project Information. Durante il download il Project ID viene scaricato nella CPU con l’applicativo ed è poi visualizzabile tramite il comando Project ID View (Figura 34).
Figura 34: visualizzazione stringa progetto. |
Contiene i comandi per l’esecuzione dell’applicativo scaricato nella CPU.
Questo comando è disponibile dopo un download. |
---|
Mette in esecuzione l’applicativo scaricato nella CPU..
Questo comando è disponibile dopo un run. |
---|
Interrompe l’esecuzione dell’applicativo residente nella CPU (i device continuano comunque a funzionare).
Questo comando è disponibile dopo uno start o uno stop. |
---|
L’esecuzione dell’applicativo viene interrotta e al RUN successivo il programma riparte dalla prima unit.
Questo comando è disponibile solo dopo l’attivazione della comunicazione seriale PC - QMOVE. |
---|
Cancella l’applicativo residente nella CPU. La cancellazione dei dati è definitiva; viene quindi richiesta la conferma al reset dell’applicativo (vedi figura 35).
Figura 35: richiesta conferma procedura di reset progetto. |
Questo comando è disponibile solo dopo un download e selezionando la finestra di editor testo. |
---|
Questo comando permette di eseguire il progetto in uso un passo alla volta; ad ogni step l’esecuzione
del flusso di programma avanza di un passo. Raggiunta l’istruzione di wait, la finestra di
editor passa a visualizzare la unit successiva permettendo in questo modo l’esecuzione del programma un
passo alla volta su tutte le unit che compongono il progetto.
Una freccia verde sulla sinistra delle finestra di editor identifica la riga di programma che non è ancora
stata eseguita (Figura 36). Nel caso di unità LADDER sarà possibile eseguire un rung ad ogni passo.
Figura 36: esecuzione programma in modalità Step. |
Questo comando è disponibile solo dopo un download e selezionando la finestra di editor testo. |
---|
Questo comando permette di eseguire il progetto in uso un’istruzione alla volta; ad ogni step
l’esecuzione del progetto avanza di un’istruzione. Raggiunta l’istruzione di WAIT, l’esecuzione del codice
continua normalmente sulle altre unit fino a ritornare a quella in uso riprendendo l’esecuzione
passo a passo.
Una freccia verde sulla sinistra delle finestra di editor identifica la riga di programma che è
stata eseguita (Figura 37). Nel caso di un’unità LADDER sarà possibile eseguire un rung ad ogni
passo.
Questo comando è disponibile solo dopo un download e selezionando la finestra di editor testo. |
---|
E’ possibile inserire un massimo di 5 breakpoint. Vengono resettati allo spegnimento della CPU e con il download del progetto. |
---|
Questo comando permette di inserire un breakpoint ovvero di identificare una riga di codice, raggiunta la quale, l’esecuzione del programma si interrompe. E’ possibile definire più punti di breakpoint. Selezionando una riga di codice sulla quale è stato inserito un breakpoint, il comando Toggle breakpoint elimina il breakpoint. L’inserimento del breakpoint viene visualizzato sulla sinistra della finestra di editor con un contrassegno rosso all’interno del quale viene visualizzata la sigla ST (Figura 37). E’ possibile inserire un breakpoint anche in una unit LADDER in corrispondenza di uno dei rung.
Figura 37: inserimento breakpoint. |
Questo comando è disponibile solo dopo un download. |
---|
Questo comando elimina da tutti i task tutti i breakpoint inseriti.
Questo comando è disponibile solo dopo un download. |
---|
E’ possibile inserire un massimo di 5 watchpoint. Vengono resettati allo spegnimento della CPU e con il download del progetto. |
---|
Questo comando permette di interrompere l’esecuzione del progetto in uso alla soddisfazione di una particolare condizione; si può quindi parlare di breakpoint condizionato. Selezionando il comando watchpoint viene proposta la finestra di figura 38 che visualizza le condizioni di interruzione del programma che sono state impostate.
Figura 38: elenco watchpoint. |
Figura 39: impostazione parametri di watchpoint. |
La finestra di figura 39, visualizzata alla pressione del tasto Add (Figura 38), permette di impostare la condizione di arresto del programma.
Contiene i comandi per la diagnostica del sistema QMOVE e dell’esecuzione di progetti.
L’ambiente Qview prevede che per i devices ci sia, oltre che alla lista di stati parametri comandi, un pannello che permetta all’utilizzatore un semplice approcio con il devices stesso. vengono visualizzati il nome assegnato al device ed il tipo di device (Figura 51).
Figura 51: elenco pannelli dei device. |
Selezionando un device (con il tasto ENTER o con doppio clic) viene proposta una finestra (Figura 52) all’interno della quale è possibile visualizzare i dati del device; per una spiegazione dei devices panel, fare riferimento all’apposito help.
Figura 52: esempio di un pannello. |
La finestra CPU MONITOR fornisce una serie di informazioni generali riguardanti lo stato della CPU e le tempistiche relative all'esecuzione del progetto. La finestra CPU Monitor Panel si compone di tre sezioni:
In questa finestra vengono fornite informazioni relative allo stato della CPU.
Si possono, inoltre, leggere i tempi MINIMUM TIME e MAXIMUM TIME che sono il minimo e massimo tempo impiegato per eseguire il progetto.
Vi è inoltre un tasto di Reset Timing il quale azzera i due valori ed il Running time riabilitando il conteggio del tempo di elaborazione.
Figura 56: CPU general panel. |
In questo menù possono essere controllati tutte le unit elaborati dal programma, e possono essere ricavate informazioni di vario genere. Tutti le unit possono dare infomazioni sul tempo di esecuzione minimo, massimo ed attuale.
Per i task normali si possono avere inoltre informazioni relative al WATCHDOG. Quando viene segnalato un WATCHDOG per un task significa che la CPU ha impiegato più di 200ms per eseguire il suo codice senza mai avere eseguito nessun altro task (questa è una anomalia che il programmatore dovrebbe risolvere).
Per tutti gli altri task si possono avere ulteriori informazioni relative a :
Figura 57: CPU general panel. |
Tutte le informazioni della videata precedente (Figura 57) possono essere visualizzate solo se i check-sum del programma in CPU e su PC corrispondono, altrimenti, nella videata di Task Info verranno visualizzati solamente i task di programma senza alcun’altra informazione (Figura 58).
Figura 58: CPU Task info. |
Nel caso di errori, i vari campi assumeranno il colore rosso, in caso contrario, i campi rimarranno di colore bianco.
L’oscilloscopio permette di visionare nel tempo cio’ che accade alla CPU (Figura 59).
Figura 59: CPU Oscilloscopio. |
La velocità di acquisizione è determinata da due fattori:
- Velocità della seriale.
- Quanti dati vogliamo controllare.
Se si vuole fare un’acquisizione si inserisce il Capture Time (S) e la scansione inizia continuando per il tempo impostato, comunque non superiore ai 9999 sec.
Quando si lancia una acquisizione tutto il resto del Qview viene bloccato proprio per non togliere risorse a questa funzionalità.
L’acquisizione può essere associata ad una variabile qualunque, tranne un datagroup, e l’acquisizione
nel tempo può essere abilitata anche con macchina in funzione senza pregiudicarne il funzionamento in quanto il controllo non grava sull’elaborazione.
L’acquisizione può essere fermata in qualunque momento tramite la pressione del tasto Backspace.
Impostazioni per la memorizzazione:
CAPTURE TASK: Questo parametro determina in quale campo agire per effettuare la misurazione:
- Su tutti i task , se impostato come CPU CICLE TIMINGS , in questo modo possiamo vedere il
tempo di ciclo di tutto il programma (Min. Max. Run).
- Su un task singolo, se impostato come task a tempo o ad interrupt, in questo modo possiamo
vedere il tempo di ciclo del singolo task seleziona to (Min. Max. Run). Naturalmente se il task
selezionato risulta essere un task normale il tempo di scansione che verrà visualizzato sara’
quello di tutto il programma, questo particolare caso comunque viene evidenziato con l’ausilio
di un messaggio (Figura 60).
Figura 60: CPU Oscilloscopio Capture Task. |
CHART: Questa finestra serve per impostare al meglio le caratteristiche grafiche di visualizzazione ed i riferimenti relativi alle misurazioni effettuate (Figura 61).
Figura 61: CPU Oscilloscopio Chart. |
Per conoscere il significato dei vari tasti basta posizionarsi sopra al tasto interessato con il
cursore del mouse e comparirà la descrizione specifica.
Oltre alle misure delle tempistiche dei task è possibile monitorare l’andamento nel tempo di
una variabile di riferimento che si puo specificare nella casella “Reference variable” nella sezione
Capture.
Se la variabile non esiste compare un messaggio di segnalazione, ma la registrazione viene
compiuta ugualmente senza, naturalmente, la variabile.
Questo comando è disponibile dopo l’apertura di un progetto esistente e l’apertura della porta di comunicazione seriale PC - QMOVE. |
---|
La finestra BUS Information (Figura 63) visualizza la composizione hardware e le versioni/release dei firmware. Queste informazioni vengono acquisite dalla CPU tra il BUS; per questo motivo sono disponibili solamente se la comunicazione è attiva.
Figura 63: composizione bus. |
Questo comando è sempre disponibile. |
---|
Il comando Upgrade QCL Card Library permette di aggiornare le librerie del linguaggio QCL (Figura 64). Tali librerie contengono informazioni relative a:
Figura 64: aggiornamento librerie. |
Questo comando è sempre disponibile. |
---|
Il comando Upgrade Functions Library permette di aggiornare le librerie di funzioni QCL (Figura 65).
Figura 65: aggiornamento librerie delle funzioni QCL. |
Questo comando è sempre disponibile. |
---|
Il comando Upgrade ladder elements permette di aggiornare le librerie degli elementi ladder (Figura 67).
Figura 67: aggiornamento librerie Ladder. |
I comandi del menu Options permettono di personalizzare alcune funzionalità di QVIEW.
Permette di aprire e chiudere la porta di comunicazione seriale PC - QMOVE.
Questo comando è sempre disponibile. |
---|
Viene presentata una finestra composta da sei diverse cartelle.
Questo comando è sempre disponibile. |
---|
Permette di personalizzare l’interfaccia grafica di QVIEW, assegnando dimensioni e colori diversi in funzione del testo QCL da editare (Figura 68).
Figura 68: personalizzazione editor QCL. |
* Font Size: definisce le dimensione del font utilizzato nella finestra di editor.
Permette di personalizzare l’interfaccia grafica di QVIEW, assegnando dimensioni e colori diversi agli elementi che conpongono l’editor LADDER (Figura 69).
Figura 69: personalizzazione editor Ladder. |
- Cell Width: definisce la larghezza delle caselle dell’editor.
- Cell Height: definisce l’altezza delle caselle dell’editor.
- Undo Levels: numero massimo di UNDO possibili.
- Cursor type: scelta del tipo di cursore.
- End Rung Mode: scelta del tipo di fine rung.
- Grid Drawing Style: scelta del tipo di tratto utilizzato per disegnare la griglia.
- Element Placing Style: grafica utilizzata come sfondo degli elementi LADDER selezionati.
- Element Contour Style: grafica utilizzata come sfondo dell’area dell’editor selezionata.
- Grid Visible: seleziona se rendere visibile la griglia.
- Note image Visible: seleziona se rendere visibili il simbolo che indica la presenza di una
nota associata ad un elemento LADDER.
- Row Number visible: seleziona se rendere visibile i numeri di riga.
- Rung Number visible: seleziona se rendere visibile i numeri di rung.
- Obsolete State Visible: seleziona se indicare gli elementi LADDER obsoleti (cambiandone i
lcolore di sfondo).
- Automatic New Rung Generation: seleziona se rendere possibile la generazione automatica
dei rung al momento dell’inserimento di un nuovo elemento LADDER.
- Automatic Element Property Editor: seleziona se far apparire automaticamente la finestra
con le proprietà dell’elemento LADDER una volta che viene inserito.
- Color: definisce il colore dello sfondo della finestra di editor.
- Element Color: permette di specificare il colore dell’elemento selezionato.
- Element Name: permette di selezionare gli elementi dell’editor per specificarne il colore.
Gli elementi selezionabili sono elencati in questa finestra.
In questa sezione del “Program Setup” è possibile associare ad una serie di HotKeys (Tasti Caldi) l’inserimento degli elementi LADDER più utilizzati. Nella Figura 70 è possibile vedere che è possibile associare l’inserimento di 10 elementi LADDER alla combinazione dei tasti CTRL + ALT + 0…9 e altri 10 a CTRL + SHIFT + 0…9. Esiste già un associamento per default, ma il programmatore potrà modificarlo.
Figura 70: associazione ai tasti caldi. |
Per utilizzare le porte COM3 e COM4 è necessario adottare degli IRQ diversi da quelli utilizzati per altri dispositivi hardware (mouse, COM1, COM2, …). |
---|
Permette di configurare la porta di comunicazione seriale (Figura 71).
Figura 71: impostazione parametri porta di comunicazione seriale. |
- COM Port: permette di selezionare la porta di comunicazione seriale da utilizzare. - Communication Speed: definisce la velocità di trasmissione della comunicazione seriale; selezionando l’opzione autodetect, QVIEW rileva automaticamente la velocità di trasmissione da adottare.
E’ possibile selezionare tra due gruppi di impostazione dei tempi della comunicazione seriale (Timeouts Group A e Timeouts Group B).
Permette di personalizzare l’ambiente di sviluppo (Figura 72).
Figura 72: impostazioni generali. |
- View Toolbar: abilita la visualizzazione della toolbar del progetto.
- View Status Bar: abilita la visualizzazione della barra di stato.
- View Ladder Toolbar: abilita la visualizzazione della toolbar del ladder.
- View Logo At Startup: abilita la visualizzazione del logo Qview allo startup del programma.
- View Ladder Warnings: abilita la visualizzazione dei messaggi di warning nella finestra con i
risultati della compilazione.
- Automatic Project Backup: abilita l’esecuzione di una copia di backup del progetto ogni volta
che viene salvato.
- Open the last project at startup: abilita l’apertura dell’ultimo progetto salvato ad ogni apertura
del Qview.
- Export unit before remove it: abilita la richiesta di esportazione dell’unità prima della cancellazione
della stessa.
- View Compilation Warning report: abilita la visualizzazione dei messagi di warning durante la
compilazione.
- Export Binary file After Compilation: abilita l’esportazione automatica del file binario risultato
della compilazione.
- Export symbol file after compiling: abilita l’esportazione automatica del file simboli ad ogni
compilazione andata a buon fine. Il file simboli verra' esportato nella stessa directory del file di
progetto con lo stesso nome del file di progetto. Se il progetto è nuovo e non ancora salvato su
disco, Qview genererà una finestra di dialogo per chiedere dove ubicare il file simboli.
- Automatic Project Information update: se selezionato appare un messaggio in cui si chiede
all’utente se le informazioni di progetto contenute in “Project information” sono state aggiornate.
Questo messaggio appare se l’applicativo non viene salvato da almeno un’ora.
- Project Information update before project saving: se selezionato, ogni volta che si salva il
progetto, appare un messaggio in cui si avvisa che i dati obbligatori (segnalati con un asterisco)
da inserire in “Project information” non sono completi.
In questa finestra è possibile salvare le impostazioni in un file e specificare anche alcuni dati relativi all’autore.
Permette di impostare i dati necessari ad inviare un'email direttamente da Qview4 senza l'ausilio di un mail client esterno (Figura 73).
Vedi figura 73: impostazioni generali. |
- Mail From…: in questo campo è possibile impostare l'indirizzo da dove la mail dovra' partire.
Tale indirizzo potrebbe essere il proprio indirizzo email.
- Mail To…: è l'indirizzo di chi riceverà la mail. Solitamente va impostato come support@qem.it,
ma è possibile impostare liberamente anche altri indirizzi email.
- User ID: ID Utente necessario per effettuare il collegamento al provider di servizi internet
(ISP).
- SMTP Host: è l'indirizzo del server di posta elettronica.
- Port: è la porta IP di comunicazione. Generalmente il valore 25 è corretto per la stragrande
maggioranza dei casi.
Questo comando è sempre disponibile. |
---|
Dal menu help è possibile richiamare gli help in linea e alcune informazioni su QVIEW.
Richiama l’help in linea relativo al linguaggio di programmazione.
Richiama l’help in linea per la programmazione in QCL.
Richiama l’help in linea relativo agli elementi LADDER.
Richiama l’help in linea relativo alle funzioni QCL.
Richiama l’help in linea relativo alle funzioni QCL realizzate dall’utente.
Per accederte a Technical Info bata selezionare:
TECHNICAL INFO. Viene visualizzata la finestra di figura 74 dove vengono raccolte tutte le
informazioni del Personal Computer nel quale è istallato il Qview, complete di impostazioni e
setup particolari , vengono inoltre registrate le DLL utilizzate per permettere di avere il massimo
numero di informazioni possibili.
Una volta raccolte tutte queste informazioni, è possibile trasferirle in modo automatico su un
documento Word pronte per essere inviate per Email (Figura 76), oppure si può eseguire l’invio
di queste informazioni via email in modo automatico direttamente da Qview 4 (Data Operations).
Figura 74: informazioni relative ai software e hardware installati. |
Le informazioni sono suddivise in tre categorie.
- PC System Info: raccoglie tutte le informazioni Hardware e Software del Computer con il
quale si stà lavorando.
- Qview System Info: raccoglie tutte le informazioni relative al programma Qview che si stà
utilizzando.
- Project Information Info: raccoglie tutte le informazioni relative al progetto aperto in Qview.
Viene visualizzata la versione di QVIEW e gli estremi per contattare la QEM srl.
Come è stato anticipato all’inizio di questo manuale, QVIEW è un indispensabile supporto per la programmazione in QCL e LADDER, sia per la stesura e la compilazione del codice, sia per il debugging del progetto realizzato.
Cos’è il debugging? Solitamente il tempo impiegato per la realizzazione di un progetto si suddivide
in maniera equa tra il tempo per la programmazione e il tempo per la correzione degli errori. Il debugging è l’insieme di tutte le operazioni che permettono di rilevare questi errori che causano funzionamenti non desiderati. Gli strumenti che il QCL e LADDER mette a disposizione sono i seguenti:
Una volta compilato e fatto il download, è possibile mettere in esecuzione l’applicativo scaricato selezionando il comando Run dal menu Debug; è anche possibile eseguire un’istruzione per volta, selezionando il comando Step dal menu Debug.
Ad ogni comando di Step, si può osservare lo scorrere di una istruzione; sull’editor viene evidenziata la riga di codice in esecuzione con una freccia sul bordo sinistro della finestra. Durante la scansione del codice, si può osservare l’effettivo flusso delle istruzioni ed il valore delle variabili.
Il comando Step esegue fedelmente la successione delle istruzioni QCL e LADDER e, la visualizzazione
sull’editor, si sposta di unit in unit quando incontra un’istruzione di WAIT. Nel caso di unit scritte in LADDER l’esecuzione passo-passo consiste nel eseguire il codice un rung per ogni passo.
Il comando Debug > Step Over ha lo stesso effetto del comando Step; la successione delle istruzioni visualizzate si limita però a quelle dell’unità visualizzata sull’editor. E’ un comando utile per la scansionare il codice contenuto in una sola delle unità componenti il progetto.
Il breakpoint è un punto preciso del programma in cui l’esecuzione del progetto si deve interrompere. Per fissare un breakpoint, posizionare con il cursore nel punto dell’editor in cui si desidera bloccare il programma e selezionare il comando Debug > Toggle Breakpoint; in corrispondenza dell’introduzione del breakpoint viene visualizzato il simbolo . Con comando di RUN il programma verrà eseguito fino all’istruzione marcata dal breakpoint (esclusa) e quindi si bloccherà; la CPU assumerà lo stato di STOP. Nella finestra CPU si accenderà il LED Breakpoint per indicare l’intervento di un breakpoint. Sull’editor la riga interessata dal breakpoint viene indicata con il simbolo . Con un nuovo RUN il programma verrà eseguito ancora una volta fino ad incontrare di nuovo il breakpoint. Questa funzionalità è molto utile per osservare lo stato delle variabili in un certo punto del codice che non sarebbe possibile apprezzare in fase di esecuzione normale. Inoltre il sistema del breakpoint può essere usato per vedere se una parte di codice viene eseguita oppure no. E’ possibile posizionare un numero massimo di 7 breakpoint contemporaneamente lungo il codice. Nel caso ci siano più di un breakpoint per visualizzare velocemente il punto del codice su cui si è bloccato il programma si può usare l’icona (Go To PC).
Il watchpoint è un breakpoint condizionato dal valore di una variabile, di un ingresso o di un’uscita
digitale, di un array, di un Data Group o di un parametro di un device.
La domanda a cui risponde il watchpoint è: in che punto del programma un parametro o una
variabile fissata acquisisce il valore impostato?
Selezionando Debug > WatchPoint, appare la finestra Watchpoint List (Figura 1). Questa finestra
contiene il parametro su cui impostare il watchpoint e il valore a cui deve “scattare”.
Figura 1:elenco watchpoint. |
Con il tasto Add è possibile scegliere nome e tipo di parametro da usare per il watchpoint.
Una volta introdotte queste informazioni, digitare il valore al quale il watchpoint si deve attivare
per bloccare l’esecuzione del programma.
Le librerie QCL sono una componente fondamentale per il compilatore QCL, mettendo a disposizione - in fase di compilazione - una serie di informazioni riguardanti i device e l’hardware. Tali informazioni sono necessarie per sapere quali parametri utilizza un device interno, le loro caratteristiche e la loro collocazione in memoria; quali comandi sono disponibili per quel determinato device e la sua sintassi di configurazione.
Al momento della realizzazione di un nuovo progetto è quindi necessario verificare che la versione di QVIEW installata contenga le librerie necessarie per la gestione dei devices e dell’hardware da utilizzare (fare riferimento alle schede tecniche hardware). Selezionare la voce Technical Info dal menu Help; Appare la finestra di figura 1.
Figura 1: componenti software installati. |
Alla riga LIBRARY viene specificato l’identificatore della libreria in uso (nell’esempio 1LIB3004).
Nel caso non si sia in possesso delle librerie richieste è necessario fare l’upgrade delle stesse
selezionando Upgrade Library… dal menu Tools e seguire le istruzioni proposte nelle finestre che
appariranno.
Durante la compilazione di alcune istruzioni QCL il compilatore genera internamente delle etichette che vengono utilizzate per successive elaborazioni. Esiste un limite di 999 etichette generabili per ogni unità, superato il quale non è possibile compilare il file sorgente. Per conoscere il numero di etichette interne generate bisogna sapere che le istruzioni IF, ELSE, CALL, SUB, o label (es. MAIN) generano una etichetta, mentre le istruzioni FOR e WHILE ne generano due. L’unica soluzione è quella di eliminare dal sorgente alcune delle istruzioni viste sopra e rientrare nei limiti ammessi.
Durante la compilazione di espressioni il massimo numero di operandi annidati è 6.
Ad esempio una istruzione di questo tipo è ammessa:
Variabile = 1+(1+(1+(1+(1+1))))
mentre questa provoca un errore:
Variabile = 1+(1+(1+(1+(1+(1+1)))))
Il numero massimo di elementi e passi ammessi in un datagroup è di 65534. Il compilatore segnala errore se tale limite viene superato.
La dimensione massima di un array (sia ARRSYS che ARRGBL) è di 65535 elementi. Il compilatore segnala errore se tale limite viene superato.
Il passo di incremento in un ciclo FOR deve essere numerico. Non è possibile usare variabili o espressioni.
Nella dichiarazione di un datagroup la sottosezione DATAPROGRAM è obbligatoria.
È importante ricordare che una conversione dal tipo intero (Flag, Byte Word o Long) al tipo Single non corrisponde ad un aumento di precisione ma cambia solamente il formato in cui il valore è rappresentato. |
---|
Per espressione si intende un insieme di operatori, costanti e variabili che, risolti, definiscono un valore numerico risultante. Il QCL mette a disposizione l’operatore di assegnamento “=” nella forma generale:
variabile = espressione
Non sono supportate le assegnazioni multiple tipo variabile = variabile = espressione
Per quanto riguarda l’istruzione di assegnamento, la regola di conversione è semplice: il QCL
converte il valore alla destra del segno uguale nel tipo del dato sinistro.
Esempio:
Consideriamo le seguenti variabili:
SYSTEM sfFlag F sbByte B swWord W slLong L ssSingle S
sbByte = swWord
Viene eliminato il primo byte della variabile swWord assegnando a sbByte solo il byte meno
significativo. Se il valore di swWord è compreso tra 127 e -128 i due valori risultano uguali e non
viene eseguito alcun troncamento. Se il valore di swWord è esterno ai valori precedentemente
considerati il valore di sbByte riflette solamente il valore del byte meno significativo di swWord.
ssSingle = slLong
Il valore di slLong viene convertito nel formato reale a singola precisione.
sfFlag = ssSingle
La variabile sfFlag viene assegnata al valore 1 se ssSingle rappresenta un valore diverso da zero.
Quando in una espressione sono utilizzati dati di tipo differente, il compilatore QCL li converte tutti nello stesso tipo e, in particolare, nel tipo della dimensione che occupa più memoria, secondo quella che nei linguaggi viene definita promozione di tipo. Dopo che il compilatore ha applicato queste regole di conversione ogni coppia di operandi risulta della stessa dimensione che sarà anche la dimensione del risultato.
Ad esempio:
Variabile = (sbByte*sfFlag) + (swWord / sbByte) - (ssSingle+sfFlag)
Prima il compilatore converte sfFlag in BYTE e calcola il valore della moltiplicazione, poi il secondo sbByte in WORD e calcola il valore della divisione, poi sfFlag in SINGLE e calcola il valore della somma; il risultato di sbByte*sfFlag viene convertito in Word e ne calcola il valore. Quindi, questo risultato viene promosso a SINGLE per eseguire la sottrazione con il risultato di ssSingle+sfFlag.
Per quanto riguarda le costanti nelle espressioni, vengono convertite sempre nel tipo intero (FLAG, BYTE, WORD o LONG) della dimensione più indicata per contenere il valore (se nella costante non vi è il punto decimale). Se la costante contiene il punto decimale, viene convertita in tipo SINGLE.
Esempio:
Variabile = swWord / sbByte
con swWord = 5 e sbByte = 2
Variabile risulta di tipo WORD con valore 2 perdendo così la parte decimale.
Se si riscrive l’espressione come:
Variabile = (swWord * 1.0) / sbByte
con swWord = 5 e sbByte = 2
Variabile risulta di tipo SINGLE con valore 2,5. Questo perchè il prodotto della variabile swWord
con una costante con parte decimale provoca la conversione del risultato in SINGLE.
Consigliamo i programmatori di seguire delle semplici convenzioni di scrittura del codice. Tali convenzioni non sono obbligatorie per il funzionamento, ma aiutano
Le regole sono:
In questo capitolo vengono riassunte le parole chiave del QCL.
ABS | valore assoluto |
---|---|
ACOS | arcocoseno |
AND | AND logico |
ANDB | And logico bit a bit |
APPLICATION | Radice implicita di ogni simbolo utilizzato |
ARRGBL | sezione file di configurazione |
ARRSYS | sezione file di configurazione |
ASIN | arcoseno |
ATAN | arcotangente |
B | byte |
BEGIN | sezione codice operativo nella unit |
BREAK | break |
BUS | sezione file di configurazione |
CALL | chiamata subroutine |
CASE | istruzione SWITCH-CASE |
CEIL | arrotondamento a intero non inferiore a quello dato |
CONST | sezione file di configurazione |
COS | coseno |
COT | cotangente |
D | double |
DATAGROUP | sezione file di configurazione |
DATAPROGRAM | sezione file di configurazione |
DEVGROUP | inizio raggruppamento device |
ELSE | “altrimenti” nell'istruzione IF |
END | fine task |
ENDDEVGROUP | fine raggruppamento device |
ENDIF | fine istruzione IF |
ENDSUB | fine subroutine |
ENDSWITCH | fine SWITCH |
ENDWHILE | fine while |
EQ | uguale |
EXP | esponenziale |
EXTDEVICE | sezione file di configurazione |
F | flag |
FLOOR | arrotondamento a intero non superiore a quello dato |
FOR | istruzione FOR |
FPROG | istruzione FPROG |
FSTEP | istruzione FSTEP |
GE | maggiore uguale |
GLOBAL | sezione file di configurazione |
GT | maggiore |
IF | istruzione IF |
INPUT | sezione file di configurazione |
INTDEVICE | sezione file di configurazione |
ISFINITE | controlla se il valore è finito |
ISINF | controlla se il valore è infinito |
ISNAN | controlla se il valore è Nan (Not a Number) |
ISNORMAL | controlla se il valore è normale |
JUMP | istruzione JUMP |
LE | minore o uguale |
LN | logaritmo naturale |
LT | minore |
MULDIV | moltiplicazione e divisione |
NEG | negazione (inversione del segno o complemento a 2) |
NEQ | operatore |
NEXT | istruzione NEXT |
NOP | istruzione NOP |
NOT | negazione |
NOTB | negazione bit a bit (complemento a 1) |
OR | OR logico |
ORB | OR logico bit a bit |
OUTPUT | sezione file di configurazione |
POW | potenza |
REFERENCE | proprietà di “riferimento” di un simbolo |
REFERENCES | inizio dell'elenco dei riferimenti |
RESOUT | reset uscite |
RESTART | istruzione di restart |
RESUME | istruzione di resume |
RETURN | istruzione di return (su subroutine) |
RMULDIV | resto di moltiplicazione e divisione |
ROUND | arrotondamento a intero più vicino |
S | single |
SETOUT | setta uscita |
SHLL | shift a sinistra |
SHLR | shift a destra |
SIN | seno |
SQRT | radice quadrata |
STEP | sezione file di configurazione |
SUB | subroutine |
SUSPEND | istruzione di sospensione |
SWITCH | istruzione SWITCH-CASE |
SYSTEM | sezione file di configurazione |
TAN | tangente |
TIMER | sezione file di configurazione |
TRUNC | arrotondamento a intero non maggiore di grandezza |
W | word |
WAIT | istruzione di wait |
WHILE | istruzione di while |
XORB | OR esclusivo bit a bit |
Oltre a queste vanno considerate le direttive del precompilatore
#DEFINE |
---|
#UNDEF |
#IFDEF |
#IFNDEF |
#ELSE |
#ENDIF |
#ERROR |
F1 | Contenuti (Contents) |
---|---|
F2 | - |
F3 | Prossima ricerca (Find Next) |
F4 | Prossima unità (Next Unit) |
F5 | Run |
F6 | Stop |
F7 | Restart |
F8 | Step |
F9 | Toggle breakpoint |
F11 | Vai a PC (Go to PC) |
F12 | Prossima unità selezionata (Next selected unit) |
SHIFT + F2 | Functions Info |
SHIFT + F4 | Unità precedente (Previous Unit) |
SHIFT + F5 | Move Rows Up (Editor LADDER) |
SHIFT + F6 | Move Rows Down (Editor LADDER) |
SHIFT + F8 | Step Over |
SHIFT + F9 | Clear All |
SHIFT + F12 | Unità selezionata precedente (Previous selected unit) |
CTRL + A | Redo |
CTRL + C | Copia |
CTRL + E | Proprietà dell'elemento LADDER (Element Properties…) |
CTRL + F | Trova (Find) |
CTRL + G | Vai a (Go to) |
CTRL + K | Compila (Compile) |
CTRL + L | Download |
CTRL + N | Salva progetto con altro nome (Save project As…) |
CTRL + P | Stampa (Print) |
CTRL + R | Sostituisci (Replace) |
CTRL + S | Salva progetto (Save project) |
CTRL + T | Ladder Network Checking |
CTRL + V | Incolla |
CTRL + X | Taglia |
CTRL + Z | Undo |
CTRL + F1 | Ladder Function Info |
CTRL + F2 | Functions Info |
CTRL + F3 | Risultati della compilazione (View compilation results) |
Viene creato da QVIEW dopo l'esecuzione del comando New Project. È un file unico per ogni applicazione.
E’ un file simboli utilizzato per la gestione dell'interfaccia operatore (terminale). Serve per l'applicazione realizzata per l'interfaccia operatore. Contiene tutte le informazioni per poter accedere alle variabili dichiarate nel progetto.
E’ un file simboli utilizzato per la gestione avanzata degli stessi da parte dei tools della QNET. Contiene tutte le informazioni per poter accedere alle variabili dichiarate nel progetto.
E’ un file risultato della compilazione che può essere utilizzato per essere trasferito nella CPU senza utilizzare la comunicazione seriale (per esempio con Multi Media Card).
L’ambiente di sviluppo è pienamente compatibile con le versioni e release precedenti.
Un progetto realizzato con Qview3, Qview 4 e Qview 5 potrà essere aperto con il Qview 6.
Al momento dell'apertura di un progetto realizzato con Qview precedenti, il Qview 6 applica delle trasformazioni automatiche di alcune parti di codice per adattarle alla nuova notazione. Queste trasformazioni sono:
Tipo di accesso | Versioni precedenti | Qview 6 |
---|---|---|
Comandi ai device | <command name> <device name> | <device name>.<command name> |
Parametri dei device | <device name>:<parameter/state> | <device name>.<parameter/state> |
Variabili di sistema | QMOVE:<system variable name> | QMOVE.<system variable name> |
Controlli schedulazione unit | T_RESTART <unit name> | <unit name>.RESTART |
T_RESUME <unit name> | <unit name>.RESUME | |
T_SUSPEND <unit name> | <unit name>.SUSPEND | |
Stato di sospensione unit | QMOVE:is_suspend <unit name> | <unit name>.is_suspended |
Dimensione array | <array name>:dim | <array name>.dim |
Tempo rimanente timer | <timer name>:remain | <timer name>.remain |
Al momento della compilazione di un progetto realizzato con Qview precedenti, è possibile che vengano notificati degli errori da Qview 6 che con i Qview precedenti non erano stati rilevati. Li elenchiamo di seguito: