Come far muovere i servo con movimento lento e attivare i segnali luminosi usando Arduino

progetto realizzato da Gianni Barbotti

ultima revisione 16/08/2018

email: cromaad91@libero.it

Da tempo inseguivo l'idea di poter comandare il movimento lento dei deviatoi, visualizzarne lo stato con led (quadro sinottico) e comandare i segnali, il tutto in ambiente DCC in modalità manuale o semiautomatica ed automatica usando software quali TrainController , Rocrail o simili senza però usare i decoder per deviatoi e segnali , ma utilizzando Arduino e l'infinità di accessori presenti per Arduino.

I punti qualificanti sono dunque:

a) Usare uno sketch per Arduino UNO R3 e Mega 2560 R3 per gestire deviatoi e segnali in un tracciato ferroviario in ambito DCC, potendo muovere in modo lento gli aghi dei deviatoi e sfumando (fade) il cambio di colore dei segnali anche con software come TCO o Rocrail ecc., utilizzando i micro-servo

b) controllare la posizione dei deviatoi con LED (per es.: rosso = percorso deviato, verde = percorso corretto o viceversa oppure con un solo led : acceso = tracciato corretto, spento = tracciato deviato o viceversa).

c) utilizzare i LED come segnali luminosi (semafori) con effetto di luce sfumata in fase d'accensione e spegnimento.

d) memorizzare lo stato dei micro-servo e dei led in modo tale che, una volta spento e quindi riacceso il sistema-plastico, ogni deviatoio e segnale luminoso si disponesse nello stato in cui si trovava prima dello spegnimento.

Allo scopo ho utilizzato un'interfaccia per Arduino UNO o Mega 2560 con scheda SD.


Quando parlo di interfacce mi riferisco ad elementi di terze parti di Arduino e le cui dimensioni, per fortuna, risultano sempre di pochi centimetri.

Quindi la discriminante era ed è l'utilizzo del microcontrollore Arduino nella versione UNO R3 o Mega 2560 R3 indifferentemente. Il materiale disponibile in rete è notevole, ma non ho trovato nulla che coniugasse tutti i livelli necessari e sufficienti per realizzare l'idea.

Sinteticamente:

  1. i servo muovono i deviatoi
  2. la potenza necessaria a far ruotare l'asse di un servo è fornita da interfacce o schede specifiche
  3. Le interfacce di cui sopra sono a loro volta attivate da Arduino con un programma (sketch) in esso memorizzato
  4. la scelta di quale servo attivare è affidata a chi controlla col palmare la centralina DCC , attraverso la selezione dell'indirizzo del servo, oppure mediante l'utilizzo del software TCO o Rocrail (in modalità automatica o manuale).

Arduino ed il DCC non “parlano” la stessa lingua. Come si può colloquiare con Arduino affinchè invii alle interfacce, che muovono i servo, i comandi in modo corretto e nella sua “lingua”? In ambiente DCC "classico" i deviatoi vengono mossi da motori sottoplancia attivati da decoder. Questi gestiscono i motori , generalmente, in gruppi di quattro ed a ciascuna coppia motore-deviatoio si associa un numero progressivo detto indirizzo. I motori sottoplancia, in questo progetto, sono sostituiti dai micro-servo ed i decoder da interfacce il cui nome è:

16-Channell 12-bit PWM/Servo Driver -I2C - PCA9685

dove :

16-Channel indica che una sola interfaccia gestisce fino a 16 servo

12-bit è la qualità del segnale : in generale più sono i bit e più il segnale è efficace

PWM modulazione di larghezza d'impulso( pulse-width modulation); è un tipo di modulazione digitale che permette di ottenere una tensione media variabile, necessaria a far muovere i servo

I2C è il protocollo con cui queste interfacce colloquiano con Arduino

PCA9685 è l'integrato della scheda-interfaccia con bus I2C che pilota i servo. Il costo unitario di queste interfacce è di molto inferiore , se paragonato a quello di un decoder. Le interfacce si trovano in vendita, in rete, anche con i pin già tutti saldati e pronte all'uso Per trovarle è sufficiente digitare 16-Channell 12-bit PWM/Servo . Il costo di unadi queste interfacce è la metà di quella di un decoder digitale a quattro vie , ma à in grado di monitorare il quadruplo dei deviatoi .

I led sono pilotati dall'interfaccia 24-Channel 12-bit PWM/Led. Ciascuna di queste interfacce possiede 24 coppie di pin alle quali possono essere collegati led monocolore. E' pure possibile gestire led RGB coi quali, miscelando i colori rosso e verde si può ottenere il giallo.

Se Arduino colloquia naturalmente con le interfacce I2C - PCA9685, ed SPI-TLC5947 non riesce però a farlo con la centralina DCC. Per questo c'è bisogno di un'ulteriore elemento, ovvero di una interfaccia o shield DCC per Arduino, la quale faccia da interprete tra la centralina DCC ed Arduino stesso. Qualsiasi DCC shield per Arduino UNO R3 o Mega 2560 va bene. Ho utilizzato alternativamente sia una shield che un'interfaccia DCC. Come interfaccia DCC ho utilizzato questa:

https://www.dccinterface.com/product/arduino-model-railway-dcc-interface/

Le sue dimensioni sono estremamente contenute : 40mm x 24 mm.

Tra l'altro il fornitore (inglese) è molto disponibile per tutte le questioni che potrebbero insorgere.

La shield mi è stata regalata e spedita gratuitamente da Luca Dentella che ringrazio per avermi avviato verso la realizzazione del progetto, affermando che era sicuramente realizzabile visto quanto proposto nel suo sito al link:

http://www.lucadentella.it/2017/11/25/dcc-decoder-accessori-per-led/


Ecco come ho realizzato l'idea utilizzando i seguenti elementi :

1) Arduino UNO Rev 3 (o un Arduino Mega 2560 in sostituzione dell'Arduino UNO se si vuol usare la scheda SD, necessaria alla memorizzazione dello stato dei servo e led. L'Arduino UNO non ha memoria sufficiente per operare con le librerie necessarie al funzionamento dell'intero sketch)

2) due schede 16-Channell 12-bit PWM/Servo Driver -I2C - PCA9685 (due per verificare che le schede lavorino collegate in serie senza alcun problema)

3) due schede Adafruit 24-Channel 12-bit PWM LED Driver - SPI Interface – TLC5947 (due per verificare che le schede lavorino collegate in serie senza alcun problema)

4) Micro Servo (gestibili in numero massimo di 32 con due schede. N schede -> Nx16 servo gestibili)

5) Alimentatore 5V DC 3A (output), 220 V AC (input) per le due 16 canali 12 Bit PWM SERVO, che vanno assolutamente alimentate separatamente, altrimenti i micro-servo non saranno alimentati e non si muoveranno. Se ne connetterete solo una il programma(sketch) funzionerà ugualmente. Alimentatore 20-30 V DC V 5-10 A per alimentare le interfacce 24-Channel 12-bit PWM/Led. Ricordate che i Led rimarranno sempre accesi ed essendo collegati nelle schede tutti in serie, va tenuto conto della caduta di potenziale, per questo la differenza di potenziale (i volt dell'alimentatore, sono così relativamente alti. Per le caratteristiche tecniche di queste interfacce fate riferimento al ai link:

Più sotto troverete un documento in PDF in cui viene spiegato in dettaglio come effettuare i collegamenti.

6) Lenz LZV100 + LH100 + Trasformatore 15 V AC (out) 220V AC (input) + Lenz LI101F + Lenz LA152 questi elementi fanno parte del corredo DCC per gestire manualmente con LH100 il tracciato anche col PC per mezzo di TrainController o Rocrail o altro. Chi non usa il PC non necessita degli ultimi due elementi.

7) PC con sistema operativo Windows 7/8/10 per chi usa TrainControl o Rocrail o altro software

8) TrainController, ma si può usare qualsiasi altro software analogo che supporti il protocollo NMRA. L'uso del software è opzionale, se non lo usate gli elementi Lenz LI101F + Lenz LA152, cioè l'interfaccia PC -> Centralina DCC , non servono.

9) Arduino ed il suo IDE (ambiente di sviluppo per scrivere, modificare e memorizzare i programmi (sketch)) sull'Arduino stesso (si scarica dal sito ufficiale di Arduino ed è gratuito.

10) alimentatore per Arduino (UNO o Mega che sia è indifferente) 9V DC (input) 220V AC output con "jack Japan" (quelli tondi col foro centrale) . Li trovate facilmente in rete , basta digitare "Alimentatore per Arduino".

11) scheda per Arduino con alloggiamento per scheda SD per memorizzare lo stato dei servo e led. Acquistate la scheda con la quantità di memoria più bassa possibile. Infatti dovrà contenere un unico file di testo che occuperà un solo K-byte. Inutile sprecare SD più capienti.

10) Uno sketch che coordini i movimenti dei servo e dei led. Per utilizzare lo sketch dovrete fare, com'è palese dal listato, la download delle librerie:

  • NmraDCC.h
  • SD.h
  • Adafruit_PWMServoDriver.h
  • Adafruit_TLC5947.h

In caso contrario lo sketch segnalerà gli errori connessi a queste mancanze.

Più sotto troverete un PDF, in italiano, nel quale sono indicati i collegamenti con immagini commentate su come connettere le interfacce ad Arduino.

Potete comunque consultare le pagine ufficiali ai seguenti link:

https://www.dccinterface.com/how-to/connecting-interface-arduino/

dove , con immagini, è spiegato molto bene come effettuare i collegamenti dei cinque elementi da connettere:

  • due per il DCC che vanno alla centralina
  • tre per collegarla ad Arduino : due connessioni (GND e 5V per l'alimentazione presa da arduino ai pin GND e 5V dell'interfaccia DCC) ed uno al pin D2 di Arduino per ricevere il segnale digitale


https://learn.adafruit.com/16-channel-pwm-servo-driver?view=all

dove troverete tutto quanto vi serve riguardo i collegamenti tra la scheda 16-Channell 12-bit PWM/Servo Driver ad Arduino UNO R3.

al link https://learn.adafruit.com/tlc5947-tlc59711-pwm-led-driver-breakout/overview

troverete le informazioni relative all'interfaccia 24-Channel 12-bit PWM/led.


N.B: se usate un Arduino Mega 2560 dovrete collegare i pin SCL e SDA della scheda 16-Channel 12-bit PWM/Servo come segue:

pin SCL al pin 21 di Arduino Mega 2560 R3

pin SDA al pin 20 di Arduino Mega 2560 R3

Questi due pin li trovate nella sezione COMUNICATION sullo stesso lato della porta USB, in fondo.

Prima di pubblicare lo sketch, aggiungo che sto lavorando sui led RGB e led bicolore RG da usare come segnali nel tracciato. Non so ancora se combinerò qualcosa di buono. Coi led monocromatici tutto è molto semplice ed è già implementato.

Il bello sarebbe usare led RGB , gestendo solo i due colori rosso e verde che mescolati danno anche il giallo, così da poter ottenere un segnale coi tre colori separati.

Con TraiController ho verificato il funzionamento complessivo, quando si attivano le route, che notoriamente, coinvolgono i movimenti anche di numerosi deviatoi e quindi servo. Ottimizzando i parametri dei deviatoi e della route ho ottenuto un ottimo risultato. Per finire: la lentezza del movimento degli aghi dei deviatoi è facilmente modificabile lavorando sul valore dell'istruzione delay(millisecondi) [Es.: delay(35);] che ho impostato a 20. Scegliete voi la velocità angolare migliore.

Solo una centralina DCC che usi le norme NMRA è adatta a questo progetto. Sicuramente tutte le centraline DCC che utilizzano il protocollo XpressNet.

Buon divertimento!

SKETCH PER IL TEST DELL'INTERFACCIA DCC PER ARDUINO o DELLA VOSTRA DCC SHIELD per ARDUINO

/ / DCC Interface Simple Testing Sketch - Ian Jeffery 2017

#include <DCC_Decoder.h>

#include <Wire.h>

#define kDCC_INTERRUPT 0 // Basic accessory packet handler

void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)

{

// Convert NMRA packet address format to human address

address -= 1;

address *= 4;

address += 1;

address += (data & 0x06) >> 1;

boolean enable = (data & 0x01) ? 1 : 0;

// The DCC Accessory Address is now stored in "address" variable

Serial.print(F("Basic addr: "));

Serial.println(address, DEC);

Serial.print(F("Activate Status: "));

Serial.println(enable, DEC);

}

void setup()

{

Serial.begin(9600);

Serial.println(F("DCC Interface Simple Sketch - Ian Jeffery. 2017"));

// tell the library which method to call when an accessory packet is detected

DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);

// set up our DCC decoder

DCC.SetupDecoder(0x00, 0x00, kDCC_INTERRUPT);

void loop()

{

// Loop DCC library

DCC.loop();

}

COME CONNETTERE SCHEDE SERVO LED SD DCC AD ARDUINO.pdf



SKETCH PER LA GESTIONE DEI SERVO CON MOVIMENTO LENTO CON UNA CENTRALINA DCC anche con Software per il controllo del tracciato (TrainController , Rocrail...).

/*

Designed by Gianni Barbotti (ITALY) Jul 15 2018

Questo sketch è stato progettato consultando i contenuti dei link indicati ed i dispositivi hardware qui sotto indicati.

1) le librerie NMRAdcc, Adafruit_PWMServoDriver;

2) lo sketch di esempio al link:

https://www.dccinterface.com/how-to/arduino-dcc-interface-accessory-decoder/

mi ha dato lo spunto necessario per approntare questo progetto al fine di realizzare

l'uso dei micro servo nel fermodellismo per muovere i deviatoi con movimento lento.

3) lo sketch di esempio al link

https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library/blob/master/examples/servo/servo.ino

4) lo sketch di Luca Dentella, col quale ho avuto uno scambio di messaggi e che mi ha dato

l'input indispensabile per intraprenderne la progettazione, pubblicato al link:

https://github.com/lucadentella/arduino-dcc/blob/master/SimpleLedAccDecoder/SimpleLedAccDecoder.ino

5) DCC Command Station Lenz LZV100 + Lenz LH100 ( opzionali: + Lenz LHI101F + LA152)

-lo sketch funziona anche su DCC command station NCE e Fleischmann Twin-Center e funziona

con tutte le centraline DCC compatibili col protocollo NMRA.

6) adattatore hama seriale-Usb per connettere la LHI101F al PC sulla porta USB (opzionale)

7) la scheda DCC Shield per Arduino Uno progettata da Luca Dentella,

il quale me l'ha regalata , spedita gratuitamente e che ringrazio nuovamente.

8) 2 x Adafruit 16-Channel 12-bit PWM/Servo Driver - I2C interface - PCA9685

9) Inoltre lo sketch è stato provato utilizzando, in sostituzione della shield di Luca Dentella,

l'interfaccia DCC che ho acquistato ordinandola al link

https://www.dccinterface.com/how-to/connecting-interface-arduino/

Entrambe funzionano magnificamente. Il vantaggio dato dall'utilizzo dell'interfaccia

progettata da Luca Dentella è che è una shield per Arduino Uno, quindi la monti sull'Arduino

e la colleghi al tracciato usando il connettore a due poli. Due collegamenti anzichè cinque.

10) Una scheda SD da 2 GB con lettore (cinese) da connettere ad Arduino e nella

quale ho memorizzato lo stato dei servo alfine di ripristinare, ad ogni nuova accensione

della centralina, lo stato preesistente della posizione degli aghi dei deviatoi

e l'impostazione dei led.


NOTA: Se un servo si trova allo stato "positivo" e si riattiva lo stesso stato,

il servo fa uno scatto e poi si riposiziona nello stato in cui si trovava

in precedenza analogamente nel caso sia nello stato "negativo".

In entrambi i casi si muove inutilmente con un effetto indesiderato.

Questo avviene automaticamente.

Nello sketch, quindi, ho incluso il controllo dello stato dei servo in modo

tale che quanto sopra descritto non avvenga.


(*) Per "opzionale" si intende che lo sketch non ha bisogno di questi elementi, ma sono però

necessari se si vuol usare un software di controllo del tracciato col PC.

*/

// *** Definizione libreria NMRA per DCC

#include <NmraDcc.h>

NmraDcc Dcc;

#define DCC_PIN 2 // definizione Pin comunicazione Arduino con interfaccia DCC

#define BOARD_ADDRESS 5

// #define PAIR_ADDRESS 1


// Definizione Libreria e parametri scheda SD

#include <SD.h>

int CS_pin = 53; // Pin CS = 10 con Ardiono UNO e pin 53 con Arduino MEGA 2560

int j;

char logfile[] = {"SERVI.txt"};

File file;


// DEfinizione Libreria e parametri per scheda Led TCL5947

#include <Adafruit_TLC5947.h>

int N_SK_LED = 2; // Numero delle schede 24-Channel 12-bit PWM/LED TCLC5974 connesse ad Arduino

// Modificare il valore 2 in base al numero effettivo di schede 24-Channel 12-bit PWM/LED

// che sino connesse ad Arduino

#define NUM_TLC5974 N_SK_LED // il parametro finale indica il numero delle schede TCLC5974 connesse ad Arduino

#define data 4

#define clock 5

#define latch 6

#define oe -1 // set to -1 to not use the enable pin (its optional)

Adafruit_TLC5947 tlc = Adafruit_TLC5947(NUM_TLC5974, clock, data, latch);


int max_lux = 3000;

int min_lux = 0; // Valore minimo luminosità LED (0 = spento ; 4096 luminosità massima)

int passo_ON = 25; // Step con cui si incrementa la luminosità dei Led per

// l'effetto di brillantezza incrementata (FADE) in fase di accensione

int passo_OFF = 15; // Step con cui si decrementa la luminosità dei Led per

// l'effetto di brillantezza sfumata (FADE) in fase di spegnimento

int a_Led; // Indirizzo base del gruppo dei led da accendere/spegnere a seguito

// della variazione di stato di un deviatoio (in questo sketch si gestiscono

// due led per ciascun deviatoio.


// **** Librerie e PARAMETRI RELATIVI AI SERVO *****

#include <Adafruit_PWMServoDriver.h> // Libreria per poter utilizzare i micro servo con Arduino

Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40); // to manage servos from 1° to the 16°(addresses 100-115)

Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41); // to manage servos from 1° to the 16°(addresses 116-131)

Adafruit_PWMServoDriver pwm3 = Adafruit_PWMServoDriver(0x42); // to manage servos from 1° to the 16°(addresses 132-147)

Adafruit_PWMServoDriver pwm4 = Adafruit_PWMServoDriver(0x43); // to manage servos from 1° to the 16°(addresses 148-163)

Adafruit_PWMServoDriver pwm5 = Adafruit_PWMServoDriver(0x44); // to manage servos from 1° to the 16°(addresses 164-179)

Adafruit_PWMServoDriver pwm6 = Adafruit_PWMServoDriver(0x45); // to manage servos from 1° to the 16°(addresses 180-195)

int start_address = 100; // Primo indirizzo gestito (modificare se desiderato, tenendo presente che il l'intervallo degli indirizzi

// deve essere un numero multiplo di 16 (16, 32, 48, 64 etc etc)

// in questo sketch vanno da [end_address - start_address]

int end_address = 195; // Ultimo indirizzo gestito (modificare se desiderato, tenendo presente quanto scritto per start_address


#define ritardo 15 // intervallo (in ms) tra un impulso ed il successivo inviato al motore del servo

#define L_ritardo 10 // intervallo (in ms) tra un impulso ed il successivo inviato al Led

#define min_servo 100 // Valore iniziale indirizzo dei servo gestiti dallo sketch

#define max_servo 195 // Valore finale indirizzo dei servo gestiti dallo sketch

#define SERVOMIN 200 // Valore iniziale della rotazione - modificare a proprio piacimento

#define SERVOMAX 280 // Valore finale della rotazione - modificare a proprio piacimento

#define i_max_servo 96 // Numero massimo dei servo gestiti in questo sketch


char status_servo[i_max_servo]; // Vettore in cui si memorizza lo stato del servo, coi tre seguenti valori:

// 0 = se gli aghi sono in posizione di tracciato CORRETTO

// 1 = se gli aghi sono in posizione di tracciato DEVIATO

// 2 = se il servo non è stato ancora "movimentato"

#define num_ch_srv 16 // Numero dei servo che ciascuna scheda 16-Channel 12-bit PWM/Servo

// può gestire - NON MODIFICARE -

#define freq_srv 60 // Frequenza funzionamento del servo - NON MODIFICARE -

int servonum; // Indirizzo fisico del Servo relativo alla scheda di appartenenza

// E' sempre un valore compreso tra 0 e 15 estremi inclusi, quindi 16 in tutto

int servo;

int scheda;

/* Per ogni scheda Adafruit16-Channell aggiuntiva inserire la riga:

Adafruit_PWMServoDriver pwmN = Adafruit_PWMServoDriver(0x4N);

dove N è il numero progressivo della scheda aggiunta.

For each additional Adafruit16-Channell add the statement:

Adafruit_PWMServoDriver pwmN = Adafruit_PWMServoDriver(0x4N);

where N is the progressive of the Adafruit breakout added

*/



void notifyDccAccState(uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State)

{

// Serial.println("notify");

int pairAddress = (OutputAddr >> 1) + 1;

int outputInPair = OutputAddr & 0x01;

servo = abs(Addr - start_address);

a_Led = 2 * servo;


performAction(Addr, outputInPair);

remove_file();

create_servi(logfile);

open2File(logfile);

while (file.available())

{

readLine();

}

closeFile();

update_status(logfile);



}


void performAction(int Addr, int outputInPair)

{

// Serial.println("perform action");

int scheda;

scheda = ((Addr - start_address) / num_ch_srv) + 1;

servonum = servo - num_ch_srv * (scheda - 1);


Serial.print(" Indirizzo LH100= ");

Serial.print(Addr, DEC);

Serial.print(" scheda= ");

Serial.print(scheda, DEC);

Serial.print(" servo = ");

Serial.print(servo, DEC);

Serial.print(" servonum= ");

Serial.print(servonum, DEC);

Serial.print(" outputInPair= ");

Serial.println(outputInPair);


if ((start_address <= Addr <= end_address) && (outputInPair == 1)) // indirizzo servo nel range controllo schede

// con selezione "SPOSTA AGHI IN TRACCIATO DEVIATO"

{

if ((status_servo[servo] == char(48)) || (status_servo[servo] == char(50))) // il servo è in posizione [-] tracciato corretto oppure mai attivato

// va ACCESO il LED ROSSO e SPENTO il LED VERDE


{

status_servo[servo] = char(49);

/* Serial.print(" status_servo= ");

Serial.println(status_servo[j]);*/

switch (scheda)

{

case 1: // attiva il servo con Addr compreso tra 100 e 115 per posizionare il deviatoio su tracciato deviato [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 2: // attiva iL servo con Addr compreso tra il 116 ed il 131 per posizionare deviatoio su tracciato deviatoto [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 3: // attiva il servo con Addr compreso tra 132 e 147 per posizionare il deviatoio su tracciato deviato [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 4: // attiva iL servo con Addr compreso tra il 148 ed il 163 per posizionare deviatoio su tracciato deviatoto [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 5: // attiva il servo con Addr compreso tra 164 e 179 per posizionare il deviatoio su tracciato deviato [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 6: // attiva iL servo con Addr compreso tra il 180 ed il 195 per posizionare deviatoio su tracciato deviatoto [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;




}

tlc.setPWM(a_Led, 0); // spengo Led Verde

tlc.write();

tlc.setPWM(a_Led + 1, 4000); // accendo Led Rosso

tlc.write();


}



/*


For each of the additional Adafruit 16-Channell PWM/Servo add the statement


case N: // activate the servos with address = [(N-1) * num_ch_srv + 100] to [(N-1) * 16 + 115]


for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwmN.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

where N is the progressive of the Adafruit16-Channell 12-Bit PWM/Servo added

*/


/*

//Ciclo per effetto FADE


for (int intensity = max_lux; intensity > 0; intensity -= passo_OFF + 5)

{

tlc.setPWM(a_Led + 1, intensity);

tlc.write();

delay(10);

}

*/

/*

//Ciclo per effetto FADE


for (int intensity = min_lux; intensity < max_lux; intensity += passo_ON)

{


tlc.setPWM(a_Led, intensity);

tlc.write();

delay(L_ritardo);

}

*/

}




if ((start_address <= Addr <= end_address) && (outputInPair == 0)) // indirizzo servo nel range controllo schede

// con selezione "SPOSTA AGHI IN TRACCIATO CORRETTO [-]"

{

if ((status_servo[servo] == char(49)) || (status_servo[servo] == char(50))) // il servo è in posizione [+] oppure mai attivato

{

status_servo[servo] = char(48);

/*Serial.print(" status_servo= ");

Serial.println(status_servo[j]);*/

switch (scheda)

{

case 1: // attiva iL servo con Addr dal 100 al 115 per posizionare deviatoio su tracciato corretto

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 2: // attiva i servo con Addr dal 116 al 131

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}


break;

case 3: // attiva iL servo con Addr dal 132 al 147 per posizionare deviatoio su tracciato corretto

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 4: // attiva i servo con Addr dal 148 al 163

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}


break;

case 5: // attiva iL servo con Addr dal 164 al 179 per posizionare deviatoio su tracciato corretto

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 6: // attiva i servo con Addr dal 180 al 195

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}


break;

}


tlc.setPWM(a_Led + 1, 0); // spengo Led Rosso

tlc.write();

tlc.setPWM(a_Led, 4000); // accendo Led Verde

tlc.write();

}

}



/*

For each of the additional Adafruit breakout add the statement

case N: // activate the servos with address = [(N-1) * num_ch_srv + 100] to [(N-1) * 16 + 115]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOmin; pulselen--)

{

pwmN.setPWM(servonum, 0, pulselen);

delay(20);

}

where N is the progressive of the adafruit breakout added

*/

/*

//Ciclo per effetto FADE


for (int intensity = max_lux; intensity > 0; intensity -= passo_OFF + 5)

{

tlc.setPWM(a_Led, intensity);

tlc.write();

delay(L_ritardo);

}

*/


//Ciclo per effetto FADE



}


void setup()

{

Serial.begin(9600);

pinMode(CS_pin, OUTPUT);

initializeSD();

openFile(logfile);

while (file.available())

{

readLine();

}

closeFile();

/*

for (j = 0; j <= i_max_servo; j++)

{

Serial.print(" status_servo[");

Serial.print(j, DEC);

Serial.print("]= ");

Serial.println(status_servo[j]);

}

*/


tlc.begin();

pinMode(4, OUTPUT);

pinMode(5, OUTPUT);

pinMode(6, OUTPUT);

if (oe >= 0)

{

pinMode(oe, OUTPUT);

digitalWrite(oe, LOW);

}

Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, 1);

Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER, 0); // Serial.println("- decoder ready");

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm1.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm1.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm2.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm2.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm3.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm3.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm4.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm4.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm5.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm5.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm6.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm6.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz


// CHECK_LED(); FUNZIONE INGLOBATA NELLA ***** CHECK_SERVO *****

CHECK_SERVO();


Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, 1);

Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER, 0); // Serial.println("- decoder ready");

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm1.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm1.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm2.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm2.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm3.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm3.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm4.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm4.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm5.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm5.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm6.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm6.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz


}



void loop()

{

Dcc.process();

}

String readLine()

{

int i;

j = 0;

String received = "";

char ch;

while (file.available())

{

ch = file.read();

if (ch == '\n')

{

return String(received);

}

else

{

status_servo[j] = ch;

received += ch;

j++;

}

}

return "";

}


void initializeSD()

{

// Serial.println("Initializing SD card...");

if (SD.begin())

{

// Serial.println("SD card disponibile");

}

else

{

Serial.println("SD card non disponibile. USCITA!!");

return;

}

}


void remove_file()

{

// Serial.println("dentro removefile");

if (SD.remove("SERVI.txt"))

{

// Serial.println("file SERVI.txt eliminato!");

}

else

{

Serial.println("file SERVI.txt NON eliminato. NON ESISTE! USCITA!!!");

return;

}

}


int openFile(char filename[])

{

// Serial.println("dentro openFile");

file = SD.open(filename);

if (file)

{

// Serial.println(" Open File SERVI OK!");

return 1;

}

else

{

default_status(logfile);

return 0;

}


}


int open2File(char filename[])

{

// Serial.println("dentro open2File");

file = SD.open(logfile);

if (file)

{

// Serial.println(" Open File SERVI OK!");

for (j = 0; j <= i_max_servo; j++)

{

file.print(status_servo[j]);

}

return 1;

}

else

{

Serial.println(" File SERVI.txt inesistente! USCITA!!!!");

return 0;

}

}



int default_status(char filename[])

{

// Serial.println("default_status");

file = SD.open("SERVI.txt", FILE_WRITE);

if (file)

{

j = 0;

for (j = 0; j <= i_max_servo; j++)

{

file.print(char(50));

status_servo[j] = char(50);

}

file.close();

// return 0;

}

else

{

Serial.println("Non è stato possibile scrivere il file SERVI.txt! USCITA!!");


return;

}

}



int CHECK_SERVO()

{

// Serial.println("Dentro CHECK_SERVO");


a_Led = 2 * servo;

// for (j = 0; j <= i_max_servo; j++)

j = 0;

do

{

a_Led = 2 * j;

scheda = (j / num_ch_srv) + 1;

servonum = j - (num_ch_srv * (scheda - 1));

if (status_servo[j] == char(48)) // il servo era posizionato con deviatoio

// tracciato corretto tasto[-] LH100

{

tlc.setPWM(a_Led + 1, 0); // spengo Led Rosso

tlc.write();

tlc.setPWM(a_Led, 4000); // accendo Led Verde

tlc.write();

switch (scheda)

{

case 1: // attiva i servo con con indirizzo compreso tra 100 e 115


for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm1.setPWM(servonum, 0, pulselen);

}


break;

case 2: // attiva i servo con Addr dal 116 al 131

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm2.setPWM(servonum, 0, pulselen);

}

break;

case 3: // attiva i servo con Addr dal 132 al 147

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm3.setPWM(servonum, 0, pulselen);

}

break;

case 4: // attiva i servo con Addr dal 148 al 163

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm4.setPWM(servonum, 0, pulselen);

}

break;

case 5: // attiva i servo con Addr dal 164 al 179

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm5.setPWM(servonum, 0, pulselen);

}

break;

case 6: // attiva i servo con Addr dal 180 al 195

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm6.setPWM(servonum, 0, pulselen);

}

break;

}

}


if (status_servo[j] == char(49)) // il servo era posizionato con deviatoio

// in tracciato deviato tasto[+] LH100

{

tlc.setPWM(a_Led, 0); // spengo Led Verde

tlc.write();

tlc.setPWM(a_Led + 1, 4000); // accendo Led Rosso

tlc.write();

switch (scheda)

{

case 1: // attiva i servo con Addr dal 100 al 115


for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm1.setPWM(servonum, 0, pulselen);

}


break;

case 2: // attiva i servo con Addr dal 116 al 131

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm2.setPWM(servonum, 0, pulselen);

}

break;

case 3: // attiva i servo con Addr dal 132 al 147

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm3.setPWM(servonum, 0, pulselen);

}

break;

case 4: // attiva i servo con Addr dal 148 al 163

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm4.setPWM(servonum, 0, pulselen);

}

break;

case 5: // attiva i servo con Addr dal 164 al 179

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm5.setPWM(servonum, 0, pulselen);

}

break;

case 6: // attiva i servo con Addr dal 180 al 195

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm6.setPWM(servonum, 0, pulselen);

}

break;

}

}


j++;


}

while (j < i_max_servo);



}


/*

int CHECK_LED()

{

//Serial.print("CHECK_LED");



for (j = 0; j <= i_max_servo; j++)

{

a_Led = 2 * j;


if (status_servo[j] == char(48))

{

tlc.setPWM(a_Led, 0);

tlc.write();

tlc.setPWM(a_Led + 1, 4000);

tlc.write();

}


if (status_servo[j] == char(49))

{

tlc.setPWM(a_Led, 4000);

tlc.write();

tlc.setPWM(a_Led + 1, 0);

tlc.write();

}


if (status_servo[j] == char(50))

{

tlc.setPWM(a_Led, 0);

tlc.write();

tlc.setPWM(a_Led + 1, 4000);

tlc.write();

}

}

}

*/


int create_servi(char filename[])

{

// Serial.println("Creao file SERVI");

file = SD.open("SERVI.txt", FILE_WRITE);

if (file)

{

// Serial.println("File servi creato");

file.close();

}


else

{

Serial.println("Non è stato possibile creare il file SERVI.txt! USCITA!!");


return;

}

}



int update_status(char filename[])

{

// Serial.println("UPDATE_status");

file = SD.open("SERVI.txt", FILE_WRITE);

if (file)

{

j = 0;

for (j = 0; j <= i_max_servo; j++)

{

file.print(status_servo[j]);

}

file.close();

}

else

{

Serial.println("Non è stato possibile AGGIORNARE il file SERVI.txt! USCITA!!");

return;

}

}


void closeFile()

{

if (file)

{

// Serial.println("dentro closefile");

file.close();

// Serial.println("File closed");

}

}



Ed ecco lo sketch che permette di gestire , per ciascun servo e quindi per ciascun deviatoio a due vie, un gruppo di quattro led con la seguente funzionalità:


a) ad ogni posizione del deviatoio sono associati due led: uno verde e l'altro rosso;

b) quando il deviatoio è posizionato in tracciato corretto i due led associati a

tale posizione risulteranno: LED VERDE ACCESO, LED ROSSO SPENTO;

mentre i due led associati alla posizione tracciato deviato risulteranno:

LED VERDE SPENTO, LED ROSSO ACCESO.

c) quando il deviatoio è posizionato in tracciato deviato i due led associati a

tale posizione risulteranno: LED VERDE ACCESO, LED ROSSO SPENTO; mentre i due

led associati alla posizione tracciato corretto risulteranno: LED VERDE SPENTO, LED ROSSO ACCESO.

d) ai quattro led , nello sketch, ci si riferisce rispettivamente con :

LED e LED + 1 per gestire l'accensione/spegnimento dei led per la posizione tracciato corretto

LED + 2 e LED + 3 per gestire l'accensione/spegnimento dei led per la posizione tracciato deviato .

Ecco il codice:


/*

Designed by Gianni Barbotti (ITALY) July 15 2018

Aggiornato il 16 Agosto 2018 per la gestione Led quadro sinottico.



Questo sketch è stato scrittoo consultando i contenuti dei link indicati ed i dispositivi hardware qui sotto indicati.

1) le librerie NMRAdcc, Adafruit_PWMServoDriver;

2) lo sketch di esempio al link:

https://www.dccinterface.com/how-to/arduino-dcc-interface-accessory-decoder/

mi ha dato lo spunto necessario per approntare questo progetto al fine di realizzare

l'uso dei micro servo nel fermodellismo per muovere i deviatoi con movimento lento.

3) lo sketch di esempio al link

https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library/blob/master/examples/servo/servo.ino

4) lo sketch di Luca Dentella pubblicato al link:

https://github.com/lucadentella/arduino-dcc/blob/master/SimpleLedAccDecoder/SimpleLedAccDecoder.ino

5) DCC Command Station Lenz LZV100 + Lenz LH100 ( opzionali: + Lenz LHI101F + LA152)

-lo sketch funziona anche su DCC command station NCE e Fleischmann Twin-Center e funziona

con tutte le centraline DCC compatibili col protocollo NMRA.

6) adattatore seriale-Usb per connettere LHI101F al PC sulla porta USB (opzionale)

7) la scheda DCC Shield per Arduino Uno progettata da Luca Dentella,

il quale me l'ha regalata , spedita gratuitamente e che ringrazio nuovamente.

8) 2 x Adafruit 16-Channel 12-bit PWM/Servo Driver - I2C interface - PCA9685

9) Inoltre lo sketch è stato provato utilizzando, in sostituzione della shield di Luca Dentella,

l'interfaccia DCC che ho acquistato ordinandola al link

https://www.dccinterface.com/how-to/connecting-interface-arduino/

Entrambe funzionano magnificamente. Il vantaggio dato dall'utilizzo dell'interfaccia

progettata da Luca Dentella è che è una shield per Arduino Uno, quindi la monti sull'Arduino

e la colleghi al tracciato usando il connettore a due poli. Due collegamenti anzichè cinque.

10) Una scheda SD da 2 GB con lettore (cinese) da connettere ad Arduino e nella

quale ho memorizzato lo stato dei servo alfine di ripristinare, ad ogni nuova accensione

della centralina, lo stato preesistente della posizione degli aghi dei deviatoi

e l'impostazione dei led.

NOTA 1: Se un servo si trova allo stato "positivo" e si riattiva lo stesso stato,

il servo fa uno scatto e poi si riposiziona nello stato in cui si trovava

in precedenza analogamente nel caso sia nello stato "negativo".

In entrambi i casi si muove inutilmente con un effetto indesiderato.

Questo avviene automaticamente.

Nello sketch, quindi, ho incluso il controllo dello stato dei servo in modo

tale che quanto sopra descritto non avvenga.


NOTA 2: Questo sketch gestisce per ogni deviatoio quattro led con questa logica:

a) ad ogni posizione del deviatoio sono associati due led: uno verde e l'altro rosso;


b) quando il deviatoio è posizionato in tracciato corretto i due led associati a

tale posizione risulteranno: LED VERDE ACCESO, LED ROSSO SPENTO; mentre i due

led associati alla posizione tracciato deviato risulteranno: LED VERDE SPENTO, LED ROSSO ACCESO.


c) quando il deviatoio è posizionato in tracciato deviato i due led associati a

tale posizione risulteranno: LED VERDE ACCESO, LED ROSSO SPENTO; mentre i due

led associati alla posizione tracciato corretto risulteranno: LED VERDE SPENTO, LED ROSSO ACCESO.


d) ai quattro led , nello sketch, ci si riferisce rispettivamente con le variabili

LED e LED + 1 per gestire l'accensione/spegnimento dei led per la posizione tracciato corretto

LED + 2 e LED + 3 per gestire l'accensione/spegnimento dei led per la posizione tracciato deviato


(*) Per "opzionale" si intende che lo sketch non ha bisogno di questi elementi, ma sono però

necessari se si vuol usare un software di controllo del tracciato col PC.


*/



// *** Definizione libreria NMRA per DCC

#include <NmraDcc.h>

NmraDcc Dcc;

#define DCC_PIN 2 // definizione Pin comunicazione Arduino con interfaccia DCC

#define BOARD_ADDRESS 5

// #define PAIR_ADDRESS 1


// Definizione Libreria e parametri scheda SD

#include <SD.h>

int CS_pin = 53; // Pin CS = 10 con Ardiono UNO e pin 53 con Arduino MEGA 2560

int j;

char logfile[] = {"SERVI.txt"};

File file;


// DEfinizione Libreria e parametri per scheda Led TCL5947

#include <Adafruit_TLC5947.h>

int N_SK_LED = 2; // Numero delle schede 24-Channel 12-bit PWM/LED TCLC5974 connesse ad Arduino

// Modificare il valore 2 in base al numero effettivo di schede 24-Channel 12-bit PWM/LED

// che sino connesse ad Arduino

#define NUM_TLC5974 N_SK_LED // il parametro finale indica il numero delle schede TCLC5974 connesse ad Arduino

#define data 4

#define clock 5

#define latch 6

#define oe -1 // set to -1 to not use the enable pin (its optional)

Adafruit_TLC5947 tlc = Adafruit_TLC5947(NUM_TLC5974, clock, data, latch);


int max_lux = 3000;

int min_lux = 0; // Valore minimo luminosità LED (0 = spento ; 4096 luminosità massima)

int passo_ON = 25; // Step con cui si incrementa/decrementa luminosità dei Led per

// l'effetto di brillantezza sfumata (FADE) in fase di accensione

int passo_OFF = 15; // Step con cui si incrementa/decrementa luminosità dei Led per

// l'effetto di brillantezza sfumata (FADE) in fase di spegnimento

int a_Led; // Indirizzo base del gruppo dei led da accendere/spegnere a seguito

// della variazione di stato di un deviatoio.


// **** Librerie e PARAMETRI RELATIVI AI SERVO *****

#include <Adafruit_PWMServoDriver.h> // Libreria per poter utilizzare i micro servo con Arduino

Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40); // to manage servos from 1° to the 16°(addresses 100-115)

Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41); // to manage servos from 1° to the 16°(addresses 116-131)

Adafruit_PWMServoDriver pwm3 = Adafruit_PWMServoDriver(0x42); // to manage servos from 1° to the 16°(addresses 132-147)

Adafruit_PWMServoDriver pwm4 = Adafruit_PWMServoDriver(0x43); // to manage servos from 1° to the 16°(addresses 148-163)

Adafruit_PWMServoDriver pwm5 = Adafruit_PWMServoDriver(0x44); // to manage servos from 1° to the 16°(addresses 164-179)

Adafruit_PWMServoDriver pwm6 = Adafruit_PWMServoDriver(0x45); // to manage servos from 1° to the 16°(addresses 180-195)

int start_address = 100; // Primo indirizzo gestito (modificare se desiderato, tenendo presente che il l'intervallo degli indirizzi

// deve essere un numero multiplo di 16 (16, 32, 48, 64 etc etc)

// in questo sketch vanno da [end_address - start_address]

int end_address = 195; // Ultimo indirizzo gestito (modificare se desiderato, tenendo presente quanto scritto per start_address


#define ritardo 15 // intervallo (in ms) tra un impulso ed il successivo inviato al motore del servo

#define L_ritardo 10 // intervallo (in ms) tra un impulso ed il successivo inviato al Led

#define min_servo 100 // Valore iniziale indirizzo dei servo gestiti dallo sketch

#define max_servo 195 // Valore finale indirizzo dei servo gestiti dallo sketch

#define SERVOMIN 200 // Valore iniziale della rotazione - modificare a proprio piacimento

#define SERVOMAX 280 // Valore finale della rotazione - modificare a proprio piacimento

#define i_max_servo 96 // Numero massimo dei servo gestiti in questo sketch


char status_servo[i_max_servo]; // Vettore in cui si memorizza lo stato del servo, coi tre seguenti valori:

// 0 = se gli aghi sono in posizione di tracciato CORRETTO

// 1 = se gli aghi sono in posizione di tracciato DEVIATO

// 2 = se il servo non è stato ancora "movimentato"

#define num_ch_srv 16 // Numero dei servo che ciascuna scheda 16-Channel 12-bit PWM/Servo

// può gestire - NON MODIFICARE -

#define freq_srv 60 // Frequenza funzionamento del servo - NON MODIFICARE -

int servonum; // Indirizzo fisico del Servo relativo alla scheda di appartenenza

// E' un valore compreso tra 0 e 15 estremi inclusi

int servo;

int scheda;

/* Per ogni scheda Adafruit16-Channell aggiuntiva inserire la riga:

Adafruit_PWMServoDriver pwmN = Adafruit_PWMServoDriver(0x4N);

dove N è il numero progressivo della scheda aggiunta.

For each additional Adafruit16-Channell add the statement:

Adafruit_PWMServoDriver pwmN = Adafruit_PWMServoDriver(0x4N);

where N is the progressive of the Adafruit breakout added

*/



void notifyDccAccState(uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State)

{

// Serial.println("notify");

int pairAddress = (OutputAddr >> 1) + 1;

int outputInPair = OutputAddr & 0x01;

servo = abs(Addr - start_address);

a_Led = 4 * servo;


performAction(Addr, outputInPair);

remove_file();

create_servi(logfile);

open2File(logfile);

while (file.available())

{

readLine();

}

closeFile();

update_status(logfile);



}


void performAction(int Addr, int outputInPair)

{

// Serial.println("perform action");

int scheda;

scheda = ((Addr - start_address) / num_ch_srv) + 1;

servonum = servo - num_ch_srv * (scheda - 1);


Serial.print(" Indirizzo DCC scelto = ");

Serial.print(Addr, DEC);

Serial.print(" scheda= ");

Serial.print(scheda, DEC);

Serial.print(" servo = ");

Serial.print(servo, DEC);

Serial.print(" servonum= ");

Serial.print(servonum, DEC);

Serial.print(" Addr a_Led V= ");

Serial.print(a_Led, DEC);

Serial.print(" Addr _Led + 1 R = ");

Serial.print(a_Led +1, DEC);

Serial.print(" Addr a_Led + 2 V = ");

Serial.print(a_Led +2, DEC);

Serial.print(" Addr a_Led + 3 R = ");

Serial.print(a_Led +3, DEC);

Serial.print(" outputInPair= ");

Serial.println(outputInPair);


if ((start_address <= Addr <= end_address) && (outputInPair == 1)) // indirizzo servo nel range controllo schede

// con selezione "SPOSTA AGHI IN TRACCIATO DEVIATO"

{

if ((status_servo[servo] == char(48)) || (status_servo[servo] == char(50))) // il servo è in posizione [-] tracciato corretto oppure mai attivato

// va ACCESO il LED ROSSO e SPENTO il LED VERDE


{

status_servo[servo] = char(49);

/* Serial.print(" status_servo= ");

Serial.println(status_servo[j]);*/

switch (scheda)

{

case 1: // attiva il servo con Addr compreso tra 100 e 115 per posizionare il deviatoio su tracciato deviato [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 2: // attiva iL servo con Addr compreso tra il 116 ed il 131 per posizionare deviatoio su tracciato deviatoto [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 3: // attiva il servo con Addr compreso tra 132 e 147 per posizionare il deviatoio su tracciato deviato [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 4: // attiva iL servo con Addr compreso tra il 148 ed il 163 per posizionare deviatoio su tracciato deviatoto [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 5: // attiva il servo con Addr compreso tra 164 e 179 per posizionare il deviatoio su tracciato deviato [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 6: // attiva iL servo con Addr compreso tra il 180 ed il 195 per posizionare deviatoio su tracciato deviatoto [+]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;




}

tlc.setPWM(a_Led, LOW); // spengo Led Verde tracciato corretto

tlc.write();

tlc.setPWM(a_Led + 2, 4000); // accendo Led Verde tracciato deviato

tlc.write();

tlc.setPWM(a_Led + 1, 4000); // accendo Led Rosso Tracciato corretto

tlc.write();

tlc.setPWM(a_Led + 3, LOW); // spengo Led Rosso tracciato deviato

tlc.write();


}



/*


For each of the additional Adafruit 16-Channell PWM/Servo add the statement


case N: // activate the servos with address = [(N-1) * num_ch_srv + 100] to [(N-1) * 16 + 115]


for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwmN.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

where N is the progressive of the Adafruit16-Channell 12-Bit PWM/Servo added

*/


/*

//Ciclo per effetto FADE


for (int intensity = max_lux; intensity > 0; intensity -= passo_OFF + 5)

{

tlc.setPWM(a_Led + 1, intensity);

tlc.write();

delay(10);

}

*/

/*

//Ciclo per effetto FADE


for (int intensity = min_lux; intensity < max_lux; intensity += passo_ON)

{


tlc.setPWM(a_Led, intensity);

tlc.write();

delay(L_ritardo);

}

*/

}




if ((start_address <= Addr <= end_address) && (outputInPair == 0)) // indirizzo servo nel range controllo schede

// con selezione "SPOSTA AGHI IN TRACCIATO CORRETTO [-]"

{

if ((status_servo[servo] == char(49)) || (status_servo[servo] == char(50))) // il servo è in posizione [+] oppure mai attivato

{

status_servo[servo] = char(48);

/*Serial.print(" status_servo= ");

Serial.println(status_servo[j]);*/

switch (scheda)

{

case 1: // attiva iL servo con Addr dal 100 al 115 per posizionare deviatoio su tracciato corretto

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 2: // attiva i servo con Addr dal 116 al 131

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}


break;

case 3: // attiva iL servo con Addr dal 132 al 147 per posizionare deviatoio su tracciato corretto

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 4: // attiva i servo con Addr dal 148 al 163

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}


break;

case 5: // attiva iL servo con Addr dal 164 al 179 per posizionare deviatoio su tracciato corretto

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm1.setPWM(servonum, 0, pulselen);

delay(ritardo);

}

break;

case 6: // attiva i servo con Addr dal 180 al 195

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm2.setPWM(servonum, 0, pulselen);

delay(ritardo);

}


break;

}


tlc.setPWM(a_Led, 4000); // accendo Led Verde tracciato corretto

tlc.write();

tlc.setPWM(a_Led + 2, 0); // spengo Led Verde tracciato deviato

tlc.write();

tlc.setPWM(a_Led + 1, 0); // spengo Led Rosso Tracciato corretto

tlc.write();

tlc.setPWM(a_Led + 3, 4000); // accendo Led Rosso tracciato deviato

tlc.write();

}

}



/*

For each of the additional Adafruit breakout add the statement

case N: // activate the servos with address = [(N-1) * num_ch_srv + 100] to [(N-1) * 16 + 115]

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOmin; pulselen--)

{

pwmN.setPWM(servonum, 0, pulselen);

delay(20);

}

where N is the progressive of the adafruit breakout added

*/

/*

//Ciclo per effetto FADE


for (int intensity = max_lux; intensity > 0; intensity -= passo_OFF + 5)

{

tlc.setPWM(a_Led, intensity);

tlc.write();

delay(L_ritardo);

}

*/


//Ciclo per effetto FADE



}


void setup()

{

Serial.begin(9600);

pinMode(CS_pin, OUTPUT);

initializeSD();

openFile(logfile);

while (file.available())

{

readLine();

}

closeFile();

/*

for (j = 0; j <= i_max_servo; j++)

{

Serial.print(" status_servo[");

Serial.print(j, DEC);

Serial.print("]= ");

Serial.println(status_servo[j]);

}

*/


tlc.begin();

pinMode(4, OUTPUT);

pinMode(5, OUTPUT);

pinMode(6, OUTPUT);

if (oe >= 0)

{

pinMode(oe, OUTPUT);

digitalWrite(oe, LOW);

}

Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, 1);

Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER, 0); // Serial.println("- decoder ready");

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm1.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm1.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm2.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm2.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm3.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm3.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm4.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm4.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm5.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm5.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm6.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm6.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz


// CHECK_LED(); FUNZIONE INGLOBATA NELLA ***** CHECK_SERVO *****

CHECK_SERVO();


Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, 1);

Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER, 0); // Serial.println("- decoder ready");

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm1.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm1.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm2.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm2.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm3.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm3.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm4.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm4.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 1

pwm5.begin();

// setto la frequenza di funzionamento per i servi della scheda 1

pwm5.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz

// apro la comunicazione con la scheda per la gestione dei servo connessi alla scheda 2

pwm6.begin();

// setto la frequenza di funzionamento per i servi della scheda 2

pwm6.setPWMFreq(freq_srv); // Frequenza fissata a 60 Hz


}



void loop()

{

Dcc.process();

}

String readLine()

{

int i;

j = 0;

String received = "";

char ch;

while (file.available())

{

ch = file.read();

if (ch == '\n')

{

return String(received);

}

else

{

status_servo[j] = ch;

received += ch;

j++;

}

}

return "";

}


void initializeSD()

{

// Serial.println("Initializing SD card...");

if (SD.begin())

{

// Serial.println("SD card disponibile");

}

else

{

Serial.println("SD card non disponibile. USCITA!!");

return;

}

}


void remove_file()

{

// Serial.println("dentro removefile");

if (SD.remove("SERVI.txt"))

{

// Serial.println("file SERVI.txt eliminato!");

}

else

{

Serial.println("file SERVI.txt NON eliminato. NON ESISTE! USCITA!!!");

return;

}

}


int openFile(char filename[])

{

// Serial.println("dentro openFile");

file = SD.open(filename);

if (file)

{

// Serial.println(" Open File SERVI OK!");

return 1;

}

else

{

default_status(logfile);

return 0;

}


}


int open2File(char filename[])

{

// Serial.println("dentro open2File");

file = SD.open(logfile);

if (file)

{

// Serial.println(" Open File SERVI OK!");

for (j = 0; j <= i_max_servo; j++)

{

file.print(status_servo[j]);

}

return 1;

}

else

{

Serial.println(" File SERVI.txt inesistente! USCITA!!!!");

return 0;

}

}



int default_status(char filename[])

{

// Serial.println("default_status");

file = SD.open("SERVI.txt", FILE_WRITE);

if (file)

{

j = 0;

for (j = 0; j <= i_max_servo; j++)

{

file.print(char(50));

status_servo[j] = char(50);

}

file.close();

// return 0;

}

else

{

Serial.println("Non è stato possibile scrivere il file SERVI.txt! USCITA!!");


return;

}

}



int CHECK_SERVO()

{

// Serial.println("Dentro CHECK_SERVO");


a_Led = 4 * servo;

// for (j = 0; j <= i_max_servo; j++)

j = 0;

do

{

a_Led = 4 * j;

scheda = (j / num_ch_srv) + 1;

servonum = j - (num_ch_srv * (scheda - 1));

if (status_servo[j] == char(48)) // il servo era posizionato con deviatoio

// tracciato corretto tasto[-] LH100

{

tlc.setPWM(a_Led, 4000); // accendo Led Verde tracciato corretto

tlc.write();

tlc.setPWM(a_Led + 2, 0); // spengo Led Verde tracciato deviato

tlc.write();

tlc.setPWM(a_Led + 1, 0); // spengo Led Rosso Tracciato corretto

tlc.write();

tlc.setPWM(a_Led + 3, 4000); // accendo Led Rosso tracciato deviato

tlc.write();

switch (scheda)

{

case 1: // attiva i servo con con indirizzo compreso tra 100 e 115


for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm1.setPWM(servonum, 0, pulselen);

}


break;

case 2: // attiva i servo con Addr dal 116 al 131

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm2.setPWM(servonum, 0, pulselen);

}

break;

case 3: // attiva i servo con Addr dal 132 al 147

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm3.setPWM(servonum, 0, pulselen);

}

break;

case 4: // attiva i servo con Addr dal 148 al 163

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm4.setPWM(servonum, 0, pulselen);

}

break;

case 5: // attiva i servo con Addr dal 164 al 179

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm5.setPWM(servonum, 0, pulselen);

}

break;

case 6: // attiva i servo con Addr dal 180 al 195

for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++)

{

pwm6.setPWM(servonum, 0, pulselen);

}

break;

}

}


if (status_servo[j] == char(49)) // il servo era posizionato con deviatoio

// in tracciato deviato tasto[+] LH100

{

tlc.setPWM(a_Led, LOW); // spengo Led Verde tracciato corretto

tlc.write();

tlc.setPWM(a_Led + 2, 4000); // accendo Led Verde tracciato deviato

tlc.write();

tlc.setPWM(a_Led + 1, 4000); // accendo Led Rosso Tracciato corretto

tlc.write();

tlc.setPWM(a_Led + 3, LOW); // spengo Led Rosso tracciato deviato

tlc.write();


switch (scheda)

{

case 1: // attiva i servo con Addr dal 100 al 115


for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm1.setPWM(servonum, 0, pulselen);

}


break;

case 2: // attiva i servo con Addr dal 116 al 131

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm2.setPWM(servonum, 0, pulselen);

}

break;

case 3: // attiva i servo con Addr dal 132 al 147

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm3.setPWM(servonum, 0, pulselen);

}

break;

case 4: // attiva i servo con Addr dal 148 al 163

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm4.setPWM(servonum, 0, pulselen);

}

break;

case 5: // attiva i servo con Addr dal 164 al 179

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm5.setPWM(servonum, 0, pulselen);

}

break;

case 6: // attiva i servo con Addr dal 180 al 195

for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--)

{

pwm6.setPWM(servonum, 0, pulselen);

}

break;

}

}


j++;


}

while (j < i_max_servo);



}


/*

int CHECK_LED()

{

//Serial.print("CHECK_LED");



for (j = 0; j <= i_max_servo; j++)

{

a_Led = 2 * j;


if (status_servo[j] == char(48))

{

tlc.setPWM(a_Led, 0);

tlc.write();

tlc.setPWM(a_Led + 1, 4000);

tlc.write();

}


if (status_servo[j] == char(49))

{

tlc.setPWM(a_Led, 4000);

tlc.write();

tlc.setPWM(a_Led + 1, 0);

tlc.write();

}


if (status_servo[j] == char(50))

{

tlc.setPWM(a_Led, 0);

tlc.write();

tlc.setPWM(a_Led + 1, 4000);

tlc.write();

}

}

}

*/


int create_servi(char filename[])

{

// Serial.println("Creao file SERVI");

file = SD.open("SERVI.txt", FILE_WRITE);

if (file)

{

// Serial.println("File servi creato");

file.close();

}


else

{

Serial.println("Non è stato possibile creare il file SERVI.txt! USCITA!!");


return;

}

}



int update_status(char filename[])

{

// Serial.println("UPDATE_status");

file = SD.open("SERVI.txt", FILE_WRITE);

if (file)

{

j = 0;

for (j = 0; j <= i_max_servo; j++)

{

file.print(status_servo[j]);

}

file.close();

}

else

{

Serial.println("Non è stato possibile AGGIORNARE il file SERVI.txt! USCITA!!");

return;

}

}


void closeFile()

{

if (file)

{

// Serial.println("dentro closefile");

file.close();

// Serial.println("File closed");

}

}