Hi landracer, The short answer is "yes", I found the code on the internet and have been trying to contact the author, but have had no success,The Code/Sketch involves Servo's, LEDs and push buttons for a model railway project using a Arduino UNO,not sure if this is the right way to post code, I'm sure someone will tell me;
include // include the Servo library
////////////////////////////////////////
//
// Definitions
//
////////////////////////////////////////
////////////////////////////////////////
// Basic parameters; adjust for your actual setup
define NUMBER_OF_TURNOUTS 5
define NUMBER_OF_SHIFT_REGISTERS 3
define STEP_DELAY 70 // servo movement step delay, in milliseconds
///////////////////////////////////////
///////////////////////////////////////
// Data Structures
///////////////////////////////////////
//////////////////////////////////////
// TURNOUT_DEF holds all configuration
// information about turnouts and panel LEDS
//////////////////////////////////////
typedef struct TURNOUT_DEF {
uint8_t button_pin; // Digital or analog pin for the button associated with this turnout
uint8_t servo_pin; // Digital pin for the servo associated with this turnout
int pos_main; // servo position for the MAIN leg, in degrees
int pos_div; // servo position for the DIVERGENT leg, in degrees
int panel_LED_main_green; // The position(s)of panel LEDS in the shift register chain
int panel_LED_main_red; // Example assumes a bi-color (red/green) LED for each turnout leg
int panel_LED_div_green; // modify these elements to reflect the actual LEDS you are using
int panel_LED_div_red;
};
/////////////////////////////////////
// TURNOUT_DATA is wrapper structure holding
// both configuration and runtime data for turnout operation
/////////////////////////////////////
typedef struct TURNOUT_DATA {
TURNOUT_DEF data; // configuration
bool is_moving;
byte alignment;
int pos_now;
int target_pos;
unsigned long last_move;
};
// Alignment state values
define ALIGN_NONE 0
define ALIGN_MAIN 1
define ALIGN_DIVERGENT 2
// pin ids for shift register chain controlling panel LEDS
define LATCH_PIN 7
define CLOCK_PIN 8
define DATA_PIN 9
//////////////////////////////////////////
//
// Global variables
//
//////////////////////////////////////////
//////////////////////////////////////////
// TURNOUT_DATA Array
// * A0, A1, etc refer to analog pins which are used for buttons in this example
// * Replace pos_main (93) and pos_div (117) with real values for each turnout
// * LEDS are identified by their output position in the shift register chain;
// the identifier is a number between 0 and (NUMBER_OF_SHIFT_REGISTERS * 8) - 1.
// Example assumes LEDS are connected to shift register outputs sequentially
// from the first output of first register. You can connect LEDS to any output in
// any order; just set the identifiers accordingly.
//
// Only the TURNOUT_DEF part of the TURNOUT_DATA structure has to be initialized here;
// The remaining elements are managed internally and are initialized automatically
//////////////////////////////////////////
TURNOUT_DATA turnouts[NUMBER_OF_TURNOUTS] = {
{{A0, 2, 93, 117, 0, 1, 2, 3}},
{{A1, 3, 93, 117, 4, 5, 6, 7}},
{{A2, 4, 93, 117, 8, 9, 10, 11}},
{{A3, 5, 93, 117, 12, 13, 14, 15}},
{{A4, 6, 93, 117, 16, 17, 18, 19}}
};
// servo objects
Servo servos[NUMBER_OF_TURNOUTS];
// array to hold shift register state bytes
byte panel_LEDS[NUMBER_OF_SHIFT_REGISTERS];
void setup()
{
// Setup pins for shift register chain
pinMode(LATCH_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(DATA_PIN, OUTPUT);
// initialize each turnout
for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){
// attach the servo
servos[i].attach(turnouts[i].data.servo_pin);
// set the pin mode for the button pin
pinMode(turnouts[i].data.button_pin, INPUT);
// test and position the turnout by moving
// to divergent then to main positions
servos[i].write(turnouts[i].data.pos_div);
turnouts[i].pos_now = turnouts[i].data.pos_div;
setTurnout(i, ALIGN_MAIN);
}
} // end of setup
void loop()
{
// get elapsed milliseconds at loop start
unsigned long currentMillis = millis();
// loop through the turnouts array
for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){
if (turnouts[i].is_moving) {
// if sufficient time has elapsed since the last move
if ( (currentMillis - turnouts[i].last_move) >= STEP_DELAY ) {
// move the turnout one degree
turnouts[i].last_move = currentMillis;
if (turnouts[i].pos_now < turnouts[i].target_pos) { // if the new angle is higher
servos[i].write(++turnouts[i].pos_now);
} else { // otherwise the new angle is equal or lower
if (turnouts[i].pos_now != turnouts[i].target_pos) { // not already at destination
servos[i].write(--turnouts[i].pos_now);
}
}
}
// if target position reached, stop turnout motion
if (turnouts[i].pos_now == turnouts[i].target_pos) {
turnouts[i].is_moving = false;
turnouts[i].last_move = 0;
setIndicators(i);
}
} else {
// if a turnout is NOT in motion, check to see if its button is pressed
int button_state = digitalRead(turnouts[i].data.button_pin);
if(button_state == HIGH){
// toggle position
if(turnouts[i].alignment == ALIGN_MAIN){
setTurnout(i, ALIGN_DIVERGENT);
} else {
setTurnout(i, ALIGN_MAIN);
}
}
}
}
}// end of main loop
////////////////////////////////////////////////////////////////
// Supporting Functions
////////////////////////////////////////////////////////////////
void setTurnout(int id, int align){
// Set indicators to show turnout in motion
turnouts[id].alignment = ALIGN_NONE;
setIndicators(id);
// Set values to trigger motion on next loop iteration
switch(align){
case ALIGN_MAIN:
turnouts[id].is_moving = true;
turnouts[id].last_move = 0;
turnouts[id].target_pos = turnouts[id].data.pos_main;
turnouts[id].alignment = ALIGN_MAIN;
break;
case ALIGN_DIVERGENT:
turnouts[id].is_moving = true;
turnouts[id].last_move = 0;
turnouts[id].target_pos = turnouts[id].data.pos_div;
turnouts[id].alignment = ALIGN_DIVERGENT;
break;
}
}
void setIndicators(int id){
switch(turnouts[id].alignment){
case ALIGN_NONE: // means the turnout is in motion and not aligned
panelWrite(turnouts[id].data.panel_LED_main_red, HIGH);
panelWrite(turnouts[id].data.panel_LED_main_green, LOW);
panelWrite(turnouts[id].data.panel_LED_div_red, HIGH);
panelWrite(turnouts[id].data.panel_LED_div_green, LOW);
break;
case ALIGN_MAIN:
panelWrite(turnouts[id].data.panel_LED_div_green, LOW);
panelWrite(turnouts[id].data.panel_LED_div_red, HIGH);
panelWrite(turnouts[id].data.panel_LED_main_green, HIGH);
panelWrite(turnouts[id].data.panel_LED_main_red, LOW);
break;
case ALIGN_DIVERGENT:
panelWrite(turnouts[id].data.panel_LED_div_green, HIGH);
panelWrite(turnouts[id].data.panel_LED_div_red, LOW);
panelWrite(turnouts[id].data.panel_LED_main_green, LOW);
panelWrite(turnouts[id].data.panel_LED_main_red, HIGH);
break;
}
}
/////////////////////////////////////////////////
// Shift Register Functions
/////////////////////////////////////////////////
void panelWrite(int id, byte state) {
int reg = floor(id / 8);
int pos = id % 8;
bitWrite(panel_LEDS[reg], pos, state);
panelRefresh();
}
void panelRefresh(){
// Prepare to shift by turning off the output
digitalWrite(LATCH_PIN, LOW);
// shift all bits out in MSB (most significant bit first) order
for(int i = (NUMBER_OF_SHIFT_REGISTERS - 1); i>=0; i--) {
// shift out the bits
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, panel_LEDS[i]);
}
// turn on the output to activate
digitalWrite(LATCH_PIN, HIGH);
}
Regards Terry