Dopo aver realizzato uno shield per interfacciare Arduino ad un bus DCC, vediamo oggi come realizzare un semplice decoder accessori per controllare dei led.
Decoder accessori
Lo standard DCC (in particolare il documento S-9.2.1 DCC Extended Packet Formats) definisce diversi tipi di decoders, ovvero di dispositivi che – collegati al bus DCC – eseguono operazioni in base ai comandi ricevuti.
Un decoder accessori è “intended for control of a number of simple functions such as switch machine control or turning on and off lights” (pensato per controllare alcune semplici funzioni come scambi o luci).
uno dei decoder DCC autocostruiti di Paco
Indirizzamento
Ogni decoder deve rispondere ad uno o più indirizzi. Il documento S-9.2.1 spiega nel dettaglio la struttura di un pacchetto DCC inviato ad un decoder accessori (basic accessory decoder packet format):
9 bit del pacchetto (AAAAAAAAA) identificano l’indirizzo del singolo decoder. I bit più significativi (MSB) dell’indirizzo sono quelli nel secondo bytes, mentre quelli meno significativi (LSB) sono quelli nel primo bytes. Per complicare un po’ le cose, i bit del secondo bytes sono in complemento a uno.
Vediamo un esempio pratico per capire meglio:
I bit più significativi sono 011. Effettuandone il complemento uno diventano 100.
I bit meno significativi sono 0010011. Concatenando i 9 bit si ottiene 1000010011, il decoder avrà quindi indirizzo 267.
2 bit (PP) indicano l’indirizzo della singola porta del decoder. Per convenzione un decoder accessori ha quindi 4 porte, ognuna formata da una coppia di uscite.
Il bit O indica, per la porta indicata dai bit PP, l’uscita a cui il comando è indirizzato. Infine il bit C indica se l’uscita deve essere attivata (1) o disattivata (0).
Alcuni produttori preferiscono utilizzare un indirizzamento “piatto” (non distinguendo tra indirizzo decoder, numero porta e uscita). Una buona spiegazione di come funzionano le diverse modalità di indirizzamento (MADA, PADA…) è presente sulla wiki di Rocrail.
Arduino
Per sviluppare lo sketch del nostro decoder accessori con Arduino, dobbiamo per prima cosa installare la libreria NmraDcc utilizzando il Library Manager:
Includiamola quindi nello sketch, istanziando anche un oggetto di tipo NmraDcc:
#include "NmraDcc.h" NmraDcc Dcc; |
Nel setup() dobbiamo configurare e inizializzare la libreria. Per prima cosa utilizziamo il metodo pin() per indicare alla libreria il pin di Arduino a cui è collegato il segnale DCC (ExtIntPinNum), il relativo interrupt (ExtIntNum). Decidiamo inoltre se abilitare o meno la resistenza di pullup interna:
void pin(uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup); |
L’elenco dei pin utilizzabili per ogni board Arduino è disponibile nella wiki, mentre si può utilizzare il metodo digitalPinToInterrupt() per ottenere il numero di interrupt associato ad un determinato pin.
Se state utilizzando lo shield che ho presentato in un precedente articolo con una scheda Arduino Uno, il pin da configurare è il numero 2 con resistenza di pullup attiva, quindi:
#define DCC_PIN 2 [...] Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, 1); |
Passiamo ora alla configurazione della libreria, con il metodo:
void init(uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV); |
I primi due valori indicano il codice produttore e la versione del decoder e possono essere ottenuti dalla centrale DCC leggendo le relative CV (configuration variables). Per i decoder autocostruiti, il ManufacturedId viene impostato a MAN_ID_DIY.
Il terzo valore consente di indicare, in OR, alcuni flags:
Per un decoder accessori dobbiamo utilizzare il terzo flag (DCC_ACCESSORY_DECODER).

FLAG_MY_ADDRESS_ONLY
Terminata la configurazione della libreria, perché questa gestisca i messaggi DCC in ingresso dobbiamo chiamare, all’interno del loop(), il metodo process() quanto più frequentemente possibile:
void loop() { Dcc.process(); } |
Alla ricezione di un messaggio diretto ad un decoder accessori, la libreria può chiamare diversi metodi, in base a quanto definito all’interno dello sketch:
- notifyDccAccState()
- notifyDccAccTurnoutBoard()
- notifyDccAccTurnoutOutput()
- notifyDccSigState()
I primi 3 metodi sono invocati per messaggi di tipo basic accessory decoder packet, mentre l’ultimo per extended accessory decoder control packet.
Per il decoder che stiamo realizzando ho scelto il metodo notifyDccAccState():
void notifyDccAccState(uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) |
Questo metodo mette a disposizione alcuni parametri. Vediamo il loro significato tenendo presente quanto spiegato ad inizio articolo sull’indirizzamento:
- BoardAddr è l’indirizzo (9 bit) del decoder
- OutputAddr rappresenta i 3 bit PP e O, ovvero l’indirizzo della porta e dell’uscita
- State è il comando (1 = attivazione, 0 = disattivazione)
- Addr è indirizzo diretto della porta (modalità PADA)
Possiamo separare l’indirizzo della porta (2 bit) da quello della relativa uscita (1 bit) con:
int portAddress = (OutputAddr >> 1) + 1; int outAddress = OutputAddr & 0x01; |
Ho aggiunto 1 all’indirizzo della porta per identificare le porte del decoder con indirizzi da 1 a 4 invece che da 0 a 3.
Il decoder di questo articolo avrà definito come costante nello sketch sia l’indirizzo della scheda, sia quello della porta (in un prossimo articolo vi mostrerò come renderli dinamici):
#define BOARD_ADDRESS 5 #define PORT_ADDRESS 1 |
Possiamo quindi verificare che il comando sia indirizzato al nostro decoder con:
if((BoardAddr == BOARD_ADDRESS) && (portAddress == PORT_ADDRESS)) { |
e modificare lo stato di due pin digitali (a cui ho collegato due led) in base all’indirizzo dell’uscita e al comando:
if(outAddress == 0) { digitalWrite(RED_LED_PIN, HIGH); digitalWrite(GREEN_LED_PIN, LOW); Serial.println("! RED led activated"); } else { digitalWrite(RED_LED_PIN, LOW); digitalWrite(GREEN_LED_PIN, HIGH); Serial.println("! GREEN led activated"); } |
Il codice sorgente del decoder è disponibile sul mio repository Github; ecco un filmato che ne mostra il funzionamento (sottotitoli in italiano disponibili):