Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati...

46
Capitolo VII Progetto di macchine con numero finito di stati 7.1. Introduzione Obiettivo fondamentale dei capitoli sviluppati finora è stata la descri- zione e l'impiego di periferiche del μC per la risoluzione di diversi problemi pratici. Nel presente capitolo si vuole invece indicare una metodologia di progetto di sistemi il cui lavoro è basato su algoritmi che prevedano l'uso di una macchina a stati, nel seguito denominata FSM, Finite State Machine. Il metodo prevede l'uso di due tecniche piuttosto simili tra loro. Con la prima tecnica si sfrutta la possibilità di disporre di puntatori a funzioni che rappresentano, poi, i diversi stati in cui può “transitare” la FSM. La seconda tecnica prevede invece l'u- so dell'istruzione switch con cui “selezionare” la sezione di codice che si riferisce al lavoro che la FSM deve svolgere nel particolare stato. Il metodo qui esposto si rivela particolarmente utile nel caso di ap- parati in cui siano implementati processi relativamente complessi, adatto alla sintesi di qualunque FSM. Lo sviluppo del progetto si limi- ta essenzialmente alla sola definizione attenta e completa del diagram- ma degli stati della FSM. Con un problema le cui specifiche e requisiti siano ben posti, è possibile definire l'intero codice in poco tempo. Gli esempi illustrati nel capitolo sono piuttosto semplificati e relativi a si- stemi di complessità poco elevata. Tuttavia, si potranno ben apprezza- re le potenzialità della metodologia e sviluppare facilmente progetti personali anche molto elaborati. 329

Transcript of Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati...

Page 1: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Progetto di macchinecon numero finito di stati

7.1. Introduzione

Obiettivo fondamentale dei capitoli sviluppati finora è stata la descri-zione e l'impiego di periferiche del μC per la risoluzione di diversi problemi pratici. Nel presente capitolo si vuole invece indicare una metodologia di progetto di sistemi il cui lavoro è basato su algoritmi che prevedano l'uso di una macchina a stati, nel seguito denominata FSM, Finite State Machine. Il metodo prevede l'uso di due tecniche piuttosto simili tra loro. Con la prima tecnica si sfrutta la possibilità di disporre di puntatori a funzioni che rappresentano, poi, i diversi stati in cui può “transitare” la FSM. La seconda tecnica prevede invece l'u-so dell'istruzione switch con cui “selezionare” la sezione di codice che si riferisce al lavoro che la FSM deve svolgere nel particolare stato.

Il metodo qui esposto si rivela particolarmente utile nel caso di ap-parati in cui siano implementati processi relativamente complessi, adatto alla sintesi di qualunque FSM. Lo sviluppo del progetto si limi-ta essenzialmente alla sola definizione attenta e completa del diagram-ma degli stati della FSM. Con un problema le cui specifiche e requisiti siano ben posti, è possibile definire l'intero codice in poco tempo. Gli esempi illustrati nel capitolo sono piuttosto semplificati e relativi a si-stemi di complessità poco elevata. Tuttavia, si potranno ben apprezza-re le potenzialità della metodologia e sviluppare facilmente progetti personali anche molto elaborati.

329

Page 2: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

7.2. Rappresentazione di una macchina a stati

Si consideri un semplice apparato in grado di fornire un certo numero di valori in uscita che dipendano dall'attivazione di alcune linee d'in-gresso. Il dimostrativo adottato in questo primo esempio segue lo schema di montaggio di Fig. 7.1. L'LCD è utilizzato per visualizzare lo stato delle possibili uscite, mentre gli ingressi sono costituiti da due soli pulsanti. Il μC è sfruttato come semplice generatore di sequenza. Le uscite possono infatti seguire la prefissata sequenza dei tre valori: “output 0”1, “output 1” e “output 2”, passando da uno al successivo ogni volta che si preme il tasto di destra, 'INC'. Viceversa, ogni volta che viene premuto il tasto di sinistra, 'DEC', dal valore attuale dell'u-scita si passa a quello precedente della sequenza. I due pulsanti sono collegati alle linee EINT0 (P0.16) ed EINT2 (P0.15) del μC2.

Figura 7.1. Schema di montaggio per il generatore di sequenza. Il collega-mento tratteggiato può essere omesso.

1 Il valore “output 0” per l'uscita deve essere presentato dal sistema ogni volta che si attiva la linea di reset. Lo stato che si ha è detto ground state.

2 Come indicato nel Cap. 4, è spesso conveniente far sì che alla pressione di un ta-sto corrisponda la generazione di un interrupt. In alternativa, lo stato dell'ingres-so potrebbe essere rivelato interrogando la GPIO (con tecnica di polling). Si ri-manda al capitolo citato per valutare gli eventuali pregi che si ottengono con una gestione che usi le interruzioni del processore.

330

Page 3: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Anche se il sistema qui descritto è piuttosto semplice, per sottoli-neare l'importanza di una descrizione completa e priva, per quanto possibile, di ambiguità, vengono qui di seguito elencate le specifiche e i requisiti relativi al problema in esame:

Generatore di sequenzaDefinizione delle configurazioni di uscita:

1) “output 0”;2) “output 1”;3) “output 2”.

Definizione degli ingressi:1) tasto 'INC';2) tasto 'DEC'.

Requisiti di funzionamento:1) al reset la macchina deve presentare la configurazione d'uscita

“output 0” (ground state)3;2) alla pressione del tasto 'INC' la FSM passa da “output i” a “out-

put i+1”, a eccezione del caso i = 2 in cui si passa a “output 0”;alla pressione del trasto 'DEC' la FSM passa da “output i” a “out-put i-1”, a eccezione del caso i = 0 in cui si passa a “output 2”;

3) nel caso in cui nessun tasto sia premuto la FSM deve permane-re nell'ultimo stato raggiunto;

4) la pressione contemporanea di 'INC' e 'DEC' è una configurazio-ne d'ingresso non permessa4.

Sebbene la descrizione, nel caso specifico, possa apparire inutil-mente dettagliata, è utile formalizzare con cura i requisiti e le specifi-che del tipo sopra riportato. In questo modo, l'interpretazione del pro-blema potrà concorrere alla corretta sintesi della macchina voluta in un modo più agevole. La metodologia sarà meglio apprezzata qualora il problema sotto esame risulti più complesso di quelli esposti in que-sto e nei successivi paragrafi del presente capitolo.

Per prima cosa viene qui definito il lavoro che le due routine di ser-vizio dell'IRQ dovranno svolgere e che risulta comune agli altri pro-getti del capitolo. Come fatto in altri casi (cfr. Cap. 4), la singola rou-

3 Si noti che lo stato in cui si trova la FSM al reset, di solito il ground state, deve essere sempre il primo requisito da definire nella specificazione di una FSM.

4 In realtà la soluzione che verrà descritta nel seguito, utilizzando il VIC per la ge-stione dei segnali generati dalla pressione dei due pulsanti, è in grado di control-lare l'eventualità in cui i due tasti vengano attivati contemporaneamente.

331

Page 4: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

tine pone semplicemente a '1' il contenuto di una variabile globale re-lativa all'evento del particolare tasto premuto. L'azzeramento della stessa variabile sarà operato dalla sezione di programma interessata, nel prefissato momento, a un tale evento. In questo modo è come se lo specifico ingresso fosse di tipo impulsivo. Su questo aspetto in parti-colare si tornerà più avanti per sottolineare l'importante risvolto, non solo pratico ma anche concettuale, utile alla descrizione della FSM.

Nel Listato 7.1 è riportato il codice delle ISR usate per la gestione dei pulsanti. Lo stato del tasto potrà essere acquisito in qualunque punto del programma principale semplicemente leggendo il contenuto delle variabili globali inc_ pressed e dec_pressed i cui valori rispec-chieranno l'attivazione, rispettivamente, dei pulsanti 'INC' e 'DEC'.

Nelle sezioni seguenti, oltre alla rappresentazione del sistema me-diante diagramma di flusso verrà indicata quella che risulta più idonea (o forse ovvia) per il caso in esame: il diagramma degli stati.

#include "lpc2103.h"#include "framework.h"#include "isr.h"extern unsigned char inc_pressed;extern unsigned char dec_pressed;void EINT0_ISR(void){ unsigned int i;

inc_pressed = 1; //switch INC pressedfor(i=0; i<700000;i++); //wait for debouncingEXTINT |= 0x01; //reset interrupt flagVICVectAddr = 0x00000000; //dummy write to VIC

} //to signal end of interrupt

void EINT2_ISR(void){ unsigned int i;

dec_pressed = 1; //switch DEC pressedfor(i=0; i<700000;i++); //wait for debouncingEXTINT |= 0x04; //reset interrupt flagVICVectAddr = 0x00000000; //dummy write to VIC

}// EOF //to signal end of interrupt

Listato 7.1. File isr.c per la gestione degli interrupt esterni EINT0 ed EINT1.

332

Page 5: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo

Il lavoro che la macchina dovrà svolgere può riassumersi con il dia-gramma di flusso riportato in Fig. 7.2. Per la natura impulsiva degli ingressi5, la transizione verso una nuova uscita è determinata in base al valore delle variabili globali menzionate nella precedente sezione. Sebbene il funzionamento sia relativamente semplice, si osserva che il diagramma presenta delle transizioni poco “lineari” nonché diversi in-croci sulle linee di percorrenza dell'algoritmo. Anche se poco “elegan-te”, la traduzione che appare migliore per il diagramma sembra essere quella che utilizzi l'istruzione di salto incondizionato goto.

Il file main.c del progetto (“FSM_goto”, CD) è riportato nel Lista-to 7.2. Oltre alla dichiarazione delle due variabili globali inc_pressed e dec_pressed, vi è l'inizializzazione del sistema relativamente al-l'LCD e alle due linee esterne di interruzione a cui vengono dedicati gli slot 14 e 15 del VIC6.

Figura 7.2. Diagramma di flusso del generatore di sequenza.

5 Verrà discusso nel dettaglio più avanti il problema che scaturisce dalla “natura” dei segnali d'ingresso che comandano la FSM.

6 Del tutto arbitrariamente si è deciso di fissare la priorità maggiore all'evento do-vuto a 'INC' rispetto a 'DEC'.

333

Page 6: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Il corpo del ciclo infinito while(1) è diviso nelle tre sezioni che si riferiscono ai possibili stati che l'uscita può assumere. Ogni sezione è identificata, all'inizio, dall'etichetta che riporta proprio il nome dell'u-scita n-esima che si deve avere: out0, out1 e out2.

Si esce dal ciclo while di ogni sezione, in cui viene scritto sull'LCD il valore dell'uscita corrente, nel caso in cui venga premuto uno dei due tasti. I due if che seguono, relativi al test sul valore di inc_pressed e dec_pressed, per prima cosa azzerano la variabile dell'ingresso che risulta attivo, rendendo così il segnale stesso di tipo impulsivo. Nello stesso campo dell'if vi è poi la diramazione, con l'istruzione goto, ver-so la zona di programma voluta in base allo specifico tasto premuto.

Sebbene la soluzione mostrata appaia piuttosto semplice bisogna dire che, soprattutto per macchine relativamente complesse, il dia-gramma di flusso è generalmente poco chiaro. Il listato che può essere creato con l'uso dell'istruzione goto risulta inoltre poco modulare, po-co lineare e per nulla strutturato (v. Par. 7.3). Inoltre appare spesso piuttosto difficile da gestire per correzioni o eventuali modifiche futu-re. Nella sezione seguente viene allora indicata la rappresentazione più indicata che è necessario impiegare in casi analoghi a questo e in gra-do di agevolare l'intero processo di progettazione.

/************************************************************ * File name : main.c * Project : FSM_goto ************************************************************/#include "lpc2103.h" //LPC2103 definitions and settings#include "framework.h" //Framework for ARM7 processor#include "HD44780.h" //LCD settings and functions#include "ext_int.h" //EINTn utilities#include "isr.h" //IRQ service routinesunsigned char inc_pressed=0, dec_pressed=0;int main(void){

InitLCD(); PutCommand(DISPLAY_CLEAR); delayMs(5);init_extIRQ(EINT0_CONN+EINT0_EDGE+EINT0_FALL+ EINT2_CONN+EINT2_EDGE+EINT2_FALL);enIRQ(EINT0_VIC_Ch, EINT0_ISR, 14);enIRQ(EINT2_VIC_Ch, EINT2_ISR, 15);

Listato 7.2. File main.c per il progetto “FSM_goto”. (continua)

334

Page 7: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

while(1){

out0: while((!inc_pressed)&&(!dec_pressed)){ PutCommand(RETURN_HOME); delayMs(5); WriteString((unsigned char*)"output 0"); }if(inc_pressed){ inc_pressed = 0; goto out1; }if(dec_pressed){ dec_pressed = 0; goto out2; }

out1: while((!inc_pressed)&&(!dec_pressed)){ PutCommand(RETURN_HOME); delayMs(5); WriteString((unsigned char*)"output 1"); }if(inc_pressed){ inc_pressed = 0; goto out2; }if(dec_pressed){ dec_pressed = 0; goto out0; }

out2: while((!inc_pressed)&&(!dec_pressed)){ PutCommand(RETURN_HOME); delayMs(5); WriteString((unsigned char*)"output 2"); }if(inc_pressed){ inc_pressed = 0; goto out0; }if(dec_pressed){ dec_pressed = 0; goto out1; }

} return 0;}//EOF

(segue) Listato 7.2.

7.2.2. Rappresentazione mediante diagramma degli stati

Il generatore di sequenza può essere descritto in modo diverso rispetto al diagramma di flusso di Fig. 7.2 facendo riferimento alla FSM che esso deve implementare. Ogni stato della macchina è indicato con un cerchio al cui interno è riportato il nome dello stato stesso o, come nel caso di figura, un numero intero che lo identifichi. Nel caso generale, nel cerchio è anche indicata la configurazione delle uscite oppure un rimando a note che illustrino le azioni svolte dal sistema nel particola-re stato. Gli stati sono poi collegati con frecce sopra le quali viene scritta la particolare configurazione degli ingressi in grado di determi-nare la transizione da uno stato al successivo. La rappresentazione del generatore di sequenza qui esaminato sarà allora quella riportata in Fig. 7.3. Come indicato nelle specifiche, le transizioni tra gli stati sono

335

Page 8: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

determinate dall'attivazione di un solo ingresso per cui non è ammessa la contemporanea attivazione di 'INC' e 'DEC'. Del resto, questa eve-nienza è automaticamente gestita dal controller delle interruzioni avendo impostato priorità diverse per i due pulsanti.

Per semplificare la rappresentazione, sulle frecce è indicato soltan-to quale segnale determina l'evoluzione verso il nuovo stato. Le frecce a “cappio” su ogni stato indicano che la FSM permane in esso se nes-sun ingresso è attivo. Per brevità, l'assenza di indicazione dei segnali su tali frecce rappresenta lo stato di riposo dei due ingressi che si ha dopo la cancellazione dell'ingresso stesso che ha provocato la transi-zione. Quindi, anche con la descrizione mediante digramma degli sta-ti, è stato sottinteso che l'attivazione di un ingresso consiste nella ge-nerazione di un impulso: come per il Listato 7.2, acquisito l'evento di “tasto premuto”, la variabile corrispondente viene azzerata.

Infine, si può notare che se viene attivato il reset, il diagramma in-dica che la FSM entra nello stato '0' considerato il ground state.

Il tipo di FSM di Fig. 7.3 rappresenta il caso particolare di macchi-na in cui le uscite dipendono soltanto dal particolare stato in cui si tro-va il sistema. Per questo le diverse configurazioni che possono assu-mere le uscite sono scritte solo nei cerchi. La FSM viene in questo ca-so denominata di tipo Moore.

Figura 7.3. Diagramma degli stati del generatore di sequenza. 'INC' e 'DEC' indicano quale ingresso deve essere attivato per avere una determinata transizione. Per ogni stato, le frecce a “cappio” senza etichette si riferiscono al caso in cui nessun ingresso sia attivo.

336

Page 9: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Viceversa, se le uscite possono dipendere, oltre che dallo stato, anche dalla possibile configurazione degli ingressi, il loro valore sarà ripor-tato sulle frecce stesse e la macchina è detta di tipo Mealy 7.

La parte più onerosa del progetto di una macchina a stati è forse proprio la descrizione completa del diagramma degli stati. Individuati tutti gli stati in cui la FSM può trovarsi, i valori delle uscite che si de-vono avere e le configurazioni degli ingressi che determinano le varie transizioni, l'operazione successiva si “limita” alla scrittura del codice che può apparire quasi una mera traduzione del lavoro “grafico” già eseguito. Ovviamente, durante la fase di scrittura dei listati, devono essere ben chiari i requisiti del sistema impiegato per la sintesi (dai quali il codice dipende fortemente). Prima di indicare la metodologia che si considera più idonea per la costruzione del codice, nella sezione successiva viene discusso il caso in cui la FSM qui esaminata sia di-pendente da ingressi attivi sul livello anziché di tipo impulsivo. Tutta-via, in tutto il capitolo si farà riferimento a diagrammi del tipo di Fig. 7.3, mentre la soluzione di problemi con segnali attivi sul livello viene lasciata per esercizio.

7.2.3. Diagramma degli stati nel caso di ingressi non impulsivi

La gestione dei due ingressi 'INC' e 'DEC' della FSM con diagramma degli stati di Fig. 7.3 avviene con interrupt attivo sui fronti (negativi). Grazie all'azzeramento della variabile specifica da parte del codice, come già più volte sottolineato, il segnale di attivazione risultante è equivalente a uno di tipo impulsivo. La descrizione di una FSM che svolga lo stesso lavoro in cui, viceversa, gli ingressi siano attivi sui li-velli è un po' più complessa. Si ritiene opportuno fare riferimento an-che a questo caso poiché in generale può presentarsi l'eventualità in cui le sorgenti d'ingresso non siano semplicemente quelle che fanno capo a pulsanti azionati da un utente, ma provengano da altri apparati o componenti (sistemi di controllo esterni o sensori).

Quando è il livello logico che determina la transizione da uno stato al successivo, è di fondamentale importanza prevedere degli stati “cu-

7 La convenzione adottata normalmente è quella di riportare accanto alle frecce le configurazioni, con la dicitura: “ingressi/uscite”.

337

Page 10: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

scinetto” in grado, cioè, di bloccare la transizione verso un numero imprecisato di stati seguenti a quello di partenza. Questo fenomeno può presentarsi facilmente per l'elevata velocità di risposta che la FSM può avere rispetto al periodo di attivazione del segnale d'ingresso. Se viene attivato un ingresso che deve determinare una transizione, prima che essa giunga allo stato definitivo è necessario che la FSM “cada” in uno stato in cui praticamente attende che il segnale stesso venga disat-tivato.

Una FSM che sintetizzi il generatore di sequenza, i cui requisiti e specifiche siano quelli esposti all'inizio di questo paragrafo, avrà un diagramma degli stati del tipo riportato in Fig. 7.4. Per semplificare il disegno, su ogni freccia è indicato lo stato della coppia INC,DEC che determina la transizione. Il valore '1' indica lo stato attivo dell'ingres-so. Si potrà osservare che i 6 stati intermedi, indicati con la coppia di valori che identifica la transizione da uno stato al successivo, evitano che la macchina possa presentare una transizione superiore a uno sta-to, attendendo che entrambi i segnali vadano al livello logico basso. Si noti altresì che avendo definito la priorità maggiore per l'ingresso 'INC', lo “scorrimento in avanti” si ha nel caso in cui INC = 1, indi-pendentemente dal valore di DEC ('1,X' sulle frecce). Viceversa, lo scorrimento all'indietro si ha solo se la coppia INC,DEC è pari a '0,1'.

Figura 7.4. Diagramma degli stati del generatore di sequenza nel caso di segnali d'ingresso attivi sul livello logico.

338

Page 11: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

7.3. Descrizione di una FSM in linguaggio C

La rappresentazione della FSM di Fig. 7.3 consente di modificare ra-dicalmente la descrizione del processo tanto che il codice potrà essere facilmente pensato perché resti entro i limiti di una programmazione strutturata. Il C infatti, grazie alle strutture sintattiche di selezione e iterazione, è considerato un linguaggio strutturato e, come tale, non dovrebbe prevedere l'uso di istruzioni di salto incondizionato. Per il diagramma di flusso di Fig. 7.2, tuttavia, le strutture di controllo fon-damentali non si rivelano particolarmente efficienti ed è meglio imple-mentare l'istruzione di salto goto8. Il codice del Listato 7.2 mette co-munque in evidenza una particolarità del sistema sintetizzato: sezioni di codice ben delimitate (dalle etichette) si riferiscono ai diversi stati della FSM. In ogni sezione esiste una parte dedicata al calcolo dell'u-scita e una che invece, in funzione della configurazione degli ingressi, “punta” alla nuova sezione relativa allo stato successivo. E questa l'i-dea che fondamentalmente è alla base delle tecniche di descrizione che verranno indicate nelle sezioni successive del presente paragrafo.

7.3.1. Puntatori a funzioni in linguaggio C

In un sistema a microprocessore, funzioni e variabili corrispondono a particolari indirizzi di memoria. In un programma si fa riferimento a esse con nomi che richiamino più propriamente operazioni e grandez-ze coinvolte. Questi, in realtà, possono essere visti come puntatori di locazioni di memoria. Dopo la compilazione i nomi saranno effettiva-mente tradotti negli specifici indirizzi fisici di memoria. Per una varia-bile, l'indirizzo corrisponderà proprio alla prima (o unica) locazione in cui il dato è depositato9 mentre, per una funzione, l'indirizzo sarà rela-8 Secondo le regole della programmazione strutturata l'utilizzo di tale istruzione

non dovrebbe essere permesso perché un suo uso “sconsiderato” rende il pro-gramma illeggibile. Tuttavia, come evidenziato nel Par. 7.2.1, è innegabile che l'uso del goto semplifica notevolmente l'operazione di stesura del programma.

9 La tecnica è molto utile in programmazione assembly quando occorre passare dei dati tra due routine: è più semplice e compatto passare il puntatore alla prima lo-cazione di memoria di una lista di dati piuttosto che doverli trasferire tutti. In tal senso, l'uso dello stack per il passaggio di parametri nella chiamata a subroutine rappresenta un esempio in cui si usa un puntatore: lo stack pointer.

339

Page 12: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

tivo alla locazione di memoria della prima istruzione della routine che sintetizza la funzione stessa. Con tale premessa è ovvia l'idea di poter usare puntatori anche in un programma: il riferimento a una funzione è realizzato puntando alla locazione di memoria della sua istruzione iniziale.

Nel linguaggio C sia per le variabili che per le funzioni è effettiva-mente possibile definire un puntatore10. La possibilità di puntare a fun-zioni semplifica notevolmente il progetto di macchine con numero fi-nito di stati: il singolo stato sarà codificato con una funzione che ne definisca le operazioni. Inoltre, dipendendo dalla configurazione degli ingressi, sarà possibile “calcolare” il nuovo puntatore e svolgere così la nuova funzione relativa al lavoro che la FSM dovrà attuare nello stato successivo voluto.

Un esempio di utilizzo dei puntatori è presente in quanto già svolto in uno dei capitoli iniziali del testo. Nella funzione WriteString( ), de-finita nel file HD44780.c per l'LCD, per passare la lista di caratteri viene in realtà passato il puntatore all'array di caratteri da visualizzare sul display. L'identificazione del puntatore è chiarita dalla presenza del simbolo '*' e la chiamata è del tipo: WriteString((unsigned char*)"Stringa da visualizzare");con cui dire al compilatore che a essere passato è l'indirizzo del primo carattere della stringa. In effetti questo puntatore è utilizzato dalla fun-zione per accedere al vettore di caratteri definito localmente come Li-neOfCharacters[ ] e scrivendo il singolo carattere con la funzione

WriteChar(LineOfCharacters[i]);in cui l'argomento i tra parentesi quadre parte da 0 e incrementa di un'unità (finché non è incontrato il carattere null o è stata completa-mente riempita la memoria del display).

In C la dichiarazione di un puntatore a una funzione, anziché a un dato, è molto simile a quella normalmente usata per definire una sem-plice funzione11. Rispetto a questa, l'identificatore dovrà essere sosti-

10 Il puntatore potrà anche fare parte di vettore o di una struttura di dati e potrà an-che essere passato, come argomento, da o verso una funzione.

11 Anche questa eventualità è stata già incontrata nel Cap. 4 ove nella routine di servizio di una IRQ veniva passato il puntatore pISR alla stessa.

340

Page 13: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

tuito dal “nome del puntatore” preceduto dal simbolo ' * '. Un esempio chiarirà meglio il concetto.

Si consideri la funzione “Quadrato”:

int Quadrato(int num){ return num*num; }

che calcola il quadrato della variabile num passata alla funzione come parametro d'ingresso. La sintassi da utilizzare per definire il puntatore pFunzione (a funzione) sarà del tipo seguente:

int (*pFunzione)(int);

in cui si osservi che è necessario inserire l'identificatore tra parentesi. L'inizializzazione di pFunzione potrà essere tale da poter puntare alla funzione Quadrato con l'assegnazione:

pFunzione = Quadrato; .

A questo punto la funzione che calcola il quadrato di num potrà essere richiamata nel modo “classico”:

ris = Quadrato(27);oppure utilizzando il puntatore pFunzione che è stato proprio inizializ-zato a essa:

ris = (*pFunzione)(27);o più semplicemente:

ris = pFunzione(27);che rende ancor più immediato l'uso del puntatore. Entrambe le chia-mate, Quadrato(27) e pFunzione(27), produrranno il risultato di 729 che sarà memorizzato nella variabile ris.

La “potenza” del metodo risiede nel fatto che il concetto ora espo-sto può essere esteso a diverse funzioni a cui giungere utilizzando sempre lo stesso puntatore pFunzione. I nomi delle funzioni potranno essere elencati in un vettore che sarà in pratica utilizzato per “chiama-re” le singole funzioni a seconda delle esigenze12. Se per esempio sono

12 Nella realtà, ciò è reso effettivamente possibile grazie al fatto che nel puntatore sarà immagazzinato l'indirizzo di memoria della specifica routine richiesta.

341

Page 14: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

definite tre funzioni: funz1, funz2 e funz3, si può creare un vettore di tre elementi in cui siano immagazzinati i puntatori alle funzioni stesse:

int (*Funzione[])(int) = {funz1, funz2, funz3};

in cui Funzione[ ] può essere vista come una sorta di tabella di funzio-ni. L'esecuzione della singola routine potrà avvenire facendo assume-re, per esempio, alla variabile Scelta, un valore compreso tra 0 e 2. La funzione Scelta sarà eseguita con la seguente riga di codice:

ris = Funzione[Scelta](val_ing);

dove la variabile val_ing rappresenta il parametro d'ingresso passato alla funzione richiesta13.

E' necessario sottolineare che l'uso di puntatori a funzioni è essen-ziale nel caso in cui l'esecuzione di eventuali algoritmi è determinata solo nel momento in cui il programma opera, in relazione a scelte e ingressi specifici. È questa la situazione in cui ci si trova quando il programma sintetizza una FSM in cui l'evoluzione del sistema e la se-quenza di esecuzione delle operazioni non sono conosciute a priori.

7.3.2. Progetto della FSM con l'uso del puntatore a funzioni

Per un sistema a μC la disponibilità di puntare a funzioni è utile per rendere agevole la descrizione e il progetto di una FSM. I diversi stati in cui può trovarsi il sistema saranno trattati al pari di funzioni. Que-ste, a seconda del valore dello stato corrente, saranno chiamate facen-do semplicemente riferimento a una tabella di puntatori. Tale tabella potrà essere vista in pratica come elenco di tutti gli stati possibili della FSM. Qui l'uso dei puntatori è essenziale poiché non è noto a priori l'ordine delle chiamate alle diverse routine.

Si supponga di dover descrivere la semplice FSM a tre stati del tipo indicato in Fig. 7.3. Il passaggio da uno stato al successivo è determi-nato da un solo ingresso il cui valore cambia in funzione della pressio-ne di un tasto. Per quanto già detto nel Par. 7.2, l'attivazione del singo-lo pulsante genera un prefissato interrupt. Le routine di servizio del-

13 Il numero di parametri passati, nonché il tipo di argomento, deve coincidere per tutte le funzioni.

342

Page 15: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

l'IRQ sono le stesse riportate nel Listato 7.1 che pongono a '1' le varia-bili globali con cui determinare lo stato dei due ingressi.

In base alle considerazioni del Par. 7.3.1, è ora possibile descrivere la macchina a stati seguendo una programmazione prettamente struttu-rata e tipica del linguaggio C.

Per prima cosa nel file main.c del progetto vi sarà la dichiarazione della “tabella delle funzioni” della FSM: void(*state_table[])(void)={State0, State1, State2};

che può essere vista come il semplice elenco di tutti i possibili stati della FSM che ora dovranno avere un nome e non potranno essere un semplice valore numerico.

Avendo definito state_table[ ] come puntatore, con essa si potrà puntare alle singole funzioni che definiscono il lavoro della FSM nei diversi stati. Le funzioni saranno proprio: State0, State1 e State2, chia-mate a seconda del valore dello stato corrente. Per accedere al singolo stato basterà utilizzare l'opportuno indice nella tabella. Ad esempio, state_table[0]( ) farà eseguire la funzione State0 (primo elemento del-la lista di funzioni), mentre con state_table[1]( ) si eseguirà la funzio-ne State1( ). Infine, State2( ) è eseguita con state_table[2]( ).

Per maggiore chiarezza, sia di progetto che di debug, le diverse funzioni che si riferiscono ai diversi stati della FSM possono essere inserite in un file dedicato states.c14. Come mostrato nel Listato 7.3, il file di intestazione, states.h, potrà essere utilizzato per dichiarare tutti gli stati della FSM e per riportare una eventuale breve descrizione del suo funzionamento.

Qui di seguito viene scritto, quale esempio, lo stralcio delle parti fondamentali che compongono la generica funzione che sintetizza uno stato della FSM:

14 Al solito, non si dimentichi di inserire il nuovo file sorgente “states.c” nell'elen-co del makefile. Inoltre, per utilizzare funzioni definite in altri file sorgente, in states.c sarà necessario inserire le opportune direttive #include. Comunque, le funzioni potrebbero essere incluse nell'unico file main.c, come verrà fatto per gli altri progetti sviluppati nei prossimi paragrafi. In questo caso è allora semplifica-ta la stesura del codice in quanto tutti gli elementi necessari saranno riportati nel-l'unico file main.c.

343

Page 16: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

void function_state(){//definizione delle uscite per lo stato corrente (Moore) if(inputs) //if input, change state {//uscite definite (eventualmente) anche qui (Mealy)

current_state = new_state; } //stato futuro}

Come indicato con i commenti, si può notare che è possibile descrive-re entrambe le tipologie di FSM: Moore e Mealy. Se infatti la configu-razione di alcune uscite viene modificata nel campo dell'if relativo allo stato degli ingressi, si avrà una macchina di Mealy. Se viceversa le uscite dipendono solo dallo stato corrente, si deve avere una descrizio-ne di tipo Moore. In tal caso la configurazione d'uscita si troverà sol-tanto fuori dal campo if, cioè dipendente solo dallo stato in cui si trova la FSM e indipendente dalla condizione attuale assunta dagli ingressi.

L'indice per il puntatore alle funzioni è la variabile current_state. Nell'if è ovviamente inclusa l'indicazione del nuovo stato che la FSM dovrà assumere se è riscontrata la particolare configurazione degli in-gressi (campo condizione dell'if stesso). L'aggiornamento del contenu-to di current_state è qui indicato con new_state

15. Il main.c del programma può essere del tipo riportato nel Listato

7.4. Si può osservare che current_state è stata definita come variabile globale poiché, come detto, sarà modificata dal particolare stato in cui si trova la FSM in un certo istante quando inc_pressed o dec_pressed (anch'esse globali) sono pari a '1'.

La gestione dei pulsanti è a opera delle medesime routine di servi-zio degli interrupt esterni EINT0 ed EINT2 scritte nel Listato 7.1.

Si può notare che il main( ) del programma, oltre all'inizializzazio-ne dell'LCD e della periferica di interrupt esterno, nel ciclo infinito while(1) esegue solo l'istruzione:

state_table[current_state]()svolgendo così il solo lavoro di richiamare continuamente la funzione relativa allo stato corrente attraverso la tabella degli stati.15 Si osservi che l'indice per accedere alle diverse funzioni che realizzano gli stati è

un numero intero. Nel Par. 7.4 verrà mostrato come associare ai numeri interi il semplice elenco degli stati. Per comodità, stato-attuale e funzione possono avere lo stesso nome. La distinzione sarà fatta adottando la norma (del tutto personale, N.d.A.) di indicare le funzioni con la lettera iniziale maiuscola mentre gli stati saranno scritti tutti in minuscolo (il compilatore C è case-sensitive).

344

Page 17: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

void State0(); //state 0 is the ground state void State1(); //state 1 void State2(); //state 2 /*####################################################### * La FSM (Moore) esegue il ciclo: * State0 <-> State1 <-> State2 * |<>-----------------<>| * La transizione può avvenire nei due versi a seconda * dello stato delle linee d'ingresso INC e DEC. * In ciascuno stato l'uscita è pari al valore “output N” * dove N è pari a 0, 1 o 2, come per gli stati. *#####################################################*/ Listato 7.3. Esempio di file states.h in cui, oltre alla dichiarazione degli stati (funzioni) può essere utile riportare una breve descrizione della FSM.

/************************************************************ * Filename : main.c * Project : FSM_pointer * Abstract : shown the use of functions as states in a FSM ************************************************************/#include "lpc2103.h"#include "framework.h"#include "HD44780.h"#include "ext_int.h"#include "isr.h" //input used to change state #include "states.h" //states definition and descriptionunsigned char current_state = 0;unsigned char inc_pressed = 0, dec_pressed = 0;//This the table of possible states: // table points to the functions (states) in the listvoid(*state_table[])(void) = {State0, State1, State2};int main(void){ InitLCD(); PutCommand(DISPLAY_CLEAR); delayMs(5);

init_extIRQ(EINT0_CONN+EINT0_EDGE+EINT0_FALL+ EINT2_CONN+EINT2_EDGE+EINT2_FALL);enIRQ(EINT0_VIC_Ch, EINT0_ISR, 14);enIRQ(EINT2_VIC_Ch, EINT2_ISR, 15);PutCommand(DISPLAY_CLEAR); delayMs(5);PutCommand(RETURN_HOME); delayMs(5);while(1){ state_table[current_state]();

delayMs(10);} return 0;

}//EOFListato 7.4. File main.c del progetto “FSM_pointer”.

345

Page 18: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Nel file states.c, Listato 7.5, vi è la vera e propria descrizione della FSM e della funzionalità in ogni singolo stato. Come già sottolineato, il file states.c è una rappresentazione diretta, in forma di testo, del dia-gramma degli stati di Fig. 7.3. Per il progetto specifico, per ogni stato bisogna solo gestire la scrittura su LCD del messaggio relativo alla posizione dello stato corrente stesso. È necessario allora includere “HD44780.h” in states.c. La struttura delle diverse funzioni rispecchia il codice per la funzione generica function_state( ) riportato preceden-temente. In particolare, rivelata la chiusura di un pulsante, viene “cal-colato” lo stato futuro e operato il reset della variabile il cui contenuto indica lo stato dello stesso tasto.

Il file di intestazione states.h coincide con quanto riportato nel Li-stato 7.3. La verifica del funzionamento del progetto completo, deno-minato “FSM_pointer” (CD), è lasciata per esercizio. Anche in que-sto caso il debug può essere eseguito inserendo opportunamente i breakpoint in modo da osservare l'evoluzione della FSM con le azioni d'ingresso e d'uscita che si hanno per ogni stato a seconda del tasto premuto o rilasciato.

/************************************************************ * Filename : states.c * Project : FSM1_pointer * Abstract : functions refer to states of the FSM ************************************************************/#include "HD44780.h" //states use LCD#include "framework.h" //#include "states.h"extern unsigned char inc_pressed;extern unsigned char dec_pressed;extern unsigned char current_state;void State0(){ PutCommand(RETURN_HOME); delayMs(5);

WriteString((unsigned char*)"output 0");if(inc_pressed) //if INC pressed go to next{ current_state = 1; //This is the next state inc_pressed = 0; } //event acquired->reset itif(dec_pressed) //if DEC pressed go to previous{ current_state = 2; //This is the next state dec_pressed = 0; } //event acquired->reset it

}Listato 7.5. Definizione della funzionalità dei diversi stati. (continua)

346

Page 19: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

void State1(){ PutCommand(RETURN_HOME); delayMs(5);

WriteString((unsigned char*)"output 1");if(inc_pressed) //if INC pressed go to next { current_state = 2; //This is the next state inc_pressed = 0; } //event acquired->reset itif(dec_pressed) //if DEC pressed go to previous{ current_state = 0; //This is the next state dec_pressed = 0; } //event acquired->reset it

}void State2(){ PutCommand(RETURN_HOME); delayMs(5);

WriteString((unsigned char*)"output 2");if(inc_pressed) //if INC pressed go to next { current_state = 0; //This is the next state inc_pressed = 0; } //event acquired->reset itif(dec_pressed) //if DEC pressed go to previous{ current_state = 1; //This is the next state dec_pressed = 0; } //event acquired->reset it

}//EOF

(segue) Listato 7.5.

7.3.3. Soluzione con l'istruzione switch

Nel metodo di sintesi di una FSM con puntatore a funzioni, nel while(1) del main( ), a ogni ciclo del programma si ha la chiamata alla funzione che si riferisce allo stato attuale. A determinare il giusto “puntamento” è il contenuto della variabile current_state. Se viene ri-conosciuta una prefissata configurazione degli ingressi, current_state viene aggiornata in modo tale che la chiamata, nel ciclo successivo, sia effettivamente quella relativa alla funzione che riguarda lo stato fu-turo. Invece di puntare a una funzione, lo stesso metodo potrebbe ri-solversi con l'uso dell'istruzione switch. Infatti, a ogni ciclo del pro-gramma, l'istruzione potrà sempre valutare il valore di current_state ed eseguire la particolare sezione di codice inserita nel campo case che riguarda lo stato attuale. Nella stessa sezione, in base a eventuali valori d'ingresso, current_state verrà aggiornata in modo che nel ciclo

347

Page 20: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

seguente sia eseguito il campo case dello stato futuro16. La differenza fondamentale che si ha rispetto al metodo precedente è quella di avere un unico listato in cui sono riportate tutte le sezioni di codice relative ai diversi stati.

Con l'uso dell'istruzione switch i valori possibili di current_state sono i valori interi 0, 1 e 2. Il valore iniziale di current_state è 0 che rappresenta il ground-state della macchina. Nel Listato 7.6 è riportato il codice relativo al corpo di istruzioni inserite nel ciclo while(1) del file main.c del progetto “FSM_switch” (CD) usato come test del me-todo. (Le altre parti di codice sono formalmente identiche a quelle dei main.c degli altri progetti già esaminati in questo paragrafo.) Come nella soluzione con puntatore a funzioni, in ogni sezione case relativa a uno stato viene scritto sull'LCD il valore d'uscita corrispondente allo stato e viene “controllato” se una delle due variabili inc_pressed o dec_ pressed è attiva (contenuto pari a '1'). In questo caso viene ag-giornato il valore di current_state (che avrà effetto al prossimo ciclo). Al solito, la corrispondente variabile d'ingresso viene azzerata perché ormai la sua informazione è stata acquisita. Ovviamente, anche in que-sto caso per una FSM di tipo Mealy i valori dell'uscita potranno essere definiti negli opportuni campi dell'if relativo al particolare stato delle linee di ingresso.

switch(current_state){case 0: // state0 PutCommand(RETURN_HOME); delayMs(5); WriteString((unsigned char*)"output 0"); if(inc_pressed)// go to next value { current_state = 1;

inc_pressed = 0; }Listato 7.6. Funzione switch per la descrizione della FSM di Fig. 7.3. (cont.)

16 Allo stesso risultato si può anche giungere usando if in cascata, annidati cioè tra loro. Tuttavia nei casi in cui si hanno molti if, l'istruzione switch consente di ri-solvere il problema in modo più efficiente e, soprattutto, leggibile. La differenza sostanziale tra l'istruzione switch e gli if in cascata è che la prima può eseguire solo confronti di uguaglianza, mentre con i secondi si possono valutare espres-sioni in cui siano presenti anche diversi operatori logici. Per la sintesi di una FSM è comunque la sola condizione di uguaglianza sul valore di current_state a essere utile nei confronti.

348

Page 21: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

if(dec_pressed)//go to previous value { current_state = 2;

dec_pressed = 0; } break; case 1: // state 1 PutCommand(RETURN_HOME); delayMs(5); WriteString((unsigned char*)"output 1"); if(inc_pressed)// go to next value { current_state = 2;

inc_pressed = 0; } if(dec_pressed) { current_state = 0;

dec_pressed = 0; } break; case 2: // state 2 PutCommand(RETURN_HOME); delayMs(5); WriteString((unsigned char*)"output 2"); if(inc_pressed) { current_state = 0;

inc_pressed = 0; } if(dec_pressed) { current_state = 1;

dec_pressed = 0; } break;}

(segue) Listato 7.6.

7.3.4. Confronto tra le due soluzioni e osservazioni

L'uso dell'istruzione switch per la sintesi di una FSM risulta intuitiva-mente la più indicata per garantire un'occupazione di memoria flash minore rispetto a quella necessaria per il codice con chiamata a fun-zioni. Tuttavia, con le impostazioni del compilatore indicate nel Cap. 2, le prove effettuate su diversi progetti (di dimensione fino a 16 kbyte circa) indicano un risparmio che ammonta all'1-2 % soltanto. Nel caso di istruzione switch, il disassembly del codice mostra che sono impie-gate istruzioni di salto incondizionato B <address>. La soluzione è del tutto simile a quanto realizzato con il programma in linguaggio C in cui è usata l'istruzione goto. Viceversa è piuttosto interessante os-servare il tipo di soluzione offerta dal compilatore per l'assembly nel caso di chiamata a funzione.

349

Page 22: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Per prima cosa viene creata la tabella degli indirizzi relativi alle di-verse routine degli stati a cui accedere con un'istruzione di branch wi-th link. Il salto avviene in realtà in due passi. Nel ciclo while(1) del main( ) avviene il primo passo. Qui è inserita l'istruzione BL <indiriz-zo-fisso> di salto a un prefissato indirizzo17. Con tale tipo di salto, l'in-dirizzo dell'istruzione successiva a BL è salvato nel link register LR. Nella locazione [indirizzo-fisso] è inserita l'istruzione BX Rn, cioè il secondo passo con cui avviene anche il cambio nella modalità Thumb. Il salto all'indirizzo dettato dal contenuto del registro Rn è finalmente verso la funzione desiderata poiché, precedentemente, nel registro è stato salvato l'indirizzo prelevato dalla tabella menzionata in base al contenuto della variabile current_state.

All'ingresso della singola funzione si ha l'esecuzione dell'istruzione PUSH {<elenco registri>, LR} con cui salvare, oltre al contenuto dei registri utilizzati dalla funzione stessa, il link register che contiene l'indirizzo di ritorno al main( ). Al termine della routine sono infine in-serite istruzioni POP atte a ripristinare il contenuto originario dei di-versi registri impiegati nonché il POP Rn finale (che ha l'effetto di co-piare il contenuto di LR in Rn) con cui tornare effettivamente al main( ) grazie alla successiva esecuzione dell'istruzione BX Rn (con ovvio cambio della modalità, da Thumb ad ARM).

Malgrado la maggiore complessità che deriva da quanto esposto e che implica l'uso di un numero maggiore di istruzioni, l'impiego della modalità Thumb giustifica una densità di codice praticamente pari a quella della soluzione con switch.

Qualora la dimensione del programma non risulti il fattore limitan-te di un progetto, la scelta di una o dell'altra soluzione rientra nel gusto personale del programmatore. Forse, l'unica pecca che la soluzione con switch presenta, nel caso di FSM complesse, è la lunghezza del-l'intero codice main( ). Quella con salto a funzioni appare infatti di per sé automaticamente suddivisa in moduli tanto da rendere l'osserva-zione durante la stesura e il debug più agevoli e, probabilmente, indi-cata per eventuali modifiche o aggiornamenti futuri del progetto origi-nario.

17 Solitamente, per la limitata dimensione, l'indirizzo è quello della prima locazione libera al di sotto dell'intero codice disassemblato.

350

Page 23: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

7.4. Progetto di un orologio con funzione set

L'esempio di un orologio che visualizzi su LCD l'ora corrente nel for-mato “hh:mm:ss” già visto nel Par. 6.8.1 viene ora ripreso per inserire la funzionalità di set con cui poter impostare i valori di ora e minuti. Per la regolazione saranno usati due tasti: 'SET' per passare alla moda-lità di programmazione, in cui è possibile modificare l'orario voluto; 'MODE' per incrementare il valore delle ore o dei minuti visualizzati (solo se è stato precedentemente premuto 'SET').

Al reset, il sistema deve presentare sull'LCD l'orario corrente me-morizzato nell'RTC. Se non viene premuto 'SET', si resta in questa modalità altrimenti si passa a quella in cui è possibile variare il conte-nuto del registro HOUR dell'RTC. In questo secondo caso, dopo aver premuto 'SET' una prima volta, sul display appare la scritta “hh:” se-guita da 5 spazi in modo che risulti evidente la funzionalità corrente. Con 'MODE' si può incrementare il valore di HOUR di un'unità, tra 0 e 2318, a ogni pressione. Se viene ancora premuto 'SET' si passa all'im-postazione dei minuti, tra 0 e 59, con la stessa possibilità di incremen-to del registro MIN, agendo sempre su 'MODE'. Durante l'impostazio-ne, sul display è visualizzato il valore corrente dei minuti nel formato “mm:” preceduto da 3 spazi e seguito da altri 2. Infine, se si preme 'SET' per la terza volta si torna alla visualizzazione dell'orario corrente come stabilito dall'RTC. Si rimane in questa modalità in cui è acquisi-to e presentato sull'LCD l'orario dell'RTC se non si preme nessun ta-sto. Lo schema di montaggio è del tutto identico a quello di Fig. 7.1. L'unica differenza consiste nel nome dei due pulsanti, 'INC' e 'DEC' ora denominati, rispettivamente, 'MODE' e 'SET'.

Il codice del progetto potrebbe essere sviluppato seguendo il dia-gramma di flusso di Fig. 7.5 che illustra le operazioni che il sistema dovrà svolgere in dipendenza dell'attivazione del particolare pulsante. Per il controllo di flusso si useranno istruzioni iterative while( ) per i

18 È necessario includere il controllo sul valore massimo dei contatori dell'RTC poiché questi, in scrittura, sono normali registri. Infatti, entro la sua risoluzione, è possibile inizializzare un contatore a qualunque valore. Per esempio, il registro HOUR è a 5 bit e si potrebbe memorizzare un numero maggiore di 23. In tal ca-so, solo dopo aver raggiunto il limite superiore di 31 si avrà la corretta periodici-tà del conteggio modulo 24.

351

Page 24: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

loop mantenuti se 'SET' non è attivo. Al loro interno sarà invece inse-rito l'if che controlla lo stato del pulsante 'MODE'. Il salto verso le di-verse modalità potrà avvenire con l'istruzione goto. La possibile solu-zione è lasciata come utile esercizio di approfondimento.

Nel seguito verranno indicate le soluzioni con i metodi già applicati per il progetto della macchina a stati del precedente paragrafo. Infatti, risulterà evidente che il sistema ora esaminato può essere pienamente descritto come una FSM.

La soluzione che non preveda l'uso di una FSM risulta piuttosto semplice. Tuttavia, nel presente progetto si vuole proprio mostrare la versatilità dei metodi esposti per poter dotare la macchina di funziona-lità aggiuntive senza avere la necessità di ripensare l'intero progetto.

Figura 7.5. Diagramma di flusso di un orologio con set.

7.4.1. Descrizione della FSM

Il sistema di orologio con set può essere descritto in modo diverso ri-spetto al diagramma di flusso di Fig. 7.5 facendo riferimento alla mac-china a stati che esso deve implementare in base alle specifiche di fun-zionamento enunciate. In Fig. 7.6 è rappresentata la FSM che diretta-

352

Page 25: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

mente deriva da quanto detto: dallo stato “Display Time” (stato che si ha al reset) si passa a “Set hour” premendo 'SET'. In questo secondo stato si hanno due transizioni possibili a seconda del tasto premuto: verso “Set min” con il 'SET'; nello stato “Incr hour” con 'MODE'. Analogamente, raggiunto lo stato “Set min” è possibile incrementare il valore del registro MIN dell'RTC premendo 'MODE'. Si torna allo sta-to iniziale se viene attivato 'SET'. Si noti che l'uscita dagli stati “Inc hour” e “Inc min” avviene automaticamente: dopo un ciclo, il sistema si sposta verso “Set hour” o “Set min” senza che la transizione sia do-vuta all'attivazione di un ingresso.

Per la FSM di Fig. 7.6 l'effetto sulle uscite è indicato solo negli stessi cerchi che rappresentano gli stati poiché, in effetti, l'aggiorna-mento delle uscite (valori dei registri e scritta visualizzata) dipendono solo dallo stato corrente. La macchina in questo caso è di tipo Moore.

Poiché a determinare la transizione tra due stati della FSM è l'atti-vazione di uno tra i due possibili ingressi 'SET' o 'MODE', anche per questo progetto si farà uso di interrupt generati proprio dall'attivazione di un pulsante: 'SET' è connesso a EINT0 (P0.16) mentre 'MODE' è collegato a EINT2 (P0.15). Le due routine di servizio dell'IRQ per la gestione dei pulsanti saranno identiche a quelle riportate nel Listato 7.1 a eccezione dei nomi delle due variabili globali, ora indicate con set_pressed e mode_pressed, che hanno il solito compito di segnalare allo stato corrente l'attivazione del tasto specifico.

Figura 7.6. Diagramma degli stati utile a descrivere l'orologio con set. Anche in questo caso, i “cappi” privi di etichetta si riferiscono agli ingressi non attivi.

353

Page 26: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

7.4.2. Soluzione con puntatore a funzioni

Tenendo conto del diagramma degli stati di Fig. 7.6, per maggiore chiarezza le funzioni che definiscono le azioni da svolgere nei diversi stati avranno un nome che riprende direttamente quello degli stati stes-si. La loro dichiarazione, nel file main.c, sarà del tipo:

void DisplayTime(), SetHour(), SetMin(), IncHour(), IncMin();

mentre il vettore di puntatori a tali funzioni, state_table[ ], sarà defini-to con la riga di codice:

void(*state_table[])(void) = {DisplayTime, SetHour, SetMin, IncHour, IncMin}; .

L'elenco degli indici con cui poter chiamare la funzione specifica in base al valore della variabile current_state può essere dato con le se-guenti definizioni:

#define display_time 0#define set_hour 1#define set_min 2#define inc_hour 3#define inc_min 4

aventi, cioè, lo stesso ordine che si ha in state_table[ ] per le funzioni. In questo modo l'indice per lo stato futuro riprende in pratica il nome stesso della funzione a esso relativa. Allo stesso risultato si può giun-gere, in modo più “elegante” e compatto, utilizzando il tipo enum così che gli “stati” possibili siano sinonimi della sequenza di numeri interi ordinata a partire dal valore 0 assegnato per il primo indice:

typedef enum {display_time=0, set_hour, set_min, inc_hour, inc_min} State_Type; .

La parola chiave typedef permette di definire come State_Type il tipo di dati per il gruppo elencato. La variabile current_state, relativa allo stato corrente, è allora dichiarata proprio come State_Type e inizializ-zata al valore display_time (ground state) con l'istruzione:

State_Type current_state = display_time; .

354

Page 27: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Per la funzionalità specifica del sistema, il main.c del progetto do-vrà anche includere il file rtc.h relativo alle funzioni dell'RTC.

Nel main( ) del programma, prima del ciclo while(1), saranno ini-zializzate tutte le periferiche utilizzate: interrupt esterni EINT0 ed EINT2, LCD ed RTC. Al solito, il ciclo while(1) contiene solo la chia-mata alla funzione corrente. Il listato completo di questa sezione del file main.c è riportato nel Listato. 7.7.

/************************************************************ * Filename : main.c * Project : clock_pointer ************************************************************/#include "lpc2103.h"#include "framework.h"#include "HD44780.h"#include "ext_int.h"#include "isr.h" //input used to change state #include "rtc.h" //Real Time Clock initializationunsigned char set_pressed=0, mode_pressed=0;typedef enum {display_time=0, set_hour, set_min, inc_hour, inc_min} State_Type;State_Type current_state = display_time;void DisplayTime(), SetHour(), SetMin(), IncHour(), IncMin();void(*state_table[])(void) = {DisplayTime, SetHour, SetMin, IncHour, IncMin};int main(void){ init_extIRQ(EINT0_CONN+EINT0_EDGE+EINT0_FALL+

EINT2_CONN+EINT2_EDGE+EINT2_FALL);enIRQ(EINT0_VIC_Ch, EINT0_ISR,14); enIRQ(EINT2_VIC_Ch, EINT2_ISR,13);InitLCD();PutCommand(DISPLAY_CLEAR); delayMs(5);PutCommand(RETURN_HOME); delayMs(5);InitRTC(171210,150500); //17/12/2010 ; 15:05:00while(1){

state_table[current_state]();delayMs(10);

}return 0;

}Listato 7.7. File main.c del progetto “clock_pointer”: definizioni delle variabi-li, inizializzazione delle periferiche e codice per la funzione main( ).

355

Page 28: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Nel Listato 7.8 è riportato il codice della funzione DisplayTime( ). Si osserva che l'if è relativo solo all'attivazione del tasto 'SET'. Tutta-via, per evitare che eventuali pressioni precedenti di 'MODE' siano ri-conosciute dallo stato successivo, se la condizione è verificata entram-be le variabili sono azzerate.

Nel Listato 7.9 è invece riportato il codice relativo alle due funzioni SetHour( ) e IncHour( ). Si può notare, per la prima, che l'if relativo allo stato di 'MODE' è verificato solo se 'SET' non viene trovato atti-vo. In pratica è come aver stabilito che il tasto 'SET' abbia una “priori-tà maggiore” rispetto a quello 'MODE' 19.

void DisplayTime() // hh:mm:ss format{ PutCommand(RETURN_HOME); delayMs(5);

Write_2digitsval(HOUR); WriteChar(':');Write_2digitsval(MIN); WriteChar(':');Write_2digitsval(SEC);if(set_pressed) //if set{ current_state = set_hour;

set_pressed = 0;mode_pressed = 0; }

}Listato 7.8. File main.c: funzione displayTime( ).

void SetHour(){ PutCommand(RETURN_HOME); delayMs(5);

Write_2digitsval(HOUR); // display hourWriteString((unsigned char*)": ");if(set_pressed) //if set{ current_state = set_min;

set_pressed = 0; }else

if(mode_pressed) //if mode{ current_state = inc_hour;

mode_pressed = 0; }}void IncHour(){ HOUR++; if(HOUR==24) HOUR = 0;

current_state = set_hour;}

Listato 7.9. File main.c: funzioni SetHour( ) e IncHour( ).

19 La priorità “reale” nel caso di eventi contemporanei è comunque stabilita dagli slot del VIC coinvolti.

356

Page 29: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

La particolarità della seconda funzione è invece il fatto che, dopo l'ag-giustamento del contenuto del registro HOUR, lo stato successivo è aggiornato al valore set_hour. Quindi, automaticamente, al ciclo suc-cessivo la FSM entra nello stato voluto senza alcuna influenza da par-te degli ingressi. Le funzioni SetMin( ) e IncMin( ) risultano del tutto simili a quelle discusse. Il progetto completo si trova nella cartella de-nominata “clock_ pointer” (CD).

7.4.3. Soluzione con l'istruzione “switch”

Il diagramma degli stati di Fig. 7.6 può essere descritto con un codice che usi l'istruzione switch seguendo le indicazioni date nel Par. 7.3.3. La sintesi non presenta novità rispetto alla soluzione discussa nel para-grafo precedente: è sufficiente inserire i listati delle diverse funzioni nei campi delimitati dai singoli case-break

20. Invece di riprodurre il si-stema con le medesime funzionalità, si vuole qui indicare la modifica utile alla semplificazione del diagramma degli stati stesso che, ovvia-mente, darà luogo a un codice in linguaggio C più compatto.

Quanto osservato nel paragrafo precedente relativamente agli stati “Inc hour” e “Inc min” fa comprendere che in realtà l'operazione di aggiornamento dei registri HOUR e MIN dell'RTC possa avvenire ne-gli stati “Set hour” e “Set min” stessi. Quando il sistema si trova in uno di questi stati, ogni volta che viene attivato 'MODE' deve essere incrementato il contenuto del registro specifico. Il diagramma si ridu-ce allora a 3 stati soltanto e diviene del tipo riportato in Fig. 7.7.

Figura 7.7. Diagramma degli stati semplificato dell'orologio con set.

20 La soluzione con l'istruzione switch( ) può essere sviluppata per esercizio e con-frontarla col progetto “clock_switch_Moore”, CD.

357

Page 30: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

La macchina a stati che deriva da tale semplificazione è di tipo Mealy (si noti infatti che l'aggiornamento dei registri suddetti, HOUR++ e MIN++, è riportato sulle frecce relative alle transizioni che si hanno dall'attivazione dell'ingresso 'MODE').

Per la soluzione occorre tenere conto del fatto che, se nello stato “Set hour” viene premuto 'SET', si passa allo stato “Set min”. Se vice-versa è attivo 'MODE', il contenuto della variabile current_state non deve essere modificato mentre è solo incrementato il valore del regi-stro HOUR. Analogamente, le stesse considerazioni valgono nel caso in cui il sistema si trovi nello stato “Set min”. La sezione di codice re-lativa a tali stati è riportata nel Listato 7.10 mentre le altre, come det-to, sono simili a quanto già esposto nel Par. 7.4.2.

case set_hour: // set hh:PutCommand(RETURN_HOME); delayMs(5);Write_2digitsval(HOUR); WriteChar(':');if(set_pressed){ set_pressed = 0;

current_state = set_min;}if(mode_pressed){ mode_pressed = 0;

HOUR++; if(HOUR>23) HOUR = 0;}

break;case set_min: // set __:mm:

PutCommand(RETURN_HOME); delayMs(5);WriteChar(' ');WriteChar(' ');WriteChar(' ');Write_2digitsval(MIN); WriteChar(':');if(set_pressed){

set_pressed = 0;current_state = display_time;

}if(mode_pressed){

mode_pressed = 0;MIN++; if(MIN>59) MIN = 0;

}break;

Listato 7.10. Sezione di codice, con uso dell'istruzione switch, per la descri-zione degli stati “Set hour” e “Set min” del diagramma di Fig. 7.7.

358

Page 31: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Il codice completo può essere confrontato con la soluzione presente nella cartella “clock_ switch”, (CD).

Si noti che nello stato “Set hour”, è stata tolta la sezione di codice che permetteva la scrittura di 5 spazi dopo “hh:”. All'uscita dallo stato “Display Time” sarà allora necessario inserire la riga di codice

PutCommand(DISPLAY_CLEAR); delayMs(5);

nel campo dell'if relativo all'attivazione del pulsante 'SET', in modo che la “vecchia” scritta dell'orario completo non si sovrapponga a quella nuova. La cancellazione non è invece necessaria negli altri casi.

7.4.4. Un'ulteriore modifica: orologio con datario

Il progetto di orologio descritto nelle pagine precedenti può essere ul-teriormente modificato per inserire la possibilità di visualizzare la data corrente che l'RTC gestisce.

Per entrambe le soluzioni del paragrafo precedente, nello stato “Di-splay Time” l'ingresso 'MODE' non è utilizzato. Si può allora fare in modo che alla sua attivazione la visualizzazione passi dall'orario alla data e viceversa. La data sarà presentata nel formato “gg/mm/aa”, mentre l'orario ha lo stesso formato già indicato nel progetto preceden-te: “hh:mm:ss”.

Se il sistema si trova nello stato in cui è visualizzata la data, pre-mendo 'SET' deve essere possibile cambiare il contenuto dei diversi campi seguendo le stesse modalità che si hanno per l'orario. Il dia-gramma degli stati che descrive il nuovo sistema può essere del tipo riportato in Fig. 7.8.

Si crei un nuovo progetto “clock_date” in cui riportare il contenuto completo di “clock_pointer”. Nel file main.c bisogna aggiungere le nuove funzione e i nuovi “stati” che la FSM deve avere. Nel Listato 7.11 è indicata la parte di codice relativa a tali modifiche.

Nella funzione DisplayTime( ) bisogna aggiungere il seguente if:if(mode_pressed){

mode_pressed = 0;current_state = display_date;

}

359

Page 32: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

con cui aggiornare la variabile current_state nel caso in cui sia premu-to 'MODE'.

La funzione DisplayDate( ) si può ottenere con semplici modifiche dalla DisplayTime( ). In questo stato, il contenuto di current_state de-ve essere pari a display_time nel caso in cui sia premuto 'MODE'.

Per le nuove funzioni IncYear( ), IncMonth( ) e IncDay( ) si adotta-no soluzioni simili a quelle scritte per le analoghe funzioni relative al-l'orario. Il programma potrà essere confrontato con la soluzione propo-sta nella cartella “clock_date” (CD).

Figura 7.8. Diagramma degli stati per un orologio con datario. I “cappi”, che indicano la permanenza nello stato quando gli ingressi non sono attivi, sono stati omessi per non appesantire il disegno.

typedef enum {display_time=0, display_date, set_hour, set_min, set_year, set_month, set_day} State_Type;State_Type current_state = display_time;void DisplayTime(), DisplayDate(), SetHour(), SetMin(), SetYear(), SetMonth(), SetDay();void(*state_table[])(void) = {DisplayTime, DisplayDate, SetHour, SetMin, SetYear, SetMonth, SetDay};

Listato 7.11. Dichiarazione degli “stati” e delle funzioni per il progetto di un orologio con datario che segua il digramma di Fig. 7.8.

360

Page 33: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

(Viene anche lasciato per esercizio la verifica del programma che usi l'istruzione switch da confrontare, eventualmente, con quella contenu-ta in “clock_date_switch”, CD)

7.4.5. Ulteriori sviluppi del progetto

La verifica del funzionamento del sistema descritto in questo paragra-fo mette in luce che è piuttosto scomodo che l'incremento del partico-lare parametro avvenga di una sola unità a ogni pressione del tasto 'MODE'. Per i minuti, ad esempio, nel caso peggiore saranno necessa-rio fino a 59 pressioni consecutive per la programmazione. Per supera-re questa difficoltà il codice potrà essere modificato in modo da dotare il tasto della funzionalità di autorepeat descritta nel Par. 6.4.1.

Sempre nella direzione di rendere agevole l'impostazione per l'u-tente, un altro sviluppo può consistere nella modifica sostanziale del diagramma degli stati del progetto originario come indicato in Fig. 7.9. Gli stati in cui è possibile aggiornare il contenuto dei registri MIN e HOUR dell'RTC sono stati raddoppiati in modo che l'incremento avvenga sulla singola cifra. La modifica del progetto è relativamente semplice perché è sufficiente ridefinire le funzioni già create prece-dentemente purché si riferiscano a una sola cifra.

Figura 7.9. Modifica del diagramma degli stati dell'orologio con set con cui è possibile programmare il valore della singola cifra dei parametri. Sono omes-si i “cappi” relativi alla permanenza in uno stato per ingressi non attivi.

361

Page 34: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Le due nuove funzioni saranno inoltre molto simili a queste. Infine, invece di cambiare la scritta sul display che segnali che ci si trova nel-la modalità di set, si potrà far in modo che appaia il cursore (come sot-tolineatura, v. Par. 3.6) che segnala la posizione della cifra che può es-sere modificata.

Le modifiche suggerite, che prevedono anche il controllo dei valori entro gli intervalli idonei, sono lasciate come utile esercizio per la rea-lizzazione di un sistema che sia praticamente identico a ciò che è di-sponibile in commercio.

7.5. Modifica del progetto “thermostat”

Il progetto di termostato illustrato nel Par. 5.7 può essere modificato implementando una macchina con numero finito di stati. Ciò non solo renderà più chiara la stesura dell'algoritmo, ma consentirà di migliora-re l'interfaccia verso l'utilizzatore. Infatti, con una FSM ogni pulsante può essere dotato di diverse funzionalità a seconda dello stato in cui si trova il sistema. In Fig. 7.10 è riportato lo schema di montaggio del circuito già adottato nel paragrafo citato.

Figura 7.10. Schema del sistema di regolazione della temperatura ambiente (si riveda il Par. 5.7, Cap. 5, per maggiori dettagli).

362

Page 35: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Rispetto a quello di Fig. 7.1 è stato aggiunto il trasduttore di tempera-tura LM35 (alimentato con i 5aV che giungono all'LCD), il DACMCP4921 e il LED collegato alla sua uscita. Si potrà notare che i no-mi dei due tasti sono stati nuovamente cambiati in 'INC' e 'DEC'. In-fatti, si vuole fare in modo che l'utente possa accedere alla modalità di impostazione del valore di temperatura desiderata Tset premendo uno qualunque dei due tasti: dallo stato di partenza in cui è visualizzato il valore di temperatura ambiente, entrambi funzionano come tasti di set. Successivamente, agendo sugli stessi, sarà possibile incrementare o decrementare il valore di Tset in passi di 1°C. In questa modalità, se il μC non rileva la pressione di nessun tasto per 2 s, il sistema torna a vi-sualizzare il valore di temperatura ambiente Tamb generando, eventual-mente, la tensione di controllo d'uscita Vout.

Ragionando sulle funzioni che la macchina dovrà svolgere, la FSM che permette il passaggio attraverso i diversi modi operativi avrà il diagramma a 4 stati di Fig. 7.11(a) di tipo Moore. La stessa funziona-lità si può comunque ottenere con la macchina Mealy di Fig. 7.11(b) che presenta soltanto due stati. Per semplificare la rappresentazione è stata omessa la freccia relativa al reset che fa entrare la macchina nello stato '0' e i “cappi” che indicano la permanenza in uno stato se nessun tasto è attivo.

Per entrambe le soluzioni, nello stato '0', denominato “Display”, il sistema è nella condizione di normale funzionamento in cui si ha l'ac-quisizione del valore di Tamb e l'aggiornamento di Vout in uscita dal DAC. Si passa allo stato “1”, Set, premendo 'INC' o 'DEC'.

Figura 7.11. Diagramma degli stati per la gestione dei tasti 'INC' e 'DEC' del termostato: macchina di Moore (a) e di Mealy (b).

363

Page 36: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Da questo stato si ottiene l'incremento o il decremento della variabile Tset a seconda dell'ingresso specifico attivato. Per il diagramma di Fig. 7.11(a), l'uscita dagli stati “Incr” o “Decr” è automatica nel senso che, una volta attuato l'incremento o il decremento di Tset, lo stato successi-vo è in ogni caso “Set” indipendentemente dagli ingressi. Nel caso di Fig. 7.11(b), invece, l'incremento o il decremento della variabile av-viene nello stesso stato “Set”.

Per risolvere il problema dell'uscita dallo stato “Set” e tornare in “Display” si può pensare di programmare un timer affinché generi un interrupt quando raggiunge un prefissato valore che indichi che sono trascorsi 2 s (valore del tutto arbitrario). La routine di servizio dell'in-terrupt potrà memorizzare uno “stato logico alto” nella variabile time_2s_elapsed_event che verrà trattata come un qualunque altro in-gresso che fa evolvere la FSM. Anche in questo caso sarà lo stato stes-so a determinare il reset di un tale “ingresso”. Ovviamente, ogni volta che la macchina rileva la pressione di uno dei pulsanti perché si abbia un incremento o un decremento di Tset, il timer dovrà essere azzerato e riavviato per ricominciare un nuovo periodo di “misura” di 2 s.

Si potrà giungere allo stesso risultato anche senza che sia necessa-rio coinvolgere l'ulteriore segnale di interrupt proveniente dal timer. Infatti, la periferica potrà essere inizializzata la prima volta quando si sta per uscire dallo stato “Display”. Il timer viene riavviato quando si entra negli stati “Incr” e “Decr” per la macchina di Moore o si ha l'ag-giornamento di Tset per quella di Mealy. Nello stato “Set” si verifiche-rà continuamente se il conteggio ha raggiunto il valore limite di 2 s. In questo caso si dovrà tornare nello stato “Display”. Nel seguito il pro-getto sarà sviluppato adottando questa seconda soluzione che non coinvolga l'uso di interrupt21.

Tutte le funzioni che si riferiscono ai diversi stati possono essere inserite in un unico file main.c le cui sezioni vengono ora descritte. Come anticipato, sarà considerato il caso di FSM di tipo Moore di Fig. 7.11(a).

21 La prima soluzione, con generazione di interrupt, può essere svolta per esercizio, molto utile per verificare l'effettiva conoscenza sull'uso di IRQ generati da un ti-mer (v. Cap. 6). La soluzione potrà essere ottenuta con semplici modifiche di quanto esposto in questo paragrafo. Si potrà così valutare la differenza tra le di-mensioni dei codici che si hanno nei due casi.

364

Page 37: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Il Listato 7.12 si riferisce alla prima sezione principale del file main.c dedicata alla dichiarazione delle variabili globali, delle funzio-ni e alla definizione del codice del main( ). Sono stati inclusi i medesi-mi file utilizzati per il progetto “thermostat” del Par. 5.7. Si rimanda a questo paragrafo per la descrizione dei file specifici per i dispositivi convertitori, ADC e DAC. Altri file si riferiscono a quelli ormai noti e inseriti quasi in ogni progetto affrontato finora (LCD e infrastruttura).

Le due variabili globali inc_pressed e dec_pressed sono gestite da due routine di interrupt del tutto identiche a quelle riportate nel Listato 7.1 che in pratica sono state impiegate in tutti i progetti del capitolo.

Inoltre, anche la variabile Tset è globale poiché verrà utilizzata quasi da tutti gli stati: nello stato “Display” essa è utile a calcolare il valore di tensione d'uscita per il DAC, mentre gli stati “Incr” e “Decr” si oc-cuperanno del suo aggiornamento.

Segue la definizione degli stati della FSM, (utilizzando il tipo enum già visto nel paragrafo precedente). La variabile current_state relativa allo stato corrente, è dichiarata proprio come State_Type ed è inizializzata a display_Tamb (ground state, in cui si entra al reset). Al solito, le funzioni che definiscono le azioni da svolgere nei diversi sta-ti, dichiarate nelle successive due righe, hanno un nome che riprende direttamente quello degli stati stessi.

Nella funzione main( ) vengono inizializzate tutte le periferiche co-sì come era stato svolto nel progetto “thermostat”.

Come accennato, nello stato “Set”, il Timer 0 viene utilizzato per verificare se sono trascorsi 2 s senza che sia stato premuto alcun pul-sante. Esso viene programmato perché si abbia una risoluzione di 1 ms.

Infine, il ciclo while(1) richiamerà con state_table[ ] una delle quattro possibili funzioni di stato a seconda del valore assunto da cur-rent_state.

Nello stato “Display”, current_state è pari a display_Tamb e viene eseguita la funzione DisplayTamb( ) riportata nel Listato 7.13. In que-sta funzione viene acquisito il valore di tensione fornita dal trasduttore LM35 attraverso il canale CH0 dell'ADC (P0.22). Il valore restituito dal convertitore è trasformato in mV e scritto sul display nel formato “###.# °C” (si riveda quanto svolto nel Par. 5.3).

365

Page 38: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

/************************************************************ * File Name : main.c * Project : thermostat_FSM * Abstract : thermostat project modified using FSM ************************************************************/#include "lpc2103.h"#include "framework.h"#include "HD44780.h"#include "adc.h"#include "dac.h"#include "ext_int.h"#include "isr.h"unsigned char inc_pressed=0, dec_pressed=0;unsigned int Tset=10; //every state uses Tsettypedef enum {display_Tamb=0,set_Tset,

inc_Tset, dec_Tset} State_Type;State_Type current_state = display_Tamb;void DisplayTamb(), SetTset(), IncTset(), DecTset();void(*state_table[])(void) = {DisplayTamb, SetTset, IncTset, DecTset};

int main(void){ InitLCD(); PutCommand(RETURN_HOME); delayMs(5); WriteString((unsigned char*)"Start..."); delayMs(500); init_extIRQ(EINT0_CONN+EINT0_EDGE+EINT0_FALL+

EINT2_CONN+EINT2_EDGE+EINT2_FALL); enIRQ(EINT0_VIC_Ch, EINT0_ISR,14); enIRQ(EINT2_VIC_Ch, EINT2_ISR,13); SEL_ADC0; InitADC(); //set ADC CH0 (P0.22) LM35 input IODIR |= SDI+SCK+CS; //set P0.19, P020, P021 as output IOSET = CS; delayUs(1); IOCLR = SCK; delayUs(1); WriteDAC(CHA+UNBUFF+GAINx1+SHDNoff);//Send data to DAC (0V) TIMER0_TCR = 0x02; //stop and reset timer 0 TIMER0_PR = PCLK/1000; //set prescaler for ms resolution TIMER0_IR = 0xff; //reset all interrrupt flags

while(1) {

state_table[current_state](); //call state functiondelayMs(10);

} return 0;}

Listato 7.12. File main.c: definizioni iniziali e listato main( ).

366

Page 39: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Nel caso in cui il valore desiderato Tset superi quello Tamb 22 viene aggiornato il valore da inviare al DAC. Il numero a 12 bit ottenuto è concatenato ai 4 bit di configurazione, già scalati opportunamente gra-zie alle definizioni scritte nel file dac.h e la parola a 16 bit ottenuta è trasmessa all'MCP4921 con la funzione WriteDAC( ).

Nel caso in cui sia intervenuto un interrupt esterno dovuto alla pressione di un tasto, current_state viene opportunamente aggiornato allo stato che dovrà essere eseguito mentre Timer 0 è avviato.

void DisplayTamb(){ unsigned int Tamb, DACdata; Tamb =(VREF_mV*(ReadADC(CH0, 10))) >> 10; //sample CH0 PutCommand(RETURN_HOME); delayMs(5); Write_ndigitsval(Tamb/10, 3); delayMs(1); WriteChar('.'); delayMs(1); Write_ndigitsval(Tamb%10, 1); delayMs(1); WriteChar(' '); WriteChar(0xDF); WriteChar('C'); if((10*Tset)>Tamb) {

DACdata =(((10*Tset)-Tamb)*4096)/165;if(DACdata>2482) DACdata=2482; //max Vout=2 V

} else DACdata = 0; WriteDAC(CHA+UNBUFF+GAINx1+SHDNoff+DACdata);//Send data if(inc_pressed || dec_pressed) {

current_state = set_Tset; //Next stateinc_pressed = 0; //reset eventdec_pressed = 0;TIMER0_TCR = 0x01; //start timer

} delayMs(100);}

Listato 7.13. File main.c: funzione DisplayTamb() per lo stato “Display”.

22 Come indicato nel Par. 5.7, la cifra meno significativa di Tamb è pari a 0.1 °C mentre quella di Tset è 1 °C e quindi il confronto deve essere 10xTset > Tamb.

367

Page 40: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Il Listato 7.14 si riferisce allo stato in cui l'utente può aggiornare il valore desiderato di temperatura Tset. Nella funzione SetTset( ) viene cambiato il messaggio sul display proprio per segnalare che il sistema si trova nella modalità di setting. La funzione verifica tre possibili condizioni che determinano l'uscita dallo stato stesso. Nelle prime due la verifica riguarda la pressione di un pulsante. Il valore della variabile current_ state è modificato in inc_Tset o dec_Tset in base all'evento. In questi casi il Timer 0 è resettato e avviato nuovamente in modo che i 2 s si riferiscano al successivo caso di nessun tasto premuto. La terza condizione è relativa al conteggio assunto da Timer 0. Se questo ha su-perato il valore di 2000 (ms) significa che il sistema deve ritornare alla funzione DisplayTamb( ). Allora, la variabile current_state assumerà in questo caso il valore display_Tamb mentre Timer 0 può essere re-settato e fermato per riutilizzarlo in una chiamata futura di SetTset( ).

void SetTset(){ PutCommand(RETURN_HOME); delayMs(5); WriteLine((unsigned char*)"Set:", 0); Write_2digitsval(Tset); delayMs(1); WriteDAC(CHA+UNBUFF+GAINx1+SHDNoff);//Send data to DAC (0V) if(inc_pressed) {

current_state = inc_Tset; //Next stateinc_pressed = 0; //reset eventTIMER0_TCR = 0x02; //stop and reset timer 0TIMER0_TCR = 0x01; //restart timer 0

} if(dec_pressed) {

current_state = dec_Tset; //Next statedec_pressed = 0; //reset eventTIMER0_TCR = 0x02; //stop and reset timer 0TIMER0_TCR = 0x01; //restart timer 0

} if(TIMER0_TC > 2000) //if 2s elapsed {

current_state = display_Tamb; //return to ground stateTIMER0_TCR = 0x02; //stop and reset timer 0

}}

Listato 7.14. File main.c: funzione SetTset( ) per lo stato “Set”.

368

Page 41: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Si noti che ponendo per ultima la verifica sul timer, se il tasto viene premuto in concomitanza dello scadere dei 2 s, non si salterà allo stato di aggiornamento di Tset. Volendo evitare che il tasto non sia acquisito nel caso in cui sia premuto allo scadere dei 2 s sarà sufficiente inserire l'ultimo if in uno dei campo else precedenti23.

Le due funzioni relative all'aggiornamento e memorizzazione del valore di Tset sono indicate con il Listato 7.15. Si noti che è stato scel-to un valore di temperatura compreso tra i 10 e i 35 °C.

Il progetto completo può essere trovato nella cartella “thermostat_ FSM” (CD).

Per progetti semplici come quello qui presentato si può obiettare che non esista alcun vantaggio rispetto a una soluzione che non usi una FSM. Nel caso specifico del termostato analizzato, il diagramma di flusso dell'algoritmo è del tipo riportato in Fig. 7.12. Questo risulta lineare, nel senso che il flusso non prevede incroci nelle transizioni.

void IncTset(){ Tset++; if(Tset>35) Tset=10; current_state = set_Tset; //Next state}

void DecTset(){ Tset--; if(Tset<10) Tset=35; current_state = set_Tset; //Next state}

Listato 7.15. File main.c: funzioni IncTset( ) e DecTset( ) per gli stati “Incr” e Decr”.

23 Anche se per l'applicazione specifica questo non risulta molto importante, in ge-nerale si deve sempre considerare la priorità che in pratica si assume quando di-versi if sono posti in sequenza.

369

Page 42: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

Quale confronto con il progetto esposto nelle pagine precedenti, so-prattutto in termini di dimensione nella memoria flash del μC, si provi a sintetizzare il sistema che implementa l'algoritmo di Fig. 7.12 (una soluzione è proposta nel progetto “thermostat_IF-”, CD). Tuttavia, come già osservato, il metodo di stesura, basato su una macchina a stati che faccia uso di puntatori a funzioni o lo switch, facilita notevol-mente non solo la scrittura del progetto, ma anche il suo eventuale ag-giornamento.

Figura 7.12. Diagramma di flusso della soluzione con if per il sistema con diagramma degli stati di Fig. 7.11.

370

Page 43: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

7.6. Esercizi

E7.1 Per il generatore di sequenza discusso nel Par. 7.2 si ricavi la soluzio-ne nel caso in cui gli ingressi siano attivi sul livello. È opportuno che i pulsanti usati nello schema di Fig. 7.1 siano sostituiti con due interrut-tori seguendo il suggerimento dato nella figura riportata qui di seguito. Utilizzando resistori di pull-down, l'attivazione corrisponderà allo sta-to ligico alto. Per i segnali di ingresso si consiglia di non ricorrere a una gestione mediante routine di servizio di interruzioni, ma di inseri-re, nei diversi stati, il test sul valore dei bit b15 e b16 del registro IOPIN. Il diagramma degli stati della FSM è quello descritto nel Par. 7.2.3.

E7.2 Compilare i progetti “clock_pointer” e “clock_switch” e osservare le dimensioni di ciascuno per valutare la percentuale di risparmio nel-l'occupazione di memoria che si ha a seconda del metodo.

E7.3 Nei progetti “clock_pointer” e “clock_switch” quando si ha il set di ore e minuti, al ritorno, nella modalità di visualizzazione, il valore dei secondi rimane comunque quello corrente. Modificare i progetti in modo che invece il valore dei secondi sia azzerato, ma solo nel caso in cui sia stato modificato almeno uno tra i due parametri dell'orario.

E7.4 Modificare il codice del progetto “clock_pointer” per inserire la varia-bile sec_elapsed_event posta a '1', a seguito di un'interruzione, ogni volta che trascorre 1 s. Con essa si deve fare in modo che la scritta sul display sia aggiornata solo con cadenza di 1 s anziché continuamente.

E7.5 Nel progetto di un orologio con datario (v. Par. 7.4.4), si inserisca, per il pulsante 'MODE', la funzionalità di tasto con autorepeat descritta nel Par. 6.4.1 in modo da rendere più agevole l'aggiornamento dell'o-rario durante il set.

371

Page 44: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII

E7.6 Per il progetto dell'esercizio precedente, apportare le modifiche neces-sarie in modo che durante il set si abbia il lampeggio della grandezza che viene modificata.

E7.7 Si provi a descrivere il sistema dell'orologio con datario per mezzo di un diagramma di flusso e a tradurre l'algoritmo nel codice che utilizzi l'istruzione goto. Si valutino i vantaggi e gli svantaggi del metodo ri-spetto all'uso di una descrizione con la macchina a stati illustrata nel testo.

E7.8 Progettare un orologio con la funzione di sveglia. Il set dell'orario cor-rente avviene con le stesse modalità viste per il progetto “clock_poin-ter”: 'SET' per entrare nella modalità di impostazione; 'MODE' per la modifica dei valori di ora e minuti. Per l'allarme si deve implementare un soluzione del tipo usata nell'orologio con datario. In particolare, premendo il pulsante 'MODE' viene visualizzato il valore impostato per la sveglia; se non si preme alcun tasto per 3 s, si torna alla visua-lizzazione dell'orario corrente. Viceversa, se entro i 3 s si preme 'SET' si entra nella modalità in cui è possibile cambiare i valori dell'ora e dei minuti dell'allarme. Quando l'orario corrente è pari a quello dell'allarme deve essere co-mandata l'accensione di un LED che può essere spento premendo il pulsante 'MODE'.

E7.9 Modificare il progetto dell'esercizio precedente per inserire la funzio-ne snooze: se viene premuto il tasto 'MODE', in condizione di allarme, l'allarme cessa e il LED si spegne, ma si ha la ripetizione dell'allarme, con accensione del LED, dopo 5 minuti. L'allarme è definitivamente tolto solo se si preme il tasto 'SET'.

E7.10 Nel progetto relativo al termostato (Par. 7.5) apportare la modifica ne-cessaria perché l'acquisizione della temperatura ambiente avvenga una volta al secondo e non ogni volta che si entra nello stato “Display”.

372

Page 45: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Progetto di macchine con numero finito di stati

Riferimenti

• MARTIN GOMEZ, Embedded State Machine Implementation, in “Embedded Systems, World Class Design”, ed. J. Ganssle, chap. 6, Newnes, Elsevier, New York, 2008.

373

Page 46: Progetto di macchine con numero finito di stati · Progetto di macchine con numero finito di stati 7.2.1. Soluzione mediante il diagramma di flusso dell'algoritmo Il lavoro che la

Capitolo VII374