E D O C
W O L F o s r o c
Flowcode permette di apprendere in maniera molto intuitiva lo sviluppo di software per applicazioni embedded, in quanto il codice viene scritto facendo uso di oggetti grafici, in luogo dei classici linguaggi di programmazione come il C e l’Assembler. Prima puntata.
corso di programmazione in
FLOWCODE di Francesco Ficili e Daniele Defilippi
al giorno dell’invenzione del primo transistor, avvenuta ormai nel 1947, l’elettronica è diventata parte integrante della nostra vita, e sarebbe impensabile ormai, credere di poter fare a meno di questo tassello fondamentale della storia dell’evoluzione umana. Una delle derivazioni più comuni di questa disciplina è sicuramente rappresentata dal mondo dei dispositivi embedded. Quando facciamo una telefonata, o navighiamo su internet usando il nostro smartphone, quando guidiamo la nostra auto, quando facciamo la spesa pagando con la nostra carta di credito, in ognuna di queste circostanze, diversi dispositivi elettronici
D
dotati di intelligenza elaborano milioni di informazioni al secondo, semplicandoci la vita. Dietro tali dispositivi, veri e propri instancabili ed invisibili servitori dei nostri giorni, si cela comunque la mano dell’uomo: qualcuno ne ha ideato le funzionalità, li ha progettati elettronicamente e ne ha sviluppato la logica. Anche lo sviluppo dei sistemi embedded ha subito una sua evoluzione nel corso degli anni, e si è passati dai dispositivi totalmente analogici ai sistemi a microcontrollore che, per svolgere il compito specico, devono essere opportunamente programmati, usando appositi linguaggi di programmazione. La programmazione, vero e proprio cuore dello sviluppo, è stata
Elettronica In ~ Giugno 2013
127
Fig. 1 Logo della Matrix Multimedia.
per anni appannaggio di poche aziende nel mondo, essendo di fatto inaccessibile alle aziende non specializzate ed ai privati, per via degli altissimi costi dei sistemi di sviluppo. Negli ultimi vent’anni, con l’avvento dei primi controllori basati su memorie FLASH (riprogrammabili elettricamente), il costo dei sistemi di sviluppo è calato vertiginosamente, rendendo questo tipo di tecnologie accessibili anche agli sviluppatori privati ed al mondo hobbistico. Sono così comparsi i primi ambienti di sviluppo software e compilatori (generalmente basati su linguaggi come il C e l’assembler) a basso costo. Tali ambienti hanno, comunque, continuato a mantenere caratteristiche di complessità d’uso ed i linguaggi utilizzati richiedono, per essere impiegati efcacemente, delle basi di programmazione non indifferenti. Così lo sviluppo su sistemi embedded è diventato più accessibile dal punto di vista economico, ma le difcoltà tecniche nell’uso dei tools sono rimaste comunque uno scoglio notevole da superare per i neoti della programmazione software. Per ovviare a problematiche di questo tipo sta nascendo, in questi anni, una nuova generazione di ambienti di sviluppo, che ha lo scopo di astrarre le difcoltà intrinseche di un linguaggio di programmazione text-based, facendo uso di formalismi più comuni. Uno degli esponenti di spicco di questa nuova generazione di ambienti di sviluppo è Flowcode, prodotto da Matrix Multimedia, azienda leader nel settore della produzione di sistemi di sviluppo hardware/software per microcontrollori. Programmazione grafica con Flowcode
L’ambiente di sviluppo Flowcode, giunto ormai alla versione 5, nasce per ovviare al problema della complessità degli ambienti di sviluppo tradizionali e per consentire lo sviluppo di applicazioni embedded complesse anche a chi ha una minima (se non nulla) conoscenza di linguaggi di programmazione. Flowcode è un completo IDE (Integrated Development Enviroment) per microcontrollori ad 8, 16 e 32-bit. Gli attuali target supportati sono: • Microchip PICmicro della serie 10, 12, 16
128
Giugno 2013 ~ Elettronica In
e 18 (8-bit), • Microchip dsPIC30F, dsPIC33F, dsPIC33E e PIC24 (E, H ed F), • Atmel AVR e piattaforma Arduino, • Atmel ARM. Il concetto su cui si basa Flowcode è l’uso di una rappresentazione graca basata su diagrammi di usso (o owchart, da cui il nome Flowcode) per lo sviluppo di un programma per target embedded. Questo approccio permette di rimpiazzare l’implementazione basata sulle keywords, tipica dei linguaggi di programmazione tradizionali. Un esempio di frammento di codice graco scritto in Flowcode è riportato in Fig. 2. L’ambiente di sviluppo, oltre a generare l’eseguibile per la programmazione del chip (ed eventualmente anche la traduzione in codice sorgente C), integra un simulatore ed un ICD ( in-circuit debugger) per eseguire il debugging del codice direttamente sul target. Una delle caratteristiche più interessanti di Flowcode è, come vedremo in dettaglio nelle prossime puntate, la disponibilità di una ricca libreria di componenti per l’utilizzo delle periferiche normalmente integrate nei microcontrollori. L’uso dei componenti semplica notevolmente l’accesso alle periferiche, anche nel caso delle periferiche più complesse, come
Fig. 2 Esempio di codice Flowcode.
c o r s o
F L O W
C O D E
Fig. 1 Logo della Matrix Multimedia.
per anni appannaggio di poche aziende nel mondo, essendo di fatto inaccessibile alle aziende non specializzate ed ai privati, per via degli altissimi costi dei sistemi di sviluppo. Negli ultimi vent’anni, con l’avvento dei primi controllori basati su memorie FLASH (riprogrammabili elettricamente), il costo dei sistemi di sviluppo è calato vertiginosamente, rendendo questo tipo di tecnologie accessibili anche agli sviluppatori privati ed al mondo hobbistico. Sono così comparsi i primi ambienti di sviluppo software e compilatori (generalmente basati su linguaggi come il C e l’assembler) a basso costo. Tali ambienti hanno, comunque, continuato a mantenere caratteristiche di complessità d’uso ed i linguaggi utilizzati richiedono, per essere impiegati efcacemente, delle basi di programmazione non indifferenti. Così lo sviluppo su sistemi embedded è diventato più accessibile dal punto di vista economico, ma le difcoltà tecniche nell’uso dei tools sono rimaste comunque uno scoglio notevole da superare per i neoti della programmazione software. Per ovviare a problematiche di questo tipo sta nascendo, in questi anni, una nuova generazione di ambienti di sviluppo, che ha lo scopo di astrarre le difcoltà intrinseche di un linguaggio di programmazione text-based, facendo uso di formalismi più comuni. Uno degli esponenti di spicco di questa nuova generazione di ambienti di sviluppo è Flowcode, prodotto da Matrix Multimedia, azienda leader nel settore della produzione di sistemi di sviluppo hardware/software per microcontrollori. Programmazione grafica con Flowcode
L’ambiente di sviluppo Flowcode, giunto ormai alla versione 5, nasce per ovviare al problema della complessità degli ambienti di sviluppo tradizionali e per consentire lo sviluppo di applicazioni embedded complesse anche a chi ha una minima (se non nulla) conoscenza di linguaggi di programmazione. Flowcode è un completo IDE (Integrated Development Enviroment) per microcontrollori ad 8, 16 e 32-bit. Gli attuali target supportati sono: • Microchip PICmicro della serie 10, 12, 16
128
Giugno 2013 ~ Elettronica In
e 18 (8-bit), • Microchip dsPIC30F, dsPIC33F, dsPIC33E e PIC24 (E, H ed F), • Atmel AVR e piattaforma Arduino, • Atmel ARM. Il concetto su cui si basa Flowcode è l’uso di una rappresentazione graca basata su diagrammi di usso (o owchart, da cui il nome Flowcode) per lo sviluppo di un programma per target embedded. Questo approccio permette di rimpiazzare l’implementazione basata sulle keywords, tipica dei linguaggi di programmazione tradizionali. Un esempio di frammento di codice graco scritto in Flowcode è riportato in Fig. 2. L’ambiente di sviluppo, oltre a generare l’eseguibile per la programmazione del chip (ed eventualmente anche la traduzione in codice sorgente C), integra un simulatore ed un ICD ( in-circuit debugger) per eseguire il debugging del codice direttamente sul target. Una delle caratteristiche più interessanti di Flowcode è, come vedremo in dettaglio nelle prossime puntate, la disponibilità di una ricca libreria di componenti per l’utilizzo delle periferiche normalmente integrate nei microcontrollori. L’uso dei componenti semplica notevolmente l’accesso alle periferiche, anche nel caso delle periferiche più complesse, come
Fig. 2 Esempio di codice Flowcode.
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 3 Sito Matrix multimedia per download di FlowCode.
ad esempio la porta USB, la porta Ethernet o altri sistemi di comunicazione e/o controllo. Una descrizione più dettagliata dei componenti sarà fatta in seguito, ma è importante sottolineare che la disponibilità di queste librerie consente di sviluppare applicazioni anche molto complesse con l’interconnessione di pochi semplici blocchi funzionali. Installazione e configurazione di Flowcode V5
Come primo argomento del corso illustriamo come installare e congurare l’IDE. Il pacchetto di installazione di Flowcode è scaricabile dal sito web della Matrix (www. matrixmultimedia.com) e, come già detto precedentemente, attualmente sono supportati diversi target, a cui corrispondono diverse versioni del software. Come versione base del corso è stata scelta la versione per i microcontrollori PIC della Microchip Technology. Dopo esserci collegati al sito web della Matrix, accediamo alla sezione download e scarichiamo la versione per PICmicro. Al termine del download eseguiamo il le FlowcodeV5 - PICMicro.exe e avviamo l’installazione del programma. Comparirà il wizard di installazione, la cui prima schermata è riportata in Fig. 4. Premiamo il pulsante Next per accedere alla schermata successiva, confermiamo di accettare la licenza d’uso e proseguiamo.
Fig. 4 - Finestra iniziale di installazione di FlowCode.
Fig. 5 - Accettazione della licenza d’uso.
Elettronica In ~ Giugno 2013
129
Fig. 6 - Inserimento dati di installazione.
Fig. 7 - Selezione codice attivazione prodotto.
Inseriamo ora il nostro nome ed il nome nell’organizzazione (che in questo caso abbiamo indicato come “ElettronicaIn”), come illustrato in Fig. 6, e premiamo ancora una volta il pulsante Next. Selezioniamo la cartella di destinazione e procediamo alla schermata successiva. A questo punto il wizard ci chiede conferma di proseguire con l’installazione e dopo averla ricevuta inizierà il processo di copia dei le su disco. Al termine dell’operazione viene richiesto di attivare il prodotto mediante una chiave di attivazione, o di attivare una licenza free, come possiamo vedere in Fig. 7. La licenza free non ha limitazioni in termini di tempo, ma è attivato un set ridotto di componenti all’interno dell’ambiente. Installazione scheda di sviluppo EB006
A questo punto il nostro ambiente di
130
Giugno 2013 ~ Elettronica In
sviluppo è correttamente installato e possiamo procedere alla realizzazione delle nostre applicazioni. Come supporto hardware al corso verrà utilizzato un sistema modulare di schede di sviluppo, prodotte sempre dalla Matrix, che prende il nome di E-block. Il sistema è costituito da una scheda madre alla quale possono essere connessi diversi blocchi per espanderne le funzionalità. Ogni blocco offre le risorse hardware necessarie per implementare una specica interfaccia, come, ad esempio, porte USB o Ethernet, display graci, interfacce CAN, driver per motori passo-passo, etc. La scheda scelta come scheda madre per lo sviluppo delle applicazioni che saranno presentate lungo la durata del corso è la EB006. La scheda EB006 è corredata di un CD di installazione che serve per installare tutti i driver necessari per poter utilizzare correttamente il sistema di sviluppo. Inseriamolo all’interno del nostro lettore CD e posizioniamoci all’interno della cartella “drivers\ EB-006”. In base all’architettura del nostro PC scegliamo dpinst_amd64 (64 bit AMD o Intel), dpins_ia64 (64 bit itanium) oppure dpins_x86 (32bit) ed avviamo l’eseguibile. Comparirà la schermata di Fig. 8, che ci informa che premendo sul pulsante “Avanti” verrà avviata la procedura di installazione dei driver. Proseguiamo e, nel caso ci venga noticato da Windows che non è possibile vericare l’autenticità dei driver, scegliamo di proseguire con l’installazione. Al termine dell’operazione apparirà la
Fig. 8 Schermata iniziale installazione driver per E-block EB006.
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 9 Interfaccia FlowCode.
schermata che ci indica che l’installazione è stata eseguita correttamente. Per concludere l’installazione premiamo il pulsante “Fine”. Colleghiamo ora la scheda di sviluppo EB006 mediante il cavo USB (fornito in dotazione) al computer. Il sistema operativo installerà i driver aggiuntivi ed uno dei due led sulla scheda si accenderà, segnalandoci che il debugger è attivo. Interfaccia di Flowcode
A questo punto anche il nostro hardware di sviluppo è congurato e pronto per essere utilizzato, passiamo quindi alla descrizione dell’interfaccia di programmazione dell’IDE. Come già detto nella parte introduttiva di questa puntata, Flowcode è un ambiente di sviluppo graco: questo vuol dire che il programma non viene rappresentato, come avviene invece con i linguaggi di programmazione tradizionale, da un codice testuale, ma verrà composto facendo uso solo di oggetti graci. Nel caso di Flowcode la rappresentazione scelta è quella dei diagrammi di usso (o owchart). Gli elementi base del diagramma di usso implementano le strutture di controllo fondamentali del programma, come i blocchi decisionali, i cicli, i ritardi, le selezioni multiple, le operazioni logiche e matematiche e altro ancora. Per la gestione delle periferiche più complesse sono invece forniti una serie di componenti che non sono altro che dei contenitori che offrono delle funzioni predenite, per semplicare
la gestione della periferica. Inne, tramite un opportuno wizard di congurazione, è possibile impostare la congurazione base del microcontrollore, come la frequenza del clock interno, eventuali protezioni, le impostazioni sulla memoria, etc. L’interfaccia di FlowCode è suddivisa principalmente in barre e pannelli, ognuno dei quali ha uno specico compito che ora andremo ad analizzare. Qualora non tutte le barre siano visualizzate, è possibile aggiungerle dal menu “visualizza” semplicemente aggiungendo una spunta vicino al nome che le identica. In Fig. 9 è rappresentata la schermata principale di Flowcode. Al centro dello schermo è presente un tab (che nel nostro caso si chiama “ Main”), che chiameremo “area di progetto” nel quale verrà implementato il diagramma di usso. Nella parte sinistra dello schermo è invece presente la barra delle icone, dalla quale è possibile scegliere quale blocco inserire all’interno del programma.
Elettronica In ~ Giugno 2013
131
Fig. 10 Barre degli strumenti.
Fig. 11 Barre delle icone.
Fig. 12 Opzioni di progetto.
In alto, sopra l’area di progetto troviamo la barra degli strumenti (illustrata in Fig. 10), che ci fornisce i comandi base per gestire il progetto, generare codice, debuggare, compilare e simulare il nostro progetto. Tra la barra degli strumenti e l’area di progetto troviamo invece la barra dei componenti che ci consente di utilizzare, all’interno dei nostri progetti, componenti complessi quali USB, Ethernet, controllo di motori brushless, e molto altro ancora, semplicemente inserendoli all’interno del pannello che è visibile in basso al centro della schermata del programma. La barra delle icone, rappresentata in Fig. 11, contiene tutti i possibili blocchi che possono essere aggiunti all’interno del diagramma di usso. Per inserire un blocco è sufciente trascinarlo all’interno del diagramma: una freccia gialla ci indicherà il punto esatto in cui lo stiamo inserendo e l’icona del mouse viene modicata prendendo la forma dell’oggetto che vogliamo inserire all’interno del nostro diagramma di usso. Descriveremo nelle prossime puntate le altre barre e pannelli che non abbiamo approfondito in questa sezione. Creare un progetto
Per creare un progetto apriamo Flowcode e premiamo sul pulsante “ Nuovo progetto” nella barra degli strumenti. Congureremo questo progetto in modo da poterlo utilizzare negli esempi che vedremo in seguito. Selezioniamo il microcontrollore scegliendo la famiglia 18 e successivamente
132
Giugno 2013 ~ Elettronica In
Fig. 13 18F4550, come indicato in Fig. 12. Ora Inserimento passiamo al tab “ Descrizione progetto” e descrizione progetto. inseriamo una descrizione signicativa. Dal punto di vista della funzionalità del programma non cambia nulla se lasciamo vuoti questi campi ma, per poter capire meglio che cosa realizza il nostro progetto, sarebbe buona norma inserirne almeno una breve descrizione. Nel nostro caso abbiamo inserito il titolo e la descrizione del progetto che realizzeremo al termine di questa puntata: un semplice programma che fa lampeggiare un LED. All’interno del tab “Operazioni Generali”, visibile in Fig. 14, conguriamo il progetto in modo che rispecchi l’implementazione hardware del sistema. La casella “Velocità di clock del PIC” deve essere impostata a 48MHz e la casella “ Congura componente” deve essere selezionata. Passiamo ora a congurare i settaggi specici del microcontrollore cliccando sul pulsante
c o r s o
F L O W
C O D E
E D O C
Fig. 14 Impostazioni generali nuovo progetto.
W O L F o s r o c
“Congura componente”, che ci farà accedere a una schermata di congurazione come quella rappresentata in Fig. 15. Per motivi di tempo ci limiteremo a settare ogni campo come indicato in gura, senza soffermarci sul perché di ogni scelta, che potrà comunque essere approfondita leggendo il datasheet specico del microcontrollore utilizzato. Dopo aver correttamente compilato ogni campo premiamo il pulsante OK, per tornare alla schermata di congurazione di progetto e nuovamente premiamo OK per iniziare a realizzare il diagramma di usso. Per poter utilizzare questa congurazione negli esempi successivi salviamo il progetto, premendo sul pulsante “Salva progetto” nella barra degli strumenti, con il nome “CongurazioneBase.fcf ”. Aggiunta di blocchi nel diagramma di flusso
Una volta completata la congurazione dell’hardware, torniamo nell’area progetto per inserire blocchi del diagramma di usso. Per inserire un blocco basta trascinarlo dalla barra delle icone all’interno dell’area di progetto. Una freccia gialla ci indicherà il punto esatto in cui lo stiamo inserendo. Per rimuovere un blocco basta selezionarlo e premere il tasto “Canc”. Cliccando sul blocco con il tasto destro è possibile eseguire altre operazioni quali tagliarlo, copiarlo, esaminarne le proprietà e altro ancora che vedremo nelle puntate successive. Proviamo ora a esaminare le proprietà di
un blocco. Come prima operazione inseriamo il blocco di gestione delle uscite del microcontrollore, trascinando all’interno dell’area di progetto l’icona uscita, (presente nella barra delle icone) tra i blocchi di INIZIO e FINE, già presenti di default all’interno del diagramma. Cliccando con il tasto destro sul blocco che abbiamo inserito appare la nestra a scomparsa di Windows. Scegliamo l’opzione “Proprietà” ed esaminiamo la nestra che si è aperta, riportata per comodità nella Fig. 16. Possiamo ora impostare tutte le proprietà disponibili per il blocco che abbiamo selezionato. Il blocco è utilizzato per controllare lo stato delle uscite del nostro microcontrollore. Nella lista a scorrimento “Port” possiamo selezionare la porta della quale vogliamo modicare il valore
Elettronica In ~ Giugno 2013
133
Fig. 15 Configurazione specifica del microcontrollore.
Fig. 16 Proprietà blocco uscita.
durante la stesura di un codice realizzato in un qualsiasi linguaggio di programmazione.
Fig. 17 Proprietà blocco ritardo.
di uscita, mentre nella casella “ Variabile o Valore” indichiamo il valore alla quale vogliamo impostare la porta selezionata. Solitamente non vogliamo impostare il valore dell’intera porta di uscita, ma solo di uno o alcuni bit. Per far ciò ci viene in aiuto il pannello “Uscita a”. Se selezioniamo “Singolo bit” possiamo scegliere quale bit impostare lasciando invariato il valore degli altri pin della porta. Selezionando “Intero Port” e selezionando la casella “Usa Maschera” è possibile selezionare quali bit devono essere impostati. In questo modo è possibile lasciare invariati i valori dei pin della porta il cui bit non è contrassegnato nella maschera. La casella di testo “Etichetta” permette di modicare il testo che verrà indicato sopra il blocco all’interno del diagramma. È molto importante indicare per ogni blocco un’etichetta signifcativa perché, anche se per progetti molto semplici può sembrarci inutile, qualora volessimo realizzare diagrammi complessi, potrebbe esserci molto di aiuto avere a disposizione etichette che, con poche parole, ci indichino che cosa implementa quel particolare blocco. Sono in pratica l’equivalente dei commenti scritti
Fig. 18 Struttura decisionale binaria e panello di configurazione del confronto.
Inseriamo adesso un ritardo software all’interno del nostro schema a blocchi. Per eseguire questa operazione selezioniamo l’icona del blocco di ritardo, presente sempre nella barra delle icone, e trasciniamola all’interno del diagramma, posizionandola proprio sotto il blocco precedentemente inserito. A questo punto accediamo alle proprietà del blocco, cliccando con il tasto destro del mouse, come abbiamo fatto precedentemente. Come è possibile vedere in Fig. 17, il blocco permette di inserire un ritardo nell’esecuzione del usso del programma. Possiamo scegliere l’entità del ritardo da inserire indicandone il valore e l’unità di misura. Il valore che possiamo inserire deve essere di tipo intero, cioè senza virgola, ma possiamo comunque inserire ritardi minori del secondo passando all’unità di misura con risoluzione maggiore. Ad esempio per aggiungere un ritardo del valore di 0.5s basterà che inseriamo all’interno della casella “valore ritardo”, il numero 500, mentre come unità indichiamo “millisecondi”. Ricordiamoci che 1 millisecondo equivale a 1000 microsecondi e che 1 secondo equivale a 1000 millisecondi. Le strutture di controllo flusso
Passiamo ora ad analizzare alcune delle
c o r s o
F L O W
134
Giugno 2013 ~ Elettronica In
C O D E
E D O C
W O L F o s r o c
Fig. 19 Struttura di selezione multipla.
altre icone presenti nella “barra delle icone”. In Flowcode possono essere utilizzate tutte le normali strutture di controllo presenti normalmente nei linguaggi di programmazione come, a titolo di esempio, il C. Decisione binaria Mediante l’icona decisione è possibile
implementare la funzionalità di decisione binaria. Il blocco fa sì che il usso di programma passi per il primo o il secondo ramo, in base al valore del confronto effettuato all’interno del blocco. In pratica, se la condizione è vericata, il programma continuerà l’esecuzione dei blocchi presenti nel ramo identicato dall’etichetta “si”, altrimenti eseguirà l’altro ramo. Per coloro che conoscono il linguaggio C il blocco è l’equivalente dell’istruzione “if ”. Selezione multipla Utilizzando l’icona selezione è possibile
implementare la funzionalità di selezione multipla. Il usso di programma è deviato attraverso il ramo per il quale l’equazione di confronto soddisfa il valore indicato all’interno del caso specico. Qualora nessuno dei casi indicati soddis l’equazione di selezione, il programma eseguirà le istruzioni presenti nel ramo di default. Possono essere realizzate selezioni con massimo 10 differenti casi, ma questo numero è più che sufciente per realizzare la maggior parte dei possibili programmi. In pratica se uno dei rami indicati ha come etichetta il valore che soddisfa l’equazione viene eseguito, altrimenti viene scartato. Solo uno dei rami può essere eseguito ed ognuno deve avere un valore di selezione differente dall’altro. È l’equivalente del costrutto “switch… case” di un programma implementato in linguaggio C. Un esempio d’uso della struttura di selezione multipla è riportato in Fig. 19. Icona ciclo L’icona Ciclo permette di realizzare tre dif-
Il blocco implementa di default la struttura “Finché ”, ma per realizzare gli altri due costrutti basta modicarne le proprietà come visto per gli altri blocchi nelle sezioni precedenti. Analizziamo le tre opzioni offerte: Ciclo “Finché”
Fintanto che l’equazione di confronto risulta vera vengono eseguite le istruzioni all’interno del ciclo. Il confronto è effettuato al primo ingresso nel blocco di ciclo ed ogni volta che vengono terminate tutte le istruzioni interne al ciclo. Quando il confronto risulta falso le istruzioni interne non sono più eseguite e il programma continua attuando le istruzioni successive al ciclo. Nel caso in cui l’equazione di confronto risulti falsa al primo controllo, il codice interno al ciclo non viene eseguito neppure una volta e il programma continua la sua esecuzione ignorando le istruzioni contenute all’interno dei due blocchi di ciclo. Un esempio di ciclo di questo tipo è riportato in Fig. 20.
ferenti controlli di usso: - Finché - Esegui...nché - Ripeti
Ciclo “Esegui…Finché”
Impostando la proprietà del blocco “ Testa il ciclo a:” al valore “Termine”, come in
Elettronica In ~ Giugno 2013
135
Fig. 20 Ciclo “while” (Finché vero).
Fig. 21 - Ciclo “Esegui ...Finché”. Il confronto è effettuato al termine del blocco.
Fig. 21, lo rendiamo equivalente al blocco realizzato in C con le istruzioni “Do While”.
In questo caso l’istruzione di confronto è eseguita al termine di ogni attuazione delle istruzioni contenute all’interno del ciclo. Il codice interno è quindi eseguito almeno una volta. Ciclo “Ripeti”
Selezionando la proprietà del blocco a “Numero cicli:”, come è stato fatto in Fig. 22, il ciclo viene impostato per funzionare come un “ for”. Congurato in questo modo le istruzioni interne vengono eseguite un numero di volte pari al numero indicato
Fig. 23 Scheda EB006 a sinistra e scheda E-Blocks EB004 a destra.
Fig. 22 - Ciclo “Ripeti”.
nella cella a anco dell’impostazione “Numero cicli:”. Il blocco è fondamentale quando abbiamo bisogno che una porzione del nostro diagramma di usso venga eseguita per un numero predenito di volte. Esempio pratico: facciamo lampeggiare un LED…
Ora che conosciamo i blocchi principali e le possibili variazioni per il controllo di usso, possiamo implementare un semplice diagramma per far lampeggiare un LED. Per realizzare questo esempio abbiamo bisogno dei seguenti componenti: - EB006 “USB PICmicro multiprogram-
c o r s o
F L O W
136
Giugno 2013 ~ Elettronica In
C O D E
E D O C
W O L F o s r o c
Fig. 24 Metodo per la rimozione del microcontrollore PIC.
con uno a 12MHz e spostiamo il jumper di selezione della sorgente di clock su “OSC” e l’interruttore di selezione oscillazione su “XTAL“. Un riassunto graco dell’impostazione dei vari jumper è riportato in Fig. 25. Colleghiamo ora la scheda EB006 con la EBlocks EB004 utilizzando la PORT A, come illustrato in Fig. 26.
L’hardware è ora pronto e possiamo dedicarci all’implementazione del programma. Apriamo Flowcode e carichiamo la congurazione di base che avevamo salvato mer board” durante la congurazione del nostro primo - EB004 “LED Board” progetto. Premiamo sul pulsante “ Apri - PIC18F4550 progetto” nella barra degli strumenti e - Quarzo 12MHz selezioniamo il le “CongurazioneBase.fcf ”. Per evitare di “sporcare” il le, dato che La scheda EB006 contiene il Flowcode durante alcune operazioni salva microcontrollore e l’hardware necessari automaticamente il progetto, salviamo per interfacciarsi con le altre schede EBlocks e il PC dal quale lo programmiamo; immediatamente il progetto con un nuovo nome. Dal menu scegliamo “File/Salva con deve essere congurata per poter essere nome...” e indichiamo come nuovo nome utilizzata nel nostro esempio. I jumper di selezione dell’alimentazione devono essere “LampeggioLed.fcf ”. Proviamo ora a pensare Fig. 25 Configurazione posizionati sul lato di sinistra, in modo selettori e jumper da far sì che l’alimentazione provenga scheda EB006. dall’USB. Il jumper di programmazione deve anch‘esso essere settato su USB, in modo da poterlo programmare direttamente da PC, senza l’ausilio del programmatore ICSP della Microchip. Sostituiamo ora il microcontrollore che è attualmente Jumper selezione montato sulla scheda con il PIC18F4550. alimentazione Questa operazione è molto delicata, quindi dobbiamo prestare molta attenzione nel Jumper selezione rimuovere il microcontrollore senza danProgrammatore neggiare la scheda di sviluppo. Per evitare danni aiutiamoci con il tappo di una biro ed eseguiamo l’operazione come indicato nella sequenza di Fig. 24. Facendo attenzione alla direzione dell’alJumper selezione loggiamento a 40 pin, inseriamo il PIfunzione pin oscillatore C18F4550, assicurandoci che tutti i piedini entrino senza piegarsi, all’interno dello Selettore zoccolo. Per piegare correttamente i pieoscillatore dini del PDIP40, possiamo aiutarci con il piano della nostra scrivania, appoggiando il PDIP di traverso e facendo leva sul case, nché i piedini risultano paralleli al bordo. A questo punto sostituiamo il quarzo
Elettronica In ~ Giugno 2013
137
Fig. 26 Configurazione completa per la realizzazione dell’esempio.
alle operazioni che devono essere eseguite per fare in modo che si veda lampeggiare un LED sulla scheda. Innanzitutto dobbiamo realizzare un ciclo innito che il programma dovrà eseguire per tutto il tempo di attività e per questo scegliamo il blocco “Finché ”. Impostiamo in modo che il ciclo venga sempre eseguito come descritto nella sezione precedente. Abbiamo poi bisogno di qualcosa che ci permetta di modicare il valore di un pin del microcontrollore ed il blocco che fa al caso nostro è l’icona uscita. Inseriamo due blocchi all’interno del ciclo e impostiamoli in modo che il primo setti il bit 0 al valore 1 e il secondo il bit 0 al valore 0. Se eseguissimo il usso così com’è attualmente implementato, Fig. 27 Diagramma di flusso per il lampeggio del led collegato alla porta A pin 0.
138
Giugno 2013 ~ Elettronica In
vedremmo a causa dei fenomeni sici interni al nostro occhio il LED sempre acceso, ma con un’intensità minore rispetto a quella massima. Per evitare questo problema inseriamo un blocco di ritardo dopo il set a uno della porta e un altro – identico - dopo il blocco di set a zero della porta. Impostiamo il valore del ritardo a 1 secondo per entrambi i blocchi inseriti. Se avete eseguito tutto correttamente dovreste ottenere un diagramma di usso simile a quello riportato in Fig. 27. Il nostro usso è ora pronto per essere caricato sulla scheda. Salviamo il progetto premendo il pulsante “salva progetto” nella “barra degli strumenti” perché lo riutilizzeremo in seguito come base di partenza per altri esempi. Premiamo il pulsante “compila e trasferisci” per caricare il programma all’interno del microcontrollore presente sulla nostra scheda di sviluppo. Attendiamo che il programma esegua le operazioni e al termine del caricamento potremo notare che il nostro primo programma viene eseguito sulla scheda con il LED che si accende e si spegne ogni g secondo.
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Continuiamo il nostro viaggio alla scoperta di Flowcode, l’innovativo sistema di sviluppo grafico per microcontrollori proposto da Matrix Multimedia. Flowcode permette di sviluppare con facilità il software per applicazioni embedded in quanto il codice viene scritto facendo uso di oggetti grafici, in luogo dei classici linguaggi di programmazione come il C e l’Assembler. Seconda puntata.
corso di programmazione in
FLOWCODE di Francesco Ficili e Daniele Defilippi
ella scorsa puntata del corso abbiamo iniziato a prendere condenza con l’ambiente di sviluppo graco FlowCode, sviluppato da Matrix Multimedia. È stato presentato l’ambiente graco, descritta dettagliatamente l’interfaccia, presentate le strutture di controllo ed è stato illustrato un primo esempio di programmazione. In questa puntata spiegheremo l’uso delle variabili, delle costanti e descriveremo i blocchi ingresso e calcolo. Successivamente verranno descritte due funzionalità molto potenti di owcode: le macro e i componenti. Con le conoscenze acquisite realizzeremo il secondo progetto pratico: la gestione del modulo E-block
N
LED tramite il modulo KeyPad, usandone i rispettivi componenti software. Le variabili in Flowcode
Nella puntata precedente abbiamo utilizzato unicamente periferiche di uscita e non abbiamo mai fatto uso di variabili, che sono invece una parte molto importante della programmazione in quanto ci permettono di memorizzare dati ed effettuare calcoli. Attraverso il menu principale di Flowcode “Visualizza->Esplora progetto”, apriamo il pannello aggiuntivo nel quale possiamo esaminare tutte le costanti e le variabili globali disponibili all’interno del nostro progetto, come illustrato in Fig. 1.
Elettronica In ~
Luglio / Agosto 2013
113
Fig. 1 Progetto Flowcode con pannello esplora progetto visibile sulla destra della schermata.
Aggiungere variabili
Per aggiungere una nuova variabile dobbiamo posizionare il mouse sull’etichetta “variabili” e cliccare con il tasto destro in modo da poter scegliere dal menu a tendina la casella “aggiungi nuovo”, come mostrato in Fig. 2.
Fig. 2 - Aggiunta variabile.
Premendo sul pulsante “ Ag giungi nuovo” viene aperta la nestra di creazione di una nuova variabile, come evidenziato in Fig. 3.
I tipi di dati nora supportati spaziano da logici a numerici, con o senza segno, numeri a virgola mobile e stringhe. Per congurare la variabile dobbiamo inserire il nome, il valore iniziale, una breve descrizione e il tipo. Premendo il pulsante “OK” la variabile viene creata e aggiunta alla lista nella nestra di esplorazione del progetto.
Fig. 3 - Finestra di creazione/ configurazione variabile.
Aggiungere costanti
Alla creazione di un nuovo progetto sono già presenti due costanti pre-congurate: “ false” e “true”, rispettivamente ai valori 0 e 1. Per ag-
114
Fig. 4 - Finestra di creazione/ configurazione costante.
Luglio / Agosto 2013 ~ Elettronica In
giungere una nuova costante posizioniamo il mouse sull’etichetta “costanti”, clicchiamo con il tasto destro e scegliamo dal menu a tendina “ Aggiungi nuovo”. Nella nestra di congurazione, mostrata in Fig. 4, inseriamo il nome della costante, il suo valore e una breve descrizione. Le costanti non necessitano dell’indicazione di tipo perché vengono trattate come delle “#dene”. Rimozione di variabili/costanti Qualora volessimo cancellare una variabile o una costante è sufciente selezionare con il mouse l’elemento desiderato dal pannello “esplora progetto”, all’interno della sezione “Globali”, e premere il pulsante “Canc”. Al termine del progetto potrebbe risultare molto utile rimuovere tutte quelle variabili/costanti che risultano incluse nella lista, ma non sono utilizzate all’interno del nostro progetto. Per far ciò basta cliccare con il tasto destro su “Variabili” o “Costanti” all’interno del pannello “Esplora progetto” e scegliere
c o r s o
F L O W
C O D E
Fig. 5 Blocco di ingresso e finestra di configurazione
E D O C
W O L F o s r o c
selezione che può aiutarci a scegliere quale variabile utilizzare, come mostrato in Fig. 6. Possiamo scegliere tra Blocco ingresso e calcolo La scorsa puntata avevamo le variabili locali o tra quelle esaminato il blocco di output globali e, qualora non fossero e quello di ritardo. Siamo ancora state create, possiamo quindi capaci di imporre crearle direttamente dalla il valore di una porta/pin nestra come abbiamo fatto di uscita e di attendere un in precedenza dal pannello tempo pressato tra due “esplora progetto”. Facendo Fig. 6 - Finestra di selezione operazioni. Impariamo ora a doppio clic su una variabile variabile. utilizzare il blocco di ingresso presente nella lista, possiamo e di calcolo. inserirla direttamente nella casella di testo di congurazione del pannello. Blocco ingresso Il blocco ingresso è il blocco Esattamente come per il duale del blocco uscita che pannello di congurazione abbiamo utilizzato nella delle uscite, sono disponibili puntata precedente per le opzioni “Singolo Bit” e la controllare i pin di uscita del mascheratura. Nell’esempio Fig. 7 - Esempio di microcontrollore. Per inserire mascheratura porta di ingresso. in Fig. 7 la variabile assumeil blocco, trasciniamo dalla rà il valore di PORTA, ma “Barra delle icone” l’icona corriunicamente per il 2° e 4° bit spondente nel diagramma di usso. Come perché solo il pin 1 e 3 hanno la spunta. per gli altri blocchi, eseguendo un doppio Facciamo un esempio. Supponiamo che clic sull’icona, è possibile aprire la nestra PORTA abbia un valore pari a 9, che in di congurazione, mostrata in Fig. 5. binario equivale a 0b00001001. Nella vaSelezionando dalla lista a scorrimento riabile “VariabileIngresso” avremo il valore “Port:”, impostiamo la porta dalla quale vo- 8 mascherato con 0b00001010 che ha come gliamo effettuare la lettura e, nella casella risultato 0b00001001 AND 0b00001010 = di testo “Variabile:”, inseriamo il nome della 0b00001000, cioè 8. variabile nella quale vogliamo caricare il valore letto. Premendo sulla freccia a destra Blocco calcolo della casella di testo apriamo la nestra di Altro blocco di fondamentale importanza è dal menu a tendina l’opzione “Cancella inutilizzati”.
Elettronica In ~
Luglio / Agosto 2013
115
Fig. 8 Finestra proprietà del blocco calcolo.
quello che ci permette di svolgere i calcoli all’interno del nostro diagramma di usso. Per inserirlo basta scegliere l’icona calcolo dalla “Barra delle icone” e trascinarlo all’interno dell’area di progetto. Facendo doppio clic sul blocco entriamo nella nestra di congurazione, come mostrato in Fig. 8. Tabella 1 -
Operatori logico/matematici.
(,)
Parentesi
= , <>
Uguale a, diverso da
+ , - , * , / , MOD
Addizione, sottrazione, moltiplicazione, divisione e modulo
<, <= , > , >=
Minore di, minore o uguale a, maggiore di, maggiore o uguale a
>>, <<
Spostamento a destra, spostamento a sinistra.
~,&,|,^
NOT, AND, OR, OR Esclusivo, bit per bit
NOT, AND , OR , XOR
NOT, AND, OR, OR Esclusivo ,bit per bit
&& , || , !
AND, OR, NOT, logici
Tabella 2 -
Funzioni utilizzabili in Flowcode.
float = fadd(float, float)
Somma due numeri in notazione a virgola mobile
float = fsub(float, float)
Differenza tra due numeri in notazione a virgola mobile
float = fmul(float, float)
Moltiplica due numeri in notazione a virgola mobile
float = fdiv(float, float)
Divide due numeri in notazione a virgola mobile
float = fmod(float, float)
Esegue il MODULO di due numeri in notazione a virgola mobile
byte = isinf(float)
Verifica se il numero in virgola mobile è infinito
byte = isnan(float)
Verifica se il numero in virgola mobile è un numero
byte = float_eq(float, float)
Verifica l’uguaglianza di due numeri in virgola mobile
byte = float_ge(float, float)
Controlla se un numero in virgola mobile è maggiore o uguale all’altro
byte = float_gt(float, float)
Controlla se un numero in virgola mobile è maggiore dell’altro
byte = float_le(float, float)
Controlla se un numero in virgola mobile è minore o uguale all’altro
byte = float_lt(float, float)
Controlla se un numero in virgola mobile è minore dell’altro
int = random()
116
Genera un numero casuale tra -32768 e 32767
Luglio / Agosto 2013 ~ Elettronica In
Nella casella di testo “Calcoli” possono essere inserite le righe nelle quali specichiamo i calcoli da effettuare, mentre nella parte di destra è presente un pannello di selezione dal quale possiamo attingere i valori delle variabili, delle costanti e delle funzioni che Flowcode ci mette a disposizione. Gli operatori logico/matematici che possiamo utilizzare sono rappresentati in Tabella 1.
Le funzioni valide sono invece riportate in Tabella 2.
Per capirne meglio il funzionamento facciamo un semplice esempio. Supponiamo di avere la variabile “LunghezzaInch” che contiene il valore di una lunghezza rappresentato in pollici e di volerla Fig. 9 Esempio di calcolo per conversione di unità di misura da pollici in centimetri.
convertire in centimetri all’interno della variabile “LunghezzaCm”. Il frammento di codice necessario per svolgere questa semplice operazione è indicato in Fig. 9. Le macro e i componenti software
Gli esempi che abbiamo visto no ad ora utilizzavano un numero limitato di blocchi per implementare la funzionalità, ma normalmente non è possibile implementare un intero usso su un unico diagramma. Il blocco macro ci è di ausilio in questo compito. In pratica ci permette di creare delle sottoparti di diagramma su aree di lavoro differenti e di poterle richiamare agevolmente. Creare una macro
Per creare una macro entriamo nel menu “ Macro” e premiamo su “Nuova..”. La nestra di congurazione ci permette di gestire e congurare tutte le caratteristiche salienti della macro. All’interno della casella “ Nome della nuova macro” inseriamo il nome con il quale richiameremo la macro all’interno
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 10 Barra dei componenti.
del nostro diagramma di usso e, anche se non è obbligatorio, è vivamente consigliato inserire dei commenti all’interno della casella “descrizione nuova macro ” per facilitare in futuro la comprensione della funzionalità che svilupperemo all’interno. Una macro può comunicare con il diagramma che la istanzia facendo uso di parametri, di valori di ritorno e di variabili globali, esattamente come avviene per una classica funzione in linguaggio C. I parametri sono utilizzati quando è necessario passare dei valori dal diagramma chiamante alla macro. Il valore di ritorno è utilizzato quando si vuole restituire al diagramma chiamante un valore mentre le variabili globali possono essere utilizzate in tutti gli altri casi. Quando una macro utilizza delle variabili globali sarebbe buona norma indicare, nella descrizione della macro, tipo e nome delle variabili globali in modo che, qualora si dovesse riutilizzare la macro in altri diagrammi, si possano ricreare tutte le variabili in modo corretto. Una volta creata, la macro può essere istanziata nel diagramma di usso usando l’icona “macro” e valorizzando opportunamente gli eventuali parametri. Durante la spiegazione del progetto pratico di questa puntata, vedremo un esempio che ci aiuterà a comprendere come congurare e utilizzare una macro all’interno di un progetto Flowcode.
componenti sono stati realizzati da Matrix Multimedia per esserci di aiuto nello sviluppo di progetti complessi. La libreria dei componenti è suddivisa in base alla tipologia. Possiamo trovare i seguenti principali raggruppamenti: Comuni, Ingressi, Uscite, Trasmissioni Dati, Wireless, Periferiche, Elettromeccanici, Moduli Miac e Varie. Per il momento i gruppi e i componenti disponibili sono quelli che vi mostreremo durante il corso, ma nelle versioni successive questa libreria sarà sicuramente più ampia e ricca di nuove funzionalità. La barra dei componenti
La libreria dei componenti di Flowcode è accessibile mediante la “barra dei componenti” mostrata in Fig. 10. I blocchi disponibili sono organizzati per area tematica in modo da facilitarci nella ricerca. I componenti possono essere utilizzati per aiutarci nella realizzazione di sistemi, anche molto complessi, permettendoci di trascurare l’implementazione effettiva del driver del componente, lasciandoci così concentrare sulla
Esportare e importare una macro Mediante il menu “macro” nella barra prin-
cipale di Flowcode è possibile esportare una macro in modo da renderla disponibile per altri progetti. La macro scelta verrà quindi salvata in formato “*.fcm” e potrà essere importata utilizzando lo stesso menu. Questa potenzialità di Flowcode ci permette in pratica di creare una libreria di macro che possiamo incrementare ogni qualvolta creiamo una funzione che pensiamo possa essere utile e riutilizzabile in altri progetti. I componenti
Fig. 11 Principali componenti disponibili in Flowcode.
La possibilità di creare delle macro è molto importante, mentre fondamentale è la possibilità di utilizzare i componenti. I
Elettronica In ~ Luglio / Agosto 2013
117
Fig. 12 Inserire il componente “LED” utilizzando la “Barra dei componenti”.
funzionalità che vogliamo implementare. Per essere correttamente utilizzato, un componente - dopo essere stato inserito - deve essere congurato utilizzando la propria interfaccia specica. Nelle sezioni successive ne vedremo alcuni esempi. Aggiungere un componente software
Per aggiungere un componente software basta cliccare sulla barra di libreria (nel nostro caso inseriamo un LED, come rappresentato in Fig. 13) e vedremo apparire
nel pannello, in basso, il componente che abbiamo scelto. Ora il componente è attivo all’interno del nostro progetto ma, per funzionare correttamente, deve avere le connessioni congurate opportunamente. Clicchiamo sul componente con il tasto destro del mouse, come in Fig. 13. A questo punto si apre un menu a tendina: premiamo su “Connessioni” in modo che si apra la nestra di settaggio come mostrato in Fig. 14. Conguriamo le connessioni per collegare
Fig. 13 Menu connessioni relativo al componente.
c o r s o
F L O W
118
Luglio / Agosto 2013 ~ Elettronica In
C O D E
Fig. 15 Macro disponibili per il componente LED.
E D O C
W O L F o s r o c
Fig. 14 Esempio di connessione per il componente LED.
il componente LED al pin 0 di PORTA. Ora il componente software è congurato ed è possibile inserirlo, dove necessario, all’interno del nostro usso di programma. Per far ciò basta inserire l’icona “macro com ponente ”, selezionandola dalla “Barra delle icone” e trascinarla in posizione corretta all’interno del nostro diagramma. Più blocchi possono utilizzare lo stesso componente in modo da svolgere una o più attività all’interno del diagramma di usso. Per poter funzionare correttamente, il blocco deve essere congurato. Per far ciò basta che con doppio clic entriamo nella nestra “Proprietà: Componente macro ” e selezioniamo nella parte di sinistra il componente al quale deve far riferimento il blocco, nel nostro caso LED(0). Vedremo così apparire nella parte di destra le macro che possono essere chiamate, come mostrato in Fig. 15. In questo caso, avendo scelto il LED, abbiamo a disposizione due macro: quella per accendere il led “LEDOn” e quella per spegnerlo “LEDOff”. Selezioniamo la funzionalità voluta e premiamo il pulsante “OK ” per terminare la congurazione.
condenza con i primi componenti di Flowcode. Quello che ci proponiamo di realizzare è un sistema di controllo che gestisca i dati in ingresso da un KeyPad a 12 tasti (il classico KeyPad telefonico) e che utilizzi le informazioni lette per gestire un gruppo di tre LED. Le speciche del nostro sistema sono le seguenti: • alla pressione del tasto 1 del KeyPad accendere il LED1 e spegnere gli altri LED; • alla pressione del tasto 2 del KeyPad accendere il LED2 e spegnere gli altri LED; • alla pressione del tasto 3 del KeyPad accendere il LED3 e spegnere gli altri LED; • alla pressione del tasto cancelletto del Keypad spegnere tutti i LED. Abbiamo utilizzato i LED per semplicità didattica ma avremmo potuto, con lo stesso sistema, pilotare dei relè, delle elettrovalvole o altri carichi esterni.
Tutti i componenti hanno inoltre delle proprietà extra, accessibili mediante tasto destro sul componente, selezionando la voce “Proprietà extra”. Per ogni componente verrà aperta una nestra specica con differenti caratteristiche congurabili. Nel pannello relativo al componente LED è possibile impostarne la forma, il colore e la polarità, come mostrato in Fig. 17. Progetto Pratico: gestione di 3 LED tramite Keypad
Passiamo adesso alla realizzazione di un progetto che ci consenta di mettere in pratica alcuni dei concetti esposti in questa puntata e che ci aiuti a prendere maggior
Fig. 16 - Proprietà extra r elative al componente LED.
Elettronica In ~ Luglio / Agosto 2013
119
Fig. 17 - Collegamento E-Blocks per la realizzazione del progetto pratico.
Per realizzare questo progetto abbiamo bisogno dei seguenti componenti: - EB006 “USB PICmicromultiprogrammerboard” (PIC18F4550 e Quarzo 12MHz) - EB004 “LED Board” - EB014 “Keypadboard” Colleghiamo ora le schede in modo da avere i LED su PORTA ed il tastierino sulla PORTB, come mostrato in Fig. 17. Apriamo ora il progetto vuoto che avevamo creato con il nome “CongurazioneBase. fcf ” e salviamolo con il nome “SwitchLed.fcf ”. In questo modo il microcontrollore risulta già congurato per funzionare con l’hardware a nostra disposizione: possiamo così dedicarci alla realizzazione del diagramma di controllo del sistema. Fig. 18 Finestra connessioni del componente keypad.
120
In questo nuovo progetto faremo uso dei primi componenti, quindi, dalla barra dei componenti inseriamo nel nostro progetto un componente “Keypad” e tre componenti “LED”, che sono le periferiche che dovremo gestire. Come spiegato in precedenza, per inserire un componente bisogna selezionarlo dalla barra dei componenti. Dopo averlo selezionato, il componente comparirà nel pannello sotto l’area di progetto. A questo punto conguriamo le connessioni dei componenti, cominciando dal KeyPad. Eseguiamo un clic con il tasto destro sul componente keypad comparso sul pannello e selezioniamo l’opzione “connessioni”. Comparirà la schermata di Fig. 18. Come evidenziato in gura, colleghiamo le tre colonne e le quattro righe alla porta B (le tre colonne ai pin 0, 1 e 2 e le quattro Fig. 19 Finestra connessioni
del componente LED.
Luglio / Agosto 2013 ~ Elettronica In
c o r s o
F L O W
C O D E
E D O C
Fig. 20 Finestra di proprietà del componente. Fig. 21 Creazione della variabile di LetturaKeypad.
W O L F o s r o c
righe ai pin 4, 5, 6 e 7). Una volta eseguite le connessioni confermiamo premendo su “Fatto…”. Allo stesso modo conguriamo i tre LED, collegandoli rispettivamente ai pin 0, 1 e 2 della porta A. In Fig. 19 è possibile vedere la congurazione del primo LED. A questo punto possiamo iniziare la stesura del blockdiagram, inserendo il classico ciclo principale, all’interno del quale creeremo la nostra applicazione. Una volta realizzato il ciclo, inseriamo anche un blocco “ Macro Componente” ed una struttura “ Selezione”,
dotandola di quattro casi. A questo punto eseguiamo un doppio clic sul blocco “ Macro Componente”, ed esaminiamo la nestra che si apre, riportata per comodità in Fig. 21. Selezioniamo il componente Keypad e la macro GetKeypadNumber che ci consentirà di rilevare il tasto premuto. A questo punto ci serve una variabile per immagazzinare il valore, che poi utilizzeremo nella successiva struttura di selezione. Creiamo una variabile sfruttando il pulsante con il simbolo della freccia in basso presente sulla nestra attiva, e chiamiamola LetturaKeypad (come tipo scegliamo un unsigned byte). Se avete eseguito tutto correttamente dovreste avere un risultato simile a
Fig. 22 Schema a blocchi parziale del progetto.
Elettronica In ~
Luglio / Agosto 2013
121
Fig. 23 Macro LED0.
Fig. 24 Proprietà del componente
quello riportato in Fig. 21. la descrizione, come riportato Passiamo ora alla gestione della in Fig. 23. struttura di selezione. AssociaNella macro inseriamo tre mo alla selezione la variabile blocchi “ Macro componente” con precedentemente creata e valoi quali gestiremo i componenti rizziamo i primi tre casi con i vaLED precedentemente creati. lori numerici 1, 2 e 3 ed il quarto Chiamiamo la funzione LEDOn con il valore 11 (cancelletto). A per il LED0 e la funzione LEquesto punto il diagramma di DOff per i LED 1 e 2. Se abbiausso dovrebbe apparire come mo eseguito tutto correttamente quello riportato in Fig. 22. otterremo uno schema come Abbiamo quasi nito: non ci quello riportato in Fig. 25. Fig. 25 resta che gestire correttamente Creiamo altre due macro analoSchema a blocchi della il pilotaggio delle uscite nei vari ghe per l’accensione dei LED 1 macro LED0. casi. Per evitare di rendere il e 2 ed una macro di spegnimen blockdiagram troppo complesto che chiameremo LEDOff. so, utilizziamo delle macro speciche per Ora posizioniamo quattro blocchi “ Chiamata il pilotaggio delle uscite. Cominciamo dal Macro” nei quattro rami della struttura di caso corrispondente al tasto 1 che, secondo selezione e chiamiamo opportunamente le nostre speciche, dovrebbe accendere il le macro appena create. Il nostro progetto LED0 e spegnere gli altri. Creiamo una nuo- è concluso; il blockdiagram complessivo è va macro, che chiameremo appunto LED0, riportato in Fig. 26, a questo punto non ci come abbiamo visto in precedenza nel resta che collegare opportunamente gli g paragrafo dedicato alle macro ed inseriamo E-block e testare quanto realizzato.
Fig. 26 Schema a blocchi complessivo.
LED.
c o r s o
F L O W
122
Luglio / Agosto 2013 ~ Elettronica In
C O D E
E D O C
W O L F o s r o c
Continuiamo il nostro viaggio alla scoperta di Flowcode, l’innovativo sistema di sviluppo grafico per microcontrollori proposto da Matrix Multimedia. In questa puntata ci occupiamo dell’implementazione degli interrupt in Flowcode e iniziamo ad analizzare i componenti. Terza puntata.
corso di programmazione in
FLOWCODE di Francesco Ficili e Daniele Defilippi
elle precedenti puntate abbiamo analizzato in dettaglio l’ambiente di sviluppo, descrivendone la struttura ed analizzando gli elementi di base come le strutture di controllo e le strutture dati. In questa puntata completeremo l’analisi delle strutture di controllo, descrivendo la gestione degli interrupt, e continueremo l’analisi dei componenti (che sono uno dei principali valori aggiunti di Flowcode) descrivendo il componente ADC ed il componente LCD. Successivamente passeremo alla descrizione della gestione delle memorie non volatili, analizzando il componente EEPROM. Sfruttando le nuove conoscenze acquisite realizzeremo un progetto prati-
N
co più evoluto rispetto ai precedenti: un termometro con display LCD. Per i progetti di questa puntata cambieremo microcontrollore, passando dal PIC18F4550 al PIC18F4580. Vedremo così quanto sia semplice, gestendo i progetti con Flowcode, cambiare target senza risentire di problematiche di congurazione e faremo qualche esperimento con un PIC diverso. Per agevolare i lettori nella sperimentazione abbiamo generato un le di congurazione base anche per il PIC18F4580, così come avevamo fatto in precedenza. Gli interrupt
Come tutti gli ambienti di sviluppo per
Elettronica In ~ Settembre 2013
129
Fig. 1 Proprietà del blocco interrupt.
microcontrollori, anche Flowcode prevede la gestione degli interrupt. In un sistema embedded un interrupt (o interruzione) è un segnale asincrono rispetto all’esecuzione del programma principale, proveniente da una specica periferica, che segnala una situazione particolare che richiede una gestione differente rispetto al resto del programma. Un interrupt può provenire da una porta di comunicazione, da una risorsa interna, da un timer, eccetera. Normalmente, quando viene generato un interrupt, la gestione del programma si arresta, la posizione corrente del program counter ed il contesto di esecuzione vengono salvati nello stack e il programma salta a una locazione specica, che è funzione dell’interrupt stesso e dell’architettura specica del microcontrollore. A questo punto, a seconda dei casi, viene eseguita una funzione speciale (in genere denominata ISR, Interrupt Service Routine) che “serve” l’interrupt e che, una volta terminata, ritorna il controllo al programma principale, che ricomincia dal punto in cui era stato interrotto (recuperando tutte le informazioni necessarie dallo stack, all’interno del quale era stata salvata la posizione corrente ed il contesto). In Flowcode esiste un blocco speciale, presente all’interno della barra delle icone e denominato appunto “blocco interrupt”, che serve ad implementare la gestione degli interrupt all’interno di un programma Flowcode. Se inseriamo questo blocco all’interno di uno schema Flowcode e clicchiamo due volte con il tasto sinistro, potremo accedere alla nestra proprietà del blocco, come riportato in Fig. 1. Da questa nestra è possibile selezionare la sorgente dell’interrupt che ci interessa, accedendo al menu a tendina “Interrupt Attivi”. Analizzando questo menu, vedremo che per il PIC18F4580, sono disponibili
130
Settembre 2013 ~ Elettronica In
diversi interrupt sui timer, sugli ingressi della porta B, sulla ricezione della porta UART e altro ancora. Una volta selezionata la sorgente dell’interrupt, bisognerà indicare anche la relativa ISR. Flowcode gestisce questo aspetto, fornendo la possibilità di chiamare un’opportuna macro creata in precedenza. Tutto ciò non è molto diverso da quello che accade con altri sistemi di sviluppo, basati su linguaggi classici come, ad esempio, il C: in quel caso la ISR è generalmente una comune funzione scritta in linguaggio C, che ha però la particolarità di essere chiamata quando viene generato il relativo interrupt. Il concetto di interrupt è abbastanza delicato in ambito di sviluppo embedded, in quanto gli interrupt sono largamente utilizzati nella gestione dell’hardware e sono di fondamentale importanza man mano che i sistemi sviluppati si fanno più complessi. Cerchiamo di ssare questo concetto con un esempio, riproponendo il progetto pratico visto nella prima puntata con una gestione ad interrupt. Nella prima puntata avevamo fatto lampeggiare un LED alla frequenza di 1 Hz, sfruttando i ritardi software. Proviamo adesso a fare la stessa cosa, ma anziché generare il ritardo con dei cicli software vuoti, proviamo a generare la temporizzazione con una risorsa hardware interna al microcontrollore. Per farlo ci serviamo del Timer 2, che può generare un interrupt quando il suo valore corrisponde a quello di un registro di confronto. Procediamo quindi creando un nuovo progetto Flowcode, partendo dal template CongurazioneBase2, fornito insieme al materiale relativo a questa puntata, e cambiamo il nome del progetto in Interrupt.fcf. Per prima cosa creiamo la macro che useremo come ISR, nominandola LED. Eseguiamo i passi necessari come abbiamo visto nella puntata precedente e generiamo anche una variabile che chiameremo LedStatus (booleana, valore iniziale false) ed un’altra che chiameremo Counter (byte, valore iniziale 0). A questo punto passiamo sullo schema a blocchi principale, inseriamo un blocco interrupt, e a seguire un blocco ciclo. Il ciclo ci serve solo per evitare che il pro-
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 2 Proprietà interrupt timer 2.
gramma termini e riparta dal principio, lo possiamo quindi considerare come la nostra “applicazione principale”, anche se non fa nulla. A questo punto conguriamo il blocco interrupt. Nel menu a tendina, alla voce “interrupt attivi” selezioniamo TMR2 e clicchiamo su proprietà. Otterremo la nestra di Fig. 2, che ci permette di Fig. 3 congurare l’interrupt sul Timer 2. Flowchart della macro LED. Funzionando a 12 MHz, anche intervenendo sui vari pre e post-scaler non c’è modo di generare un interrupt a 1Hz. Conguria- cambiato e che ora il pin controllato è D0) e vedrete lo stesso effetto ottenuto nel mo quindi l’interrupt con i valori riportati caso dell’oscillazione generata con i ritardi in gura, per ottenere un interrupt a circa software. Notate che questo esempio non 50 Hz. Partendo da questa base tempi ci basterà semplicemente utilizzare un conta- è puramente didattico. Infatti, se volessimo aggiungere funzionalità a questo tore di servizio per generare la frequenza programma, ci basterebbe inserire i relativi di 1Hz che ci serve per pilotare oppor blocchi sul ciclo principale che attualmente tunamente il nostro LED. Completiamo è vuoto, “dimenticandoci” della gestione la congurazione tornando sulla nestra ad interrupt, che non viene disturbaprecedente e selezionando la macro LED ta dall’esecuzione del main (in quanto alla voce “verrà chiamata la macro”. Queasincrona rispetto a quest’ultimo), mentre sto fa sì che ad ogni interruzione generata dal timer 2 venga chiamata la nostra macro. la stessa cosa non si potrebbe dire per la versione fatta con i ritardi software. A questo punto non ci rimane altro da fare che completare la macro precedentemente Il componente ADC creata. Per vedere come abbiamo fatto ci Passiamo ora all’analisi di uno dei comserviamo della Fig. 3. Come si può vedere ponenti che utilizzeremo nel prossimo dallo schema a blocchi, ad ogni chiamata della macro viene incrementato il contatore progetto pratico: il componente ADC. Que“Counter”. Se il valore è inferiore al valore sto componente permette di congurare e gestire in maniera semplice un canale della costante timeout (che abbiamo impostato pari a 50) non succede nulla, altrimen- analogico di ingresso, sfruttando il convertitore integrato nel microcontrollore. ti si passa alla gestione effettiva del LED. Il componente ADC può essere inserito In questo ramo del owchart si controlla il selezionandolo dalla barra dei componenti, valore della variabile LedStatus, invertensotto la voce “ingressi”. Una volta inseridolo, di volta in volta, rispetto al suo stato to, nel pannello comparirà una manopola attuale e pilotando di conseguenza il LED. del tutto simile a quella che si trova nei A questo punto provate a “ashare” il pannelli frontali della strumentazione da microcontrollore con il owchart fornilaboratorio. Come abbiamo già visto nella to come esempio (notate che il micro è
Elettronica In ~ Settembre 2013
131
Fig. 4 Finestra connessioni del componente ADC.
ne impostazioni base del componente, come la tensione di riferimento (Vref) , la velocità di conversione e altro ancora. Per quanto riguarda invece le macro che il componete ADC può sfruttare, in Tabella 1 sono elencate le principali macro disponibili. Il componente dispone anche di macro più speciche, ma al momento non le prenderemo in considerazione in quanto non strettamente necessarie. Il componente LCD
Fig. 5 Proprietà extra del componente ADC.
puntata precedente per il componente LED, anche il componente ADC è dotato di “connessioni” e di “proprietà extra”. È possibile accedere a questi due menu cliccando con il tasto destro sull’icona del componente presente sul pannello. Cliccando sulla voce “connessioni” comparirà la nestra di Fig. 4, che permette di impostare il pin del micrcocontrollore da utilizzare come ingresso analogico (nell’esempio An0). Per accedere alle “proprietà extra”, basta selezionare la relativa voce nel menu che compare sempre cliccando con il tasto destro sull’icona del pannello. La nestra proprietà extra del componente ADC è riportata in Fig. 5. Com‘è possibile vedere - impostazioni dell’icona a parte - sono disponibili alcuTabella 1 -
132
Passiamo ora all’analisi del componente LCD, che ci permetterà di aggiungere un output visuale ai nostri progetti. Il componente LCD permette di gestire un display a cristalli liquidi con controller Hitachi HD44780 (noto anche come Hitachi compatibile); questa interfaccia costituisce lo standard de facto per gli LCD alfanumerici monocromatici con interfaccia parallela. In particolare, il componente sfrutta la congurazione parallela a 4-bit, in modo da poter impiegare una singola porta per il controllo del dispositivo (oltre ai 4 bit di dato vengono infatti utilizzati 2 segnali di controllo). Il componente LCD può essere inserito dalla barra dei componenti, selezionando, sotto la voce “uscite”, il componente “LCD”. Una volta eseguita questa operazione, all’interno del pannello verrà posizionata l’immagine di un display alfanumerico 16x2. Come per gli altri componenti visti in precedenza, anche per il componente LCD sono disponibili le solite proprietà “connessioni” e “proprietà extra”. Se clicchiamo sulla voce connessioni, comparirà la nestra di Fig. 6, che ci permette di congurare le connessioni del display. Da questa nestra è
Principali macro disponibili per il componente ADC.
Nome Macro
Descrizione
LeggiComeByte
Il valore del canale selezionato è acquisito e il risultato è fornito con formato numerico e 8-bit di risoluzione.
LeggiComeIntero
Il valore del canale selezionato è acquisito e il risultato è fornito con formato numerico e 10-bit o 12-bit di risoluzione (a seconda del convertitore).
LeggiComeTensione
Il valore del canale selezionato è acquisito e il risultato è fornito con formato in tensione (il valore deve essere immagazzinato in una variabile di tipo oat).
LeggiComeStringa
il valore del canale selezionato è acquisito e il risultato è fornito come stringa di caratteri (il valore deve essere immagazzinato in un array di caratteri).
Settembre 2013 ~ Elettronica In
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
possibile impostare le 6 linee necessarie all’interfacciamento del componente con il microcontrollore. Se apriamo invece la nestra “proprietà extra”, rappresentata in Fig. 7, sarà possi bile congurare la dimensione del display (16x1, 16x2, 16x4, 20x4…), più altre caratteristiche che comunque sono utili più ai ni della simulazione che altro. Diamo ora uno sguardo alle macro disponibili per questo componente, per capire come poterlo gestire efcacemente nei no-
Fig. 6 Connessioni del componente LCD.
stri progetti. In Tabella 2 sono indicate le macro disponibili per il componente LCD corredate della relativa descrizione. Le memorie non volatili
Come sappiamo, diversi PIC dispongono al loro interno di un certo quantitativo di memoria non volatile di tipo EEPROM (Electrical Erasable and Programmable Read Only Memory); questa può essere utilizzata per l’immagazzinamento di dati che non devono essere persi dopo uno spegnimento del sistema. Una on-board EEPROM può essere un grande vantaggio nel caso in cui si debba sviluppare un sistema embedded che ha esigenze di memorizzazione permanente di alcuni dati, perché in questo caso non è necessario ricorrere all’uso di una memoria esterna I2C o SPI. Il PIC18F4580 dispone di 256 byte di on-board EEPROM, garantiti per circa un milione di cicli di scrittura e con una ritenzione di più di 40 anni. Il componente EEPROM
Flowcode dispone di un componente apposito per la gestione della EEPROM interna. Tale componente può essere inserito dalla barra dei componenti, selezionando sotto la voce “varie” il componente “EEPROM”. Una volta inserito il componente vedrete comparire nel pannello un array bidimensionale che mostra la locazione di memoria e il suo contenuto. Per il componente EEPROM non sono presenti le connessioni, in quanto questo componente non è collegato esternamente in quanto il bus per la gestione della memoria è interno al chip. È disponibile invece l’opzione
Fig. 7 Proprietà extra del componente LCD.
Tabella 2 -
Principali macro disponibili per il componente LCD.
Nome Macro
Descrizione
Inizio
Inizializza il display.
Trasparente
Cancella tutte le righe del display.
Vi su al iz zaAS CI I
Vi su al iz za i l c arat te re AS CI I c or ri spo nde nte al by te p ass ato c ome argo me nto.
Comando
Invia il comando passato come argomento.
Cursore
Posiziona il cursore alla posizione indicata dai due argomenti x e y (coordinate del cursore).
VisualizzaNumero
Visualizza il numero passato come argomento già conver tito in ASCII.
VisualizzaStringa
Visualizza la stringa passata come argomento
CancellaLinea
Cancella la linea passata come argomento.
Scrivi_RAM
Scrive nella RAM del controller i dati passati come argomento.
Elettronica In ~ Settembre 2013
133
Fig. 8 Proprietà extra del componente EEPROM.
Tabella 3 Nome Macro
Descrizione
Read
Legge la locazione di memoria specicata con il parametro address e ritorna il valore letto nella variabile di ritorno.
Write
Scrive la variabile specicata con il parametro data all’interno della locazione specicata con il parametro address.
“proprietà extra”, che può essere selezionata sempre premendo il tasto destro sull’icona del componente presente sul pannello. La nestra delle proprietà è visibile in Fig. 8. Sono disponibili più che altro proprietà relative alla simulazione ed è possibile settare a mano la dimensione della EEPROM, altrimenti l’ambiente imposta quella massima relativa al chip utilizzato. In Tabella 3 sono riportate le macro disponibili per il componente che sono tutte molto semplici. L’unica accortezza da utilizzare è quella di lasciare un intervallo di almeno 200 microsecondi tra una scrittura e la successiva, per garantire il tempo necessario al completamento dell’operazione. Per testare la EEPROM è stato realizzato un owchart di prova che scrive in tutte le 256 locazioni di memoria un numero crescente da 0 a 256. Il sorgente Flowcode EepromTest.fcf è reperibile all’interno del materiale di supporto. Progetto Pratico: Termometro LCD
Passiamo ora alla descrizione del progetto pratico relativo a questa puntata, nello sviluppo del quale metteremo in pratica le nuove conoscenze acquisite. Ciò che ci proponiamo di realizzare è un termometro digitale che impiega un LM335 ed un display LCD Hitachi compatibile. Le specifiche del nostro progetto sono: • Lettura del termometro digitale sul canale analogico AN0, c o r s o
Fig. 9 Collegamento E-Blocks per la realizzazione del progetto pratico.
134
Settembre 2013 ~ Elettronica In
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 11 Connessioni del componente ADC.
Fig. 10 Collegamento LM335.
• Conversione del dato di temperatura in gradi Celsius, • Visualizzazione continua della temperatura sul display. Per la realizzazione del progetto utilizzeremo i seguenti componenti: - EB006 “USB PICmicro multiprogrammer board” (PIC18F4580 e Quarzo 12MHz), - EB005 “LCD board”, - EB016 “Prototype board”. Useremo la EB016 per la realizzazione del circuito di acquisizione della temperatura tramite l’LM335. Naturalmente Matrix dispone di alcune schede con sensori di temperatura, più o meno evolute, ma volevamo mostrare ai lettori come sia possi bile interfacciare qualsiasi tipo di sensore usando la scheda di prototipazione. Colleghiamo le schede come segue: • EB016 collegata alla porta A ed alla porta B della EB006, • EB005 collegata alla porta C della EB006. I collegamenti sono illustrati in Fig. 9. Prima di andare avanti, bisogna realizzare il circuito di acquisizione della temperatura sulla scheda di prototipazione. Per farlo abbiamo fatto riferimento al datasheet dell’LM335, che riporta alcuni esempi di circuiti. La nostra scelta è caduta sul sensore con circuito di calibrazione, il cui schema è riportato in Fig. 10. Questo circuito ci consente di avere una misura più precisa della temperatura, in quanto si utilizza un potenziometro per calibrare il sensore. Una volta completato il progetto, potremo eseguire la calibrazione semplicemente agendo sul potenziometro ed utilizzando un termometro calibrato per
ottenere la temperatura di riferimento. A questo punto procediamo alla realizzazione del circuito sulla breadboard e colleghiamo l’uscita del sensore all’ingresso analogico AN0 del microcontrollore, che troviamo disponibile sulla strip montata a ridosso del connettore J1 sulla EB016. Ora che i collegamenti di segnale sono ultimati, non ci resta che distribuire anche le alimentazioni ai vari E-Block. Per farlo preleviamo riferimento e tensione di alimentazione dalla scheda madre (presenti sulla morsettiera J10) e li portiamo alle morsettiere a vite J1 della EB005 e J3 della EB016. Ora che l’hardware è pronto, possiamo procedere allo sviluppo delle componenti software. Per prima cosa preoccupiamoci di inserire e collegare opportunamente tutti i componenti che utilizzeremo nel progetto. Viste le speciche, ci occorre sicuramente un componente ADC ed un componete LCD. Non abbiamo da memorizzare informazioni permanenti, quindi in questo progetto non avremo bisogno del componente EEPROM. Procediamo trascinando i componenti sul pannello. A questo punto effettuiamo le connessioni. Il componente ADC dovrà leggere il canale analogico 0 (AN0), quindi effettuiamo la connessione con quel canale, come illustrato in Fig. 11. Completate le connessioni, occupiamoci delle proprietà extra del convertitore analogico-digitale. Per questo progetto impostiamo: - Tempo di conversione: 50 cicli - Velocità di conversione: Fosc/16 - Opzioni Vref: Vdd Per quanto riguarda la voce “Tensione
Elettronica In ~ Settembre 2013
135
Fig. 12 Connessioni display LCD.
componente ADC di Flowcode ci offre la possibilità di acquisire la lettura del canale analogico considerato direttamente in tensione, ritornando un oat. Questa caratteristica risulta molto comoda perché così sarà più facile effettuare la conversione in temperatura. In virtù di queste considerazioni creiamo una variabile di tipo “virgola mobile” e chiamiamola “Tensione” (come illustrato in Fig. 13) con la quale immagazzineremo il valore di tensione letto sul canale AN0. Creiamo anche una ulteriore variabile, chiamandola “Temperatura”, sempre di tipo “virgola mobile”, all’interno della quale immagazzineremo il corrispondente valore di temperatura.
Fig. 13 Creazione della variabile “Tensione”.
Passiamo ora alla realizzazione dello schema a blocchi che sarà composto da un owchart principale e da tre macro: - Inizializzazione del sistema, - Lettura del sensore di temperatura, - Visualizzazione della lettura.
Vref” possiamo impostare 4,5V se alimentiamo il sistema tramite la porta USB (è la tensione tipica) o 5V se alimentiamo dall’esterno con un regolatore stabilizzato. In ogni caso potremo aggiustare in seguito la misura, usando il circuito di calibrazione che ci siamo preparati in precedenza. A questo punto passiamo alle connessioni del display LCD, collegato sulla porta C, come illustrato in Fig. 12. Ricordiamo che l’interfaccia del display è parallela a 4-bit e utilizza due ulteriori segnali: RS ed Enable. Assicuriamoci di avere la nestra delle connessioni del display congurata come quella in Fig. 12 e di avere il jumper della EB005 posizionato su “default”. Non ci sono proprietà extra rilevanti per il display, quindi per quanto riguarda la congurazione dei componenti e delle connessioni abbiamo concluso. Prima di passare all’analisi del owcart ci serve ancora la denizione della struttura dati sulla quale andremo a lavorare. Il
136
Settembre 2013 ~ Elettronica In
c o r s o
F L O W
Fig. 14 Macro Inizializzazione.
C O D E
E D O C
W O L F
Fig. 15 Flowchart della macro “Acquisisci LM335”.
Partiamo dalla macro di inizializzazione, che ha lo scopo di inizializzare il display e le variabili e di scrivere una prima riga di testo per informare l’utente. Il owchart della macro di inizializzazione è riportato in Fig. 14. Come si vede, si utilizzando tre blocchi “Chiamata Macro Componente”, un blocco “Calcolo” e un blocco “Ritardo”. In sequenza le operazione eseguite sono le seguenti: si inizializza il display, lo si pulisce, si visualizza la stringa “Init System…”, si inizializzano le variabili e si genera un
o s r o c
Fig. 16 Finestra proprietà del blocco “Chiamata Macro Componente”.
ritardo di 1 secondo. Molto semplice. A questo punto passiamo alla macro di lettura del sensore di temperatura, che abbiamo chiamato “AcquisisciLM335”, il cui owchart è riportato in Fig. 15. Questa macro è il cuore del programma, eppure la potenza di Flowcode ci permette di ridurla a due soli blocchi. Il compito da eseguire è quello di acquisire il dato in tensione ed effettuare la conversione in temperatura, in modo che possa poi essere facilmente visualizzata dal display. Per prima cosa si sfrutta la macro “LeggiCo-
meTensione” del componente ADC, che permette di acquisire un canale analogico riportando direttamente il dato in tensione (in Volt), associabile ad una variabile di tipo oat (virgola mobile). Noi associamo il valore di ritorno alla variabile “Tensione”, che avevamo creato in precedenza. In Fig. 16 è riportata la nestra di proprietà del blocco “Chiamata Macro Componente” che realizza l’operazione. A questo punto bisogna convertire il dato letto in un dato di temperatura. L’LM335 ha un segnale in uscita proporzionale alla temperatura con fattore di proporzionalità di 10mV/Kelvin. Invertiamo la formula, scaliamo il valore di tensione da V a mV e sottraiamo 273 per ottenere la temperatura in gradi Celsius. Per introdurre questa formula nel codice usiamo un blocco calcolo, come riportato in Fig. 17. Il dato immagazzinato all’interno della variabile “Temperatura” è già correttamente convertito in gradi Celsius, quindi basterà convertirlo in codica ASCII per ottenere la visualizzazione corretta. Ora anche la seconda macro è completata. Passiamo all’ultima macro da realizzare, la macro di visualizzazione, che chiameremo “VisualizzaTemperatura”, il cui owchart è riportato in Fig. 18. In questo owchart usiamo solo chiamate a macro di componeti, in quanto il dato è già pronto e l’unica cosa che dobbiamo fare è scriverlo correttamente sul display, sfruttando le funzioni a corredo del componente LCD nonché le stringhe di contorno. Per prima cosa si pulisce il display, in modo che non rimangano porzioni di stringe scritte in precedenza. Fatto questo si visualizza la stringa “Temperatura:”, come stringa di intestazione. A questo punto si usa la funzione “Cursore” per muoversi sulla seconda riga, che verrà usa-
Elettronica In ~ Settembre 2013
137
Fig. 17 Conversione del dato in tensione nel corrispondete valore di temperatura.
Fig. 18 Flowchart della macro “VisualizzaTemperatura”.
ta per visualizzare il dato. Qui possiamo usare la macro “VisualizzaNumero” per visualizzare su display il valore immagazzinato nella variabile “Temperatura” che, come abbiamo visto prima, contiene il valore della temperatura in gradi Celsius. Ora non ci rimane altro da fare che visualizzare il carattere “C” per indicare che la temperatura è in gradi Celsius e riportare il cursore alla posizione di partenza: la nostra terza macro è così pronta. Ora abbiamo le tre macro pronte all’uso, l’ultima operazione da fare è metterle insieme sul owchart principale e lanciare la compilazione. Il owchart principale è riportato in Fig. 19. Come potete vedere è stata chiamata prima di tutto la macro “Inizializzazione”. Poi, all’interno di un ciclo while innito, sono state inserite le due chiamate alle macro “AcquisisciLM335” e “VisualizzaTemperatura”. La prima macro acquisisce il valore di tensione proveniente dal sensore di temperatura e passa i dati alla seconda, che li visualizza sul display LCD. Per evitare un eccessivo effetto “Refresh” sul display
138
Settembre 2013 ~ Elettronica In
Fig. 19 Flowchart principale dell’esempio pratico Termometro LCD.
è stato inserito un ritardo software di un secondo. Possiamo ora procedere con la compilazione e l’esecuzione del programma. Una volta programmato il micro, se abbiamo eseguito tutto correttamente, vedremo comparire il valore della temperatura letta dal sensore sul display. Se la lettura non fosse corretta, possiamo agire sul potenziometro del circuito di calibrazione per regolarla. In questa puntata abbiamo iniziato a prendere condenza con i componenti di Flowcode, realizzando un primo programma di un certo peso (un dispositivo che ha una reale funzione), e abbiamo cominciato a renderci conto di come, inserendo i componenti appositi e collegando pochi blocchi, sia possibile implementare in breve tempo anche funzioni di una certa complessità. Nella prossima puntata continueremo questo percorso, esaminando in dettaglio le interfacce di comunicazione che ci permettono di realizzare sistemi più complessi, interfacciati a periferiche esterg ne più intelligenti.
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Continuiamo il nostro viaggio alla scoperta di Flowcode, il sistema di sviluppo grafico per microcontrollori proposto da Matrix Multimedia, in cui il codice viene scritto facendo uso di oggetti grafici. Quarta puntata.
corso di programmazione in
FLOWCODE di Francesco Ficili e Daniele Defilippi
elle scorse puntate abbiamo spiegato la gestione degli interrupt in Flowcode e insegnato a utilizzare i componenti ADC, LCD e la memoria EEPROM interna. In questa puntata parleremo delle principali interfacce di comunicazione seriali a disposizione dei microcontrollori di bassa gamma: l’UART (o RS232), l’I²C, SPI e l’OneWire. Termineremo con un progetto pratico nel quale svilupperemo un controllo di una batteria di relé comandata tramite porta seriale.
N
Le periferiche di comunicazione di base
I sistemi che abbiamo trattato nora erano in grado di gestire solo sistemi chiusi, cioè
non potevano interfacciarsi con piattaforme esterne. Parleremo ora di altri componenti fondamentali di un microcontrollore, che sono le interfacce di comunicazione. I bus di comunicazione sono in continua evoluzione ed oggigiorno ve ne sono di moltissime tipologie. Facciamo un piccolo passo indietro ed analizziamo brevemente le interfacce di comunicazione che sono state utilizzate in questi ultimi decenni. Con l’avvento dell’era digitale, il sistema di comunicazione maggiormente utilizzato è stato quello “parallelo”, dove i dati sono scambiati a pacchetti, solitamente di 8 bit, ed uno o più segnali trasportano l’informazione del clock. Il trasporto dei dati in parallelo non è
Elettronica In ~ Ottobre 2013
113
Fig. 1 Pannello SPI.
• SCK/SCLK (Serial Data Clock) su cui viene trasmesso il segnale di clock.
consigliabile sulle grandi distanze, in quanto richiederebbe molti li e -per contrastare il degrado del segnale- l’amplicazione per ciascuno di essi; per questa ragione che sono state inventate le comunicazioni seriali, nelle quali il valore digitale da trasmettere è suddiviso in singoli bit, che sono trasmessi in ordine sequenziale sullo stesso canale di trasmissione, impiegando quindi due soli li. Possiamo suddividere i sistemi di comunicazione in due grandi famiglie, in base alla distanza che riescono a coprire: quelli “ interni” permettono la comunicazione tra sistemi vicini o comunque appartenenti allo stesso sistema, mentre quelli “tra sistemi” collegano apparati con compiti solitamente differenti su distanze anche molto ampie. Inizieremo parlando di quelli interni ed in particolare di SPI, I²C e OneWire. Successivamente passeremo alla descrizione della RS232, interfaccia con la quale realizzeremo un progetto pratico. Serial peripheral interface (SPI)
L’interfaccia SPI (acronimo di Serial Peripheral Interface) è semplice da utilizzare ed afdabile e, per queste ragioni, è divenuta il sistema di comunicazione comunemente utilizzato da memorie, ADC e DAC esterni al microcontrollore. La comunicazione mediante porta SPI necessita di tre collegamenti: • SDO/MOSI (Serial Data Output) dal quale i dati vengono inviati; • SDI/MISO (Serial Data Input) dal quale i dati vengono ricevuti;
114
Ottobre 2013 ~ Elettronica In
I dati trasmessi e ricevuti passano su due connessioni differenti e, per questa ragione, la comunicazione è detta di tipo full-duplex. Più periferiche possono essere collegate allo stesso bus di comunicazione, ma, in questo caso, solo una di esse è di tipo “master”, mentre tutte le altre sono di tipo “slave”. Per poter utilizzare questo sistema di comunicazione non è comunque necessaria una conoscenza approfondita del livello sico e di protocollo, perché Flowcode mette a disposizione una potentissima libreria di componenti che ci permette di utilizzarla e gestirla in modo ancora più semplice. All’interno della barra dei componenti nel menu Trasmissione dati troviamo il componente SPI ; se lo inseriamo nel nostro progetto mediante un clic sulla relativa icona, notiamo che appare, nel pannello, come una nestra suddivisa in tre parti. Partendo dall’alto verso il basso possiamo così esaminare i caratteri inviati, quelli ricevuti e in basso i caratteri in coda, come mostrato in Fig. 1. Ora che il componente è stato inserito nel progetto, è necessario congurarlo in modo che possa comunicare correttamente con le periferiche. I campi della nestra delle proprietà, mostrata in Fig. 2, devono essere valorizzati esaminando il data-sheet del componente che vogliamo collegare esternamente, in modo che tutto possa funzionare correttamente. Il box in cui si può indicare se trasmettere byte o caratteri non inuenza la modalità Fig. 2 Pannello di configurazione del bus SPI.
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Tabella 1 - Parametri
di configurazione del bus SPI.
Parametro
Descrizione
Rappresenta la velocità di trasmissione dei dati. Deve obbligatoriamente essere minore di quella supportata dal componente più lento collegato al bus di comunicazione. Facciamo un semplice esempio supponendo che il componente slave supporti una velocità massima di comunicazione di 300 kHz ed il microcontrollore abbia una frequenza di oscillazione pari a 4 MHz. SPI Clock
Dividendo la frequenza massima della comunicazione per la frequenza di oscillazione del microcontrollore, otteniamo il rapporto massimo che vi può essere tra le due grandezze e scegliamo il valore più grande, tra quelli disponibili nel menu a tendina, che risulta minore del risultato della frazione. È utilizzato per denire lo stato di inattività (idle) del segnale di clock.
SPI Clock polarity SPI Clock Edge
Serve per scegliere se il dato è scritto durante il fronte di salita o discesa del segnale di clock.
SPI Sample bit
Indica quando il dato deve essere campionato per poter effettuare una corretta trasmissione/ricezione del dato da tutti i dispositivi collegati. In pratica, modica il punto di campionamento del dato.
di trasmissione/ricezione dei dati sul bus di comunicazione, ma unicamente la loro visualizzazione sul componente nel pannello di Flowcode. Al termine della congurazione possiamo inserire le macro gestite del componente dal menu delle icone, come fatto per il componente KeyPad e per l’ADC esaminati nelle puntate precedenti. In questo caso le principali macro a nostra disposizione sono quelle elencate nella Tabella 2. Vi sono altre macro speciche, mostrate in Tabella 3, che ci possono essere di aiuto nel Tabella 2 - Macro Nome Macro SPI_Init
caso volessimo utilizzare la scheda EB013, che contiene al suo interno una memoria FRAM (rimpiazzabile con una memoria EEPROM) ed un convertitore digitale/analogico, entrambi su bus SPI. Per poter utilizzare questi componenti è inoltre necessario congurare le connessioni esterne dei piedini di abilitazione. Utilizzando queste semplici macro è quindi possibile utilizzare una memoria EEPROM/ FRAM od un DAC in modo davvero semplice ed intuitivo. Qualora il componente scelto non appartenesse a questa lista o non
disponibili per il controllo del bus SPI. Descrizione
È utilizzata per inizializzare le periferica di comunicazione SPI. Solitamente è posta ad inizio programma e viene chiamata una volta sola.
SPI_Send_Char
È utilizzata per inviare un carattere.
SPI_Get_String
È utilizzata per ricevere una stringa di caratteri.
SPI_Send_String
È utilizzata per inviare una stringa di caratteri.
SPI_Get_Char SPI_Unint
Tabella 3 - Macro Nome Macro
È utilizzata per ricevere un carattere. È utilizzata per rimuovere le inizializzazioni della connessione SPI e poter quindi utilizzare i pin del microcontrollore come normali bit della porta di I/O.
supplementari per componenti specifici su bus SPI. Descrizione
DAC_Send_Char
Invia un carattere/byte al convertitore digitale/analogico che lo trasformerà direttamente in un valore analogico visibile sui morsetti esterni.
NVM_Send_Char
Invia un dato alla memoria EEPROM che verrà caricato all’interno della cella selezionata.
NVM_Get_Char
Legge il valore memorizzato all’interno della cella di memoria indicata.
FramOutput
Invia un valore alla memoria FRAM.
EnableFRAM
Abilita la memoria FRAM/EEPROM. Prima di ogni comando verso la memoria, è necessario abilitarla altrimenti tutti i comandi verrebbero ignorati.
DisableFRAM
Disabilita la memoria FRAM/EEPROM in modo da poter comunicare con altri dispositivi collegati sullo stesso bus SPI.
Elettronica In ~ Ottobre 2013
115
Fig. 3 Pannello del componente I2C Master.
fosse compatibile, basterà semplicemente utilizzare le macro generiche in modo da realizzare il protocollo corretto. La porta I²C
Passiamo ora a descrivere il bus di comunicazione I²C, il cui protocollo richiede unicamente due linee di comunicazione: • SDA (Serial Data Line) per la trasmissione/ricezione dei dati ; • SCL (Serial Clock Line) per la trasmissione del clock di sincronizzazione. Sullo stesso bus possono essere collegati no a 112 dispositivi differenti. A differenza dell’SPI, sia i dati in trasmissione che quelli in ricezione viaggiano sulla stessa connessione sica. Il bus SPI è di tipo half-duplex perché solo un componente alla volta può trasmettere i dati; inoltre, la comunicazione può essere iniziata solo dal master, mediante una stringa che contiene un bit di start, l’indirizzo dello slave con il quale vuole comunicare e un bit che indica se è richiesta Tabella 4 - Parametri
di configurazione componente I 2 C.
Parametro
Descrizione
Enableslew rate control
Attiva il controllo sullo slew-rate (velocità dei fronti) del segnale trasmesso sul bus. Abilita l’utilizzo del SMBus sulla connessione I²C (modalità di compatibilità).
Enable SMBus Inputs
116
una risposta. Successivamente vengono inviati, in sequenza, i dati veri e propri, iniziando sempre dal bit più signicativo. All’interno della barra dei componenti possiamo selezionare il controller per il bus I²C ed inserirlo all’interno del pannello di Flowcode. Il pannello appare come in Fig. 3 e ci permette di visualizzare le comunicazioni presenti sul bus e poter interagire aggiungendo byte nella comunicazione in modo da rendere la simulazione interattiva. Per utilizzare il componente è necessario congurarlo come abbiamo fatto precedentemente con il bus SPI, ma i parametri da settare sono differenti; nel caso del bus I²C, essi sono quelli elencati nella Tabella 4. Invece le macro a disposizione sono riassunte in Tabella 5. Continuando nel nostro percorso di descrizione di bus di comunicazione, passiamo al bus con il minor numero di connessioni possibili: una connessione unica per la trasmissione/ricezione di dati e segnale di sincronizzazione: il bus OneWire.
Baud rate
Imposta la frequenza con la quale vengono trasmessi i dati sul bus di comunicazione. Deve obbligatoriamente, come visto per il bus SPI, essere minore della velocità massima supportata dal componente più lento collegato al bus. Possono essere utilizzati i valori pre-congurati (preset), oppure dei valori custom scelti utilizzando la barra a scorrimento.
IC2 hardware
Seleziona quale periferica, messa a disposizione dal microcontrollore, è coinvolta nella trasmissione dei dati. Qualora ve ne fossero più di una disponibili, come mostrato in Fig. 4, possono essere inseriti due componenti I²C, ciascuno su un dif ferente canale in modo da avere due bus distinti di comunicazione.
Ottobre 2013 ~ Elettronica In
Fig. 4 Proprietà del componente I2C master.
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Tabella 5 -
Macro disponibili per la gestione della connessione I 2 C master.
Nome Macro MI2C_Init MI2C_Start MI2C_Restart MI2C_Stop
Descrizione
Inizializza la periferica interna di comunicazione I²C. Deve essere chiamata uno volta prima di eseguire le altre macro altrimenti non verrebbe trasmesso/ricevuto alcun byte. Invia il segnale di start della comunicazione sul bus I²C. Invia il segnale di riavvio della comunicazione sul bus I²C. Invia il segnale di stop della comunicazione sul bus I²C.
MI2C_Transmit_Byte
Trasmette un byte sul bus di comunicazione. Restituisce zero se rileva la ricezione di una conferma di ricezione “acknowledge”.
MI2C_Receive_Byte
Riceve un byte dal bus di comunicazione. Necessita della valorizzazione del parametro che, se posto a uno, indica che il byte da ricevere è l’ultimo.
MI2C_Send_Byte_Transaction MI2C_Receive_Byte_Transaction
Invia ad uno specico dispositivo il valore che deve essere posto all’indirizzo indicato. Riceve da uno specico dispositivo il valore caricato all’indirizzo di memoria scelto.
La porta OneWire
Il bus OneWire è stato realizzato da Dallas Semiconductor per consentire comunicazioni tra due o più dispositivi attraverso un unico lo di interconnessione. Non essendoci un lo dedicato per la trasmissione del segnale di sincronizzazione, quest’ultimo deve essere trasmesso assieme ai dati. Per evitare problemi di cortocircuiti sulla linea è presente un pull-up, cioè una resistenza collegata tra la linea e l’alimentazione, e tutti i dispositivi possono imporre uno zero sulla linea attivando il transistor/MOSFET di pilotaggio della porta connessa. La velocità di comunicazione non è elevatissima (è pressata a 16 kbps), tuttavia permette comunicazioni tra dispositivi in modo davvero semplice. Si tratta di un bus di tipo Master/Slave, dove ogni dispositivo ha un indirizzo univoco e questo deve essere utilizzato dal master per iniziare la comunicazione con lo slave. La codica dei simboli differisce notevolmente dai casi esaminati in precedenza, perché sono codicati in base alla lunghezza dell’impulso, come indicato in Tabella 6. Nel caso di ricezione, cioè durante la comunicazione di dati dallo slave verso il master, lo slave mantiene la linea al valore 0 per 60 µs qualora voglia inviare un valore logico zero mentre non fa nulla se intende inviare il valore logico uno a seguito di ogni impulso generato dal master.
Tabella 6 - Tempi
di impulso per la trasmissione dei dati su bus OneWire. Linea a 0 per almeno 480 µs
Reset Valore logico uno
1÷15 µs linea a 0
Valore logico zero
60 µs linea a 0
Per accertarsi che il pacchetto di dati sia stato correttamente ricevuto/inviato, è presente il controllo mediante CRC a 8 bit che è trasmesso come primo byte. Nella nestra di congurazione del componente, mostrata in Fig. 5, possiamo unicamente scegliere se utilizzare o no il controllo CRC. Le macro disponibili in Flowcode per gestire questa porta sono riassunte nella Tabella 7. In Tabella 8 sono riportate altre macro che potrebbero risultare utili qualora si volesse utilizzare il dispositivo DS1820. Prima di poter utilizzare il componente è
Fig. 5 Proprietà del componente OneWire.
Elettronica In ~ Ottobre 2013
117
Tabella 7 - Macro
disponibili per la gestione del bus OneWire.
Nome Macro
Descrizione
Invia un comando di reset e restituisce uno se nessun dispositivo risulta resettato oppure non vi sono dispositivi collegati al bus.
oo_BusReset
oo_GetPadByte
Restituisce il dato letto dal dispositivo identicato dal parametro passato alla macro; I dispositivi letti sono al massimo 9 ed il parametro può variare da 0 a 8 se un dispositivo risulta resettato oppure non vi sono dispositivi collegati al bus.
oo_Tx_Byte
Trasmette un byte sul bus.
oo_Rx_Byte
Riceve un byte dal bus.
oo_ScanBus
Esegue una scansione del bus per l’identicazione del numero di dispositivi. Restituisce 1 se vi sono stati dei problemi durante la scansione. Restituisce il numero di dispositivi rilevati sul bus dopo un comando di scansione del bus.
oo_Get_DeviceCount
Legge il dispositivo identicato dal numero in ordine di scansione.
oo_ReadDevice
Tabella 8 - Macro
per la gestione del componente DS1820 su bus OneWire.
Nome Macro
Descrizione
DS1820_Start_Conversion
Avvia la conversione del dato del dispositivo DS1820. Restituisce uno se il dispositivo è entrato in time-out senza terminare la conversione.
DS1820_Read_Scratchpad
Legge i valori dal dispositivo DS1820. Può essere utilizzata unicamente qualora vi sia un unico dispositivo collegato al bus altrimenti è necessario utilizzare la macro oo_ReadDevice.
DS1820_Get_Temp
Legge la temperatura del dispositivo DS1820. Il valore letto è rappresentato su un intero con risoluzione di 0,0625°C.
necessario congurare il piedino che sarà utilizzato per trasmettere/ricevere i dati, come indicato in Fig. 6.
Un semplice esempio di diagramma di usso per il controllo del bus OneWire per la gestione del componente DS1820 è rafgurato in Fig. 7: con l’utilizzo di soli quattro blocchi possiamo comunicare con il componente dimenticandoci completamente tutte le problematiche inerenti al livello sico e del protocollo di comunicazione. Ora che abbiamo esaminato tre esempi di
bus di comunicazione interni, passiamo a descrivere la porta RS232, che è una tra le più usate e semplici interfacce seriali. La Porta RS232
La RS232 è una linea di comunicazione asincrona, in quanto il segnale di temporizzazione non viene trasmesso, ma generato in modo autonomo da entrambe le periferiche collegate. La connessione è di tipo punto-punto, quindi permette di far comunicare tra loro solo due dispositivi. Fig. 7 - Esempio di flusso di controllo per il componente DS1820.
Fig. 6 - Configurazione connessioni bus OneWire.
118
Ottobre 2013 ~ Elettronica In
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Tabella 9 -
Macro disponibili per la gestione della connessione RS232.
Nome Macro
Descrizione
SendRS232Char
Invia un dato a 8-bit sulla seriale.
SendRS232String
Invia una stringa di caratteri sulla seriale.
ReceiveRS232Char
ReceiveRS232String
ChangeHWBaud
Riceve un carattere sulla seriale. La macro accetta come parametro il valore del tempo massimo di attesa del dato e qualora non venga ricevuto entro il tempo massimo indicato restituisce il valore INVALID_RETURN (255).
È simile alla ReceiveRS232Char ma legge una stringa di caratteri la cui lunghezza è indicata dal parametro Length. Modica la velocità di trasmissione dei dati. Accetta un valore numerico intero compreso tra 0 e 7 codicato come nella Tabella 10.
I dati vengono trasmessi in modo seriale, in pacchetti da 8-9 bit racchiusi tra un bit di start ed uno di stop. La durata di ogni bit dipende dalla velocità di comunicazione; afnché tutto funzioni correttamente, quest’ultima deve essere uguale per entrambi i dispositivi. Flowcode dispone di un componente specico per la gestione della RS2332, le cui macro sono riassunte in Tabella 9. Per poter utilizzare il componente dobbiamo congurarlo (come fatto per gli altri visti in precedenza) attraverso la nestra di congurazione, accessibile dal menu a tendina del componente nel pannello; qui abbiamo a disposizione i controlli per impostare la velocità di comunicazione (baud-rate), il numero di bit del frame, nonché la possibilità di utilizzare le connessioni per il controllo di usso. Non ci soffermeremo sui dettagli di ogni singola congurazione, perché il nostro obiettivo è dare a tutti le nozioni base per utilizzare i componenti trattati in modo rapido e efcace; qualora si volessero approfondire alcune caratteristiche e funzionalità, è sempre possibile utilizzare l’help di Flowcode, che consigliamo di tenere sempre sottomano, perché potrebbe, soprattutto all’inizio, permettervi di imparare molto. Questo tipo di connessione è molto semplice da utilizzare e permette comunicazioni con dispositivi anche molto complessi come ricevitori GPS o display grafici. Per comprenderne meglio le potenzialità, passiamo ora alla realizzazione di un semplice progetto pratico, che ci permetterà di gestire una batteria di relé tramite l’interfaccia seriale del PC.
Tabella 10 - Valori
disponibili per la modifica al volo della velocità di connessione. Parametro
Velocità
0
1200 bps
1
2400 bps
2
4800 bps
3
9600 bps
4
19200 bps
5
38400 bps
6
57600 bps
7
115200 bps
Gestione di una scheda a relé tramite interfaccia RS-232
Nella realizzazione di questo semplice progetto tralasceremo i passaggi base che abbiamo già spiegato nelle puntate precedenti e ci soffermeremo maggiormente sui nuovi concetti. Il nostro sistema presenta le caratteristiche seguenti. • Comunica via RS232 bidirezionale tra PC e scheda di controllo a relé. • Deve supportare i seguenti comandi: - “A”: Attiva relé; - “D”: Disattiva relé; - “R”: Leggi stato relé. • La sintassi dei comandi è
, dove x identica il codice del comando (che può essere uno dei tre comandi visti al punto precedente), mentre p identica il relé controllato, ed è rappresentato da un numero con codica ASCII. Quindi, ad esempio, per attivare il relé 3 inviamo il comando “”, per spegnere il relé 2 inviamo “” mentre per leggere lo stato del relé 1 inviamo il comando “”. • La sintassi delle risposte ai comandi è la
Elettronica In ~ Ottobre 2013
119
seguente: . In essa, x e p hanno lo stesso signicato assunto al punto precedente, mentre v è il valore o l’esito del comando. Qualora il comando non richieda un valore di ritorno e sia stato eseguito correttamente, v avrà valore “K” mentre nel caso vi siano errori avrà valore “N”. Ad esempio, come risposta al comando di attivazione del relé 1 con esito positivo, si avrà , mentre se l’esito fosse stato negativo la risposta sarà . Nella risposta al comando di lettura, v vale 1 o 0 in base al valore letto. Ad esempio, nel caso che il relé 2 sia attivo e ne venga chiesta la lettura, la risposta sarà .
Fig. 8 Assemblaggio dei moduli necessari a pilotare una batteria di relé attraverso la connessione RS232.
Ora che abbiamo steso le direttive principali per realizzare il nostro progetto, passiamo all’identicazione dei componenti necessari per la realizzazione, che sono: Fig. 10 - Configurazione del componente LED array.
c o r s o
F L O W
Fig. 9 - Configurazione del componente RS232.
120
Ottobre 2013 ~ Elettronica In
C O D E
E D O C
EB006 sono quelle già utilizzate nella scorsa puntata. Flowcode non dispone di un componente Relé Array, ma il funzionamento di un relé, dal punto di vista del comando, è del tutto simile a quello di un LED, quindi utilizzeremo il componente LED array per controllare la nostra batteria di relé. Apriamo il progetto “CongurazioneBase2. fcf” ed inseriamo, prendendoli dalla barra dei componenti, il componente RS232 ed il LED array. Impostiamo la RS232 mediante il menu a scomparsa “Proprietà extra” in modo da avere una velocità di comunicazione pari a 9.600 bps, il “timeout” indicato in millisecondi e scegliamo la porta UART1 come indicato in Fig. 9. Conguriamo anche il componente LED
W O L F o s r o c
Fig. 11 - Main del programma di controllo.
-
EB006 “USB PICmicromult iprogrammerboard”(PIC18F4580 e quarzo 12 MHz); EB038 “Relay Board”; EB015 “RS232 Board”. Colleghiamoli in modo da avere la scheda EB038 sulla porta A e la EB015 sulla porta C, come mostrato in Fig. 8. Le schede devono essere alimentate per poter funzionare correttamente, perché attraverso il connettore DB9 passano solo le connessioni dati ed il riferimento di massa perciò, utilizzando dei li da prototipazione, colleghiamo tutti i morsetti con indicato “+V” al corrispondente morsetto della scheda EB006. Posizioniamo, inoltre, i connettori di patch in posizione C e 2 per la scheda EB038, e in posizione LOW per la scheda EB015. Le altre congurazioni della scheda
array seguendo la stessa procedura come indicato in Fig. 10. Quindi scegliamo i pin al quale sono collegati mediante il menu a scomparsa “Connessioni” ed assegniamoli alla porta A dal pin 0 al pin 4. Ora che è tutto pronto, possiamo dedicarci alla stesura del diagramma di usso. Per ottimizzare l’uso di Flowcode possiamo pensare di suddividere, utilizzando le macro, l’intero programma in tre parti principali: • Inizializzazione = inizializza tutto ciò che deve essere preimpostato prima che il ciclo principale inizi; • Main = chiama l’inizializzazione del sistema, legge i caratteri ricevuti da seriale e li aggrega in un’unica stringa in modo da esaminarla mediante un semplice controllo di correttezza; • ControllaComando = esegue il controllo
Elettronica In ~ Ottobre 2013
121
del controllo, il comando viene resettato in modo da abilitare la ricezione di nuovi comandi; • in tutti gli altri casi, il carattere viene aggiunto alla stringa di comando. L’intero usso in Flowcode è rappresentato nella Fig. 11.
Fig. 12 Macro Controlla Comando.
Fig. 13 Macro di Inizializzazione.
sulla correttezza del comando ricevuto, esegue il comando ed invia la risposta. Main
Il main contiene la chiamata alla macro di inizializzazione, oltre ad un ciclo innito nel quale viene richiesta una lettura da seriale ed è analizzato il carattere ricevuto: quindi, ogni volta che viene ricevuto un carattere da seriale, esso viene analizzato. Dopo la ricezione e l’analisi ci sono tre possibilità: • il carattere è “<”, allora viene azzerata la stringa che contiene il carattere ricevuto; • il carattere è “>”, allora la stringa di comando è stata ricevuta completamente e quindi viene controllato il comando attraverso la specica macro; al termine Tabella 11 - Formato Tempo di esecuzione [ms]
122
c o r s o
F L O W
del file .cvs. Stato Relé 1
Ottobre 2013 ~ Elettronica In
Stato Relé 2
Stato Relé 3
Stato Relé 4
C O D E
E D O C
W O L F o s r o c
Fig. 14 - Sezione “Manual Control” dell’interfaccia sw.
Fig. 15 - Sezione “Automatic Control” dell’interfaccia sw.
Macro “ControllaComando”
Realizza il controllo del comando ricevuto come parametro, lo esegue nel caso sia stato ricevuto correttamente e, in ogni caso, invia una risposta sulla linea seriale. Nella prima parte della macro vengono estrapolati dalla stringa il carattere di comando ed il parametro associato. Viene fatto un controllo sul valore del parametro (che nel nostro caso deve essere compreso tra 1 e 4) e successivamente, in base al carattere del comando, viene eseguita l’operazione di accensione, spegnimento o lettura del relé. Gli stati del relé sono memorizzati in un vettore globale di appoggio chiamato “StatoRele”. Al termine dell’esecuzione, prima di ritornare il controllo alla funzione chiamante, la macro invia la risposta utilizzando la macro SendRs232String. L’intero diagramma è visibile in Fig. 12. Macro “Inizializza”
È utilizzata per inizializzare lo stato dei relé e le variabili di appoggio del programma. In questo caso l’unica variabile che deve essere azzerata è il vettore con lo stato dei relé “StatoRele” che, per essere concorde allo stato sico, deve essere impostato a zero. Il diagramma Flowcode è rappresentato nella Fig. 13. Interfaccia Software
Per l’utilizzo della scheda relé appena realizzata è stata sviluppata un’apposita interfaccia software, scritta in Labview 2010. L’interfaccia permette sia il controllo manuale dei 4 relé, sia l’esecuzione di sequenze automatizzate. Subito dopo l’avvio dell’interfaccia possiamo scegliere tra le due modalità, mediante un radio button posto in basso, sulla destra del pannello. Uno scre-
Fig. 16 Esempio di file .cvs.
enshoot dell’interfaccia software è visibile in Fig. 14. Come si può notare, è possibile selezionare la porta RS-232 (COM1 o COM2), selezionare il baud-rate (l’impostazione predenita è 9600) mentre sono presenti due tab, “Manual Control” e “Automatic Control”, contenenti i comandi specici per le due modalità. Per la modalità di controllo manuale sono presenti 4 pulsanti, con i quali è possibile controllare lo stato dei relé. Due parole in più merita la sezione automatica, della quale in Fig. 15 riportiamo uno screenshoot. Tale sezione permette di automatizzare il controllo della scheda da PC, impostando sequenze di controllo temporizzate. Per impostare le sequenze automatizzate è sufciente generare un le .cvs con la formattazione indicata nella Tabella 11. Come si può vedere, il primo campo indica il tempo (in ms) al quale verranno inviate le istruzioni presenti nei 4 campi successivi, che rappresentano lo stato dei 4 relé (0 o 1). Un esempio di le .cvs è riportato in Fig. 16. Tramite questa modalità, è possibile impostare sequenze di controllo che possono essere impiegate per le più svariate necessità, dall’automazione alla domotica, al controllo g di macchinari.
Elettronica In ~ Ottobre 2013
123
E D O C
W O L F o s r o c
Continuiamo il nostro viaggio alla scoperta del sistema di sviluppo grafico per microcontrollori proposto da Matrix Multimedia. In questa puntata iniziamo a lavorare con le periferiche di comunicazione avanzate, partendo da quella che ha riscosso un notevole e crescente successo negli ultimi 15 anni: il CAN-Bus. Quinta puntata.
corso di programmazione in
FLOWCODE di Francesco Ficili e Daniele Defilippi
l mese scorso abbiamo illustrato l’uso delle periferiche di comunicazione di base, imparando ad utilizzare le porte di comunicazione UART, I²C, SPI e OneWire. In questa puntata introduciamo una periferica di comunicazione decisamente più avanzata, che permette di creare reti anche piuttosto complesse e largamente utilizzata ai giorni nostri, specialmente nel settore automotive: stiamo parlando della porta CAN (Controller Area Network), che oggi costituisce lo standard de facto per le reti di comunicazione delle automobili e si sta espandendo anche ad applicazioni industriali e custom, grazie alla sua robustezza, alla relativa sempli-
I
cità rispetto a soluzioni simili e ai costi ridotti dei componenti. Come fatto nelle puntate precedenti, arricchiremo il tutto con un progetto pratico: realizzeremo un prototipo di sensore di parcheggio per autoveicoli. Controller Area Network (CAN)
Il protocollo CAN nasce negli anni ’80 del secolo scorso dalla Robert Bosch GmbH, che aveva l’esigenza di sviluppare uno standard per le comunicazioni seriali a corto raggio tra diverse unità elettroniche di controllo, di tipo multicast, dotato di elevata immunità ai disturbi, basso costo ed elevata afdabilità. Lo standard im-
Elettronica In ~ Novembre 2013
127
piega come mezzo trasmissivo una linea differenziale bilanciata (i due terminali sono indicati come CANH e CANL), esattamente come nel caso dell’RS485. Il massimo bit rate raggiungibile è di 1Mbit/s, con estensione massima della rete di circa 100 m. Accontentandosi di velocità inferiori è possibile coprire distanze maggiori (ad esempio con 125 kbit/s si arriva a 500 m). In Tabella 1 sono riportati alcuni esempi di estensioni massime della rete rispetto alla velocità trasmissiva. La tecnica trasmissiva del CAN usa un modello basato su bit “dominanti” e “recessivi”, in cui i bit dominanti sono gli 0 logici ed i bit recessivi sono gli 1 logici. Se, durante una trasmissione, il nodo A invia un bit dominante e, contemporaneamente, il nodo B invia un bit recessivo, allora il bit dominante “vince” fra i due. Durante la trasmissione, ogni nodo che sta trasmettendo verica lo stato del bus e confronta il bit ricevuto con il bit trasmesso: se viene rilevato un bit dominante quando ne viene trasmesso uno recessivo, allora il nodo che ha rilevato l’errore interrompe la comunicazione. Con questa tecnica, se due nodi iniziano una trasmissione contemporaneamente, essi si contendono l’uso esclusivo del bus (arbitraggio) trasmettendo i propri dati, bit dopo bit, nché uno dei due non rileva un errore di trasmissione, autoescludendosi (si dice che il nodo in questione perde l’arbitraggio) dal bus. Nella teoria delle reti di comunicazione, un approccio di questo tipo è denito CSMA/BA (Carrier Sense Multiple Access/Bitwise Arbitration). Il protocollo CAN è centralizzato sui messaggi, che sono chiamati in genere anche frames, identicati per mezzo di un ID. Ogni nodo gestisce uno o più frame in ricezione e/o trasmissione, a seconda dell’architettura della network. Tabella 1 - Data-rate riferito all’estensione della rete CAN. Data-rate(kbps)
Estensione massima (m)
125
500
250
250
500
100
128
Novembre 2013 ~ Elettronica In
I frame possono essere di quattro tipi: • Data frame, frame contenente i dati che il nodo trasmette; • Remote frame; richiede la trasmissione di un determinato identicatore; • Error frame; trasmesso da un qualsiasi nodo che ha rilevato un errore; • Overload frame; frame che introduce un ritardo fra data frame e/o remote frame. I Data frame sono quelli cui è afdata l’effettiva trasmissione dei dati e possono essere di due tipi, a seconda della versione dello standard CAN presa in considerazione: • Base frame format; ID ad 11 bit (versione 2.0A); • Extended frame format; ID a 29 bit (versione 2.0B). I dispositivi standard CAN devono riconoscere il formato base frame e possono riconoscere (ma devono comunque tollerarlo) il formato extended frame format. Il CAN base permette 2 11=2048 tipi di messaggi diversi, ma da speciche Bosch se ne possono usare solo 2031. Nella versione extended si possono avere no a 229=536.870.912 tipi di messaggi. L’extended frame format, detto anche CAN esteso, è oggi il formato più diffuso nelle varie applicazioni che utilizzano questo standard. Un’applicazione che faccia uso del protocollo CAN necessita di almeno un paio di componenti elettronici aggiuntivi: un controller ed un transceiver; quest’ultimo è l’elemento che si occupa dell’interfacciamento a livello sico con il bus. È quindi responsabile della corretta traslazione e dell’adattamento dei livelli logici delle linee. Si interfaccia direttamente con il controller. Ci sono diverse aziende al mondo che producono transceiver CAN; noi utilizzeremo il transceiver della Microchip, MCP2551. Il controller è l’elemento che si occupa dell’implementazione del livello data link (livello 2 dello stack OSI); quindi ad esso è demandata la gestione delle principali logiche del bus, svincolando l’utilizzatore dalla gestione di problematiche di arbi-
c o r s o
F L O W
C O D E
E D O C
Fig. 1 - Connessioni del componente Extended CAN.
Fig. 2 - Proprietà extra del componente Extended CAN.
W O L F o s r o c
traggio, di gestione degli errori, di politiche di ritrasmissione, ecc. Il controller dispone anche di buffer di trasmissione, di ricezione e di maschere, che permettono di congurare il set di messaggi in ricezione e trasmissione, riducendo l’overhead della CPU del microcontrollore a cui è interfacciato. Anche per i controller, esistono diverse aziende produttrici al mondo; nel nostro caso noi faremo uso del controller della Microchip MCP2515. Il componente CAN in Flowcode
Analizziamo adesso il componente Flowcode che ci permette di semplicare la gestione di un’interfaccia CAN nelle nostre applicazioni. Flowcode dispone di due componenti CAN, uno per la gestione del base frame format (che si chiama semplicemente CAN) e uno per la gestione dell’extended format (chiamato Extended CAN) quindi, se decidiamo di sviluppare un’applicazione CAN, la prima scelta da fare sarà quella relativa al tipo di formato. Nella versione attuale dell’ambiente, i controller interni sono supportati solo dal componente che supporta il base format, quindi se usiamo il componente extended saremo vincolati all’uso di un controller SPI esterno. In questa puntata ci occuperemo del componente CAN Extended, e quindi utilizzeremo il controller MCP2515 nelle nostre applicazioni. Per inserire il componente CAN all’interno del nostro progetto Flowcode, sele-
zioniamo il componente dalla barra dei componenti, cliccando sulla voce Extended CAN . Una volta inserito, l’icona relativa al componente comparirà sul pannello, ed a questo punto possiamo congurarlo per adattarlo alle esigenze del progetto specico. Per prima cosa analizziamo le connessioni, che nel caso di questo componente si riducono al pin di CS del controller CAN (che è un SPI slave). Possiamo accedere alle connessioni cliccando con il tasto destro sull’icona del componente e selezionando la voce “Connessioni”. Apparirà la nestra rappresentata in Fig. 1. Per impostazione predenita, il pin di CS è il pin 6 della porta C; se non c’è l’esigenza di cambiarlo (ad esempio nel caso in cui venga utilizzato l’E-block CAN) può essere mantenuto così. Per congurare il componente clicchiamo con il tasto destro sulla relativa icona e selezioniamo la voce “Proprietà Extra”. Comparirà la nestra di Fig. 2. Dalla prima scheda di questa nestra è possibile selezionare le principali opzioni di congurazione del bus, come il baud-rate, il sample point ed altri ancora. Questi parametri dipendono a loro volta dalle caratteristiche proprie della rete, come la sua estensione, il numero di nodi, il bus load, ecc. I tab successivi permettono di congurare i vari buffer di ricezione e trasmissione. Nel progetto pratico, vedremo un esempio di congurazione dei buffer.
Elettronica In ~ Novembre 2013
129
Tabella 2 -
Macro disponibili per il componente CAN.
Nome Macro
Descrizione
Init
Inizializza il componente CAN.
SendBuffer
Invia il messaggio contenuto all’interno del buffer di trasmissione (passato come parametro)
CheckRx
Controlla se ci sono messaggi ricevuti su un determinato buffer di ricezione (passato come p arametro).
ShowLEDs
Controlla lo stato dei LED della EB018.
ReadSwitches
Legge lo stato degli switch della EB018.
GetRxDataCount
Riceve il conteggio dei byte del messaggio contenuto in un determinato buffer (passato come parametro).
GetRxData
Estrae un determinato byte dal messaggio presente in un determinato buffer di ricezione. Riceve come parametro sia il buffer che l’indice del byte.
SetTxStdID
Modica lo standard ID di un determinato buffer di t rasmissione (passato come parametro).
SetTxExtID
Modica l’extended ID di un determinato buffer di trasmissione (passato come parametro) come combinazione dell’ID standard e dell’ID extended.
SetTxExtAsFull
Modica l’extended ID di un determinato buffer di trasmissione (passato come parametro).
GetRxStdID
Estrae un determinato byte di un determinato messaggio con ID standard. Vengono controllati tutti i buffer e viene passato come parametro l’indice del byte.
GetRxExtID
Estrae un determinato byte di un determinato messaggio con ID extended, visto come combinazione di un ID standard e di un ID extended.. Vengono controllati tutti i buf fer e viene passato come parametro l’indice del byte.
GetRxExtIDAsFull
Estrae un determinato byte di un determinato messaggio con ID extended.. Vengono controllati tutti i buffer e viene passato come parametro l’indice del byte.
Ora, come di consueto, procediamo con l’analisi delle macro messe a disposizione da questo componente, che trovate riepilogate nella Tabella 2.
• Invio dati sulla distanza espressa in cm; • Autodiagnosi su stato batteria e stato link I2C con il sensore; • Modalità sleep attivabile tramite messaggio da nodo display.
Progetto pratico: sensore di parcheggio
Passiamo adesso al progetto pratico relativo a questa puntata. Come abbiamo già accennato, abbiamo pensato di realizzare un progetto pratico un po’ più impegnativo, proprio per evidenziare le potenzialità di rapid development offerte da owcode, che permette la realizzazione di progetti anche piuttosto complessi in tempi ridottissimi e con un ottimo risultato nale. Nel caso specico ci cimentiamo nella realizzazione di un prototipo di sensore di parcheggio per auto, costituito da due nodi: un nodo sensore ed un nodo display, collegati tra di loro tramite bus CAN. Quindi realizzeremo due progetti Flowcode distinti, che utilizzeremo per generare gli eseguibili binari con cui programmare le due schede. Come di consueto, analizziamo le speciche di progetto, in questo caso raggruppate per nodo. Nodo Sensore: • Interfacciamento con sensore ad ultrasuoni SFR02, su bus I²C; • Interfaccia CAN 2.0B a 500 kbaud;
130
Novembre 2013 ~ Elettronica In
Nodo Display: • Interfacciamento con display alfanumerico 16x2; • Interfaccia CAN 2.0B a 500 kbaud; • Lettura e visualizzazione dei dati sulla distanza; • Lettura e visualizzazione dei dati diagnostici; • Gestione della modalità sleep tramite pulsante. Sebbene il CAN sia nativamente una rete peer-to-peer, è possibile forzare delle relazioni di tipo master/slave, agendo a livello dell’applicazione; è ciò che faremo in questo esempio, dove il nodo display agisce da nodo master (può mettere “a dormire” lo slave nodo sensore), inviando un messaggio apposito per forzare lo stato di sleep, in modo da disabilitare il sistema durante le fasi di guida ed abilitarlo in fase di parcheggio. Per quanto riguarda la realizzazione hardware, in questo progetto avremo bisogno delle seguenti schede:
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 3a Prototipo del nodo sensore.
- 2x EB006 “USB PICmicro multiprogrammer board” (PIC18F4580 e quarzo da 12MHz); - 2x EB018 “CAN bus Board ”; - 1x EB005 “LCD board”; - 1x EB016 “Prototypeboard”. Non disponendo di un e-block specico, per interfacciare l’SRF02 ci serviremo, come già fatto in passato, della EB016, che colleghiamo sulle porte A e B. Posizioniamo l’SRF02 sulla breadboard e colleghiamo i terminali di alimentazione e quelli di comunicazione SDA ed SCK del bus. Non potendo utilizzare la porta hardware I²C (perché, per interfacciare l’MCP2515 usiamo la MSSP in modalità SPI), emuliamo il collegamento I2C a livello software, e quindi usiamo RB0 ed RB1, rispettivamente per SCK ed SDA. Oltre all’SRF02, sulla EB016
dobbiamo posizionare anche un partitore di tensione con rapporto di partizione 1:4, allo scopo di leggere lo stato della batteria, che colleghiamo all’ingresso analogico An0. Completiamo il nodo sensore collegando la EB018 sulla porta C. Per il nodo display, colleghiamo la EB018 sulla porta C e la EB005 sulla porta B. Per entrambi i nodi, l’impostazione dei jumper della EB018 è la seguente: • J4 su A; • J5 inserito; • J6 e J7 disinseriti.
Fig. 3b Prototipo del nodo display.
Poi, assicuriamoci di chiudere su entram be le schede J8, in modo da terminare la linea da entrambi i lati e collegare i cavetti per l’alimentazione.
Elettronica In ~ Novembre 2013
131
Tabella 3a - Caratteristiche
messaggio 0xC40A5.
ID
0xC40A5
Type
Periodico
Tx
Nodo_Sensore
Rx
Nodo_Display
Periodo
250ms
Byte 0
Byte 1
Byte 2
Byte 3
Byte 4
Byte 5
Byte 6
Byte 7
DistHighByte
DistLowByte
DiagSts
Not Used
Not Used
Not Used
Not Used
Not Used
Distanza in cm
0 = No fail 1 = Battery fail 2 = I²C fail 3 = Mult. fail
Tabella 3b - Caratteristiche
messaggio 0xC40A4.
ID
0xC40A4
Type
Ad evento
Tx
Nodo_Display
Rx
Nodo_Sensore
Periodo
NA
Byte 0
Byte 1
Byte 2
Byte 3
Byte 4
Byte 5
Byte 6
Byte 7
SystemSts
Not Used
Not Used
Not Used
Not Used
Not Used
Not Used
Not Used
0 = Sleep Mode 1 = Awake Mode
La congurazione hardware dei due nodi è riportata nelle Fig. 3a e Fig. 3b. Mappa Messaggi
Prima di passare ai dettagli software analizziamo un punto fondamentale di ogni rete basata su protocollo CAN, ossia la mappa messaggi: in un CAN Bus, essa è il documento che descrive le principali caratteristiche dei messaggi che si scambiano i vari nodi all’interno della network. In questo documento sono indicati le tipologie dei messaggi, i relativi indirizzi, il signicato dei byte che li compongono, quali nodi trasmettono e quali sono i destinatari di ogni singolo messaggio. Nel nostro caso, abbiamo un totale di due messaggi, uno trasmesso dal nodo sensore e ricevuto dal nodo display, ed uno che transita nel verso opposto. In Tabella 3a e Tabella 3b sono riporta-
te le caratteristiche dei due messaggi. Passiamo ora alla descrizione dell’implementazione software, con la premessa che, data la complessità del progetto, la descrizione di alcune parti non fondamentali verrà omessa o sarà trattata solo marginalmente. Nodo Sensore
Secondo le speciche, questo nodo deve acquisire i dati relativi alla distanza dal sensore ad ultrasuoni, effettuare l’autodiagnosi su livello batteria e stato del bus I²C e comunicare queste informazioni al nodo master tramite messaggio CAN.
c o r s o
Tabella 4 - Periodicità
e descrizione dei task del software del nodo sensore. Task
Periodo [ms}
Descrizione Gestisce la trasmissione del messaggio CAN del nodo sensore.
CanTxTask
250
CanRxTask
50
Gestisce la ricezione del messaggio CAN dal nodo display.
DiagTask
50
Gestisce la diagnostica del sistema.
SensorRangingTask
10
Gestisce la comunicazione con il sensore ad ultrasuoni SRF02.
132
Novembre 2013 ~ Elettronica In
Fig. 4 Main del progetto in Flowcode.
F L O W
C O D E
E D O C
Fig. 5 - Configurazione dell’interrupt del timer2.
Per congurare l’interrupt clicchiamo due volte all’interno del blocco, in modo da accedere alle nestre di congurazione, riportata in Fig. 5. In questa nestra selezioniamo l’opzione “Abilita Interrupt”, e tra le sorgenti del menu a tendina selezioniamo la voce “TMR2”. Poi, nella sezione “Verrà chiamata la macro”, inseriamo la macro
W O L F o s r o c
Fig. 6 - Impostazione dei registri del timer 2.
Deve inoltre essere gestita una modalità sleep, su richiesta del nodo master. Per cominciare, esaminiamo l’impostazione dell’architettura di base del sistema. Il rmware in questione ha diversi task da eseguire in maniera simultanea; scegliamo quindi di servirci di uno scheduler per gestire le chiamate ai vari task. Decidiamo di generare uno scheduler con un tick a 10ms e di generare le altre periodicità attraverso dei contatori incrementati ad ogni tick di sistema. In Tabella 4 sono riportati i task gestiti con le descrizioni e le relative periodicità. Per la generazione del tick base di sistema (sul quale è basato il funzionamento dello scheduler), ci serviamo di un interrupt sul timer 2. Come detto nella seconda puntata di questo corso, per inserire un blocco interrupt trasciniamo dalla barra delle icone un blocco interrupt all’interno del nostro main, come visibile in Fig. 4 (nello schema a blocchi è già stata effettuata la chiamata alla funzione di inizializzazione per i componenti utilizzati).
Fig. 7 - System scheduler.
Elettronica In ~ Novembre 2013
133
Registri interni del sensore SRF02 in modalità I 2 C. Tabella 5 -
Locazione di memoria
Accesso in lettura
Accesso in scrittura
0
Software Revision
Command Register
1
Unused (reads 0x80)
N/A
2
Range High Byte
N/A
3
Range Low Byte
N/A
4
Autotune Minimum - High Byte
N/A
5
Autotune Minimum - Low Byte
N/A
MainScheduler (che possiamo creare al momento o aver già creato in precedenza). In questo modo, ad ogni occorrenza dell’interrupt verremo indirizzati alla macro contenente lo scheduler di sistema. Non ci rimane che impostare il timer per avere il tick di sistema a 10ms; allo scopo, clicchiamo sul tasto “Proprietà..”. Si aprirà la nestra di Fig. 6. Per avere un interrupt ogni 10ms occorre generare una frequenza di circa 100Hz, per ottenere la quale, con un sistema che gira a 12MHz, selezioniamo un prescaler di 16, un postscaler di 8 e un rollover di 234. Clicchiamo su OK e procediamo. Ora abbiamo il nostro tick di sistema congurato; ciò che rimane da fare è generare il codice dello scheduler in modo da avere le periodicità elencate in Tabella 3 (a e b). Per farlo, generiamo tre variabili globali, ossia CanRxTaskCounter , CanTxTaskCounter e DiagTxTaskCounter , che utilizzeremo come contatori per determinare le periodicità dei task a partire Tabella 6 -
Set di comandi dell’SRF02.
Comando (Hex)
Descrizione
0x50
Esecuzione di un ranging – risultato in pollici.
0x51
Esecuzione di un ranging – risultato in cm.
0x52
Esecuzione di un ranging – risultato in microsecondi.
0x56
Esecuzione di un fake ranging – risultato in pollici.
0x57
Esecuzione di un fake ranging – risultato in cm.
0x58
Esecuzione di un fake ranging – risultato in microsecondi.
0x5C
Trasmissione di 8 cicli a 40kHz (ultrasonic burst).
Tabella 7 -
dal tick base di sistema. Ricordiamoci che alcuni task sono vincolati ad andare in sleep su richiesta del nodo master, quindi in questa condizione non devono essere eseguiti. Per implementare tale caratteristica creiamo una variabile globale che chiamiamo SystemStatus (essa può assumere due valori: SYSTEM_ACTIVE e SYSTEM_NOT_ACTIVE), che sarà, insieme alla periodicità, una delle condizioni di attivazione della chiamata al task. L’unico task che non è controllato da questa variabile è CanRx, usato per consentire il risveglio del sistema da messaggio CAN. L’implementazione dello scheduler (senza le chiamate ai task per il momento) è descritta nella Fig. 7. I contatori sono incrementati ad ogni ciclo e le condizioni di attivazione dei vari task (all’interno dei blocchi decisione) sono: - CanRx CanRxTaskCounter >= TASK_CAN_RX_TIMEOUT; - CanTx (CanTxTaskCounter >= TASK_CAN_TX_TIMEOUT) && (SystemStatus = SYSTEM_ACTIVE); - Diag (DiagTxTaskCounter >= TASK_DIAG_TIMEOUT) && (SystemStatus = SYSTEM_ACTIVE); - SensorRanging SystemStatus = SYSTEM_ACTIVE. →
→
→
→
Come si può vedere, il task CanRx non è vincolato alla variabile SystemStatus per garantire la possibilità di risvegliare il sistema tramite messaggio CAN, ed il task SensorRanging non ha un contatore per la periodicità, in quanto il periodo di chiamata di questo task è proprio 10ms. Analizziamo adesso come è stata implementata la lettura del sensore ad ultrasuoni: per interfacciarsi con il dispositivo che lo utilizza, l’SRF02 ha la capacità di utilizzare sia l’interfaccia seriale che l’I2C. Nel nostro caso, come interfaccia di comunicazione abbiamo scelto l’I2C.
Macro scritte per la gestione dell’SRF02.
Nome Macro
Descrizione
Sensor_SendCommand
Invia al dispositivo con indirizzo 0xE0 il comando 0x51 in scrittura.
Sensor_RequestReadResult
Invia al dispositivo con indirizzo 0xE0 la richiesta di lettura a partire dall’indirizzo 2.
Sensor_ReadResult
Legge i byte all’indirizzo 2 (Range High Byte) e 3 (Range Low Byte) e chiude la transazione.
134
Novembre 2013 ~ Elettronica In
c o r s o
F L O W
C O D E
E D O C
Fig. 8 Macro SensorRangingStateMachine.
W O L F o s r o c
Nel caso di interfacciamento di tipo I 2C, l’SRF02 funziona in modo molto simile ad una memoria EEPROM della famiglia 24xx: il dispositivo si presenta come un set di registri con accesso in lettura o in scrittura, come riassunto dalla Tabella 5. L’accesso in scrittura alla locazione 0 permette di eseguire una delle operazioni riportate in Tabella 6 (sono riportati solo i comandi principali). Nel nostro caso utilizziamo i comandi di ranging, che eseguono sia l’operazione di invio del burst ad ultrasuoni che la successiva rilevazione del tempo di volo dell’eco ed il conseguente calcolo della distanza. In questo caso il risultato del ranging viene salvato nei registri 2 e 3 (Range High Byte e Range Low Byte), dai quali può successivamente essere recuperato con un’operazione di lettura. Oltre al comando, sul bus deve essere inviato l’indirizzo del dispositivo (quello predenito in caso di interfaccia I 2C è 0xE0) ed il bit di read/write. Quindi, per ogni trasmissione viene inviato un totale di due byte. La procedura per ottenere il dato sulla distanza è la seguente: 1) invio del comando 0x51 in scrittura (ri-
Fig. 9a - Tab general della finestra di configurazione del componente CAN.
chiesta di ranging con risultato in cm); 2) invio dell’indirizzo del registro contenente il risultato in lettura; 3) ricezione dei due byte del registro contenente il risultato. Per realizzare queste tre operazione sono state scritte tre macro, riportate nella Tabella 7.
Queste macro sono utilizzate dalla macro SensorRangingStateMachine, che viene chiamata dallo scheduler principale e che fornisce, come output per il resto del sistema, la variabile globale SensorResult più alcune informazioni sulla diagnostica del collegamento I²C. In Fig. 8 è riportato il diagramma a blocchi Flowcode della macro SensorRangingStateMachine. Questo owchart implementa una macchina a stati che esegue in sequenza e con le corrette temporizzazioni le tre macro riportate in Tabella 6, in modo da ottenere il risultato del ranging. Per farlo, viene utilizzato il contatore SensorRangingCounter, incrementato ad ogni ciclo (ricordiamo che la macro è chiamata direttamente dallo scheduler principale, quindi ha un tempo di chiamata di 10ms).
Fig. 9b - Tab tx buffer 0 della finestra di configurazione del componente CAN.
Fig. 9C - Tab rx buffer 0 della finestra di configurazione del componente CAN.
Elettronica In ~ Novembre 2013
135
Fig. 10 Proprietà della macro SetTxData del componente CAN.
La prima macro chiamata è la Sensor_ SendCommand (dopo 10ms dall’avvio della macchina a stati). La seconda chiamata avviene dopo 250ms (ossia quando il contatore raggiunge il valore della constante TIMING_REQ_READ, pari a 25) e viene chiamata la macro Sensor_RequestReadResult. Il ritardo di 250ms serve a fare in modo che l’SRF02 riceva l’eco del burst ad ultrasuoni inviato in seguito alla ricezione del comando 0x51 e faccia i necessari calcoli. A questo punto, dopo altri 100ms viene letto il contenuto dei registri contenenti il risultato, tramite la macro Sensor_ReadResult (contatore uguale a TIMING_READ_RESULT, pari a 35). Inne, dopo altri 150ms la macchina a stati si resetta (semplicemente resettando il contatore) e il ciclo ricomincia dal punto di partenza. In questo modo si ottiene Fig. 12 Codice grafico per la ricezione del messaggio CAN.
136
Novembre 2013 ~ Elettronica In
Fig. 11 Codice grafico per l’invio del messaggio CAN.
un aggiornamento della posizione ogni 500ms circa. Ora che abbiamo compreso la gestione del sensore ad ultrasuoni, esaminiamo come vengono inviati i dati al nodo master tramite il bus CAN. Per prima cosa dobbiamo congurare correttamente il componente, quindi accediamo alla nestra delle proprietà extra. Nel tab principale inseriamo i settaggi principali, selezionando un bau-rate di 500kB, un sample point dell’80% e SJW pari a 1. Passiamo adesso al tab TX Buffer 0, dove, nella sezione frame Identier, selezioniamo “Extended Frame” ed inseriamo nella casella “Full ID” l’indirizzo 0xC40A5, come riportato nella mappa messaggi. Inne passiamo sul tab RX Buffer 0 e impostiamo un ltro in ricezione, selezionando la spunta “Message ID 0” ed inserendo il seguente ID nella relativa casella “Full ID”: 0xC40A4. La congurazione, riportata per comodità in Fig. 9 (a, b e c) è così completata. A questo punto possiamo inserire, all’interno del nostro scheduler, il codice Flowcode per l’invio del messaggio contente i dati di distanza e di diagnosi (ID 0xC40A5). L’invio si compone di due macro componente: per prima cosa usiamo la macro SetTxData, per riempire correttamente il messaggio in trasmissione; tale macro prende come parametri il buffer di trasmissione utilizzato, il numero di byte
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Tabella 8 -
Periodicità e descrizione dei task del software del nodo display.
Task
Periodo [ms]
Descrizione
CanRxTask
500
Riceve e decodica il messaggio CAN proveniente dal nodo sensore.
DisplayTask
500
Visualizza i dati decodicati dal task CanRxTask.
SwitchTask
200
Legge lo stato del pulsante ed invia il relativo messaggio CAN ad evento per il nodo sensore.
da inviare (DLC) e gli 8 byte del messaggio. I dati da inviare sono le seguenti variabili globali: - SensorResultHighByte Byte 0; - SensorResultLowByte Byte 1; - SensorDiagStatus Byte 2. →
→
denza, controlla l’esecuzione di tutti i task (ad eccezione proprio del task CanRx). Il frammento di codice graco che realizza quanto descritto è riportato in Fig. 12.
→
Nodo Display
Le prime due variabili sono ricavate dalla macro SensorRangingStateMachine, mentre la variabile SensorDiagStatus è calcolata (e codicata come indicato nella mappa messaggi) dalla macro DiagnosticTask. In Fig. 10 è riportata la nestra di proprietà della chiamata alla macro componente. Una volta riempito correttamente il messaggio in trasmissione, per inviare il messaggio è sufciente chiamare la macro SendBuffer e passare il buffer di trasmissione. In Fig. 11 è riportato il frammento di codice graco, così come appare dopo l’inserimento delle chiamate alle macro del componente CAN. A questo punto la nostra applicazione lato nodo sensore è quasi completa; rimane da gestire l’ingresso/uscita dalla modalità sleep controllata dal messaggio CAN inviato dal nodo display. Analizzando la mappa messaggi, si vede che il parametro che determina lo stato del sistema (sleep o awake) viene impostato dal byte 0 del messaggio con ID 0xC40A4. Bisogna quindi gestire un task di ricezione all’interno del quale viene letto questo byte e viene aggiornata una variabile che usiamo per identicare lo stato del sistema. Il nostro scheduler ci offre già un entry point per la ricezione a 50ms; per completare il codice, introduciamo due chiamate a macro di componente, ed in particolare una CheckRx ed una GetRxData, entrambe sul buffer 0. Il risultato della GetRxData viene salvato all’interno della variabile SystemStatus, la quale, come abbiamo visto in prece-
La descrizione del software del nodo sensore è ultimata; passiamo adesso al nodo display, che eredita molti concetti del nodo sensore, come ad esempio lo scheduler (che è praticamente identico). La funzione del nodo display è ricevere il messaggio periodico inviato dal nodo sensore e visualizzare le relative informazioni sul display LCD. Inoltre è il nodo che può mandare in sleep o risvegliare l’interno sistema, rilevando la pressione di un tasto sulla EB018. Il software del nodo display è composto da tre task principali, elencati in Tabella 8. La losoa di gestione del sistema è molto simile a quanto visto per il nodo precedente. A titolo di esempio, descriviamo come viene implementato il task CanRxTask; questo task ha il compito di ricevere e decodicare il messaggio con ID 0xC40A5, proveniente dal nodo sensore. Per prima cosa è stato congurato il componente CAN in maniera analoga a quanto fatto per il nodo sensore, con la differenza che l’ID del messaggio in trasmissione in questo caso è 0xC40A4, mentre il ltro di ricezione viene impostato sull’ID 0xC40A5. La ricezione avviene in maniera analoga a quanto visto nel caso precedente; in particolare, viene chiamata la CheckRx e per tre volte la GetRxData, per acquisire i due byte di dati che costituiscono l’informazione sulla distanza ed il byte contenente le informazioni diagnostiche. Inne, il byte 0 ed il byte 1 del messaggio vengono compattati in una word, tramite il seguente codice inserito in un blocco calcolo:
Elettronica In ~ Novembre 2013
137
Fig. 13 Codice grafico che implementa il task CanRxTask.
ad analizzare il progetto Flowcode e cercare di capirne il funzionamento. A questo punto possiamo anche testare il nostro sistema, collegando tra di loro i due nodi con un doppino intrecciato ed alimentando il sistema con una tensione di circa 12V. Sul nodo display vedremo apparire le informazioni sulla distanza dal sensore ad ultrasuoni ricevute dal nodo sensore. In Fig. 14 è riportato un tracciato CAN dell’interscambio di messaggi tra i due nodi, eseguito usando il CAN Analyzer Microchip. Come si può vedere, il messaggio del nodo sensore invia sul bus una distanza rilevata di circa 317 cm (byte 0-1 pari a 0x13D) ed una diagnosi senza fault attivi (byte 2 pari a 0x00). Alla ricezione della richiesta di sleep (byte 0 del messaggio 0xC40A4 pari a 0), il sistema interrompe la trasmissione. Conclusioni
SensorData = ((SensorDataHigh << 8) | SensorDataLow)
Lo schema a blocchi che implementa quanto descritto in precedenza è riportato in Fig. 13. I task per la gestione del display e per la lettura del tasto di sleep non presentano particolarità implementative di rilievo e non saranno trattati nel dettaglio in questa puntata; vi invitiamo, come esercizio,
Concludendo questa puntata, possiamo dire che l’approccio al CAN con Flowcode permette di gestire diverse tipologie di componenti e periferiche con relativa semplicità, oltre a generare codice estremamente facile da comprendere e mantenere. Nelle prossime puntate esamineremo altre periferiche complesse, come l’USB, g lo ZigBee e la porta Ethernet.
c o r s o
F L O W
Fig. 14 - Tracciato CAN del sistema durante in funzionamento fino alla ricezione di una richiesta di sleep.
138
Novembre 2013 ~ Elettronica In
C O D E
E D O C
W O L F o s r o c
Proseguiamo il nostro viaggio alla scoperta di Flowcode, affrontando la gestione dell’USB e realizzando un convertitore seriale RS232-USB, oltre ad un tastierino numerico e ad un analizzatore di stati logici, sempre su USB. Sesta puntata.
corso di programmazione in
FLOWCODE di Francesco Ficili e Daniele Defilippi
elle scorse puntate abbiamo parlato del bus di comunicazione avanzato CAN ed imparato a gestirlo in modo semplice e intuitivo grazie a Flowcode. In questa puntata faremo altrettanto con il bus USB, spiegando come funziona la comunicazione, in che modo si possa convertire un progetto RS232 in una periferica USB in pochi semplici passi e realizzeremo due tipi differenti di periferiche, ovvero una tastiera numerica per il PC e un analizzatore di stati logici.
N
La porta USB
L’interfaccia maggiormente utilizzata oggigiorno per la comunicazione tra
Personal Computer e periferiche è il bus USB. Esso ha sostituito praticamente tutte le altre precedenti interfacce sia seriali che parallele perché permette di trasferire dati ad una velocità molto elevata e collegare molti dispositivi (teoricamente no a 127) ad un’unica porta, mediante uno o più hub eventualmente disposti in cascata. Altra caratteristica fondamentale dell’USB è la possibilità di collegare e rimuovere i dispositivi senza dover riavviare il computer, il che fa del bus un vero Plug&Play. I dispositivi collegati possono essere alimentati direttamente dal bus o, qualora richiedano correnti superiori a 500 mA (il limite erogabile da una porta USB; se si connetto-
Elettronica In ~ Dicembre 2013 / Gennaio 2014
115
Fig. 1 Struttura di un pacchetto trasmesso sul bus USB.
116
• ID: identica se il dispositivo funziona da controllore (master) o periferica (slave); nel connettore di tipo A è collegato a GND per fare in modo che il dispositivo collegato alla porta mini/micro debba funzionare da periferica.
no più dispositivi, devono spartirsi questa corrente), devono avere una connessione di Lo standard 3.0 prevede il raddoppio delle alimentazione a parte. connessioni dati in modo da poter avere Lo standard USB 1.0 nacque nel 1996 e due linee per la ricezione dei dati ad altretconsentiva una velocità di connessione pari tante dedicate unicamente alla trasmissione. a 1,5 Mbit/s; le successive versioni offrono I dati sono trasmessi in modo pseudo-diffevelocità di comunicazione maggiori: per renziale perché la linea D- ha come valore esempio la 1.1 permette di raggiungere i 12 l’opposto della linea D+, ma ciò non è vero Mbit/s), la 2.0 i 480 Mbit/s e la più recente nel caso dell’identicatore del termine 3.0 permette una velocità massima di 4.8 pacchetto. Gbit/s. Mentre dalla prima versione alla 2.0 Nell’USB, la codica è di tipo NRZ ed il vala connessione è rimasta invariata (quattro lore zero provoca l’inversione del valore locontatti) con la 3.0 è stato introdotto un gico trasmesso. Il segnale di clock è trasmesnuovo connettore che ha i contatti sdoppiati so in modo implicito durante l’invio dei dati e di fatto prevede un doppio canale dati; la perciò, per evitare che il bus stia fermo allo connessione rimane comunque compatibile stesso valore per troppo tempo, dopo 6 bit con le vecchie, in quanto una la di contatti consecutivi di valore 1 viene trasmesso un tocca quelli dello spinotto tradizionale. bit aggiuntivo di valore zero. Esistono differenti connettori sici che La comunicazione sica è suddivisa in tre permettono la connessione al bus USB: parti principali: A, B, mini e micro. Dal 2011 il connettore • Pacchetto di start : Viene inviata la semicro-USB è diventato la porta standard di quenza di sincronizzazione 00000001. Nel comunicazione con tutti i sistemi cellulari, caso di pacchetti più grandi la sequenza ma con l’avvento degli smartphone è sorta di sincronizzazione è di 32bit; la necessità di sviluppare un protocollo che • Pacchetto di dato: La lunghezza dipende permetta di decidere all’atto della connesdal tipo di connessione, da 1 a 1024 byte, sione quale dispositivo diventa il master ed il primo bit trasmesso è quello meno e quale lo slave. La soluzione al problema signicativo; si chiama USB-On-The-Go e permette di • Pacchetto di Stop: Viene trasmessa una impostare, all’atto della connessione, quale sequenza non differenziale in cui entramdei due dispositivi è il master e quale lo bi i segnali restano al valore logico basso slave. Questo accorgimento fa in modo, ad per due cicli e poi il segnale D+ torna al esempio, che uno smartphone possa essere valore logico alto. visto come uno slave se connesso ad un PC o come master nel caso sia connesso ad una In Fig. 1 è mostrato un esempio di trasmisperiferica di archiviazione di massa come sione dati sul bus USB nel quale possiamo un hard-disk. Vediamo ora quali connessio- identicare le tre parti principali nel quale ni sono disponibili su un connettore USBè suddiviso, la codica NRZ ed il frame di mini/micro: stop. • VBUS; permette di alimentare le periLo standard USB prevede la classicazione feriche erogando 5V stabilizzati e una delle periferiche in “classi” in modo da facorrente massima di 500mA; cilitare la gestione ed identicazione dei ne• GND; è la massa di riferimento per i cessari driver; in questo modo i dispositivi segnali e l’alimentazione; standard come mouse, tastiere e memorie, • D-; dato -; non richiedono l’installazione di driver e • D+; dato +; sono quindi subito pronti all’uso.
Dicembre 2013 / Gennaio 2014 ~ Elettronica In
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Passiamo ora a scoprire come dotare un nostro progetto di una connessione USB in modo molto semplice e rapido senza neppure dover rigenerare il codice del microcontrollore. Il chip FT232BL
Il metodo probabilmente più semplice per gestire periferiche è usare la porta seriale: ciò, sia per la semplicità del rmware da caricare nel micro che governa la periferica, sia per il software di gestione lato personal computer. Il problema è che attualmente pochi PC hanno ancora il connettore DB9 della COM e i notebook non l’hanno più da tempo. Per questa ragione possiamo realizzare la periferica gestendo unicamente la connessione RS232 ed utilizzando un componente che si occupi della conversione di protocollo da RS232 ad USB. In questo
Fig. 3 Connessioni progetto convertito da seriale in USB.
modo vedremo dal punto di vista del PC una seriale che potremo gestire normalmente con il microcontrollore che riceverà i dati attraverso la seriale senza doversi occupare della complessa gestione del bus USB. Questa metodologia di lavoro è molto funzionale ed utilizzata soprattutto per la rigenerazione di vecchi progetti perché non richiede la modica del codice sorgente.
Per far ciò possiamo avvalerci del componente FT232BL fornito dalla FTDI Chip, che si accollerà tutte le procedure di gestione del protocollo USB. In Fig. 2 è mostrato lo schema ed il pin-out. Nel seguente progetto pratico esamineremo nel dettaglio come trasformare il progetto realizzato nella 4° puntata per il controllo di una batteria di relé rendendolo utilizzabile anche su computer sprovvisti di connettore DB9. Progetto pratico: convertire da RS232 a USB
Questo semplice esempio ci permetterà di capire in modo approfondito come dotare di una pseudo-connessione USB un progetto basato unicamente su una connessione RS232 senza dover modicare radicalmente il codice sorgente.
Elettronica In ~ Dicembre 2013 / Gennaio 2014
117
Fig. 2 Piedinatura e schema di riferimento per il componente FT232BL di FTDI.
Fig. 4 - Nuova configurazione componente RS232.
automaticamente le seriali virtuali eventualmente connesse al PC. Il componente USB in Flowcode
I componenti necessari per la realizzazione sono i seguenti: • EB006 “USB PICmicromultiprogrammerboard” (PIC18F4580 e quarzo 12MHz); • EB038 “Relay Board ”; • EB039“USB232 Board ”. La scheda EB039 sostituisce la EB015 sulla porta C (Fig. 3) ed al posto della connessione di uscita su DB9 è presente la porta USB di tipo B. Le modiche, a parte quelle all’hardware, sono davvero poche. Vediamo dunque come realizzare il nostro progetto passo passo: apriamo il progetto “RS232.fcf”, che avevamo salvato al termine della 4^ puntata, e modichiamo le impostazioni del componente RS232 come mostrato in Fig. 4. La connessione RS232 deve essere impostata a 9.600 baud, 8bit e il controllo di usso deve essere gestito mediante il pin RTS sulla porta C0 e il pin CTS sulla porta C4. Ricompiliamo il progetto e ricarichiamo il tutto sulla scheda di sviluppo, per vederne i risultati. Collegando il connettore USB tipo B, mediante un cavo, al connettore USB tipo A del nostro PC, il sistema operativo rileverà un nuovo hardware, corrispondente al componente FTDI, del quale dovremo installare il driver come indicato nel box “installiamo il driver del componente FTDI”. Per questa variante del progetto è stata aggiornata l’interfaccia software presentata a corredo della 4° puntata , permettendone l’utilizzo anche con una porta COM virtuale. Il funzionamento rimane sostanzialmente invariato, con la differenza che ora la selezione della porta di comunicazione viene fatta tramite una combo box che rileva
118
Dicembre 2013 / Gennaio 2014 ~ Elettronica In
Flowcode permette di utilizzare principalmente tre tipi di congurazione per il bus USB: • Serial; permette di gestire la porta USB come se fosse una normale connessione seriale; • HID; permette di creare un dispositivo di tipo “ Human interface device ”come ad esempio un mouse, una tastiera, un joystick, ecc.; • Slave; permette di creare un dispositivo custom. La scelta di uno tra i sopraelencati tipi dipende dalla funzionalità che la nostra periferica implementa. La più semplice e intuitiva da utilizzare è quella di tipo seriale perché è vista dal calcolatore come una semplice porta COM, come per il caso del chip della FTDI che abbiamo precedentemente utilizzato, ed i comandi che abbiamo a disposizione dal punto di vista del microcontrollore sono quelli standard di una comunicazione seriale limitandosi all’invio e alla ricezione di caratteri e stringhe. Se volessimo realizzare un mouse o comunque un dispositivo standard di input dovremmo scegliere il tipo HID, in modo da poterlo utilizzare senza dover installare alcun driver aggiuntivo mentre negli altri casi dovremmo avvalerci del tipo slave. Il componente USB-HID
È contenuto all’interno della barra dei componenti nel sotto-menu “ periferiche ” e permette di gestire un dispositivo di tipo “ Human interface device ”. Dopo aver inserito il componente all’interno del pannello possiamo esaminare le proprietà del componente. Essendo abbastanza complesso, a differenza degli altri componenti più semplici, necessita di tre pagine di congurazione. Iniziamo ad analizzare la prima, illustrata nella Fig. 5. Il parametro VID è il cosiddetto “VendorIdentier” ed è, in pratica, l’identicativo univoco del venditore della periferica; viene assegnato a fronte del pagamento
c o r s o
F L O W
C O D E
Tabella 1
E D O C
Nome macro
W O L F o s r o c
Descrizione
RetVal = Initialise_HID()
È utilizzata per inizializzare il driver USB per la comunicazione ed attivare il servizio di enumerazione delle periferiche. Restituisce zero se la procedura termina senza errori.
SetDataByte(idx, value)
È utilizzata per scrivere uno specico byte sul vettore che verrà inviato via USB. In ingresso necessita dell’indice del byte da scrivere ed il valore che si vuole scrivere. Questa macro non invia sicamente i dati ma li immagazzina nel buffer di trasmissione senza trasmetterli.
SendData()
Quando viene chiamata trasmette sul bus USB i dati che sono stati caricati nel buffer dalla funzione SetDataByte.
SendDataDirect(String)
Invia i dati contenuti all’interno della stringa passata come parametro sul bus USB.
NumBytes =CheckRx()
Aggiorna i dati che sono stati ricevuti dal canale USB. Restituisce la lunghezza dei dati presenti all’interno del buffer.
Value = ReceiveByte(idx)
È utilizzata per leggere un byte indenticato dall’indice passato come parametro dal buffer di lettura dei dati ricevuti. Il primo dato è identicato dell’indice zero.
String =ReceiveString(NumBytes)
É utilizzata per leggere l’intera stringa ricevuta sul bus USB. Richiede che gli sia passato come parametro il numero di byte da leggere e caricare sulla stringa restituita dalla funzione.
della quota associativa al consorzio USB. Coloro che producono in grandi quantità dispositivi USB hanno un loro VID, mentre le piccole aziende e gli hobbisti possono utilizzare il VID del costruttore del chip, che nel nostro caso è quello della Microchip. Per l’uso personale del dispositivo realizzato, non è necessario avere un VID valido. Il parametro PID è l’identicativo del dispositivo realizzato. A fronte dell’acquisto di un VID possiamo quindi avere a disposizione 65.535 differenti prodotti. Se volessimo vendere piccole/medie quantità di dispositivi USB potremmo domandare alla Microchip, mediante un particolare richiesta scritta disponibile sul sito www. microchip.com , l’autorizzazione ad utilizzarne uno. All’interno del campo Name e Manufacturer possiamo inserire il nome della nostra applicazione ed il nostro nome mentre come versione indichiamo 1.0.
In Fig. 6 vediamo le altre congurazioni speciche al dispositivo che intendiamo realizzare. I parametri principali che dobbiamo impostare sono: • Maximum current ; corrente massima che il dispositivo è abilitato ad assorbire tramite la tensione di alimentazione dell’USB; • Transmitpacketsize ; dimensione dei pacchetti trasmessi al computer dal dispositivo durante l’interrupt sul bus; • Transmitpacketperiod; numero di millisecondi che intercorrono tra due trasmissioni di dati; • Receivepacketsize ; dimensione dei pacchetti ricevuti dal dispositivo durante l’interrupt del bus; • Receivepacketperiod; numero di millisecondi che intercorrono tra due ricezioni di dati; • Subclass ; è la sottoclasse dei dispositivi USB ed è valida unicamente per mouse e
Fig. 5
Fig. 6
Elettronica In ~ Dicembre 2013 / Gennaio 2014
119
Fig. 7
tastiere (HID); • Interface ; è utilizzata per denire la classe del dispositivo. Il tab “ HID Descriptor” visibile in Fig. 7 permette di descrivere in modo dettagliato la comunicazione ed il signicato di ogni singolo byte trasmesso. La descrizione dei dispositivi è standard quindi, qualora volessimo ad esempio realizzare un gamepad, ci basterà cercarne la sua descrizione su Internet ed inserirla all’interno della nostra nestra. In modo automatico, appena connesso il dispositivo al calcolatore, verrà riconosciuto come tale senza bisogno di altre congurazioni ed installazioni. Le macro che Flowcode ci mette a disposizione sono riassunte nella Tabella 1. Grazie a queste semplici funzioni possiamo realizzare qualsiasi tipo di dispositivo HID ma per meglio capirne il funzionamento proviamo ora a mettere in pratica questi concetti realizzando un tastierino USB. Progetto pratico: realizziamo un tastierino numerico USB
Il dispositivo che stiamo realizzando sarà riconosciuto in automatico dal PC al quale verrà collegato come una normale tastiera USB. Per realizzarlo abbiamo bisogno dei seguenti componenti: • EB006 “USB PICmicromultiprogrammerboard” (PIC18F4450 e quarzo 12 MHz); • EB014“Keypadboard”; • EB055“USB interfaceboard”. Colleghiamo la scheda EB014 alla porta D e
120
Dicembre 2013 / Gennaio 2014 ~ Elettronica In
la EB055 alla porta C, come mostrato in Fig. 8. Per poter utilizzare il componente senza doverlo alimentare esternamente, come le normali tastiere USB, basta collegare il morsetto V+ della scheda EB006 al morsetto +5 della scheda EB055. In questo modo il microcontrollore viene alimentato direttamente dalla porta USB. La connessione è effettuata mediante il lo giallo mostrato nella stessa Fig. 8. È inoltre necessario, come visto nelle precedenti puntate, congurare la scheda in modo da avere la frequenza adatta per poter utilizzare correttamente il bus USB. Ogni volta che è necessario gestire un bus a frequenza ssa bisogna stare molto attenti nel congurare correttamente tutti i parametri; nel nostro caso la congurazione è mostrata in Fig. 9. La frequenza di oscillazione del PLL è quindi 96 MHz, ma le periferiche interne lavorano a 24 MHz in modo da poter supportare la connessione USB Low-Speed. Ora che l’hardware è pronto, possiamo dedicarci alla realizzazione del software di controllo: per prima cosa dobbiamo capire quali dati vengono scambiati tra PC e tastiera in modo da poterla emulare; allo scopo, possiamo andare sul sito ufciale USB e scaricare i le “Hut1_12v2.pdf” e “HID1_11.pdf”. Analizzandoli, riusciamo a capire cosa viene trasmesso e cosa è ricevuto. In Fig. 10 sono riassunti i dati trasmessi tra PC e tastiera USB. Sempre nel le, troveremo la codica Fig. 8 Configurazione hardware per realizzare il tastierino numerico.
c o r s o
F L O W
C O D E
E D O C
Fig. 10 - Riassunto dati scambiati con la tastiera USB.
W O L F o s r o c
Fig. 9 - Configurazione del microcontrollore per la realizzazione del tastierino numerico.
dei caratteri da trasmettere perché questi non seguono la normale tabella ASCII. I valori numerici dall’uno al 9 partono dal valore esadecimale 0x1E mentre lo zero ha codica 0x27. In questo semplice esempio trasmetteremo unicamente un carattere per volta e non saranno quindi possibili combinazioni di tasti premuti in contemporanea. Per questa ragione ci basterà valorizzare unicamente il byte 2, lasciando gli altri al valore predenito 0x00. Ora che abbiamo tutte le informazioni necessarie possiamo trascinare nel pannello il componente Keypad ed il componente USBHID. Il componente Keypad richiede una corretta congurazione delle connessioni. Nel nostro caso dovranno essere impostate come mostrato in Fig. 11. Per quanto riguarda la congurazione del componente HID, è necessario scegliere nella pagina HID descriptors l’opzione Keyboard mentre congurare il tab HID options come indicato in Fig. 12. L’applicazione potrebbe sembrare complessa, per il fatto che utilizza il bus USB, ma il diagramma di controllo risulta semplice e non richiede neppure di realizzare macro di supporto. Come primo passo è necessario inizializzare la periferiche HID e successivamente, mediante un ciclo innito,
scandire il tastierino numerico e trasmettere periodicamente, mediante la macro di aggiornamento della periferica HID, le informazioni sul tasto premuto. Se nessun tasto è premuto, viene trasmesso il valore 0x00 altrimenti il codice relativo al tasto. Per evitare di sovraccaricare il bus di dati non utili, qualora il tasto premuto risulti sempre lo stesso, i dati vengono trasmessi unicamente a seguito di una variazione del tasto premuto ed il tempo minimo di ritardo tra una trasmissione e l’altra è di 10 ms. Per ovviare a problemi di inizializzazione è stato aggiunto un ritardo di inizializzazione pari a 100 ms. Le variabili utilizzate sono le seguenti: • DatiUSB[8]: è un vettore di 8 byte nel quale vengono memorizzati i dati da trasmettere sul bus; • EsitoInizializzazione : variabile byte che serve per memorizzare l’esito dell’inizializzazione della periferica USB; • Keypad : memorizza il valore letto dal Keypad in una variabile di tipo byte; • Keypad_precedente : è utilizzata per memorizzare lo stato precedente letto sul keypad ed è di tipo byte. Il usso di programma completo è mostrato in Fig. 13.
Elettronica In ~ Dicembre 2013 / Gennaio 2014
121
Installiamo il driver del componente FTDI Per poter funzionare correttamente, il PC al quale colleghiamo il convertitore FTDI, deve avere installati i driver necessari. Per far ciò inseriamo il CD fornito assieme alla scheda EB001 a fronte della richiesta del PC di installare il driver e indichiamo di volerlo cercare nel computer ( Fig. A); inseriamo l’indirizzo alla cartella “\drivers\EB-O39” contenuta all’interno del nostro lettore CD e procediamo premendo il pulsante “Avanti”.
pulsante “Generate Driver File” che si trova in essa serve per generare il le .inf che viene richiesto quando colleghiamo la periferica ad un PC per l’installazione del driver. È necessario rigenerare il driver ogni qualvolta, nella nestra di dialogo, modichiamo i parametri di congurazione. Le macro a disposizione sono elencate in Tabella 2. Con queste semplici macro possiamo realizzare qualsiasi tipo di periferica USB che emuli una comunicazione seriale. Per meglio capirne il funzionamento passiamo ora alla realizzazione di un semplice analizzatore di stati logici.
Fig. A – indicazione del percorso di ricerca del driver USB.
Al termine della procedura di installazione otterremo l’indicazione che il driver è stato aggiornato ed è quindi pronto all’uso come indicato in Fig. B.
Fig. 11 - Configurazione Keypad.
Fig. B – Installazione driver completata con successo.
c o r s o
Il componente USB-Serial
Questo tipo di controllo permette di gestire in modo molto semplice una connessione USB perché è vista sia lato PC che lato Sistema embedded come una comunicazione di tipo seriale RS232. Il componente si trova nella barra dei componenti all’interno del menu “periferiche” dove avevamo precedentemente visto gli altri componenti USB. Come possiamo osservare nella nestra di dialogo visibile in Fig. 14, i parametri che possiamo congurare sono gli stessi che avevamo visto per il componente HID; il
122
Dicembre 2013 / Gennaio 2014 ~ Elettronica In
F L O W
Fig. 12 - Configurazione USB-HID.
C O D E
E D O C
Progetto pratico: realizziamo un analizzatore di stati logici
W O L F o s r o c
Fig. 13 Diagramma completo per la realizzazione di una tastiera USB.
Un analizzatore di stati logici permette di visualizzare gli stati di una serie di connessioni in modo da poter debuggare sistemi digitali. È molto utile per la lettura di comunicazioni su bus paralleli. Il materiale di cui abbiamo bisogno è il seguente: • EB006 “USB PICmicromultiprogrammerboard ” (PIC18F4550 e quarzo 12MHz) • EB055 “USB interfaceboard” • EB016“Prototypeboad” In Fig. 15 sono visibili le interconnessioni tra le schede della MatrixMultimedia per la realizzazione del progetto. La scheda EB055 è connessa alla porta C mentre la EB016 alla porta A e B. Per poter funzionare correttamente, il microcontrollore deve esse congurato come mostrato in Fig. 16 in modo da poter operare a una frequenza di clock di 48 MHz. In pratica il sistema embedded legge il valore della porta B e lo invia in modo seriale. Dal lato PC è possibile realizzare un programma terminale che legge i dati e li
stampa a video in modo da poterli analizzare semplicemente. Dato che la comunicazione USB non è “real-time”, aggiungeremo alla stringa inviata serialmente anche il cosiddetto “TimeStamp” in modo che si possa sapere quando i dati sono stati campionati. La sequenza trasmessa sarà quindi: dove xxx rappresenta il TimeStamp mentre y è il valore della porta B. Ogni 100ms verrà inviato un dato sulla comunicazione e quindi potremo avere una risoluzione massima di 0.1 secondi sull’asse dei tempi. Il timestamp è rappresentato in decimi di secondo mentre il valore della porta B in decimale. In questo modo anche con un semplice terminale è possibile interpretare il segnale. Se per esempio volessimo trasmettere il valore 236 al tempo 1,5 secon-
Elettronica In ~ Dicembre 2013 / Gennaio 2014
123
Fig. 15 – Configurazione HW per analizzatore di stati logici.
Fig. 14 Finestra delle proprietà del componente USB seriale.
di invieremo la stringa “<000015-236>. Il tempo massimo è di 99999.9 secondi (27,7 giorni) dopo il quale, si ha la ripetizione del valore di TimeStamp. Generare la stringa a lunghezza ssa, cioè con l’aggiunta dello zero per mantenere la lunghezza ssa, è probabilmente la parte più difcile di tutto il progetto perché il comando per la conversione da numero a stringa inserisce unicamente le cifre signicative. Per questa ragione realizzeremo una macro che avrà il compito di convertire un numero e di portarlo a lunghezza ssa. La macro si chiama “ConvertiInStringaFissa” e necessita dei seguenti parametri: • ValoreNumerico: è il valore che vogliamo convertire; • LunghezzaFissa: è la lunghezza della stringa in uscita. Il primo ciclo si occupa della formattazione della stringa mediante l’aggiunta del carat-
Tabella 2 -
tere che identica lo zero mentre il secondo carica all’interno del valore di ritorno il valore convertito mediante la funzione Length$ con allineamento a destra come mostrato in Fig. 17. Ora che la nostra macro è pronta possiamo passare alla realizzazione del programma principale. Per prima cosa inseriamo all’interno del pannello il componente USB-Seriale e lo conguriamo come visto nel paragrafo precedente. Come di routine suddividiamo il programma in due parti principali: l’inizializzazione del sistema ed il ciclo principale. Nell’inizializzazione inseriamo l’azzeramento delle variabili e la macro “Intitialize_Serial()” per la connessione USB. Il ciclo principale si occupa invece della sequenza di lettura della portaB, Conversione del valore letto e del TimeStamp, generazione della stringa da trasmettere e inne trasmissione del dato su bus USB. Per fare in modo che i dati ven-
Macro disponibili per la gestione della connessione USB-Seriale. Nome Macro
Descrizione
Initialise_Serial()
É utilizzata per inizializzare la comunicazione USB avviando il servizio di enumerazione in modo che il PC possa identicare il dispositivo. Restituisce come valore di ritorno 0 qualora venga eseguita correttamente mentre 255 in caso di errore.
Send_Byte(Byte)
Trasmette il byte passato come parametro inserendolo nel buf fer di scrittura.
Send_String(String, Length)
Invia la stringa passata come parametro “String”. Il parametro “Length” deve contenere la lunghezza dei caratteri da trasmettere contenuti nella stringa.
Read_Byte(timeout_ms)
Legge dal buffer di lettura un byte e lo restituisce come valore di ritorno. Il parametro “timeout_ms” serve per stabilire un timeout massimo, in millisecondi, per il quale la macro deve attendere in attesa di un dato. Qualora venga posto al valore 255 l’attesa non termina no a quando un dato non è disponibile nel buffer di ricezione. Nel caso nessun dato venga ricevuto entro il timeout il valore di ritorno è 255.
Read_String(timeout_ms, String, Length)
Legge dal buffer di lettura una sequenza di caratteri la cui lunghezza è ssata dal parametro “Length” e la restituisce come valore di ritorno della funzione. Come per la macro Read_Byte il parametro “timeout_ms” serve per permettere alla macro di restituire il controllo alla funzione chiamante senza che nessun dato sia stato ricevuto.
124
Dicembre 2013 / Gennaio 2014 ~ Elettronica In
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 17 - Macro ConvertiInStringaFissa utilizzata all’interno dell’analizzatore di stati logici.
Fig. 16 – Configurazione microcontrollore per analizzatore di stati logici.
Fig. 18 Diagramma del “Main” dell’analizzatore di stati logici.
gano campionati e trasmessi ogni 100ms è necessario inserire un ritardo di 100ms. Il ciclo principale è, come sempre, racchiuso all’interno di un ciclo innito per evitare che il programma termini dopo il primo invio di dati. I più esperti nella realizzazione di sistemi embedded si saranno sicuramente accorti del fatto che utilizzare un delay per cadenzare una misurazione per periodi così lunghi porta ad un accumulo dell’errore sul timestamp. Per ovviare a questa pro blematica è comunque sufciente utilizzare un timer. In questo esempio è stato scelto di non utilizzarlo unicamente per poterci soffermare maggiormente sull’impiego del bus di comunicazione piuttosto che sulle altre problematiche di contorno che, a questo punto del corso, dovreste essere già in grado di risolvere in modo autonomo. In Fig. 18 è mostrato il diagramma principale per la realizzazione dell’analizzatore di stati logici. Per testare il programma possiamo utilizzare un qualsiasi terminale per porte COM che supporti le comunicazioni seriali virtuali. Bene, anche con questa puntata abbiamo concluso. Nelle prossime conosceremo altri componenti forniti da Flowcode, tra i quali g lo ZigBee e l’Ethernet.
Elettronica In ~ Dicembre 2013 / Gennaio 2014
125
E D O C
W O L F o s r o c
Continuiamo il nostro viaggio alla scoperta di Flowcode, l’innovativo sistema di sviluppo grafico per microcontrollori proposto dalla Matrix Multimedia. In questa puntata analizzeremo una periferica wireless: ZigBee. Settima puntata.
corso di programmazione in
FLOWCODE di Francesco Ficili e Daniele Defilippi
elle puntate precedenti ci siamo occupati di diverse periferiche di comunicazione, che avevano una caratteristica comune, ossia quella di essere tutte periferiche di comunicazione cablate. Analizziamo adesso l’implementazione Flowcode di una periferica wireless, ossia interfacciamo il nostro microcontrollore con una periferica ZigBee.
N
Il Protocollo ZigBee
Il protocollo ZigBee nasce ufcialmente il 14 dicembre 2004, giorno in cui la ZigBee Alliance (consorzio di aziende che si occupano dello sviluppo e dell’aggiornamento dello standard e della promozione
della tecnologia su di esso basata) rilascia le speciche 1.0. Come era già avvenuto in passato per la denizione di altri standard, il lavoro relativo allo standard ZigBee è stato diviso in due tronconi. Al task group IEEE 802.15.4 (parte del work group IEEE 802.15) è stato assegnato il compito di denire le speciche relative al livello sico e MAC dello standard, mentre la ZigBee Alliance è stata incaricata di arrivare alla denizione delle speciche di alto livello (livelli Network e Application). La relazione che esiste tra 802.15.4 e ZigBee è la stessa che esiste tra 802.11 e WiFi e tra 802.15.1 e Bluetooth. Non bisogna quindi confondere le
Elettronica In ~ Febbraio 2014
129
Tabella 1 -
Confronto tra le più diffuse tecnologie wireless. ZigBee™ 802.15.4
Bluetooth™ 802.15.1
Wi-Fi™ 802.11b
GPRS/GSM 1XRTT/CDMA
Application Focus
Monitoring & Control
Cable Replacement
Web, Video, Email
WAN, Voice, Data
System Resource
4KB-32KB
250KB+
1MB+
16MB+
Battery Life (days)
100-1000+
1-7
1-5
1-7
Nodes Per Network
255/65K+
7
30
1,000
Bandwidth (kbps)
20-250
720
11,000+
64-128
Range (meters)
1-75+
1-10+
1-100
1,000+
Key Attributes
Reliable, Low Power, Cost Effective
Cost, Convenience
Speed, Flexibility
Reach, Quality
speciche dello standard IEEE 802.15.4 con lo standard ZigBee: con il primo ci si riferisce ad un insieme di speciche di basso livello sulle quali si basa il secondo per la denizione di uno standard più complesso. Sulle speciche indicate dallo standard ZigBee si basano i costruttori per la realizzazione del silicio. Chi a sua volta acquista i chip dai produttori, li ingloba in un sistema più complesso, il quale aggiunge un ulteriore strato a livello applicativo, caratteristico dell’applicazione nale vera e propria. Come è stato già accennato nell’introduzione il protocollo ZigBee è un protocollo wireless caratterizzato da bassi consumi energetici, semplicità nell’implementazione del codice (generalmente indicata come consumo approssimativo di memoria programma per la realizzazione di un Fig. 1 nodo) ed elevato numero di nodi costiLogo della tuenti la rete; la velocità di comunicazioZigBee Alliance. ne è relativamente bassa.
Fig. 2 - Confronto tra tecnologie wireless in funzione di portata trasmissiva e data-rate.
130
Febbraio 2014 ~ Elettronica In
I dispositivi facenti parte di una PAN ZigBee si chiamano nodi; i nodi non sono tutti uguali ma lo standard ZigBee ne prevede tre tipi: • Coordinator; è il nodo centrale della rete e ad esso sono demandate le funzioni più importanti, come ad esempio la creazione della rete stessa, l’assegnazione degli indirizzi, la scelta del canale RF ed altro ancora; ne può esistere al massimo uno per rete e può fungere da ponte tra reti diverse (è anche chiamato Gateway); • Router; agisce come router intermedio, passando i dati da e verso altri dispositivi; • End Device; include le funzionalità minime per dialogare con il loro nodo padre (Coordinator o Router), non possono trasmettere dati provenienti da altri dispositivi. La Tabella 1 mette a confronto lo standard ZigBee con alcune tra le più diffuse tecnologie wireless esistenti. Il data-rate tipico dichiarato sul canale radio è 250 kbps, mentre il data rate dell’interfaccia può assumere valori che variano da 1.200 a 115.200 bps; tale parametro non sempre si trova nei data-sheet dei dispositivi, in quanto lo ZigBee non è stato specicamente studiato per lo scam bio di grosse moli di dati, come potrebbe invece essere per il WiFi. La portata dipende dal dispositivo considerato, dall’antenna e dalla potenza irradiata in trasmissione: valori tipici sono compresi tra le decine e le centinaia di metri. In Fig. 2 è riportato un graco che mette a confronto diverse tecnologie wireless in funzione del range trasmissivo e del data rate (in Mbps). Come si vede Bluetooth e ZigBee occupano zone molto vicine nel graco, ma mentre il primo
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 3 - Esempio di Mesh ZigBee.
privilegia la velocità in trasmissione, il secondo la sacrica in funzione di una maggiore portata trasmissiva. Oltre a ciò, ZigBee presenta una interessante caratteristica che lo differenzia da Bluetooth e da altri protocolli wireless, e gli permette di estendere il suo range utile a valori molto superiori rispetto alla portata di un singolo dispositivo. Infatti lo standard permette di mettere in comunicazione due nodi qualsiasi anche se non posti in collegamento radio diretto, è sufciente che tra i due nodi in questione esista almeno un percorso costituito da nodi intermedi, che in questo caso fungono da routers. Questa interessante caratteristica viene generalmente indicata come Mesh Networking, una cui rappresentazione graca è riportata in Fig. 3. La gestione di reti Mesh è una prerogativa del protocollo, che viene implementata adottando i più recenti algoritmi di routing, oltre ad un efciente sistema di indirizzamento dei dispositivi, che si avvale di due indirizzi, un indirizzo denominato MAC ed uno denominato Short. Il MAC è un codice identicativo a 64 bit (8 byte), univoco per ogni dispositivo prodotto al mondo. Tale codice è memorizzato all’interno di Tabella 2 -
un’apposita memoria ROM e non può essere modicato. Invece lo Short è un codice identicativo a 16 bit (2 byte) che permette di identicare univocamente un dispositivo all’interno di una rete ZigBee. Viene memorizzato in un’area di memoria protetta, ma riscrivibile, quindi può cambiare, in seguito, ad esempio, all’associazione del dispositivo con un’altra rete. Gli indirizzi Short sono assegnati dal Coordinator all’atto della creazione della rete. Per quanto riguarda le bande radio utilizzate, lo standard sfrutta le frequenze assegnate nella banda ISM (Industrial, Scientic, Medical), che variano a seconda del paese considerato. In particolare può usufruire delle frequenze radio a 433MHz e 868 MHz in Europa e a 315 MHz e 915 MHz negli USA. Inoltre può usufruire della banda radio a 2,4 GHz praticamente in tutto il mondo. Su questa frequenza sono disponibili ben 16 canali e quindi, a meno di casi particolari, questa risulta essere la scelta più frequente dei costruttori. Le caratteristiche intrinseche di ZigBee rendono questo standard la scelta ideale per un gran numero di applicazioni. Si va dalla building automation al controllo industriale, dalle periferiche wireless per PC (come tastiere e mouse) ad applicazioni wireless di sicurezza. Un importante segmento è sicuramente costituito dalla
Fig. 4 Applicazioni tipiche del protocollo Zigbee.
Applicazioni del protocollo ZigBee.
Settore di applicazione
Possibili applicazioni
Termoregolazione
HVAC, controllo temperatura, controllo umidità
Monitoraggio ambientale
Terra, qualità aria, qualità acqua.
Automazione industriale
Accelerometri, Vibrazioni, Pressione, Spostamenti
Monitoraggio strutturale
Monitoraggio gallerie, Monitoraggio ponti, Monitoraggio dighe, Monitoraggio edifci a rilevanza storica o artistica
Domotica
Sistemi di sicurezza e controllo
Elettronica In ~ Febbraio 2014
131
due modalità di funzionamento, modalità trasparente (denominata normalmente modalità AT) e modalità API. In modaliFig. 5 - Modulo tà trasparente tutto ciò che viene inviato Xbee Serie 2. sulla seriale del modulo viene ritrasmesso sul canale radio e viene successivamente realizzazione di reti che vengono general- ritrasmesso in uscita sulla porta seriale mente indicate come WSN (Wireless Sen- del modulo ricevente. I radiomodem sor Network) ossia reti di sensori wireless aggiungono alla sorgente e tolgono alla custom per applicazioni di monitoraggio destinazione tutto l’header necessario alla di vario tipo. La Fig. 4 illustra alcune del- comunicazione, ecco perché la modalità le applicazioni tipiche del protocollo. viene denita “trasparente”. Non è possiLa Tabella 2 elenca sinteticamente alcune bile intervenire sull’header, che contiene delle più comuni applicazioni del protoinformazioni quali indirizzo destinaziocollo. Tra i vari dispositivi ZigBee prene, lunghezza campo dati, checksum, etc. senti al mondo hanno acquisito una certa In modalità API, invece, la gestione dei fama (specialmente nel mondo hobbistipacchetti è decisamente più complicata. co) i dispositivi Xbee, prodotti dalla Digi/ Maxstream. Si tratta di una famiglia di radiomodem con interfaccia seriale, il cui esemplare è riportato in Fig. 5. Tali disposivi sono stati scelti anche dalla Matrix come modulo hardware ZigBee per i dispositivi e-block. L’hardware è molto semplice, e consiste in un piccolo PCB, all’interno del quale Fig. 6 - Possibili scelte per l’antenna dei moduli Xbee. trova posto tutta l’elettronica necessaria al funzionamento, inclusa l’antenna che Nei data-sheet sono deniti una serie di può essere a chip, a lo o con connettore RPSMA. La Fig. 6 illustra le diverse possi- frame utilizzabili, divisi per funzione, bili scelte per l’antenna dei moduli Xbee. e caratterizzati da differente numero di byte, codice identicativo ed altro ancora. L’interfacciamento verso l’esterno è afdato a due le di 10 pin a passo 2 mm. Il componente ZigBee in Flowcode L’interfaccia di comunicazione è una seriale standard UART, con baud rate se- Analizziamo adesso il componente Ziglezionabile da 1200 bps a 115200 bps, sic- Bee integrato in Flowcode. Il componente si trova sotto il gruppo dei componenti chè il collegamento minimo richiesto per il funzionamento dei moduli consiste nel- wireless, all’interno della barra dei comle due linee della seriale, TX ed RX e nelle ponenti. Per inserirlo nel nostro progetto due linee di alimentazione. Sono previste è sufciente trascinarlo sul pannello, Tabella 3
132
- Caratteristiche moduli Standard e PR. Specifcation
Xbee
Xbee PRO
Indoor/Urban Range
30 m
100 m
Outdoor Range
100 m
1500 m
Transmit Power Output
1 mW (0 dBm)
100 mW (20 dBm)
RF data rate
250 kbps
250 kbps
Interface Data Rate
1200 – 115200 bps
1200 – 115200 bps
Receiver Sensitività
- 92 dBm
- 100 dBm
Supply Voltage
2.8 – 3.4 V
2.8 – 3.4 V
Transmit Current
45 mA
270 mA
Receive Current
50 mA
55 mA
Febbraio 2014 ~ Elettronica In
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 7 – Proprietà extra.
come più volte abbiamo fatto in precedenza. Una volta posizionato il componente possiamo esaminarne le proprietà extra, cliccando con il tasto destro. La nestra delle proprietà extra del componente è riportata in Fig. 7. Come si può vedere è possibile scegliere che tipo di componente si vuole implementare (Coordinator, Router, End node), impostare la PAN id (random e impostata dall’utente), impostare il numero massimo di hops, i canali da includere all’interno della procedura di scan ecc. Come per gli altri componenti, sono disponibili delle API che ne facilitano l’utilizzo, sinteticamente riportate in Tabella 4. Progetto pratico: nodo wireless per controllo relé
Passiamo adesso al progetto pratico relativo a questa puntata. Questa volta ci proponiamo di realizzare una mesh ZigBee costituita da nodi in grado di controllare una batteria di 4 relé. Ogni nodo sarà identicato all’interno della mesh tramite un indirizzo costituito da due cifre numeriche codicate ASCII. Sarà possibile modicare l’indirizzo del nodo tramite il canale wireless e sarà inoltre possibile intervenire su alcuni parametri di funzionamento. I vari parametri saranno memorizzati all’interno della EEPROM del dispositivo, in modo che possano essere recuperati anche nel caso in cui il nodo venga privato della sorgente di alimentazione, in modo da non dover ripristinare Tabella 4 -
la congurazione in futuro. Come già fatto per gli altri progetti pratici, esaminiamo le speciche di progetto, elencate di seguito. • Controllo di ogni singolo nodo tramite indirizzo in formato ASCII su due cifre. • Attivazione/disattivazione di 4 relé. • Gestione delle seguenti opzioni: - abilitazione/disabilitazione LED funzionamento; - abilitazione/disabilitazione Eco comando; - selezione periodo lampeggio LED. • Memorizzazione delle opzioni di sistema su memoria EEPROM. Il nostro progetto prevede quindi l’utilizzo di un protocollo livello applicazione che si appoggia sul protocollo ZigBee. La denizione del protocollo di livello applicazione è riportata di seguito. • La stringa di comando inviata dal master è una stringa ASCII composta da 7 caratteri.
Macro del componente ZigBee Flowcode.
Nome Macro
Descrizione
Init_Network
Inizializza il modulo Xbee e prova ad eseguire il setup della network (coordinator) oppure ad ef fettuare il join ad una network eseistente (router o end device).
Restart_Network
Re-inizializza la network Zigbee.
Scan_Network
Esegui uno scan per individuare una rete associabile.
Connect_To_Address
Connette il modulo ad uno specifco indirizzo all’interno della network.
Connect_To_Coordinator
Connettiti al coordinator.
Connect_To_All
Connettiti a tutti i nodi (trasmissione broadcast)
Node_Congure_Sleep
Imposta la modalità sleep del nodo (applicabile solo agli end device). Prende in ingresso due parametri, la modalità di sleep (1=Hibernate, 2=Doze, 4=Cyclic Sleep, 5=Cyclic Doze) e il timeout in ms.
Node_Wake
Risveglia i nodi gli dallo sleep mode.
Get_Signal_Level
Leggi il livello del segnale radio
Send_Char
Invia un byte sul canale radio.
Receive_Char
Restituisci il carattere ricevuto dal canale radio.
Elettronica In ~ Febbraio 2014
133
• La stringa di comandi è divisa in due sezioni, una sezione di identicazione ed una sezione di controllo, separate dal carattere ASCII “-“. • La sezione di identicazione serve ad indirizzare il nodo che si vuole controllare. È composta da 3 caratteri ASCII: un primo carattere S (Slave) seguito da due caratteri numerici ASCII da “0” a “9”. Quindi per identicare il nodo 01, si invierà la stringa “S01”. • La sezione di controllo è divisa in 3 sottofunzioni: - sottofunzione “R”, usata per il controllo diretto dei relé. In questa sottofunzione la lettera “R” è seguita da un carattere numerico ASCII da 1 a 4, usato per identicare il relé e dai caratteri “a” e “d” usati, rispetti-
Fig. 8 Connessione E-Block per progetto pratico.
vamente, per abilitare/disabilitare il relé (ad esempio per abilitare il relé 1 sul nodo 15 si userà la stringa S15R1a); - sottofunzione “I”, usata per impostare un nuovo indirizzo del nodo. In questa sottofunzione, la lettera “I” è seguita da due caratteri numerici da “0” a “9”, che costituiscono la nuova coppia di valori per l’indirizzo del nodo(Es. per cambiare l’indirizzo del nodo 0 in 35 si userà la stringa S00I35); - sottofunzione “C” , usata per impostare la congurazione del sistema. Le opzioni di congurazione attualmente disponibili permettono di abilitare/disabilitare il working LED e selezionarne il periodo di lampeggio ed abilitare/disabilitare l’eco. La lista degli e-block necessari per la realizzazione di un nodo slave è riportata di seguito: • 1x EB006 “USB PICmicro multiprogrammer board” (PIC18F4580 e quarzo a 12 MHz); • 1x EB051 “ZigBee board” (congurazione Router/End Node); • 1x EB030 “Relay board”; • 1x EB004 “LED board”. Per quanto riguarda il nodo Coordinator, possiamo utilizzare una delle tante board di interfacciamento per nodi Xbee, come ad esempio la “Xbee explorer USB”, distribuita da Futura Elettronica. Quanto alle connessioni, dovremo collegare la EB051 sulla porta C (in modo da poter utilizzare la porta USART hardware per
c o r s o
F L O W
134
Febbraio 2014 ~ Elettronica In
C O D E
E D O C
W O L F o s r o c
Tabella 5
- Periodicità e descrizione dei task del software del nodo ZigBee slave. Task
Periodo [ms]
Descrizione
RxTask
1 (attivo), 1000 (riposo)
Riceve e decodica i dati sul canale wireless.
RelayTask
500
Attua lo stato dei relé impostato dai comando wireless.
EepromTask
100
Aggiorna i parametri su memoria non volatile.
LedTask
Impostabile
Gestisce il working LED.
parlare con il modulo Xbee), e la EB030 sulla porta D. Inne colleghiamo la EB004 sulla porta A. Non dimentichiamo che sia la EB051 che la EB030 necessitano anche dei collegamenti di alimentazione. In Fig. 8 sono rappresentati i collegamenti hardware dei vari E-block.
- TSK_EepromTaskCounter; - TSK_LedTaskCounter; - TSK_RxTaskCounter .
Non potendo analizzare tutti i task implementati in quanto una singola puntata non sarebbe sufciente, ci soffermeremo
Implementazione software
A questo punto possiamo iniziare ad esaminare i dettagli implementativi del software del nodo slave. Secondo le speciche che ci siamo forniti, il nodo slave deve essere in grado di gestire i 4 relé, prevedere una gestione della memoria non volatile, gestire il “working” LED (LED che segnala che il nodo è connesso alla rete ed operativo) e, naturalmente, gestire il protocollo applicazione che abbiamo descritto in precedenza. L’architettura utilizzata per l’implementazione del nodo prevede l’utilizzo di uno scheduler ad 1 ms, ed un totale di 4 task, riportati per completezza in Tabella 5, insieme alle relative periodicità. L’implementazione dello scheduler di sistema è del tutto simile a quella vista nella puntata 5, con la differenza che questa volta è stato impostato un interrupt sul timer 2 con periodo di 1ms, in modo da avere la granularità richiesta. Si noti la differenza di tempistiche del task RxTask. Questo è il task più delicato dell’intero sistema, e quello che occupa maggiori risorse. Si è quindi deciso di diminuire l’intervallo tra le chiamate quando non ci sono dati in transito sul canale wireless ed aumentarla al massimo durante la fase di ricezione attiva. Analizzeremo in seguito il meccanismo software implementato per ottenere questo comportamento. L’implementazione del main scheduler è riportata in Fig. 9. Come si può vedere, le chiamate ai vari task sono scandite dallo stato delle 4 variabili: - TSK_RelayTaskCounter;
Fig. 9 - System scheduler.
Elettronica In ~ Febbraio 2014
135
Fig. 10 – Task RxTask.
solo sui task più importanti. Prendiamo ad esempio il task RxTask, che esegue uno dei compiti più importanti del sistema, ossia la decodica del pacchetto dati inviato dal Coordinator. Poiché questo task risulta essere piuttosto pesante per la CPU durante l’esecuzione, anche senza pacchetti in arrivo, si è scelto di dargli una periodicità differente in caso di ricezione dati e non. In sostanza, in caso di assenza di attività RF il task esegue una volta al secondo, mentre se c’è attività sul canale radio, il tempo di esecuzione passa ad 1ms, in modo da decodicare immediatamente il pacchetto e passare nuovamente allo stato di attesa (con conseguente sovraccarico minimo della CPU). Questo tipo di comportamento è stato realizzato gestendo un ag globale denominato “IncomingPacket”, che può avere due valori: NEW_INCOMING_PACKET e NO_INCOMING_PACKET. Normalmente il valore è NO_INCOMING_PACKET, ma in caso di inizio di una procedura di ricezione, il task RxTask lo forza al valore NEW_INCOMING_PACKET no al termine della ricezione. Se andiamo a controllare la condizione di chiamata del task RxTask sullo scheduler, noteremo che essa vale: (TSK_RxTaskCounter >= TASK_RX_TIMEOUT) || (IncomingPacket = NEW_ INCOMING_PACKET) Ossia, se il valore di IncomingPacket è diverso da NEW_INCOMING_PACKET (situazione di attesa), il task viene eseguito con la sua periodicità classica (TASK_ RX_TIMEOUT), altrimenti si passa ad una esecuzione veloce ad ogni chiamata dello scheduler stesso (ossia una volta al ms). Lo schema a blocchi del task RxTask è riportato in Fig. 10. Come si può vedere dallo schema a blocchi, se c’è un byte in ricezione sul canale, lo si acquisisce facendo uso della macro Receive_Char(), messa a disposizione dal componente ZigBee. Dopo aver ricevuto il byte su un buffer di servizio, lo si sposta sul buffer di ricezione (e si aumenta l’indice associato al buffer) e si setta il ag IncomingPacket al valore NEW_INCOMING_
136
Febbraio 2014 ~ Elettronica In
PACKET. Contestualmente viene attivato un timer (PacketCheckTime) che rimane attivo per tutta la fase di trasmissione. Scopo del timer è evitare che pacchetti tronchi blocchino il task in attesa di una parte del pacchetto. Dopo 200ms si resetta tutto e si ricomincia daccapo. Inne, quando il pacchetto è ricevuto completamente si resettano contatori e ag e viene chiamata la funzione di decodica (RxDecodeFn). La RxDecodeFn è una funzione (non un task, quindi la sua esecuzione non è
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
periodica ma event tiggered) che ha il solo scopo di decodicare il pacchetto in ricezione e impostare correttamente il valore delle variabili globali afnchè gli altri task compiano correttamente i loro compiti. Lo schema a blocchi della RxDecodeFn è riportato in Fig. 11. Descriviamo brevemente l’implementazione. In pratica la prima operazione eseguita è l’assegnamento dei vari byte del pacchetto a delle speciche variabili, in maniera da agevolare la fase succes-
Function_Parameter2 = RxBuffer[.DEC_ PAR_2]
Il primo controllo effettuato è sulla prima parte del pacchetto, quella contenente l’indirizzo del nodo. Il controllo effettuato è il seguente: (NodeType = NODE_TYPE_SLAVE) && (Packet_IDMajor = EEP_Id_NodeMajor) && (Packet_IDMinor = EEP_Id_NodeMinor)
Quindi si controlla che il nodo sia uno slave (“S”) e che l’ID corrisponda con I valori caricati dalla memoria EEPROM.
Fig. 11 - Schema a blocchi della funzione RxDecodeFn.
siva. Nello specico viene utilizzato un blocco calcolo che esegue le seguenti assegnazioni: NodeType = RxBuffer[.DEC_NODE_TYPE] Packet_IDMajor = RxBuffer[.DEC_ID_ MAJ] Packet_IDMinor = RxBuffer[.DEC_ID_ MIN] Function_MainFunction = RxBuffer[.DEC_ MAIN_FUNCT] Function_Parameter1 = RxBuffer[.DEC_ PAR_1]
Se il controllo ha esito positivo si prosegue, altrimenti il pacchetto viene scartato. Dopo aver effettuato questo check preliminare si passa alla decodica dell’istruzione vera e propria del pacchetto. Prima di farlo però, si controlla se l’opzione Eco è attiva (EEP_Conf_EcoEnabled = ECO_ENABLED?) e, in caso positivo, si trasmette l’eco del pacchetto ricevuto. Successivamente, un blocco selezione multipla decodica il campo dati effettivo del pacchetto, impostando adeguatamente le variabili globali utilizzate dagli
Elettronica In ~ Febbraio 2014
137
Fig. 12 – Schema a blocchi del task RelayTask.
Fig. 13 - Schema a blocchi del task EepromTask.
altri task per l’esecuzione delle azioni speciche. In particolare, la sezione relativa al controllo dei relé, una volta vericato che il byte Function_MainFunction corrisponda al valore ASCII “R”, effettua le seguenti assegnazioni:
138
da aggiornare, si utilizza una variabile globale. Così, ad esempio, per aggiornare il parametro di congurazione relativo all’abilitazione dell’eco, il relativo blocco calcolo imposta:
RelayNumber = Function_Parameter1 RelayStatus = Function_Parameter2
EEP_Conf_EcoEnabled = Function_Parameter2 EepUpdateRequest = UPDATE_EEP_REQUEST
Queste informazioni vengono poi utilizzate dal task RelayTask per il controllo effettivo dei relé. Una parola a parte merita la gestione della memorizzazione dei parametri in EEPROM (questo riguarda, ad esempio, tutte le opzioni di congurazione). Tale gestione è demandata al relativo task, ma, anche in questo caso, per sapere se i parametri in memoria sono
EEP_Conf_EcoEnabled contiene il valore del parametro, mentre il ag EepUpdateRequest segnala al task EepromTask che deve essere eseguito un aggiornamento dei parametri in memoria. Passiamo ora ad esaminare il task di controllo dei relé, che risulterà di semplice comprensione, ora che è stata esaminata la logica di comunicazione tra i task. Lo
Febbraio 2014 ~ Elettronica In
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Fig. 14 - Esempio di comunicazione.
schema a blocchi del task RelayTask è riportato in Fig. 12. Questo task gira a 500ms e non fa altro che monitorare lo stato delle due variabili globali RelayNumber e RelayStatus. La prima dice qual è il relé da controllare, mentre la seconda ne indica lo stato. Come abbiamo potuto esaminare in precedenza, queste variabili sono impostate dal task RxTask, ed in particolare dalla RxDecodeFn. Una volta determinato il relé da controllare ed il suo stato si agisce opportunamente sulla porta D tramite dei blocchi di uscita. Vediamo adesso come viene gestita la memoria non volatile, elemento fondamentale nel funzionamento del sistema, dato che contiene l’indirizzo del nodo ed anche i parametri di congurazione. Ci sono diversi modi di gestire una memoria EEPROM in un progetto embedded, e la scelta della modalità non è mai una questione banale. In questo progetto si è deciso di utilizzare una gestione di tipo mirror. Ossia, i dati immagazzinati nella memoria EEPROM sono copiati in opportune locazioni di memoria RAM all’avvio del sistema (mirror della EEPROM). Se durante la vita operativa del sistema, uno di questi parametri cambia, viene avviata una procedura che aggiorna la EEPROM (il mirror viene ricopiato sulla EEPROM). In questo modo, al successivo riavvio verranno caricati i dati aggiornati. Quindi il blocco EEPROM all’interno di questo progetto è costituito da due parti distinte. Una funzione di inizializzazione, che copia il contenuto della EEPROM all’interno delle varia bili “mirror”, ed un task run time che si occupa dell’aggiornamento, quando necessario. La funzione di inizializzazione non è particolarmente complessa, quindi la tralasciamo. Esaminiamo invece il task, il cui schema a blocchi è riportato in Fig. 13. Come abbiamo spiegato in precedenza, il compito del task è quello di aggiornare i dati in EEPROM copiandovi il contenuto delle rispettive variabili “mirror”. Per evitare di gravare troppo sulla CPU i dati non sono copiati tutti insieme, ma è stata costruita una sequenza che copia un dato per ciclo di schedu-
ling, se la procedura è attiva. In questo modo riduciamo al minimo indispensa bile il carico di lavoro in fase di aggiornamento dei dati in EEPROM, al prezzo di un tempo complessivo maggiore per eseguire l’intera operazione. L’implementazione è molto semplice: all’inizio il task controlla se c’è stata una richiesta di aggiornamento della memoria non volatile (EepUpdateRequest = UPDATE_EEP_REQUEST?). In caso affermativo viene avviata la procedura e i dati sono salvati in sequenza, uno per ciclo. La sequenza è stata realizzata facendo uso di un blocco selezione multipla e di una variabile globale (EepromUpdateSequence). Al termine della sequenza viene resettato anche il ag EepUpdateRequest (EepUpdateRequest = UPDATE_EEP_ COMPLETE). Con quest’ultima analisi i task più signicativi sono stati analizzati. Possiamo adesso testare il nostro sistema, usando un qualsiasi programma terminale per comunicare con il coordinator. Per eseguire i nostri test abbiamo utilizzato X-CTU, il software fornito dalla Digi per lo congurazione dei radiomodem Xbee. In Fig. 14 è possibile vedere uno screenshot di comunicazione nel quale era stata precedentemente attivata la funzione eco (vengono attivati e poi disattivati in sequenza i quattro relé). In questa settima puntata abbiamo analizzato in dettaglio il componente ZigBee, oltre a presentare un progetto pratico di una certa complessità, che ci ha permesso di ssare alcuni importanti concetti visti nelle puntate precedenti. Nella prossima e ultima puntata analizzeremo (e proveremo con un progetto pratico) i componenti g TCP/IP e il Webserver.
Elettronica In ~ Febbraio 2014
139
E D O C
W O L F o s r o c
Concludiamo il nostro viaggio alla scoperta di Flowcode, l’innovativo sistema di sviluppo grafico per microcontrollori che consente di scrivere il codice facendo uso di oggetti grafici. In questa ottava ed ultima puntata spiegheremo come connettere all’ethernet sistemi embedded mediante protocollo TCP/IP.
corso di programmazione in
FLOWCODE di Francesco Ficili e Daniele Defilippi
ella scorsa puntata abbiamo introdotto la periferica wireless che consente la comunicazione secondo lo standard ZigBee, ed illustrato la relativa implementazione in owcode. Ora, a conclusione del corso, parleremo di come realizzare sistemi embedded connessi alla rete ethernet, in grado di gestire protocolli complessi come quello TCP/IP. Questo tema ci apre le porte alla gestione e alla realizzazione di sistemi domotici che oggigiorno tendono ad essere sempre più connessi alla rete globale del world wide web. Inizieremo il nostro percorso parlando del protocollo TCP/IP e al termine della puntata realizzeremo in pochi semplici
N
passi un Web Server integrato in grado di inviare dati dinamici sulla rete. Sviluppo di applicazioni Internet con Flowcode
Gestire sistemi integrati connessi alla rete Ethernet è molto complesso ed implica una profonda conoscenza di molteplici protocolli di comunicazione, ma Flowcode ci mette a disposizione i componenti necessari per risolvere questo problema in modo semplice e intuitivo. Mediante i componenti TCP/IP, UDP e WebServer possiamo realizzare praticamente qualsiasi applicazione che contempli una comunicazione ethernet senza costringerci ad approfondir-
Elettronica In ~ Marzo 2014
129
ne tutte le problematiche. I componenti in libreria ci permettono di gestire l’integrato W5100, grazie al quale ci si può connettere direttamente alla Ethernet. Come punto di partenza iniziamo ad esaminare il protocollo TCP/IP. Il protocollo TCP/IP
TCP/IP è l’acronimo di “Transmission Control Protocol / Internet Protocol ”; il protocollo corrispondente racchiude tutte le speciche necessarie per comunicare correttamente attraverso la rete Internet. È suddiviso in strati detti “Layer” (Fig. 1). Ciascuno dei layer dipende da quello che sta al di sotto e può comunicare solamente con quelli connanti; ognuno ha un compito differente e i pacchetti, durante il transito verso gli strati inferiori, vengono sempre più incapsulati e, viceversa, man mano che risalgono vengono ripuliti dai dati di incapsulamento non più necessari. Questo tipo di architettura permette di poter trasferire in modo “sicuro” i dati tra un calcolatore ed un altro. Il protocollo IP si occupa della corretta ricezione/trasmissione di dati; attualmente esistono due versioni di IP: IPv4 e IPv6. La differenza principale tra i due è il numero di byte utilizzati per codicare in modo univoco gli indirizzi di rete. Il protocollo TCP è invece incaricato del riordino dei pacchetti e della ricomposizione del dato originale senza perdita di dati. Ogni computer è identicato da un indirizzo IP che lo identica in modo univoco all’interno della rete internet. L’assegnazione di questo indirizzo può essere di tipo dinamico oppure statico; solitamente possiamo decidere se assegnarne uno di un tipo oppure di un altro perché, essendo collegati ad un ISP (Internet Service Provider), l’indirizzo effettivo visto dalla rete sarà quello dell’ISP e non quello scelto da noi. Quando vogliamo raggiungere un calcolatore collegato a Internet mediante un browser, digitiamo un nome, ad esempio www.futuranet.it, e questo, mediante il servizio di DNS, verrà trasformato nel corrispondente indirizzo IP utilizzabile con il protocollo TCP/IP. Questo processo permette così di utilizzare dei nomi che sono più facili da ricordare rispetto ad una sequenza di 4 o 6 numeri a tre cifre.
130
Marzo 2014 ~ Elettronica In
Fig. 1 Suddivisione in Layer del protocollo TCP/IP.
Dato che l’indirizzo IP può cambiare in modo dinamico, è necessario basarsi su un qualcosa di sso ed immutabile che possa identicare un sistema connesso sulla rete. Per questa ragione è utilizzato l’indirizzo MAC: esso è univoco per ogni scheda in grado di collegarsi alla rete ed è perciò ssato in fase di produzione della scheda ed assegnato in modo automatico a ne linea. Tornando al livello più alto, possiamo trovare un ulteriore livello di astrazione: le cosiddette “porte” di comunicazione. Ogni porta è adibita ad un particolare tipo di protocollo ma è possibile utilizzarle anche in modo differente; quella più nota e comunemente utilizzata è la 80, usata per la comunicazione http, ma ve ne sono altre come la 20,21 per l’FTP, la 53 per il DNS e molte altre ancora. Con queste nozioni basilari possiamo ora accingerci ad esaminare il componente che Flowcode ci mette a disposizione per gestire il protocollo TCP/IP, UDP e MAC. Il componente TCP/IP per Flowcode
Nella barra dei componenti nel menu “Periferiche” troviamo il componente TCP/IP che ci permette di gestire i protocolli TCP/ IP, UDP e MAC. Per poterlo utilizzare è sufciente inserirlo nel pannello e successivamente procedere alla congurazione. In Fig. 2 è mostrata l’unica pagina di congurazione delle proprietà del componente. Innanzitutto dobbiamo scegliere quale versione della scheda EB023 abbiamo a disposizione; troviamo facilmente questa indicazione sulla scheda che abbiamo acquistato (se stiamo realizzando una scheda custom, la deduciamo dal componente utilizzato). È ora necessario inserire le informazioni riguardanti la connessione di rete.
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Tabella 1 - Macro utilizzabili con il componente TCP/IP Nome macro
Descrizione
Initialize
Resetta ed inizializza la periferica Ethernet.
Create_MAC_Socket
Chiamando questa macro, viene creato un socket in grado di ricevere i dati trasmessi sulla rete ethernet. I mpostando ad uno il valore del parametro: - Promiscuous mode per leggere tutto il trafco circolante sulla rete senza tener conto dell’indirizzo MAC; - Broadcast mode per leggere anche i pacchetti di tipo Broadcast; - Error mode per ricevere anche i pacchetti che contengono errori. Il valore di ritorno, se diverso da zero, indica che l’operazione di congurazione è andata a buon ne.
Create_UDP_Socket
La macro crea un socket per la ricetrasmissione di dati mediante il protocollo UDP. É necessario indicare come parametri: - Channel, ossia il canale scelto per la comunicazione (da 0 a 3); è possibile utilizzare contemporaneamente canali congurati in modo dif ferente n ad un massimo di quattro; - l’indirizzo della porta sorgente suddiviso in src_port_hi e src_port_lo. Il valore di ritorno, se diverso da zero, indica che l’operazione di congurazione è andata a buon ne.
Create_IP_Socket
Crea un socket per la ricetrasmissione di dati mediante il protocollo IP. È necessario indicare il canale scelto (channel) e il protocollo che si intende realizzare mediante il set dei due parametri interni alla macro. Il valore di ritorno, se diverso da zero, indica che l’operazione di congurazione è andata a buon ne.
Create_TCP_Socket
Crea un socket di tipo TCP. Necessita delle stesse congurazioni utilizzate con la macro Create_UDP_Socket.
Set_Destination
É utilizzata con socket di tipo IP e UDP e serve per impostare l’indirizzo IP e la porta verso il quale si vogliono trasmettere i dati. Richiede come parametri il canale, l’indirizzo IP e la porta di destinazione. Per connessioni di tipo IP non è necessario indicare la porta.
Set_My_IP
Questa macro è utilizzata per modicare, durante l’esecuzione, l’indirizzo IP del dispositivo; non è necessaria se si desidera mantenere l’indirizzo IP inserito nella nestra di congurazione del componente.
GetSocketStatus
La macro restituisce lo stato attuale del socket. I valori possibili sono diciannove, ma quelli principali sono i seguenti: - 0 (SOCK_CLOSED) = il socket è chiuso (non sono né trasmessi né ricevuti dati); - 6 (SOCK_ESTABLISHED) = il socket è pronto e la comunicazione è attiva in modalità passiva; - 7 (SOCK_CLOSE_WAIT) = il socket è in fase di chiusura; - 14 (SOCK_INIT) = il socket è in fase di inizializzazione.
TCP_Listen
Imposta il canale scelto (indicato come parametro) in modalità passiva in modo che possa essere pronto a ricevere dei dati.
TCP_Connect
Imposta il canale scelto (indicato come parametro) in modalità attiva in modo che possa essere pronto per trasmettere dei dati sul canale di comunicazione. Necessita come parametri il valore del canale, l’indirizzo IP e la porta di destinazione. Se il valore restituito è differente da zero vuol dire che la comunicazione è stata stabilita con successo e che possono quindi essere trasmessi dei dati.
TCP_Close
Chiude la connessione TCP mediante un’operazione attiva e porta il socket in attesa di terminazione.
Tx_start
Avvia la trasmissione di dati sul canale specicato dai parametri ma, per funzionare correttamente necessita delle macro successive (Tx_sendbyte, Tx_sendmymac, Tx_sendmymac e Tx_end) . La sequenza corretta inizia con un comando di Tx_start, prosegue con sequenze di Tx_sendbyte, Tx_sendmymac, Tx_sendmymac nell’ordine prescelto (può anche solo essere utilizzata una sola macro delle tre) e termina con Tx_end per effettuare l’invio dei dati sul canale di comunicazione.
(segue)
In base alla tipologia di rete impostiamo l’indirizzo IP, che deve essere di tipo statico, e la Subnet Mask. Il gateway Address deve essere impostato uguale all’indirizzo del “router” o del modem con il quale si accede a Internet, almeno se vogliamo inviare pacchetti al di fuori della rete LAN; qualora questo indirizzo fosse sbagliato, non sareb be possibile comunicare con computer non direttamente collegati a Intranet. Il settaggio dell’indirizzo MAC (Hardware Address) è la parte più delicata: tale valore dovrebbe essere univoco sull’intera rete Internet. Per fare delle prove all’interno della rete LAN possiamo impostarlo ad un valore qualsiasi: basta che differisca da quello di tutte le altre schede di rete wireless ed ethernet affacciate su di essa. Per utilizzarlo su Internet bisogna essere certi di assegnare un indirizzo che non corrisponda ad alcuna periferica ethernet affacciata al momento su Internet nel
mondo; il modo migliore per fare ciò è prendere l’indirizzo di una scheda di rete attualmente non utilizzata, così si è certi che il relativo IP non sia attivo. Ulteriore passo è la congurazione delle connessioni; per poter funzionare correttamente è necessario impostare i pin sul quale vengono mappati il piedino di interrupt ed il c.s. Questa congurazione varierà in base a come colleghiamo la scheda alla nostra piattaforma oppure su come realizziamo il PCB in caso di progetti Custom. Passiamo ora ad esaminare le macro che Flowcode ci mette a disposizione per gestire le comunicazioni su rete ethernet. Nella Tabella 1 sono descritte le principali. Queste macro permettono di gestire in modo molto semplice comunicazioni sulla rete ethernet utilizzando socket a differenti livelli: MAC, UDP e TCP/IP. Il componente TCP/IP è quello che ci permette di gestire i principali protocol-
Elettronica In ~ Marzo 2014
131
Tabella 1 - Macro utilizzabili con il componente TCP/IP (seguito) Nome macro
Descrizione
Tx_sendbyte
Invia i dati al buffer di trasmissione per il canale specico. Oltre al canale deve essere indicato il parametro di dato. Come dato possono anche essere utilizzate stringhe.
Tx_sendmymac
Invia nel buffer di t rasmissione, del canale selezionato, l’indirizzo MAC attuale della scheda.
Tx_sendmyip
Invia nel buffer di t rasmissione, del canale selezionato, l’indirizzo IP impostato nella nestra di congurazione della scheda.
Tx_end
È la macro che permette di inviare sicamente I dati sulla linea di comunicazione.
Rx_data_available
Controlla se vi sono dati disponibili nel buffer di ricezione del canale. Il valore di ritorno, se differente da zero, indica che vi sono dati disponibili. Questa macro è anche utilizzata per inizializzare il buffer per la ricezione dei dati qualora non lo fosse già. In pratica azzera l’indice con il quale viene scandito il buffer con la macro Rx_data_size.
Rx_data_size
Macro utilizzata per sapere quanti byte sono disponibili all’interno del buffer di ricezione.
Rx_readheader
Macro utilizzata per leggere l’header dei dati ricevuti. Richiede come parametri di ingresso il canale di comunicazione e l’indice idx del byte che si vuole leggere. In base al tipo di comunicazione utilizzata sul canale scelto si possono avere le informazioni seguenti. - UDP mode ● Idx 0 - 1: Dimensione del pacchetto (MSB idx=0); ● Idx 2 - 5: Indirizzo IP sorgente (MSB idx=2); ● Idx 6 - 7: indirizzo della porta (MSB idx=7). - IP mode ● Header size = 6; ● Idx 0 - 1: Dimensione del pacchetto (MSB idx=0); ● Idx 2 - 5: Indirizzo IP sorgente (MSB idx=2). - MAC mode ● Header size = 3; ● Idx 0 - 1: Dimensione del pacchetto (MSB idx=0); ● Idx 2: Stato del pacchetto ricevuto: ■ Bit 7 = 1 indica che il MAC di destinazione equivale all’indirizzo della scheda; ■ Bit 5 = 1 indica che l’indirizzo è di tipo broadcast; ■ Bit 4 = 1 indica che il pacchetto contiene degli errori.
Rx_readbyte
Legge dal buffer di ricezione del canale scelto un byte che viene restituito come valore di ritorno.
Rx_skipbytes
Permette di “saltare” dei dati dal buffer di ricezione.
Rx_match2bytes Rx_match4bytes Rx_match6bytes
Legge 2/4/6 byte dal buffer di ricezione e li confronta con quelle indicate nei parametri con la quale viene chiamata. Restituisce un valore differente da zero se i valori coincidono.
Rx_match_mymac
Legge 6 byte dal buffer di ricezione e li confronta con l’indirizzo MAC con il quale è stata congurata la scheda. Restituisce un valore differente da zero se i valori coincidono.
Rx_match_myip
Legge 4 byte dal buffer di ricezione e li confronta con l’indirizzo IP con il quale è stat a congurata la scheda. Restituisce un valore differente da zero se i valori coincidono.
li di comunicazione su rete ethernet, tuttavia per realizzare un Web Server in modo ancora più semplice abbiamo a disposizione un componente specico; tale componente, a patto di sottostare ad alcune limitazioni, ci permette di realizzare il Web Server in modo ancora più semplice e intuitivo.
Fig. 2 - Finestra delle prop rietà del componente TCP/IP.
132
Marzo 2014 ~ Elettronica In
Il componente Webserver
La maniera più immediata per poter comunicare con sistemi remoti, anche a migliaia di chilometri di distanza, è quello di utilizzare semplici pagine web, perché necessitano unicamente che entrambi i sistemi siano connessi alla rete Internet. L’intero sistema è veramente economico ed è molto intuitivo da utilizzare. Realizzare un Web Server su un calcolatore è ab bastanza semplice, ma su una piattaforma embedded con potenza di calcolo limitata diventa assai più complesso. Per queste ragioni, Flowcode ci viene in soccorso fornendoci un componente specico che troviamo nella barra dei componenti nel menu “Periferiche” con il nome Webserver. Nelle puntate precedenti abbiamo visto come periferiche o sistemi molto complessi possano essere realizzati in modo molto semplice grazie all’utilizzo del programma; è così anche in questo caso. Come
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Tabella 2 - Macro utilizzabili con il componente WebServer Nome macro
Descrizione
Initialize
Resetta ed inizializza la periferica Ethernet. Questa macro deve essere chiamata prima di ogni qualsiasi altra macro per la gestione del Web Server.
CreateServerSocket
La macro crea un socket per la ricetrasmissione di dati su Web Server. É necessario indicare come parametri: - Channel il canale scelto per la comunicazione comunicazione (da 0 a 3); è possibile utilizzare contemporaneam contemporaneamente ente canali congurati in modo differente n ad un massimo di quattro; - l’indirizzo della porta dal quale quale trasmettere e ricevere i dati dati suddiviso in src_port_hi src_port_hi e src_port_lo. src_port_lo. Il valore di ritorno, se diverso da zero, indica che l’operazione di congurazione è andata a buon ne.
CheckSocketActivity
Richiede in ingresso il canale sul quale si vuole effettuare il controllo di attività. Deve periodicamente periodicamente essere richiamata in modo da permettere la gestione delle richieste entranti.
vediamo in Fig. 3, la nestra di congurazione del componente è semplice e intuitiva: notiamo che è esattamente identica al componente TCP/IP e quindi può essere congurata allo stesso modo. Ciò è dovuto al fatto che il componente webserver non
Fig. 3 - Proprietà del componente Webserver.
remoto. Il codice deve essere compatibile con lo standard HTML, ma ciò non vieta di inserire comandi JavaScript o altri linguaggi interpretati dal browser remoto. La caratteristica fondamentale del componente Webserver è la possibilità, che offre, di inserire nel codice HTML il valore dinamico di alcune variabili; in questo modo è possibile monitorare da remoto le variabili volute (al massimo quattro). Allo scopo basta fare riferimento, all’interno del codice HTML, al nome della variabile, inserendolo tra %. I nomi delle variabili utilizzabili sono quindi B001, B002, B003 e B004. Vi sono alcune limitazioni sulla tipologia delle variabili scelte perché non possono essere di tipo stringa o virgola mobile. Nell’esempio pratico utilizzeremo questo semplice stratagemma allo scopo di realizzare una centralina per il monitoraggio della temperatura. Progetto Pratico: Centralina per il monitoraggio della temperatura mediante Web Server
Fig. 4 - Proprietà del componente Webserver per la descrizione delle pagine HTML.
è altro che un gestore precongurato di pagine web basato su TCP/IP. Le differenze risiedono nei successivi tab di congurazione, mostrati in Fig. 4. In alto dobbiamo inserire il nome delle pagine, mentre nello spazio centrale è necessario editare il codice che intendiamo visualizzare sulla pagina richiesta da
Il Web Server integrato che realizzeremo ci permetterà di monitorare da remoto, tramite una connessione a Internet, le ultime quattro temperature misurate dal nostro sistema. Per realizzare il progetto abbiamo bisogno dei seguenti componenti: - EB006 “USB PICmicromultiprogrammer PICmicromultiprogrammer-board” (PIC18F4685 e quarzo 19,6608 MHz); - EB023 “Internet board”; - EB016 “Prototype board”; - sensore di temperatura LM35. Colleghiamo le schede come mostrato in Fig. 5 posizionando la scheda EB023 sulla porta C e la scheda di prototipazione EB016 sulle porte A e B. Alimentiamo il sensore, come indicato nella seconda
Elettronica In ~ Marzo 2014
133
Listato 1 Esempio web-server web-server <script language=JavaScript type=”text/javascript”> type=”text/javascript”> var Temperature = new Array(); Temperature[0] = %BOO1% - 128; Temperature[1] = %BOO2% - 128; Temperature[2] = %BOO3% - 128; Temperature[3] = %BOO4% - 128;
function Temp(x) { if (x/20<=1) return Temperature[0]; else if (x/20<=2) return Temperature[1]; else if (x/20<=3) return Temperature[2]; else return Temperature[3]; }
Fig. 5 Connessione delle schede per realizzare la centralina di monitoraggio temperatura.
function funGraph (ctx,axes,func,color,thick) { var xx, yy, dx=1, x0=axes.x0, y0=axes.y0, scale=axes.scale;
var iMax = Math.round((ctx.canvas.width-x0) Math.round((ctx.canvas.width-x0)/dx); /dx); var iMin = axes.doNegativeX ? Math.round(-x0/dx) : 0; ctx.beginPath(); ctx.lineWidth = thick; ctx.strokeStyle = color; for (var i=iMin;i<=iMax;i++) { xx = dx*i; yy = scale*func(xx/scale); if (i==iMin) ctx.moveTo(x0+xx,y0-yy); else ctx.lineTo(x0+xx,y0-yy); } ctx.stroke(); }
// Disegna gli assi function showAxes(ctx,axes) { var x0=axes.x0,w=ctx.canvas.width; scale=axes.scale; var y0=axes.y0, h=ctx.canvas.height; var xmin = axes.doNegativeX ? 0 : x0; var Hline = 0; ctx.beginPath(); ctx.strokeStyle = “rgb(128,128,128)”; ctx.moveTo(xmin,y0); ctx.lineTo(w,y0); ctx.moveTo(x0,0); ctx.lineTo(x0,h);
// X axis axis // Y axis
ctx.stroke(); ctx.beginPath(); ctx.lineWidth = 1; ctx.strokeStyle = “rgb(128,128,128)”; for (var i=-20;i<=50;i= i + 10) { yy = i*scale; ctx.moveTo(xmin-5,y0-yy); ctx.lineTo(w,y0-yy); ctx.font=”15px Georgia”; ctx.strokeText(i + “°C”,xmin-50,y0-yy+5);
(segue)
puntata per la realizzazione del termometro LCD, e colleghiamo l’uscita alla porta A piedino numero 2 in modo da stimolare il canale analogico An2 del microcontrollore. Conguriamo il progetto in modo da ottenere una frequenza di clock del PIC pari a 19.660.800 Hz, impostando i parametri come mostrato in Fig. 6. Ora che l’hardware è pronto possiamo
134
Marzo 2014 ~ Elettronica In
Fig. 6 - Configurazion Configurazione e del componente.
Tabella 3 - Dati di confgurazione componente WebServer GatewayAddress
192.168.0.10
SubnetMask
255.255.255.0
IP Address
192.168.0.5
HardwareAddress
0:8:220:0:0:0 1
Maximum number of WebPages
dedicarci alla stesura del diagramma di controllo. Inseriamo quindi dalla barra dei componenti il componente Webserver e il componente ADC congurato in modo che legga l’ingresso An2 collegato al sensore di temperatura LM35. Passiamo ora ad impostare il componente Webserver: indichiamo i seguenti valori all’interno dei parametri (Tabella 3). Il codice html che verrà visualizzato sulla
c o r s o
F L O W
C O D E
E D O C
W O L F o s r o c
Listato 1 (seguito) } ctx.stroke(); ctx.beginPath(); ctx.lineWidth = 3; ctx.strokeStyle = “rgb(80,80,80)”; yy = 0; ctx.moveTo(xmin,y0-yy); ctx.lineTo(w,y0-yy); ctx.stroke(); } function draw() { var canvas = document.getElementById(“canvas”); if (null==canvas || !canvas.getContext) return; // Imposta l’area di disegno var axes={}, ctx=canvas.getContext(“2d”); axes.x0 = 50; //.5 + .5*canvas.width; // x0 pixels from left to x=0 axes.y0 = 12/16*canvas.height; //.5 + .5*canvas.height; // y0 pixels from top to y=0 axes.scale = 7; // 7 pixels from x=0 to x=1 axes.doNegativeX = false showAxes(ctx,axes); funGraph(ctx,axes,Temp,”rgb(66,44,255)”,4); funGraph(ctx,axes,Temp,”rgb(66,44 ,255)”,4); } function clear(ctx) { ctx.llStyle = “rgb(255,255,255)”; ctx.llRect(0, 0, 500, 500); } <script> size=”+2”> Temperature misurate
Web size=”-2”>Web Server by
ElettronicaIN href=”http://www.eletronicain.it/”>ElettronicaIN
pagina deve essere indicato nel tab Web page 1 con il titolo index.htm. Il testo del codice html che ci permette di visualizzare le ultime quattro temperature e plottarne il graco è contenuto nel Listato 1; per poterlo utilizzare ci basterà inserirlo (mediante copia/incolla) all’interno della nestra di congurazione della pagina. Dato che abbiamo da svolgere due task principali, possiamo dividere il nostro usso di programma in due macro. La prima, il main in Fig. 8, si occuperà di inizializzare il sistema e controllare le richieste del socket al quale è collegato il webserver, mentre la seconda macro in Fig. 7, chiamata dall’interrupt del timer, si occuperà della lettura periodica del sensore di temperatura e dell’aggiornamento dell’array di temperature da visualizzare in remoto. Le variabili utilizzate sono quelle descritte qui di seguito.
- ContatoreTimer di tipo Grande+ inizializzato a -1 in modo da forzare la lettura della temperatura all’accensione del sistema. - ADC_Temp di tipo Virgola mobile per poter leggere la tensione del sensore LM35. - Temperatura_1 / Temperatura_4 di tipo intero per la memorizzazione delle temperature. - B001 / B004 di tipo intero per la visualizzazione sulla pagina HTML dei valori di temperatura. Sono state inoltre utilizzate due costanti globali per la conversione degli impulsi del timer in valori di tempo: - IMPULSI_OGNI_SECONDO vale 75 perché la frequenza di interrupt del timer0 è pressata a 75 Hz (questo valore è dovuto al fatto che il prescaler del
Elettronica In ~ Marzo 2014
135
tuito, con alcune limitazioni, è fornito ad esempio da www.dyndns.it. Basterà quindi congurare il modem in modo da comunicare correttamente con uno di questi server, scegliere l’acronimo con il quale verrà identicato il nostro sistema embedded ed il gioco è fatto: abbiamo reso accessibili, da qualsiasi parte del mondo, i dati forniti dalla nostra scheda embedded. Utilizzare MPLAB per integrare il codice generato da Flowcode
Utilizzare Flowcode per realizzare progetti sempre più complessi porta ad un incremento della difcoltà del debug del codice generato soprattutto se vi sono blocchi con all’interno del codice C. Il De bugger classico di Flowcode ci permette di monitorare le variabili e gli stati del sistema ma non è possibile, in alcun modo,
Fig. 7 - Macro per la lettura della temperatura ogni quattro ore.
timer è ssato a 256 e l’oscillatore è congurato per lavorare a 19.660.800 Hz; - SECONDI_OGNI_ORA vale 3600 ed è la costante che permette di sapere quanti secondi vi sono per ogni ora. Per poter effettuare un semplice test, possiamo collegare il sistema mediante il cavo ethernet al router con il quale ci connettiamo in rete e dal browser del nostro computer e digitare l’indirizzo del Web Server, che in questo caso è 192.168.0.5. La pagina che si aprirà è mostrata in Fig. 9. Permettere l’accesso del web server dall’esterno della nostra rete locale è più complicato, perché implica l’ottenimento di un IP sso oppure poter avere a disposizione un modem in grado di utilizzare servizi di DNS dinamico. Un servizio gra-
136
Marzo 2014 ~ Elettronica In
c o r s o
Fig. 8 - Flusso principale di programma.
F L O W
C O D E
Il linguaggio HTML
E D O C
W O L F o s r o c
Fig. 9 - Pagina inviata dal Web Server.
visualizzare direttamente i registri del microcontrollore. Per queste operazioni, che potrebbero risultare complesse per un principiante, ma che sono essenziali per un utilizzatore esperto, possiamo avvalerci di MPLAB e del compilatore C BoostC. Sono entrambi scaricabili da Internet in versione free rispettivamente all’indirizzo www. microchip.com e www.sourceboost.com. Per integrare i due sistemi è necessario prestare molta attenzione ai passi con il quale viene istallato il compilatore: per prima cosa occorre installare, se non già presente, MPLAB IDE, quindi il compilatore BoostC, seguendo attentamente la procedura. Al passo in cui viene visualizzata l’immagine in Fig. 11 è necessario scegliere la cartella dove è stato installato MPLAB IDE e fare clic sul pulsante “Integrate”; solo in questo modo sarà possibile scegliere dall’IDE il compilatore BoostC. Al termine dell’installazione è necessario aprire MPLAB IDE e impostare, dal menu Project->Set Language Tool Locations , correttamente le informazioni sul compilatore, come indicato in Fig. 12 e Fig. 13. Impostare anche gli altri indirizzi per il “BoostC Compiler for PIC18” per poterlo utilizzare anche su microcontrollori della famiglia 18. In questo caso, bisogna scegliere il boostc_pic18.exe. Utilizzando la versione gratuita di BoostC si possono compilare solo progetti che non superino i limiti di memoria RAM e ROM, mentre con la versione PRO, acquistabile dal produttore, non vi sono limitazioni di alcun tipo. Prendiamo come esempio il diagramma che abbiamo realizzato nella puntata 4 per pilotare dei relé tramite RS232. Apriamo MPLAB IDE e dal menu scegliamo il
Il linguaggio HTML, acronimo di HyperText Markup Language, è il linguaggio base con le quali vengono realizzate le pagine web. È basato sull’utilizzo di Tag che permettono di formattare il testo nel modo desiderato. Non può essere considerato un linguaggio di programmazione perché non possono essere definite alcune variabili e cicli di controllo ma unicamente un linguaggio di formattazione testuale. Per ovviare a questa limitazione è però possibile inserire all’interno della pagina dei contenuti esterni come immagini, video o script in altri linguaggio di programmazione come ad esempio il JavaScript. I tag sono racchiusi tra parentesi angolate ed ogni volta che un tag viene aperto deve poi anche essere chiuso inserendo prima del nome la barra. Ad esempio, per inserire il testo “Testo formattato” in grassetto dovremo scrivere:
Fig. 10 Pagina inviata dal Web Server. Testo Formattato
La struttura base di un file Html è raffigurata in Figura 10. Partendo dalla testa del file, si ha una descrizione del documento, alcune informazioni di servizio ed il corpo del documento nel quale viene formattato l’intero contenuto della pagina. Figura 10 - Struttura base di un file HTML
Per vedere alcuni esempi di codice HTML basta che apriamo una pagina web e, nel caso il browser sia Firefox, cliccare con il tasto destro sull’area ce ntrale e scegliere dal menu “Visualizza sorgente pagina”.
Project->Project Wizard per creare un nuovo
progetto; scegliamo il microcontrollore che avevamo scelto in Flowcode (il PIC18F4580), impostiamo come compilatore il BoostC per i pic della famiglia 18 ed aggiungiamo il le Rs232.c generato da Flowcode.
Elettronica In ~ Marzo 2014
137