INTEGRATI: Esempio SHIFT REGISTER
La board di Arduino possiede pochi pin digitali, ma fortunatamente esistono dei metodi che consentono di incrementare il numero di pin gestibili.
Un modo è quello di impiegare uno shift register a 8 bit che viene controllato da Arduino tramite la funzione ShiftOut().
APPROFONDIMENTO: SHIFT REGISTER:
I registri a scorrimento (shift register) sono componenti costituiti da una catena di celle di memoria ad
un bit interconnesse tra loro (comunemente dei flip-flop). Ad ogni impulso di clock
abbiamo lo scorrimento dei bit da una cella a quella immediatamente adiacente. Lo scorrimento può avvenire verso destra
o verso sinistra
ed in alcuni tipi, detti bidirezionali, sia verso destra che verso sinistra a
seconda dello stato (HIGH o LOW) di una linea
di controllo.
Nella sua versione più semplice il registro a scorrimento ha il seguente funzionamento:
Ad ogni colpo di clock, ciascun flip-flop passa il proprio valore al successivo mentre il primo flip-flop FFA della catena assume il valore del segnale all'ingresso D. Il valore precedentemente memorizzato nell'ultimo flip-flop FFD viene invece assegnato al segnale all'uscita QD del registro a scorrimento.
Il segnale di controllo (clock) dei flip-flop viene attivato simultaneamente su tutti i flip-flop. Ciascun flip-flop campiona il proprio ingresso D (che corrisponde al valore presente all’uscita Q del flip-flop precedente) e lo ripropone alla sua uscita D quando il segnale di controllo (clock) viene disattivato. In questo modo, il contenuto dello shift register “scorre” (shift) di una posizione all’interno della serie di flip-flop presenti.
Il modello semplice del registro a scorrimento può essere arricchito di funzionalità. Ciò richiede l'aggiunta di alcuni segnali addizionali:
- reset: imposta tutti i valori dei flip-flop a '0';
-
set: imposta tutti i valori dei flip-flop a '1';
- right/left: indica in che direzione effettuare lo scorrimento;
- enable: abilita oppure disabilita lo scorrimento durante
il ciclo di clock;
- data in/load: una volta attivato il segnale di load, imposta
all'ingresso data-in la sequenza di bit di input consentendo la
scrittura in parallelo dello shift register;
- data out porta all'esterno i valori di uscita di tutti i flip-flop, consentendo una lettura parallela del contenuto dello shift register.
Con l'aggiunta dei segnali data in/load e data out, il registro a scorrimento può essere utilizzato per la
conversione seriale/parallela dell' elaborazione.
Esistono vari tipi di Shift register:
SIPO (Serial Input - parallel output).
E' utilizzato per ampliare il numero di porte di output o per convertire un
segnale da seriale a parallelo.
Analizziamone il suo funzionamento:
impostando il pin Clear tutte le uscite in
parallelo dello Shift Register vengono poste allo stato LOW (zero).
Supponiamo ora che in ingresso sul pin
D (data in) del modulo
FFA si abbia lo stato HIGH. Al primo
impulso di clock l'output Q di
FFA e
QA verranno posti a HIGH mentre i
Q dei rimanenti moduli restano allo stato
LOW
(zero). Assumiamo che ora sul pin D di
FFA
si abbia un valore logico LOW (0). Il successivo impulso di
clock cambia l'output di FFA a
LOW (zero)
mentre l'output di FFB e
QB vengono posti
a HIGH (uno). L'1 iniziale è stato quindi shiftato di un
posto a destra. Al terzo impulso di clock l'1 viene mosso sull'output
di FFC e QC e cosi via.
PISO (Parallel Input - serial
output) E' utilizzato per ridurre le porte di input o per convertire un
segnale parallelo in seriale. L’informazione
immessa in parallelo nella serie di flip-flop viene letta in serie (un bit
alla volta) all’uscita dell’ultimo flip-flop dello shift register
SISO (Serial Input - Serial output)
- In questo tipo di registro è presente un solo terminale di ingresso su cui i bit vengono caricati uno alla volta (in forma seriale).
Appena viene attivato il
primo segnale di clock il dato presente all'ingresso D
viene trasferito all'uscita Q della prima cella. Al
successivo impulso di clock il dato passa alla seconda cella.
Successivamente, alla terza e così via fino all'uscita dell'ultima cella di memoria dove i dati vengono letti uno alla volta, quindi sempre in forma seriale.
I registri SISO possono essere utilizzati per variare la velocità di
trasferimento dei dati seriali su una linea nel caso in cui un dispositivo
lento debba trasferire dei dati ad un dispositivo più veloce. I bit che
arrivano dal dispositivo lento vengono memorizzati nel registro per poi
essere inviati con una differente frequenza. Un'altra
applicazione può essere quella di utilizzare un registro a scorrimento come
linea di ritardo per far pervenire ad un elemento di un sistema un segnale
con un certo ritardo rispetto al momento in cui viene generato. La durata
del ritardo può essere variata cambiando la frequenza del clock oppure
prelevando il segnale su una diversa uscita del registro.
PIPO (Parallel Input - parallel output).
I dati sono presentati in formato parallelo sui pin di input e shiftati sul
corrispondente pin di output quando i registri ricevono il segnale di clock.
Viene utilizzato come memoria temporanea o come device che introduce un
certo ritardo nel segnale.
I flip-flop (o bistabili) sono circuiti elettronici sequenziali molto semplici, utilizzati nell'elettronica digitale come dispositivi di memoria elementare. Il nome Flip-Flop deriva dal rumore che facevano i primi circuiti di questo tipo, costruiti con relè che permettevano il cambiamento di stato. Ne esistono diversi tipi: S-R, J-K, T, Latch D, D-Edge-Triggered.
Tratteremo solo il Latch D e il D-Edge-Triggered. Prima di introdurre la spiegazione del flip-flop D-Edge-TriggeredI partiamo illustrando il funzionamento del Latch D.
APPROFONDIMENTO: LATCH D
Nel latch D è presente un ingresso E (enable) che ha la funzione di abilitazione. Se E viene portato a 1 l'uscita Q assume il valore che in quell'istante è presente sull'ingresso D.
Quando l'ingresso E viene mantenuto a livello basso l'uscita Q conserva il proprio stato indipendentemente dal valore assunto dall'ingresso D in quell'istante. Q mantiene lo stato assunto (quindi memorizza lo stato) e lo conserva fino a che E torna ad 1 e D assume un valore diverso da Q.
La caratteristica di mantenimento dell'uscita Q da parte del latch D lo rende adatto all'impiego come interfaccia di memoria nel comando di tastiere o visualizzatori. Questo componente è trasparente in quanto lo stato all'ingresso D è trasferito immediatamente all'uscita Q quando l'ingresso E vale 1. Questo può essere causa di comportamenti indesiderati nel caso il componente fosse montato in contesti in cui l'uscita è riportata negata in ingresso. In questo caso essa comincerebbe a oscillare e, non appena E torna a 0, si verrebbe a marcare un valore del tutto casuale. Per questo motivo sono state create delle varianti non trasparenti note in letteratura come flip-flop D-Edge-Triggered (o semplicemente flip-flop) basate sull'idea di eseguire il campionamento e la memorizzazione in intervalli temporali ben distinti. Mentre il Latch D è abilitato sul livello del segnale sull'ingresso E i flip-flop D risultano attivati dai fronti di commutazione del segnale.
APPROFONDIMENTO: FLIP-FLOP D-EDGE TRIGGERED
D-Edge-Triggered Flip Flop (pilotati dal fronte di
commutazione - positivo se di salita, negativo se di discesa)
(link a sito interessante
http://www.play-hookey.com/digital/sequential/d_nand_flip-flop.html
)
Il funzionamento di un flip-flop D-Edge-Triggered è scandito non dal segnale di clock ma dai suoi fronti di commutazione. Ad esempio nel caso di un flip-flop comandato dal fronte di salita del segnale di clock il valore all'ingresso D viene trasferito all'uscita Q solo quando il clock passa da 0 a 1.
Per rendere il dispositivo sensibile solo al fronte del segnale di clock viene utilizzato un circuito ausiliario definito generatore di impulsi che sfrutta i tempi di propagazione delle porte NOT creando un impulso di durata brevissima indipendente dalla durata dello stato alto del segnale di clock (vedesi cronogramma sottostante).
A causa della presenza della porta NOT sembrerebbe che l'ingresso E non possa mai essere abilitato (livello HIGH): infatti i due ingressi
dell'AND non possono essere contemporaneamente a livello
HIGH.
Tuttavia, a
causa del ritardo di propagazione introdotto dal NOT, esiste in realtà un
brevissimo intervallo di tempo durante il quale entrambi gli ingressi dell'AND
sono effettivamente a livello HIGH. Come si può notare il segnale di abilitazione
E che giunge al latch D ha una durata brevissima, pari in pratica al ritardo di propagazione della porta
NOT. Di conseguenza l'intervallo di memorizzazione del latch risulta brevissimo e può essere sincronizzato con grande precisione
Il circuito precedente si chiama flip flop D pilotato sul fronte di salita (positive edge triggered D flip flop).
Ha
il seguente simbolo
e la seguente tabella di verità:
e il seguente schema circuitale:
Si noti il simbolo del triangolino usato per l'ingresso CK. Tale simbolo sta a indicare che CK è un segnale attivo sul fronte (e non un segnale attivo sul livello, come per esempio D).
Sostituendo la porta AND con una porta NOR si può realizzare un flip flop D pilotato sul fronte di discesa del clock.
Il simbolo di negazione (il "pallino") sull'ingresso CK indica che il segnale è attivo sul fronte di discesa. E' facile anche osservare che è possibile trasformare un Flip Flop pilotato sul fronte di salita del clock in uno pilotato sul fronte di discesa (e viceversa) semplicemente aggiungendo una porta NOT sull'ingresso CK:
Sostituendo ogni Flip-Flop D con il suo schema circuitale interno composto da porte logiche nello schema dello Shift Register otteniamo:
Nella figura successiva si osservi lo scorrimento dei valori all'interno dei registri QA ... QD in corrispondenza del fronte di salita del Clock:
Per ulteriori approfondimenti consiglio la lettura di questo sito: http://www.elemania.altervista.org/digitale/ E' possibile scaricare il file contenente il circuito qui sopra a questo link.
APPROFONDIMENTO: SHIFT REGISTER 74HC595N
Lo shift register che utilizzeremo (74HC595N) negli esempi seguenti è di tipo SIPO (serial input-parallel output - quindi i dati verranno caricati in forma seriale e verranno prelevati contemporaneamente in parallelo sulle uscite dell'integrato QA .. QH) e SISO (Serial Input - Serial Output). Tramite tale dispositivo è possibile controllare 8 uscite con solo 3 pin di Arduino. E' possibile connettere in cascata numerosi di questi integrati per pilotare un numero di porte maggiore come si vede nell'immagine sottostante.
Qui sotto la pin function dell'integrato 74HC595N.
![]() |
|
Il datasheet di 74HC595N lo identifica come “8-bit serial-in, serial or parallel-out shift register with output latches; 3-state”: questo integrato consente in breve di ricevere in modo seriale le informazioni che poi successivamente tramette in uscita in modo parallelo o seriale. Per iniziare la comunicazione seriale c’è bisogno di mettere l’integrato in uno stato di “ascolto” che avviene utilizzando un opportuno pin detto di “latch” (pin 12) e settandolo a LOW. Quando abbiamo terminato la comunicazione seriale basterà rimetterlo ad HIGH. Inoltre “3-state” fa riferimento al fatto che i dati in uscita possono essere oltre che ad HIGH o LOW anche ad “alta impedenza” ma non si può settare un singolo pin di uscita in questa modalità, ma bensì tutti insieme.
Terminato questo approfondimento sulla struttura dello SHIFT REGISTER e dei suoi componenti analizziamo il progetto di arduino. Costruiamo il seguente circuito:
Scriviamo il codice del nostro programma
/* ----------------------------------------------------------------------------------- Esempio creato partendo dal codice pubblicato all'indirizzo: http://englishjavadrinker.blogspot.it/2012/09/an-8-bit-waterfall.html "Code from an English Coffee Drinker" di pubblico dominio. Legge un input di tipo analogico (valori da 0 a 7) sul pin 4, lo trasforma in binario (8 bit) e li manda tramite la funzione shift out sui pin di output in parallelo ----------------------------------------------------------------------------------- */ int Pin_AbilitaScrittura = 2; // Pin 12 sullo SR - Cavo Bianco int Pin_ClockRegister = 3; // Pin 11 sullo SR - Cavo Blu int Pin_SerialInput = 4; // Pin 14 sullo SR - Cavo Marrone void setup() { // Setto i pin come uscite pinMode(Pin_AbilitaScrittura, OUTPUT); pinMode(Pin_ClockRegister, OUTPUT); pinMode(Pin_SerialInput, OUTPUT); Serial.begin(9600); } void loop() { int Valore; if (Serial.available()) // se ho caratteri disponibili sul monitor seriale { Valore=Serial.read()-48; // Leggi il dato sul Serial Monitor dell'IDE di Arduino if (Valore < 8 && Valore >= 0) { // Abilito la trasmissione del dato sull'ingresso seriale digitalWrite(Pin_AbilitaScrittura, LOW); // Invio il dato sulla porta seriale shiftOut(Pin_SerialInput, Pin_ClockRegister , MSBFIRST, Valore); // Disabilito la scrittura sull'ingresso seriale impostando il // risultato del processo di shift sulle 8 uscite in parallelo digitalWrite(Pin_AbilitaScrittura, HIGH); } } }
Quando utilizziamo il serial monitor ricordiamoci che solo l'ultimo carattere verrà visualizzato sui led
Dal codice si osservi:
Per scrivere un dato sullo shift register devo:
Sintassi funzione:
shiftOut(dataPin, clockPin, bitOrder, Valore)
Shiftout() permette di serializzare il parametro
Valore sul pin
dataPin inviando il segnale di clock (necessario per il
funzionamento dell’integrato) sul pin clockPin. Ogni
bit di
Valore viene scritto sul
dataPin dopo un
impulso del segnale di clock (corrisponde al fronte di discesa - da HIGH
a LOW) che segnala che
il bit è pronto. Sulla base del dato serializzato prodotto dalla funzione Shiftout()e
del segnale di clock lo Shift register parallelizza il dato serializzato in
ingresso sul
suo pin 14 (serial Input) impostando opportunamente le sue 8 uscite Q0...Q7.
I parametri
della funzione sono:
I parametri dataPin e clockPin
devono essere posti come output nel setup()
utilizzando una chiamata opportuna con pinMode();
Shiftout()lavora su un output serializzato di 8 bit
per cui se devo gestire un valore maggiore di 255 devo effettuare due passaggi
come mostrato nel codice sottostante.
/* ----------------------------------------------------------------------------------- Output serializzato a + di 8 bit ----------------------------------------------------------------------------------- */ // Caso con MSBFIRST int data = 500; shiftOut(dataPin, clock, MSBFIRST, (data >> 8)); // Scorrimento bit più significativi shiftOut(dataPin, clock, MSBFIRST, data); // Scorrimento bit meno significativi // Caso LSBFIRST data = 500; shiftOut(dataPin, clock, LSBFIRST, data); // Scorrimento bit meno significativi shiftOut(dataPin, clock, LSBFIRST, (data >> 8)); // Scorrimento bit più significativi }
Che determina i seguenti risultati
Codice Sorgente A
Obiettivo progetto: Utilizzare una fila di 8 led per rappresentare tutti i numeri in binario da 0 a 255.
soluzione:
Costruiamo il seguente circuito (non utilizzando resistenze dobbiamo utilizzare 3.3v poichè altrimenti l'integrato si surriscalda notevolmente!)
Il seguente programma implementa la richiesta:
/* ----------------------------------------------------------------------------------- Visualizza il corrispondente numero in binario sfruttando una fila di 8 led ----------------------------------------------------------------------------------- */ int Pin_AbilitaScrittura = 2; // Pin 12 sullo SR - Cavo Bianco int Pin_ClockRegister = 3; // Pin 11 sullo SR - Cavo Blu int Pin_SerialInput = 4; // Pin 14 sullo SR - Cavo Marrone void setup() { // Setto i pin come uscite pinMode(Pin_AbilitaScrittura, OUTPUT); pinMode(Pin_ClockRegister, OUTPUT); pinMode(Pin_SerialInput, OUTPUT); } void loop() { for (int Valore=0; Valore <256 ; Valore++) { // Abilito la trasmissione del dato sull'ingresso seriale digitalWrite(Pin_AbilitaScrittura, LOW); // Invio il dato sulla porta seriale shiftOut(Pin_SerialInput, Pin_ClockRegister , MSBFIRST, Valore); // Disabilito la scrittura sull'ingresso seriale impostando il // risultato del processo di shift sulle 8 uscite in parallelo digitalWrite(Pin_AbilitaScrittura, HIGH); delay(200); } }
Codice Sorgente B - 8 LED
Obiettivo progetto: Utilizzando lo stesso circuito leggere un valore tra 0 e 255 e rappresentarlo in forma binaria utilizzando una fila di 8 led
soluzione:
Costruiamo lo stesso circuito visto precedentemente e scriviamo il seguente programma
/* ----------------------------------------------------------------------------------- Visualizza in binario, sfruttando 8 led, il numero digitato sul serial monitor ----------------------------------------------------------------------------------- */ int Pin_AbilitaScrittura = 2; // Pin 12 sullo SR - Cavo Bianco int Pin_ClockRegister = 3; // Pin 11 sullo SR - Cavo Blu int Pin_SerialInput = 4; // Pin 14 sullo SR - Cavo Marrone #define MAX_DIGIT 4 // Accetto numeri con al massimo 3 cifre void setup() { // Setto i pin come uscite pinMode(Pin_AbilitaScrittura, OUTPUT); pinMode(Pin_ClockRegister, OUTPUT); pinMode(Pin_SerialInput, OUTPUT); InviaValoreAlloShiftRegister(0); // Spengo i LED Serial.begin(9600); Serial.println("Digita un numero compreso tra 0 e 255:"); } void InviaValoreAlloShiftRegister(int Valore) { // Abilito la trasmissione del dato sull'ingresso seriale digitalWrite(Pin_AbilitaScrittura, LOW); // Invio il dato sulla porta seriale shiftOut(Pin_SerialInput, Pin_ClockRegister , MSBFIRST, Valore); // Disabilito la scrittura sull'ingresso seriale impostando il // risultato del processo di shift sulle 8 uscite in parallelo digitalWrite(Pin_AbilitaScrittura, HIGH); } bool isInteger( char s[] ) { for (int i=0; i < strlen(s); i++ ) if ( !isdigit( s[i] ) ) return false; return true; } void loop() { char buffer[MAX_DIGIT]; int i=0, Valore; if ( (Serial.available() > 0) ) { // Questo Loop senza delay() permette di acquisire tutti i dati // nel buffer del Serial Monitor. while ( (Serial.available()>0) && (i<(MAX_DIGIT-1)) ) { buffer[i++] = Serial.read(); delay(10); // piccolo ritardo per evitare che i singoli digit del numero vengano spezzettati } buffer[i]='\0'; while (Serial.available()>0) Serial.read(); // Lettura a vuoto per eliminare eventuali caratteri in + if (isInteger(buffer)) { Valore=atoi(buffer); if (Valore < 256 && Valore >= 0) { InviaValoreAlloShiftRegister(Valore); Serial.println(Valore); } else Serial.println("Numero "+String(Valore)+" non accettato!"); } else Serial.println(String(buffer)+" non e' un numero!"); i=0; } }
Che produce sul serial monitor il seguente output.
Codice Sorgente C - 16 LED
Obiettivo progetto: Costruire un circuito con 16 led che sia in grado di rappresentare in binario il valore digitato sul serial monitor.
soluzione:
costruiamo questo circuito
La sua realizzazione fisica è mostrata nella foto successiva (sono state usate resistenze da 180 ohm {marrone - grigio - marrone} e 330 ohm {arancio - arancio - marrone}). La tensione utilizzata è quella a 5V.
Ecco il programma che risolve il nostro problema
/* ----------------------------------------------------------------------------------- Visualizza in binario, sfruttando 16 led, il numero digitato sul serial monitor ----------------------------------------------------------------------------------- */ int Pin_AbilitaScrittura = 4; // Pin 12 sullo SR - Cavo Bianco int Pin_ClockRegister = 5; // Pin 11 sullo SR - Cavo Blu int Pin_SerialInput = 3; // Pin 14 sullo SR - Cavo Marrone #define MAX_DIGIT 6 // Accetto numeri con al massimo 5 cifre void setup() { // Setto i pin come uscite pinMode(Pin_AbilitaScrittura, OUTPUT); pinMode(Pin_ClockRegister, OUTPUT); pinMode(Pin_SerialInput, OUTPUT); InviaValoreAlloShiftRegister(0); // Spengo tutti i LED Serial.begin(9600); Serial.println("Digita un numero compreso tra 0 e 65535:"); } // Procedura alternativa a ShiftOut ma adatta a 16 bit void My_shiftOut16Bit(unsigned int Val) { for (int j=15; j>=0 ; j--) { digitalWrite(Pin_ClockRegister,LOW); digitalWrite(Pin_SerialInput,((Val>>j)&1)); digitalWrite(Pin_ClockRegister,HIGH); } } void InviaValoreAlloShiftRegister(unsigned int Valore) { // Abilito la trasmissione del dato sull'ingresso seriale digitalWrite(Pin_AbilitaScrittura, LOW); // Effettuo lo shift di 16 bit MSBFIRST My_shiftOut16Bit(Valore); // Alternativa: doppio ShiftOut di 8 bit // shiftOut(Pin_SerialInput, Pin_ClockRegister , MSBFIRST, Valore >> 8); // High Byte // shiftOut(Pin_SerialInput, Pin_ClockRegister , MSBFIRST, Valore & 0xFF); // Low Byte // Disabilito la scrittura sull'ingresso seriale impostando il // risultato del processo di shift sulle 8 uscite in parallelo digitalWrite(Pin_AbilitaScrittura, HIGH); } // Determina se la stringa di caratteri è un numero intero bool isInteger( char s[] ) { for (int i=0; i < strlen(s); i++ ) if ( !isdigit( s[i] ) ) return false; return true; } void loop() { char buffer[MAX_DIGIT]; int i=0; unsigned int Valore; if ( (Serial.available() > 0) ) { // Questo Loop senza delay() permette di acquisire tutti i dati // nel buffer del Serial Monitor. while ( (Serial.available()>0) && (i<(MAX_DIGIT-1)) ) { buffer[i++] = Serial.read(); delay(10); // piccolo ritardo per evitare che i singoli digit // del numero vengano spezzettati durante la digitazione // sul Serial Monitor } buffer[i]='\0'; while (Serial.available()>0) Serial.read(); // Lettura a vuoto per eliminare eventuali caratteri in + if (isInteger(buffer)) { Valore=atoi(buffer); if (Valore < 65536 && Valore >= 0) { InviaValoreAlloShiftRegister(Valore); Serial.println(Valore); } else Serial.println("Numero "+String(Valore)+" non accettato!"); } else Serial.println(String(buffer)+" non e' un numero!"); i=0; } }
Codice Sorgente D
Obiettivo progetto: Costruire un circuito con 16 led che sia in grado di rappresentare in binario tutti i valori compresi tra 0 e 65.535 (216-1)
soluzione:
Riutilizziamo lo stesso circuito dell'esempio C e inseriamo nell'ide il seguente codice:
/* ----------------------------------------------------------------------------------- Visualizza sfruttando una fila di 16 led tutti i numeri da 0 a 65.535 ----------------------------------------------------------------------------------- */ int Pin_AbilitaScrittura = 4; // Pin 12 sullo SR - Cavo Bianco int Pin_ClockRegister = 5; // Pin 11 sullo SR - Cavo Blu int Pin_SerialInput = 3; // Pin 14 sullo SR - Cavo Marrone void setup() { // Setto i pin come uscite pinMode(Pin_AbilitaScrittura, OUTPUT); pinMode(Pin_ClockRegister, OUTPUT); pinMode(Pin_SerialInput, OUTPUT); } // Procedura alternativa a ShiftOut ma adatta a 16 bit void My_shiftOut16Bit(unsigned int Val) { for (int j=15; j>=0 ; j--) { digitalWrite(Pin_ClockRegister,LOW); digitalWrite(Pin_SerialInput,((Val>>j)&1)); digitalWrite(Pin_ClockRegister,HIGH); } } void loop() { for (unsigned int Valore=0; Valore <65536 ; Valore++) { // Abilito la trasmissione del dato sull'ingresso seriale digitalWrite(Pin_AbilitaScrittura, LOW); // Invio il dato sulla porta seriale My_shiftOut16Bit(Valore); // Disabilito la scrittura sull'ingresso seriale impostando il // risultato del processo di shift sulle 16 uscite in parallelo digitalWrite(Pin_AbilitaScrittura, HIGH); delay(50); } }