Nel precedente tutorial abbiamo visto come realizzare un decoder accessori DCC con Arduino.
Per semplificare lo sketch, tutti i parametri di configurazione del decoder (in particolare il suo indirizzo) sono stati definiti come costanti:
Spesso è però utile poter cambiare la configurazione del decoder senza riprogrammare il suo firmware (= lo sketch in esecuzione nel microcontrollore ATMega). Le specifiche DCC comprendono proprio un documento (S-9.2.2 DCC Configuration Variables) che introduce – per i decoder – il concetto di Configuration Variables (CV).
Le CV sono dei parametri, memorizzati in maniera non volatile (ovvero vengono mantenuti anche in mancanza di corrente) all’interno dei decoder, che possono definire diversi aspetti del funzionamento del decoder stesso.
La NMRA definisce, sempre nel documento S-9.2.2, un elenco di CV, numerandole da 1 a 1024 e attribuendo ad ognuna di esse un significato. Ad esempio per un decoder accessori è stabilito che l’indirizzo (9 bit) sia contenuto nelle CV 513 e 521:
Quando acquistiamo un decoder commerciale, nel manuale è sempre riportata una tabella che indica, per ciascuna CV supportata, il significato. Ad esempio il manuale del decoder ESU SwitchPilot Servo, decoder in grado di comandare dei servocomandi per attivare scambi o altri movimenti, elenca le CV che controllano la posizione e la velocità dei 4 servocomandi:
Molte centrali digitali supportano la service mode (documento S-9.2.3), ovvero sono in grado di programmare i valori delle CV di un decoder collegato ad una loro particolare uscita, detta binario di programmazione. Il modellista può quindi regolare il comportamento dei decoder installati nelle locomotive o che controllano accessori del plastico semplicemente posizionando le locomotive (o collegando i decoder accessori) sul binario di programmazione e programmando i corretti valori nelle CV.
NmraDcc
Una volta appreso il significato delle CV, vediamo come gestire la loro programmazione all’interno del nostro sketch.
Dobbiamo memorizzare i valori delle diverse CV in un’area di memoria che non venga cancellata ogni volta che spegniamo il decoder. Il processore ATMega328 utilizzato dal nostro Arduino Uno ha al suo interno una memoria non volatile da 1024 bytes; grazie alla libreria EEPROM di Arduino possiamo memorizzare e leggere valori in tale area di memoria.
La libreria NmraDcc può gestire autonomamente la gestione delle CV o – in alternativa – lasciarla completamente al programma esterno.
Se prendiamo il caso di scrittura di una CV (la centrale che scrive il valore di una CV nel decoder), la libreria NmraDcc offre infatti due metodi di callback:
[checklist]
- extern uint8_t notifyCVWrite( uint16_t CV, uint8_t Value);
- extern void notifyCVChange( uint16_t CV, uint8_t Value);
[/checklist]
Il primo metodo sostituisce la gestione CV standard della libreria, mentre il secondo viene chiamato per notificare che una CV ha cambiato valore. Se guardiamo il codice della libreria la differenza risulta chiara:
La libreria definisce inoltre i numeri di alcune CV standard, tra le quali quelle relative all’indirizzo del decoder:
Decoder LED
Riprendiamo lo sketch del decoder LED del precedente tutorial e aggiungiamo la gestione delle CV.
Definiamo due CV:
[checklist]
- la modalità di funzionamento (CV10)
- la velocità di lampeggio (CV11)
[/checklist]
Grazie alla CV10 sarà possibile scegliere se il led attivato sarà acceso fisso (valore della CV = 0) oppure lampeggiante (valore della CV = 1). In questo secondo caso, la velocità di lampeggio sarà configurata tramite la CV11 (dal valore 1 = 5 secondi al valore 100 = 50ms).
Definiamo per prima cosa una costante per ogni CV e il relativo numero:
#define CV_ACCESSORY_DECODER_MODE 10 #define CV_ACCESSORY_DECODER_BLINK_FREQ 11 |
Definiamo inoltre delle variabili che conterranno il valore a runtime di tali CV per evitare di leggere continuamente la EEPROM (che, secondo il datasheet, ha un ciclo di vita di circa 100.000 letture/scritture):
int decoderMode; int blinkFrequency; |
Nel metodo setup() dobbiamo quindi leggere i valori delle CV dalla EEPROM e assegnarli alle variabili:
decoderMode = Dcc.getCV(CV_ACCESSORY_DECODER_MODE); blinkFrequency = Dcc.getCV(CV_ACCESSORY_DECODER_BLINK_FREQ); |
Lasciamo gestire alla libreria la memorizzazione dei valori delle CV nella EEPROM. Per essere informati di quando uno di questi valori cambia e quindi aggiornare le nostre variabili, definiamo il metodo notifyCVChange():
void notifyCVChange(uint16_t CV, uint8_t Value) { if(CV == CV_ACCESSORY_DECODER_MODE) decoderMode = Value; else if(CV == CV_ACCESSORY_DECODER_BLINK_FREQ) blinkFrequency = Value; } |
Blink
Per gestire il lampeggio dei led, possiamo utilizzare la libreria Timer1. Tale libreria consente di eseguire periodicamente una funzione di callback.
La funzione di callback semplicemente cambia lo stato del led per ottenere il lampeggio:
void blinkLED() { digitalWrite(ledActive, !digitalRead(ledActive)); } |
Se il decoder è in modalità lampeggio, al cambio di stato dell’uscita viene identificato il led attivo e schedulata la funzione di callback in base alla frequenza configurata nella apposita CV. In caso contrario viene semplicemente acceso il led:
if(outputInPair == 0) { digitalWrite(GREEN_LED_PIN, LOW); ledActive = RED_LED_PIN; } else { digitalWrite(RED_LED_PIN, LOW); ledActive = GREEN_LED_PIN; } if(decoderMode == 1) { Timer1.setPeriod(5000000 / blinkFrequency); Timer1.attachInterrupt(blinkLED); } else digitalWrite(ledActive, HIGH); } |
Demo
Ecco un filmato che mostra come sia possibile modificare il funzionamento del decoder led programmando opportunamente le CV tramite PC (software Rocrail) e centrale digitale SPROG (sottotitoli in italiano disponibili):
Molto molto interessante. !!
Compliementi Luca, molto interessante.
Vorrei saperne di più sulla configurazione tramite CV.
Sto sviluppando un decoder per segnali configurabile via seriale ma vorrei aggiungere anche l’opzione CV’s
grazie Marcello! Sto sviluppando meglio il tema DCC con dei video su Youtube: i prossimi saranno proprio relativi allo sviluppo di un decoder e alla sua programmazione via CV!