Pushbutton Input using shiftIn Through to shiftOut

I'm new to Arduino and have decided to get involved for one reason; creating a control system using logic control. The intended use for this will be outputs to relays controlling point motors, servo motors, a number of LEDs and power feeds on a model railway.

I have spent a considerable amount of time over the past few months creating tables of routes and the required position of turnouts for each route, creating the logic control using AND gates to set the turnouts on each route to their respective positions and incorporating checks for normal and reverse positioning to check if a turnout requires switching and subsequently if it has then moved into the correct position. I have also included a route availability check to determine if any turnouts on the route selected are currently in use by another route that is already set, thus making the requested route unavailable.

I have yet to go into signalling or track feeds. However, this should be feasible to incorporate into the program at a later stage (I hope). So to give an outline of how the system should function:

  1. The route selected must be a valid route. (there are 57 routes).
  2. The route selected must not conflict with any other route already set.
  3. All the points along the route are set.
    The movement of each Fulgurex point machine is controlled by its own relay, which will be "normal" or "reversed".
  4. Changeover contacts on each point machine complete a circuit which logically represents the route.
    When this circuit is complete, it indicates that each point machine has moved correctly, and confirms the route.
    5, Separate relays connect traction current from the operator's controller to each finite element of the set route. These can be very small elements of track, only a few centimetres long in complex areas of pointwork.
  5. Mini LEDs illuminate the route on the control panel.
  6. After a few seconds delay, the necessary signals along the route are cleared.
  7. The signal aspect is repeated on the control panel

Now, to start off the plan is to get all of the turnouts set along a route with just two button presses. As this is a terminus station, the signalling is much simpler in its operation and being semaphore signalling, a little easier to control.

I have drawn up the tables of turnouts to be switched for each route and their individual positions.

The reason for the use of the shiftIn and shiftOut functions is quite obvious; there are 17 individual route buttons on the control panel, with a reset button also. The function of this button is to clear the set route, freeing up that routes resources to be used in another route. The idea is to ultimately have two operators, each with their own reset button so only their route is cleared. This is especially useful should an operator make a mistake as it has no effect on the other operator.

Using the shiftIn function, it will be necessary to first read the state of each route button to determine which route is being requested, before running through the required resources for the route to check for route conflict, required turnout position and then using the shiftOut function to switch the required point motors etc. then checking that each turnout on the route has correctly switched, confirming the route before moving onto the next procedure (track feeds, signals, mimic diagram LEDs) and so on.

I have attached a spreadsheet containing the requirements for each individual route (just turnouts). The routes with number 1 and 2 in parenthesis indicate two paths for that particular route; the routes numbered 1 will be requested and if unavailable, the 2nd option requested.

Any help in helping me understand the coding requirements and how to go about this is much appreciated.

Route Setting.pdf (43.4 KB)

Do you mean digitalRead and digitalWrite, instead of shiftIn and shiftOut?

For reading/writing multiple signals at a time, over the same line, you can use port extenders on a SPI or I2C bus. Such extenders can be placed wherever needed/convenient, with only few bus lines going to the Arduino, and up to 16 inputs or outputs to nearby sensors or actuators on each extender.

An Arduino is very good in making logical decisions, I can't see a problem here. The tables can be placed in flash or EEPROM memory, should be sufficient for more than 60 routes.

You don't need individual inputs for pushbuttons. The common solution for that is to use a switch matrix. For 20 buttons, you need only 4*5=9 I/O.

So if I scrap the idea of using a shift register for the inputs and construct a matrix 4*5 making use of 17 switches. I could use the digitalWrite to read the state of each button, using only 9 pins.

Moving on to creating the data for the Arduino to reference when a particular combination of buttons are pressed, how might I go about this? Could this be done using the switchCase method or would it be easier to create some form of array for the Arduino to work from?

Thanks for the help so far.

Use the keypad.h library to read the buttons, one at a time.

If you want to read multiple presses at once, then your original idea to capture the state of the buttons use 2 or 4 74HC165 is better.

switch:case would then work well to act on the buttons.

Maybe have a set of 74HC595 to light up LEDs to show which buttons are pressed for feedback, with an enter key and a clear key.

So after having a little play around with some of the coding. I have come up with this as a starting point. I feel there could be a simpler way of doing things here to reduce the number of lines of code. I have yet to include any of the other items to be switched, just the point motors. Likewise, I have not included any of the route proving or route conflict checks.

int rowPin1 = 22;
int rowPin2 = 23;
int rowPin3 = 24;
int rowPin4 = 25;
int colPin1 = 26;
int colPin2 = 27;
int colPin3 = 28;
int colPin4 = 29;
int colPin5 = 30;
int pts1Pin = 31;
int pts2Pin = 32;
int pts3Pin = 33;
int pts4aPin = 34;
int pts4bPin = 35;
int pts5Pin = 36;
int pts6Pin = 37;
int pts7Pin = 38;
int pts8Pin = 39;
int pts9Pin = 40;
int pts10Pin = 41;
int pts11Pin = 42;
int pts12Pin = 43;
int pts13Pin = 44;
int pts14Pin = 45;
int pts15Pin = 46;
int pts16Pin = 47;
int pts17Pin = 48;
int pts18Pin = 49;
int pts19Pin = 50;
int pts20Pin = 51;
int pts21Pin = 52;
int pts22Pin = 53;

void setup() {
  pinMode(22, INPUT);
  pinMode(23, INPUT);
  pinMode(24, INPUT);
  pinMode(25, INPUT);
  pinMode(26, INPUT);
  pinMode(27, INPUT);
  pinMode(28, INPUT);
  pinMode(29, INPUT);
  pinMode(30, INPUT);
  pinMode(31, OUTPUT);
  pinMode(32, OUTPUT);
  pinMode(33, OUTPUT);
  pinMode(34, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(36, OUTPUT);
  pinMode(37, OUTPUT);
  pinMode(38, OUTPUT);
  pinMode(39, OUTPUT);
  pinMode(40, OUTPUT);
  pinMode(41, OUTPUT);
  pinMode(42, OUTPUT);
  pinMode(43, OUTPUT);
  pinMode(44, OUTPUT);
  pinMode(45, OUTPUT);
  pinMode(46, OUTPUT);
  pinMode(47, OUTPUT);
  pinMode(48, OUTPUT);
  pinMode(49, OUTPUT);
  pinMode(50, OUTPUT);
  pinMode(51, OUTPUT);
  pinMode(52, OUTPUT);
  pinMode(53, OUTPUT);
}

void loop() {
 if(rowPin1 == HIGH && colPin1 == HIGH) {
   if(rowPin3 == HIGH && colPin3 == HIGH) {
     digitalWrite(pts1Pin, HIGH);
     digitalWrite(pts2Pin, HIGH);
     digitalWrite(pts3Pin, HIGH);
     digitalWrite(pts7Pin, LOW);
     digitalWrite(pts12Pin, LOW);
     digitalWrite(pts11Pin, LOW);
 }
}
if(rowPin1 ==HIGH && colPin1 == HIGH) {
  if(rowPin3 == HIGH && colPin4 == HIGH) {
     digitalWrite(pts1Pin, HIGH);
     digitalWrite(pts2Pin, HIGH);
     digitalWrite(pts3Pin, HIGH);
     digitalWrite(pts7Pin, LOW);
     digitalWrite(pts12Pin, HIGH);
     digitalWrite(pts13Pin, LOW);
     digitalWrite(pts10Pin, HIGH);
     digitalWrite(pts18Pin, HIGH);
  }
}
}