Problem with Interfacing Diode matrix into Arduino UNO

For my project (a model railroad turntable using a stepper motor) I have 13 push button switches wired via a diode matrix into 4 input pins (8,9,10,11) of the UNO. I use port manipulation to read a Byte variable which represents the value of the button pressed.

This works very if I use a simple input and 10k pulldown resistor as shown in the schematic.

But now I want to enhance the circuit by using a (somewhat crude!) de-bounce circuit as well as using the switch to ‘fire’ a flip-flop which then turns on an LED corresponding to the switch pressed. This is shown in the second schematic. Now the input to the Arduino never goes high when a button is pressed. If I disconnect the Arduino, the circuit goes high as expected - but if I connect the Arduino if doesn’t.

Do I need higher value pulldown resistors (for example 100k instead of 10k) or is there something else I’m doing wrong?

OP’s schematic:

That is an interesting blend of hardwired logic and micro controller logic.
The classic way of handling so many switches is to arrange them in a matrix, then scan the rows, then scan the columns, to detect key presses.
The classic way of debouncing is, when you detect a key press, ignore subsequent key presses for X mS.

Anyway, the only thing I can imagine to explain your problem, other than a wiring error, is that there is a coding error which has changed the Arduino pin from its input (high impedance) state. Ie to an output or has switched on the pull-up resistor.

With the circuit addition, does the Arduino behave as before and only the 4013 has problems?
When you say you disconnect the Arduino pin, do you leave the attached diode and pull down resistor in circuit ?

Post the code you have written.

If the input is not connected, it's floating, might read HIGH, LOW, or anywhere in between. Why not connect buttons to GND, use the builtin pullup resistors and inverted logic?

Thanks for the replies - I'll post the code later on which works absolutely fine when used with the simple matrix in first diagram. It's only when I add the debounce and link to the 4013 that it no longer reads high at the Arduino. This is because it doesn't go high anymore - I've used a logic probe to check this. If I then disconnect the Arduino input, the circuit itself goes high as I'd expect.

My code is below. Note that this is truncated purely to test the receipt of switch inputs to the Uno. With a matrix wired as per the first circuit in the diagram, this works absolutely fine. If I add all the other circuit stuff, the Arduino inputs don’t go high any more.

// removed several sections so as to be able to test the diode matrix

int posnArray [11]={0,1440,3360,4160,4320,4480,4640,160,960,1120,1280}; // Will Need updating for actual positions: 
// Note position 0 in the array is a dummy since we cannot call a zero with the push buttons
int currentPosn = 0;
int newPosn = 0;
int numSteps = 0;
int finSteps = 0;
#define STEPS 6400 // the number of steps in one revolution of the motor (400) multiplied by the micro-step fraction (1/16) (17HM15-0904S)


// Calculate steps required and optimum direction
void calcTableStepsDir(){
  numSteps = (newPosn - currentPosn);
  Serial.print("Base number of steps is: ");
  Serial.println (numSteps);
  if (numSteps < 0) {
    if (numSteps < -3200) {
      finSteps = STEPS + numSteps;
    } else {
      finSteps = numSteps;
    }
  } else {
    if (numSteps > 3200){
    finSteps = numSteps - STEPS;
  } else {
    finSteps = numSteps;
  }
  }
  Serial.print("Final number of steps is: ");
  Serial.println (finSteps);
}

void setup()
{
  Serial.begin(9600);
  Serial.println("<Arduino is ready>");
  DDRB = DDRB | B00001111;  // Sets pins 8-11 as input
 // pinMode (HALL_SENSOR, INPUT);  // define the Hall magnetic sensor line as input
 // pinMode (resetPin, OUTPUT); // define reset pin as output
 
  // Home the table
  // homefunction();
}

void loop()
{
  byte buttonNo = PINB & 0b00001111;  //read D891011
   while ( buttonNo != 0) { 
     Serial.print( "PINB = " );     
     Serial.println( buttonNo );
     if (buttonNo != 13) {
       if(buttonNo == 11){
       newPosn = (currentPosn + 1);
       }
       else if(buttonNo == 12){
       newPosn = (currentPosn - 1);
       } else {
       newPosn = (posnArray [buttonNo]);
       }
     Serial.print( "New Position is: " );     
     Serial.println( newPosn );
     calcTableStepsDir ();
     // tableMov ();
     buttonNo = 0;
     } else {
     Serial.println( "Reset function selected" );     
     // homefunction();
      buttonNo = 0;
    }
    delay(250); //Delay to ensure multiple button presses aren't registered
  }
}

Sorry, but when you have a microcontroller to do the work, attempting to use hardware de-bouncing is a really silly idea! :cold_sweat: Likewise the 4013.

That is what a microcontroller - code - is for!

This is clearly an "XY problem"!

Why are you using switches connected to 5 V?

The comment does not agree with the action.
The order here for PORTB is pin X2 X1 13 12 11 10 9 8 where X indicates a crystal pin
0 = input, 1 = output.

DDRB = DDRB | B00001111 ; // Sets pins 8-11 as input

See: Arduino - PortManipulation

Thanks for the response. Yes, you’re quite right - I’m using pins 8 - 11 as input to the Arduino from the diode matrix. The ‘Byte’ line then reads the input as a value which represents the switch pushed.

I use the microcontroller to work out which switch has been pressed and convert that into a position to which the stepper motor should move. As the code snippet states in the comment line, I’ve removed a lot of the final code so that this sketch just acts to enable me to test the diode matrix (switch input).

I’m using the 4013 etc. because I already had them in use for a previous version of the control box which didn’t use an Arduino. It drove an ‘analog’ motor and used opto-electronic sensors to stop the table in the right place. It wasn’t hugely successful because the speed of the motor (and hence it’s stopping distance) depended on the load.

Here’s the full code for the sketch so you can better see what I’m doing. As I said in the original post - this works absolutely fine with the diode matrix switches wired as per the LH diagram in the schematic - so I’m happy that the code is good!

// Revised for NEMA 17 motor with 400 steps/rev and A4988 Driver with 1/16 Micro-stepping
// 11th May 2020: Revised use of Arduino output pins so that Binary read will be in 1s instead of 4s. Revised selection logic as a result
// Needs debugging/testing

int posnArray [11]={0,1440,3360,4160,4320,4480,4640,160,960,1120,1280}; // Will Need updating for actual positions: 
// Note position 0 in the array is a dummy since we cannot call a zero with the push buttons
int currentPosn = 0;
int newPosn = 0;
int numSteps = 0;
int finSteps = 0;

#include <AccelStepper.h>
#define motorInterfaceType 1
#define STEPS 6400
#define dirPin 2
#define stepPin 3
#define resetPin 4
#define HALL_SENSOR 5

AccelStepper myStepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

// initialize start position routine
void homefunction() {
  myStepper.setMaxSpeed(500);   // Set max stepper speed to 120 steps/sec (1.125 RPM)
  myStepper.setSpeed(500);   // Set stepper speed to 500 steps/sec CW (4.7 rpm)
  while (digitalRead(HALL_SENSOR) == 1) { 
  myStepper.runSpeed(); // Step clockwise until sensor fired
  }
  while (digitalRead(HALL_SENSOR) == 0) { 
  myStepper.setSpeed(-500);   // Set stepper speed to 500 steps/sec ACW (4.7 rpm)
  myStepper.runSpeed(); // Step Anti-clockwise until sensor clears
  }
myStepper.setSpeed(320); //Set speed to 320 steps/sec (3 rpm)
myStepper.setCurrentPosition(0);
newPosn = posnArray [1];
myStepper.moveTo(newPosn);
myStepper.runToPosition(); // Go to pos'n 1
currentPosn = (posnArray [1]);
}

// Calculate steps required and optimum direction
void calcTableStepsDir(){
  numSteps = (newPosn - currentPosn);
  Serial.print("Base number of steps is: ");
  Serial.println (numSteps);
  if (numSteps < 0) {
    if (numSteps < -3200) {
      finSteps = STEPS + numSteps;
    } else {
      finSteps = numSteps;
    }
  } else {
    if (numSteps > 3200){
    finSteps = numSteps - STEPS;
  } else {
    finSteps = numSteps;
  }
  }
  Serial.print("Final number of steps is: ");
  Serial.println (finSteps);
}

void tableMov (){
  myStepper.setMaxSpeed(120);   // Set max stepper speed to 120 steps/sec (1.125 RPM)
  myStepper.setAcceleration (30); //Set acceleration to 30 steps/sec2
  Serial.print("Moving table to position:");
  Serial.println (newPosn);
  myStepper.move(finSteps); // No of steps in approporiate direction 
  myStepper.runToPosition ();
  digitalWrite (resetPin, HIGH); //Resets the LED flip-flops
  delay (100);
  digitalWrite (resetPin, LOW);
  currentPosn = newPosn;
  newPosn = 0;
}

void setup()
{
  myStepper.setMaxSpeed(500);   // Set max stepper speed to 500 steps/sec (4.7 RPM)
  myStepper.setAcceleration (30); //Set acceleration to 30 steps/sec2
  Serial.begin(9600);
  Serial.println("<Arduino is ready>");
  DDRB = DDRB | B00001111;  // Sets pins 8-11 as input
  pinMode (HALL_SENSOR, INPUT);  // define the Hall magnetic sensor line as input
  pinMode (resetPin, OUTPUT); // define reset pin as output
 
  // Home the table
  homefunction();
}

void loop()
{
  byte buttonNo = PINB & 0b00001111;  //read D891011
   while ( buttonNo != 0) { 
     Serial.print( "PINB = " );     
     Serial.println( buttonNo );
     if (buttonNo != 13) {
       if(buttonNo == 11){
       newPosn = (currentPosn + 1);
       }
       else if(buttonNo == 12){
       newPosn = (currentPosn - 1);
       } else {
       newPosn = (posnArray [buttonNo]);
       }
     Serial.print( "New Position is: " );     
     Serial.println( newPosn );
     calcTableStepsDir ();
     tableMov ();
     buttonNo = 0;
     } else {
      homefunction();
      buttonNo = 0;
    }
    delay(250); //Delay to ensure multiple button presses aren't registered
  }
}

OK. But have you corrected this error ? :

DDRB = DDRB | B00001111;  // Sets pins 8-11 as input

Ahh - that’s an error I made right back at the beginning (must have mins-interpreted the example!). Having said that, it’s never stopped it working correctly with the simple diode matrix. I’ll correct it and try again and let you know the result.

Ok - so I corrected the DDRB statement and I can now read the input via the serial monitor so thanks very much for that. I’m still puzzled as to why it worked previously with that statement incorrect but it doesn’t really matter now.

However, there is another issue which is that the result of the PINB read is inconsistent. If I press a button that should result in a multi-bit response (i.e. 5 say) the read value may be 4 on the first press and 5 on the second. It’s not consistently reading all the bits!

I can see that one of the ways around this would be to set up a cube as suggested earlier. My issue with this is that I would need 8 pins (for a 4 x 4 cube) and then another few for the 10 LEDs (buttons 1 to 10 have a corresponding LED which should light when the button is pressed and stay lit until the movement is complete. Buttons 11,12 & 13 have no LED). I also need 2 for the stepper motor (Step & Direction) and one for the hall sensor that I’m using for positional reference.

I realise that this is probably now going beyond the remit of this subject, but any assistance will be gratefully received.

Many thanks!

The result of reading PINB is not sensitive to the declaration of the pin as input or output, so for your initial circuit it worked. However, the output declaration (using DDRB) had an impact on the external circuit with the 4013

If you already have a handful of small signal diodes and you want to minimise the the number of arduino pins used, then your method is the most efficient. 4 pins for 16 buttons with your diode method versus 8 pins with the matrix method. However, if you need to go to 17 pins or more, then be ready to add another whole stack of diodes.

If, when you read the port as follows, you are getting inconsistent results

byte buttonNo = PINB & 0b00001111 ; //read D891011

then that could be a key bounce problem. If there is a change on the port, then maybe ensure that it has been stable for the last say 50 ms before accepting it as valid. After a valid result has been accepted, refuse to accept another one for a bit longer. That way, you can eliminate most spurious results.

Does the screen name "pastysmuggler" have Cornish (GB) overtones ?

Well 6v6gt - the answer to your final question is certainly yes!! It harks back to a time when you couldn't get a proper pasty outside Cornwall!! (And I happen to live here now too!).

I've got my crude de-bounce circuits in place which should be good for 1mS of protection though I might make that longer given what you say - changing the resistor value to 47k will give 47mS approx.

Odd thing is, when I first started playing about with this I used pins 2, 3, 4 & 5. Since this missed the two least significant bits, the result of the 'byte buttonNo = PIND......' statement counted up in 4s. In this case, I had to use an 'if...' statement for each button value. I didn't have any problem with missed/missing bits when I used these pins (and I didn't have my de-bounce circuits then either!

I switched to using pins 8 - 11 realising that I could just use the result of the 'PINB..' read to substitute into the value to get from the position array - which saves a lot of lines of code! Not that this actually makes much difference in terms of time!

Ah yes. Cornish pasties. I remember these as nice looking golden brown puff pastry snacks, but filled mainly with tiny cubes of potato, moistened with some grey coloured lamb and pepper flavoured gravy. However, I hasten to add, these were not the real thing, but from the county just east of yours.

Well, lets see how you get on with the hardware solution. If it doesn't work out, I'll attempt an example software debounce for you to try.

Hmmm - now I've changed the resistor to 47k on 3 of the circuits - and now they don't register at all! Oddly enough I had a problem with one previously and discovered that I'd put in a 10k instead of a 1k resistor - and that didn't register either!

I suspect my theory on de-bounce is not correct. The higher value of, what is in effect a, series resistor is enough to prevent the 5v coming through to the diode matrix.

My lash-up (with which I tested initially) didn't have any of the debounce stuff in. I may go back to that and see if I have the same issue with inconsistent results. I'll also try it again with pins 2-5 on PortD just to see if there's any difference there.

Thanks again!

(BTW - the Cornish variety is a meal in itself - Skirt of Beef, potatoes, swede (or 'turnip' as they call it down here) and onion all seasoned with salt and pepper). Shortcrust pastry (although you can get puff pastry ones!) crimped around the edge - the Devon variety is crimped over the top!)

I'm not sure which diagram now more accurately relates to your latest (unsuccessful) tests.
I've tried to put together the main elements in a simulator. You have to explicitly open the picture in your browser to have any hope of reading it. The time constant is a function of the capacitor and the resistor R2 which you have as 1K. You need one capacitor per input line (your 2^0, 2^1, 2^2 and 2^3) for button debouncing. As you can see, at 5ms it reaches the maximum voltage of 4.4 volts at the test point (which represents the Arduino pin).

It is also clear to me that the "Cornish" pasties I described came from the wrong side of the Tamar.

I actually have a 1k resistor and 1uF capacitor for each switch rather than each input line. Essentially what you've done is correct and therefore valid although I have 10k pull-downs (again on each switch as well as on each input line).

Having gone back to my lash-up (which simply feeds the switch through the diode(s) to the input line) this also gives inconsistent results (I just must not have noticed them at the time as I was more intent on getting the stepper motor control right!). I've also tried using PORTD (pins 2-5) and this is no more consistent either.

It looks to me as though I'll have to bite the bullet and use a 4 x 4 matrix - so I'm wiring one of those up now and will test with the keypad.h library. I've also got a notion of how to control the LEDs directly but need to test that out too once I've got the keypad bit right!

Once again - I really appreciate your help.

I have now re-worked the switches using a single diode for each in a 4 x 4 matrix - and the keypad library. This now seems to work fine and does give a definitive response for each keypress. I will therefore go with this in further developing the project.

I really do appreciate all the responses and help received - thank you very much