Go Down

Topic: Keyboard Matrix Reduce I/O (Read 5952 times) previous topic - next topic


 I am currently working on a project that requires a (almost) full qwerty keyboard, as well as a 4x20 lcd(standard 4 bits of data interface). Trying to fit all of this onto an atmega328 is obviously going to be a difficult task, and the standard keypad library and matrices consume far too many pins to be of any use in this project. I believe that an LCD will take up 6 general purpose I/O, leaving me with very few to create a useful keyboard.

  I came up with this project when viewing an episode of the Ben Heck Show, where he creates texting radios. His use of the Johnson counter intrigued me, but, besides a basic knowledge of standard matrices, I have very little experience with this type of coding and hardware. Fundamentally, I am attempting to lower the number of I/O it takes to run a 3x11 keyboard matrix. Should I use a Johnson Counter, or are general shift registers the way to go?

  I would greatly appreciate any pointers or advice in this task, and apologise if my basic knowledge infuriates any of you experienced electronics engineers (I've had it before)!


Oct 29, 2014, 09:14 pm Last Edit: Oct 29, 2014, 09:15 pm by robtillaart
3x11 keys == 33 keys
so you could make a 6x6 matrix so you need 12 pins.

you could also use 2 shift registers (one in , one out) to have an 8x8 matrix . The shift registers use 6 pins (3 each) and maybe you can share some lines (never tried).

Other option is to use 2 PCF8574 (I2C) chips - 8IO each - using  only 2 lines.
- https://github.com/RobTillaart/Arduino/tree/master/libraries/PCF8574 -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


Thanks Rob,

  Would you be able to provide any code for scanning the columns and rows?



Oct 29, 2014, 10:39 pm Last Edit: Oct 29, 2014, 10:40 pm by marco_c
This implementation using 3 digital control lines and a 4017 may be of interest: http://forum.arduino.cc/index.php?topic=235438

As it it can give 100 switches, by adding in another 4017 you can get 1000 switches. Scan times will obviously grow.

I wrote a library to implement this and have some circuit examples in the my codeplex libraries site (below).
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com


Thanks, and great work on the library.

  This is a complete shot in the dark here, but is it possible to use a CD4049UBE here? I only ask because I do not have immediate access to new parts. Also, do the pins defined in the sketch refer to the pins on the CD4017?



  I would also appreciate greatly and code or hardware examples of using two of these in a matrix, perhaps to create a 4x11/12 keyboard if the capacity is there. I would also like to ask if I could use some 1N400 diodes as I have them on hand (sorry, but I have rarely used diodes so do not really understand the different types and functions).

Thanks again,


Oct 30, 2014, 10:14 pm Last Edit: Oct 30, 2014, 10:15 pm by marco_c
is it possible to use a CD4049UBE here?
No. The 4049 is a hex buffer and the 4017 is a decade counter. Different functions.

do the pins defined in the sketch refer to the pins on the CD4017
Pin numbers in the sketch are usually Arduino pin numbers.

use some 1N400 diodes
Just about any diode will do. The ones I used are really cheap, small general purpose signal diodes (which is why they are used a lot).

create a 4x11/12 keyboard
You can support up to 100 keys with 2 decade counters, so 4x11 or 4x12 can be done with 2 chips. You don't need 2 independent circuits unless you have a special need for it. From memory the circuits in the pdf articles with the library include examples you are looking for.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com


Oct 30, 2014, 10:30 pm Last Edit: Oct 30, 2014, 10:45 pm by PaulRB
Hi, you can handle up to 42 buttons with 7 Arduino outputs. No other chips required, just a diode attached to each switch.



Thank you both (and sorry for the beginner questions!),

  Paul, how will I implement this in code (and can it support multiple keypresses)? And Marco, sorry but I can't find the PDFs you mentioned.



Oct 31, 2014, 01:00 am Last Edit: Oct 31, 2014, 01:02 am by PaulRB
Hi Ben. Yes, my suggestion will detect any number of simultaneous key presses.

The code would set all 7 output pins to INPUT_PULLUP initially. Then for each of the 7 pins in turn, it would set that pin to OUTPUT & LOW. Then it would read the other 6 pins. The pin would then be set back to INPUT_PULLUP before moving on to the next pin and so on.


I really do appreciate the help you are giving me, but being fairly new (14 years old) to the complex programming of MCUs I have no idea how to go about implementing this in the arduino syntax. If you could offer any more help, or point me in the right direction, I would be very grateful indeed.


Oct 31, 2014, 07:35 am Last Edit: Oct 31, 2014, 08:02 am by PaulRB
No problem Ben.

Use the "Reference" link in the "Learning" menu at the top of this web page and look at the pinMode(), digitalRead() & digitalWrite() functions.


OK I will try this thanks,



I've made a start on the code, but I could use some help for a couple of things. Firstly, my line-by-line method of declaring and setting the variables is obviously very inefficient. I tried using a For loop but I couldn't get it to work. Secondly, I have no idea how to store and use the digitalRead variables. If you have any ideas then I would be very grateful.

Code: [Select]
int pin3 = 3;
int pin4 = 4;
int pin5 = 5;
int pin6 = 6;
int pin7 = 7;
int pin8 = 8;
int pin9 = 9;

void setup() {
  //Set all pins as INPUT_PULLUP
  pinMode(pin3, INPUT_PULLUP);
  pinMode(pin4, INPUT_PULLUP);
  pinMode(pin5, INPUT_PULLUP);
  pinMode(pin6, INPUT_PULLUP);
  pinMode(pin7, INPUT_PULLUP);
  pinMode(pin8, INPUT_PULLUP);
  pinMode(pin9, INPUT_PULLUP);

void loop() {
  // put your main code here, to run repeatedly:

void Scan() {
    pinMode(pin3, OUTPUT);
    digitalWrite(pin3, LOW);

Thanks again.


Oct 31, 2014, 05:37 pm Last Edit: Oct 31, 2014, 05:38 pm by PaulRB
Ben, there's not much point saying "int pin3 = 3". It doesn't really add any advantage or clarify anything!

Better to give them names that are more descriptive of what they will be used for, such as "keyboardPin1" to "keyboardPin7" or "keyboardPinA" to "keyboardPinF" like in my diagram.

You have chosen 7 Arduino pins that are adjacent to each other (3 to 9), so you could say:
Code: [Select]

int keyboardPin1 = 3;
int keyboardPin7 = 9;


for (int p = keyboardPin1, p <= keyboardPin7, p++) {
  pinMode(p, INPUT_PULLUP);

However, its is rare to have the luxury of being able to choose 7 adjacent pins! If for example you could only use pins 3 to 5, pins 8 to 10 and pin 12, you could not do the simple for loop like above. Instead, its more normal to put the pin numbers in an array. That way you can use any pins that are available and they don't have to be adjacent:

Code: [Select]

int keyboardPin[7] = {3, 4, 5, 8, 9, 10, 12};


for (int p = 0, p <= 7, p++) {
  pinMode(keyboardPin[p], INPUT_PULLUP);

Go Up