Using a 4x4 matrix keypad

i understand there is a library to make using these devices easy, but since it looks like a simple enough circuit, i'd like to try it out from first principles.

as it involves connecting Arduino pins from an OUTPUT to an INPUT, i'd like to just confirm that what i'm about to do is infact safe !

my understanding is that it basically follows the same logic for multiplexing LED matrices, ie. drive a row (or column) HIGH, and then read which column (or row) is also HIGH meaning, the corresponding key is pressed.

my code then is like this;
(it's just a glorified continuity test to confirm which keys are pressed)

const byte row1 = 6;
const byte row2 = 7;
const byte row3 = 8;
const byte row4 = 9;

const byte col1 = 10;
const byte col2 = 11;
const byte col3 = 12;
const byte col4 = 13;


void setup() {
  pinMode(row1,OUTPUT);
  pinMode(row2,OUTPUT);
  pinMode(row3,OUTPUT);
  pinMode(row4,OUTPUT);

// col-pins are 'normal' INPUT with external pull-down 10k resistors

  Serial.begin(9600);
}

void loop() {

  digitalWrite(row1,HIGH);
  Serial.print("row1:ON\t");
  Serial.print(digitalRead(col1));
  Serial.print(digitalRead(col2));
  Serial.print(digitalRead(col3));
  Serial.print(digitalRead(col4));
  digitalWrite(row1,LOW);
  Serial.println("\trow1:OFF");

  digitalWrite(row2,HIGH);
  Serial.print("row2:ON\t");
  Serial.print(digitalRead(col1));
  Serial.print(digitalRead(col2));
  Serial.print(digitalRead(col3));
  Serial.print(digitalRead(col4));
  digitalWrite(row2,LOW);
  Serial.println("\trow2:OFF");

  digitalWrite(row3,HIGH);
  Serial.print("row3:ON\t");
  Serial.print(digitalRead(col1));
  Serial.print(digitalRead(col2));
  Serial.print(digitalRead(col3));
  Serial.print(digitalRead(col4));
  digitalWrite(row3,LOW);
  Serial.println("\trow3:OFF");

  digitalWrite(row4,HIGH);
  Serial.print("row4:ON\t");
  Serial.print(digitalRead(col1));
  Serial.print(digitalRead(col2));
  Serial.print(digitalRead(col3));
  Serial.print(digitalRead(col4));
  digitalWrite(row4,LOW);
  Serial.println("\trow4:OFF");

}

are there any safety concerns that i might have overlooked with the above ?

...

OK, so i had a peek at the library code and at first glance, it looks like it dispenses with the external resistors and uses INPUT_PULLUP.

this of course inverts the logic, and that means the one 'axis' is driven LOW, and then a key press is also indicated by a LOW reading on the input pin.

this means that the four output pins are normally ALL driving HIGH, right ?
how much current is then flowing out (and back IN?) the Arduino ?

BabyGeezer:
are there any safety concerns that i might have overlooked with the above ?

Yep! Sure are!

If two or more keys in the same column are simultaneously pressed, then you will be sequentially shorting a HIGH output to a LOW and vice versa.

If you were assembling the key matrix yourself, you would avoid this problem by putting a diode in series with each key. This would not only avoid the safety problem, but also enable "n-key rollover" - the ability to sense the pressing (and order of pressing) of any number of keys - a feature expected on a typing keyboard to facilitate high speed typing.

A crude (but terribly effective) way to avert this problem is to put a 1k resistor in series with each row line, which strictly limits the current which can pass in this situation. There is also a concern when two pins may be connected together that one set as an INPUT may accidentally become an OUTPUT.

Ignoring that last concern, the clever way to avoid the problem is to write all the outputs permanently LOW (as incidentally, they are by default, as well as initialised as INPUTs,) and instead of writing them LOW then HIGH again after the inputs have been sensed, because of course, you are using INPUT_PULLUP or additional pull-ups, not pull-downs; you set them as OUTPUTS to strobe that row of keys and INPUTS when that is done and you will move on to the next.

What else? Well, if you want to save time waiting for a keypress each time you go through the loop(), you simply set all rows to OUTPUT and check the columns, even (much) quicker if you use direct port manipulation. Once you have determined that a key is pressed, you perform the step-by-step scanning.

Finally, you need to use software de-bouncing, which is a whole separate topic. :grinning:

Paul__B:
Yep! Sure are!

okay, it looks like i still have a lot of fundamentals to get through so i hope you can bear with me going slowly...

Paul__B:
If two or more keys in the same column are simultaneously pressed, then you will be sequentially shorting a HIGH output to a LOW and vice versa.

okay, i have to step back a bit.

what exactly happens when a pin is set as "output" and "input".
OUTPUT turns it into an 'open-collector' situation ?
and
INPUT makes it into 'high-impedance' ?

the above aside, "shorting a HIGH output to a LOW" means there is conductivity from the 5V (pin@HIGH) to the GND (pin@LOW) flowing "unimpeded" (aka, overly high levels of current) through the Arduino circuitry?

Paul__B:
If you were assembling the key matrix yourself, you would avoid this problem by putting a diode in series with each key.

and that would be in the direction of "out from the key (a HIGH)" and not accidentally "incoming when it is (still) LOW"

                                    5V
                                   |
   key(COL n, ROW n) -------|>|----|
                                   |
                                   |
   key(COL n, ROW n+x) -----|>|----|
                                   |
                                   GND

Paul__B:
This would not only avoid the safety problem, but also enable "n-key rollover" - the ability to sense the pressing (and order of pressing) of any number of keys - a feature expected on a typing keyboard to facilitate high speed typing.

OK, and that's assuming that the code is capable of handling the "multiple-inputs" which will be coming "one at a time".

(will have to search "n-key rollover" ... )

Paul__B:
A crude (but terribly effective) way to avert this problem is to put a 1k resistor in series with each row line, which strictly limits the current which can pass in this situation. There is also a concern when two pins may be connected together that one set as an INPUT may accidentally become an OUTPUT.

"accidentally" meaning changed by the code and not by some physical occurrence ?

Paul__B:
Ignoring that last concern, the clever way to avoid the problem is to write all the outputs permanently LOW (as incidentally, they are by default, as well as initialised as INPUTs,) and instead of writing them LOW then HIGH again after the inputs have been sensed, because of course, you are using INPUT_PULLUP or additional pull-ups, not pull-downs; you set them as OUTPUTS to strobe that row of keys and INPUTS when that is done and you will move on to the next.

not sure i got that -- does that mean instead of;

digitalWrite(pinOUT, LOW); // assuming using inverted logic of INPUT_PULLUP
// and then back to
digitalWrite(pinOUT, HIGH);

using pinMode instead, ie;

pinMode(pinOUT, OUTPUT);
// and then back to
pinMode(pinOUT, INPUT_PULLUP);

Paul__B:
What else? Well, if you want to save time waiting for a keypress each time you go through the loop(), you simply set all rows to OUTPUT and check the columns, even (much) quicker if you use direct port manipulation. Once you have determined that a key is pressed, you perform the step-by-step scanning.

so that will look like this;

  digitalWrite(row1,HIGH);
  digitalWrite(row2,HIGH);
  digitalWrite(row3,HIGH);
  digitalWrite(row4,HIGH);
  if ((digitalRead(col1)) || (digitalRead(col2)) || (digitalRead(col3)) || (digitalRead(col4))) scanWhichKey();
  digitalWrite(row1,LOW);
  digitalWrite(row2,LOW);
  digitalWrite(row3,LOW);
  digitalWrite(row4,LOW);

Paul__B:
Finally, you need to use software de-bouncing, which is a whole separate topic. :grinning:

yes, i think this one i have a slightly better grasp of.

...

@Grumpy_Mike; you didn't have to delete your reply! :smiley:
i'm sure "sod all" means something to anybody with an electrical engineering degree, or decades of experience, but for someone who still struggles with the fundamentals, it doesn't mean anything.

i am guessing, however, that we're talking less than 1mA then ?
is this to do with 'high impedance' ?

what exactly happens when a pin is set as "output" and "input".

No you can't do that, it is the last pin assignment that applies.

OUTPUT turns it into an 'open-collector' situation ?

No, the only open collector outputs on the Arduino is the A5 & A6 pin and only then when it is in the I2C mode.

the above aside, "shorting a HIGH output to a LOW" means there is conductivity from the 5V (pin@HIGH) to the GND (pin@LOW) flowing "unimpeded" (aka, overly high levels of current) through the Arduino circuitry?

Yes that is right. The only thing limiting the current is the output impedance of around 30R which is not enough to prevent you exceeding the Absolute Maximum current for a pin.

That "diagram" shows ground and 5V being shorted out so it is not right.

"accidentally" meaning changed by the code and not by some physical occurrence ?

Exactly not.

so that will look like this;

No

i'm sure "sod all" means something to anybody with an electrical engineering degree, or decades of experience, but for someone who still struggles with the fundamentals, it doesn't mean anything.

I would have hoped that to someone knowing nothing about electronics "sod all" would mean nothing to be concerned about.

Suppose you said "I am worried about how much bacterial contamination there is from the air as I ladled the boiling jam to the sterilised jam jar". You would not need to be a micro biologist to know "sod all" was nothing to worry about. Or maybe you wouldn't?

Grumpy_Mike:
No you can't do that, it is the last pin assignment that applies.

i guess my phrasing wasn't clear, i didn't mean simultaneously.

Grumpy_Mike:
No, the only open collector outputs on the Arduino is the A5 & A6 pin and only then when it is in the I2C mode.

i see, would that be A5 & A4 if we're talking I2C mode ?

Grumpy_Mike:
Yes that is right. The only thing limiting the current is the output impedance of around 30R which is not enough to prevent you exceeding the Absolute Maximum current for a pin.

"30R" means 30 Ohm ?

Grumpy_Mike:
That "diagram" shows ground and 5V being shorted out so it is not right.

my mistake, i drew that wrong - shouldn't have made it directly to 5V / GND.

Grumpy_Mike:
I would have hoped that to someone knowing nothing about electronics "sod all" would mean nothing to be concerned about.

Suppose you said "I am worried about how much bacterial contamination there is from the air as I ladled the boiling jam to the sterilised jam jar". You would not need to be a micro biologist to know "sod all" was nothing to worry about. Or maybe you wouldn't?

fair enough if the question was "only for practical terms" - although knowing a general idea of the magnitude would be helpful as to what "nothing to be concerned about" means.

i'm not trying to be an electrical engineer overnight, but knowing some fundamentals as i stumble along would be good - - we've determined (before) that "the device draws what the current is, so i'm trying to figure out which "component in the Arduino" is the one "drawing the current from the output", ie. what is the fundamental issue to be learned from the situation.

Actually, I would be concerned about bacterial contamination from the air - but then I am scared of botulinum! That is the similar reason to why we use the "space suits" and ultra-filtered air curtain theatre when performing joint prostheses.

OK, while I note BabyGeezer has adopted my quoting technique, I do not feel like it at this time of night (?morning). :cold_sweat: I will just make a couple of notes.

The technique of setting output LOW and switching from INPUT to OUTPUT and back is a "pseudo-open-drain" approach. It has exactly the same effect.

You would not want to use INPUT_PULLUP as a mode for this, and not because it would place an unnecessary pull-up on what you want to be an output (the INPUT_PULLUP on the inputs is all that is needed) but because the actual execution of INPUT_PULLUP is to set the output register itself HIGH and is a two-step process along with clearing the data direction register, so there is an undesirable transient state between the steps. Strictly speaking, it is equivalent to firstly setting pinMode to INPUT and then digitalWrite HIGH as was the procedure in earlier versions of the IDE. If this is done in the opposite order, there will be a brief flash of HIGH on the pin. In any case, you do not want the pull-up state.

The diodes would of course, have cathodes toward the outputs which are pulling down, and anodes toward the input pins.

  digitalWrite(row1,HIGH);
  digitalWrite(row2,HIGH);
  digitalWrite(row3,HIGH);
  digitalWrite(row4,HIGH);
  if ((digitalRead(col1)) || (digitalRead(col2)) || (digitalRead(col3)) || (digitalRead(col4))) scanWhichKey();
  digitalWrite(row1,LOW);
  digitalWrite(row2,LOW);
  digitalWrite(row3,LOW);
  digitalWrite(row4,LOW);

Yes, that tedious code - presuming you are using the original polarity with the diodes the other way and your pull-down resistors which I feel is the wrong way, does reflect the suggestion, but really should be performed by direct port manipulation with a tenth of the code and execution time. :grinning:

It is most unlikely that the hardware itself would "accidentally" switch between INPUT and OUTPUT, but code errors or code crashes - possibly due to physical transients - are a concern especially during development.

30R" means 30 Ohm ?

Yes.

i see, would that be A5 & A4 if we're talking I2C mode ?

Yes sorry.

ok, thanks a lot guys - it shows i still have so much more to learn about the fundamentals.

it really comes down to "knowing how to USE a tool" vs. "knowing how the tool DOES work".

there is SO MUCH human knowledge that no ONE person can know how every tool works, we just have to trust that the experts that led to A tool being made, knew what they were doing !! :smiley:

i realize i must be asking such stupid questions about things that are clearly beyond my level, but i persist, based on the principle that "if you don't know how the tool you use works, YOU are the 'tool'..." (Exhibit A : the smartphone :wink: )

thanks again for your patience and responses.

"sod all" seems to have been a point of confusion which was never explained. It's a phrase that has nothing (or should I say "sod all") to do with electronics: it's UK slang for "nothing" (and almost never used outside of the UK)

DrAzzy:
"sod all" seems to have been a point of confusion which was never explained.

for the sake of other readers.

DrAzzy:
(and almost never used outside of the UK)

unless they are fans of classic British comedies. :slight_smile:

and almost never used outside of the UK

Didn't know that. Of course "sod" can be replaced by the "f" word but it means the same. I know it from the old song:-

A mathematician from Scunthorpe
Discovered the weight of his ball
Plus his scrotum times three
Was approximately
Two thirds of four fifths of sod all

A nineteen year old nymphomaniac
Wore a bog-paper dress to a ball
But it started tearing
She ended up wearing
Two thirds of four fifths of sod all

With premature ejeculation
It seems my endurance is small
From the time of inserting
To the moment of squirting
Two thirds of four fifths of sod all

I was seized with a stiff constipation
I crouched in a lavatory stall
I thundered and pumped
But finally dumped
Two thirds of four fifths of sod all

It's a big cock, a big cock
A big cock and bull story
Here comes the interesting bit
The parts that are true
Near enough add up to
Just about half the square root of jack sh*t

My penis is small like an acorn
Sometimes I can't find it at all
It's infinitesimal
Or expressed in decimal
Point five of point three of sod all

An ancient Egyptian urinal
Has the meaning of life on the wall
In plain simple words
It's written in tirds
Two thirds of four fifths of sod all

Now that is the end of my chanson
And if for an encore you call
Well bollocks you twat
The chances of that are
Two thirds of four fifths of sod all

"'Ere Mr. Recording Engineer, what's the chances of
this song becoming a number one hit?"
"About two thirds of four fifths of practically
nothing"

Unused verse, deservedly cut from the released version
There's a harlot with pox, clap and herpes
You can smell her from here to Bengal
She's got syph and colitis
And that's why her price is
Two thirds of four fifths of sod all

Quick note for US readers bog-paper is known as toilet paper, if you use that term. Maybe you call it "rest room paper"?