/* Library: DCC_Decoder File: DCC_Decoder-Servo_16 Descr: max 16 DCC servo's By: Ed den Ouden 2022 DCC-Edd (public domain) Remark: In order to function properly this library needs an active DCC locomotive to be on the track DCC addresses decoder: 33 to 40 (8 channels), adjustable Available extra pins: A5 on Uno, A5-A7 on Nano, many more on Mega Rocrail settings: Protocol: default, Parameter: 1, Value: 0, Options-turnout: ON, Accessory: ON Address-port: 9-1, 9-2, 9-3, 9-4, 10-1, etc */ #define NUMSERVOS 4 // enter the number of servos here #define SERVOSPEED 5 // millies between servo updates, lower is faster #include #include #define SERIALMON // serial monitor, comment/uncomment to switch off/onn const byte startPinArduino = 3; // first output pin for the servo's on Arduino board const int dccStartAddress = 33; // first DCC address to respond to unsigned long timetomove; typedef struct DCCAccessoryData { int address; // user configurable DCC address byte outputpin; // user configurable Arduino pin byte dccstate; // internal use DCC state of accessory: 1=on, 0=off byte angle; // internal use current angle of servo byte setpoint; // internal use current angle of servo byte offangle; // user configurable servo angle for DCC state = 0 byte onangle; // user configurable servo angle for DCC state = 1 Servo servo; }; DCCAccessoryData servo[NUMSERVOS]; // the DCC library calls this function in a loop to set / reset accessories void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data) { address -= 1; address *= 4; address += 1; address += (data & 0x06) >> 1; // address = address - 4 // uncomment this line for Roco Maus or Z21 #ifdef SERIALMON Serial.print("DCC-address, activate, data: "); Serial.print(address); Serial.print (", "); Serial.print (activate); Serial.print (", "); Serial.println(data); #endif boolean enable = (data & 0x01) ? 1 : 0; for (int i = 0; i < NUMSERVOS; i++) { if (address == servo[i].address) { if (enable) servo[i].dccstate = 1; else servo[i].dccstate = 0; } } } void setup() { #ifdef SERIALMON Serial.begin(115200); Serial.println("DCC decoder v1 for servo's, Ed den Ouden 2022 (lib: DCC_Decoder)"); Serial.println(""); Serial.print("First DCC-address: "); Serial.println(dccStartAddress); Serial.print("Startpin Arduino: "); Serial.println(startPinArduino); Serial.print("Nr of servo's: "); Serial.println(NUMSERVOS); Serial.println(""); Serial.println("Ready/idle, waiting for DCC-packets..."); Serial.println(""); #endif /* set DCC-addresses, outputpins and behaviour: copy & paste as many times as you have servo's the amount must be same as NUMSERVOS don't forget to increment the array index servo[x] init can also be done in a for loop DCC signal pin: 2 16 pins Uno/Nano: 3-18 32 pins Mega: 22-53 servo setup: servo[0].address = 1 ; // DCC address servo[0].outputpin = 14 ; // Arduino accessory pin servo[0].servo.attach( 3); // Arduino servo pin servo[0].offangle = 70 ; // servo angle for DCC state = 0 servo[0].onangle = 150 ; // servo angle for DCC state = 1 normal accesory (no servo): servo[1].address = 2 ; // DCC address servo[1].outputpin = 15 ; // outputpin Arduino */ servo[0].address = dccStartAddress ; // DCC address servo[0].outputpin = 21 ; // Arduino accessory pin servo[0].servo.attach(startPinArduino); // Arduino servo pin servo[0].offangle = 90 ; // servo angle for DCC state = 0 servo[0].onangle = 160 ; // servo angle for DCC state = 1 servo[1].address = dccStartAddress + 1 ; // DCC address servo[1].outputpin = 21 ; // Arduino accessory pin servo[1].servo.attach(startPinArduino + 1); // Arduino servo pin servo[1].offangle = 90 ; // servo angle for DCC state = 0 servo[1].onangle = 160 ; // servo angle for DCC state = 1 servo[2].address = dccStartAddress + 2 ; // DCC address servo[2].outputpin = 21 ; // Arduino accessory pin servo[2].servo.attach(startPinArduino + 2); // Arduino servo pin servo[2].offangle = 90 ; // servo angle for DCC state = 0 servo[2].onangle = 160 ; // servo angle for DCC state = 1 servo[3].address = dccStartAddress + 3 ; // DCC address servo[3].outputpin = 21 ; // Arduino accessory pin servo[3].servo.attach(startPinArduino + 3); // Arduino servo pin servo[3].offangle = 90 ; // servo angle for DCC state = 0 servo[3].onangle = 160 ; // servo angle for DCC state = 1 DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true); DCC.SetupDecoder( 0x00, 0x00, 0 ); // setup output pins for (byte i = 0; i < NUMSERVOS; i++) { pinMode (servo[i].outputpin, OUTPUT); digitalWrite(servo[i].outputpin, LOW); servo[i].angle = servo[i].offangle; servo[i].servo.write(servo[i].angle); delay(500); // wait 0,5 second before activating the next servo } } void loop() { for (byte i = 0; i < NUMSERVOS; i++) { DCC.loop(); // Call to library function that reads the DCC data if (servo[i].dccstate == 1) { digitalWrite(servo[i].outputpin, HIGH); servo[i].setpoint = servo[i].onangle; } else { digitalWrite(servo[i].outputpin, LOW); servo[i].setpoint = servo[i].offangle; } } // Move the servos when it is timetomove if (millis() > timetomove) { timetomove = millis() + (unsigned long)SERVOSPEED; for (byte i = 0; i < NUMSERVOS; i++) { if (servo[i].angle < servo[i].setpoint) servo[i].angle++; if (servo[i].angle > servo[i].setpoint) servo[i].angle--; servo[i].servo.write(servo[i].angle); } } }