Go Down

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


Thanks that's a great way to do it (and I used the simple variable names just to make them easy to use, but I guess adding a more descriptive name could help later on). Do you have any ideas about the code for scanning, as I can visualize it being extremely long without using some form of loop to 'automate' (like in your array) the code?

  Thanks for your continued help!


To read the entire keyboard you will need a for-loop within a for-loop. The outer loop will make the pins OUTPUT & LOW in turn. The inner loop will read the remaining pins (ignoring the pin that is currently an output). Then the outer loop will change the output pin back to input again.

As this is going on, the code will also need to keep track of which pin is being read (1..33 or 1..42 whatever) and also detect when a button has just been pressed, as opposed to having been pressed for some time. In other words, is it pressed now but was not pressed last time it was checked.


Oct 31, 2014, 08:05 pm Last Edit: Oct 31, 2014, 08:08 pm by marco_c
sorry but I can't find the PDFs you mentioned.
They should be in the doc subfolder of the library folder for MD_4017_KM. Links to the original articles:
Article 1
Article 2

I think that if you have not done I/O scanning for keypresses before you are better off learning how to do it with many I/O pins before you try and take the minimalist approach. Once you understand what the Arduino is doing with the 6-7 I/O pins, then understanding how the other circuit works will be easier.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com


 I have improved and added to the code, thanks to your suggestions, but have a few questions. Firstly, in the two if statements I have utilised, the else sections are empty, and I was wondering if I need a GOTO to break out of the for loops (they are commented in the code). Also, I'm not sure how to set the value of the keys and how the code will recognise these; maybe a 2D array? The code is as follows:

Code: [Select]

int keyboardPin[7] = {0, 1, 6, 7, 8, 9, 10}; //Using tx
//and rx as programming with ISP

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

void loop(){
void scan(){
    for (int p = 0; p <= 7; p++){//Set as output and low
      pinMode(keyboardPin[p], OUTPUT);
      digitalWrite(keyboardPin[p], LOW);
      int low = p; //Set the output pin to use later
       for (int p = 0; p <= 7; p++){//Read all other pins
         if (p != low){//Check if p is the same as the low variable
           int readPin = digitalRead(keyboardPin[p]);
             if (readPin == LOW){ //If pin is low
               //How do I know which pin this is? I.E. 33, 41
               //Should I multiply the low variable by keyboardPin[p]?
               //Do nothing? GOTO statement to break out?
            //Do nothing? GOTO statement to break out?
       }//Second for loop
    }//First for loop



Are you really programming via isp and using pins 0 and 1, or did you copy that code from somwhere? If the latter, don't use pins 0 and 1. They are used to upload the sketch and are generally only used by experts and then only as a last resort.

You are using the variable name "p" for both for loops, forcing you to copy the outer loop's value for use in the inner loop. Why not simply give the inner loop variable a different name, eg. "q"?

I don't think any action is required for either of your "else" clauses, so just omit them.

You mentioned earlier that you wanted to detect multiple key presses, so its important to complete the loops and not jump out ("GOTO"? shame on you!)

A 2D array would be a good way to map your two loop variables to a character.

The other thing you may need to think about (I mentioned earlier) is detecting when a key changes from not being pressed to being pressed. Another 2D array would be usefull here, to hold the previous HIGH/LOW status of each button.

Finally, what to do when you find a button has just been pressed? You could just set a variable to the character detected, and process it after the loop. The chances of two keys changing from not pressed to pressed on the same scan are low. But if you find that's not the case, you will need to make a small buffer.


Nov 06, 2014, 03:00 pm Last Edit: Nov 06, 2014, 03:12 pm by PaulRB
Ben, you asked for some hints on how to use 2D arrays as I suggested.

One array could hold the character for each key. It could be declared like this:

Code: [Select]

char kbMap[7][7] = { {'_','Q','W','E','R','T','Y'}, {'U','_','I','O','P','?','?'},
                              {'A','S','_','D','F','G','H'}, {'J','K','L','_','?','?','?'}
                              .... etc ....

Note each group group of 7 characters has a '_' within it at the position where p and q indexes are equal, and there is no corresponding switch in the matrix. I have put '?' where I don't know what character you want to have on your keyboard at that location.

You would then access that character like this:

Code: [Select]

char keypressed = kbMap[p][q];



  Thanks you very much Paul I think I have finally 'cracked the code' for basic functionality in the keyboard, but their is on final thing: is there any way to have a backspace key without having to implement screen memory on the LCD, or is that asking too much?

Thanks again,


Ben, I don't understand the question. Describe in a bit more detail? What kind of lcd, just a 16x2 or 20x4 character? Buffering those would take very little memory.

I assume the typed and if neccessary edited text gets sent somwhere once completed by the user... so won't you need to buffer the text in memory anyway?



is there any way to have a backspace key without having to implement screen memory on the LCD, or is that asking too much?
The essence of "backspace" is to remove the previous character, and to move the cursor one to the left - unless it is on the margin.  The sequence to do this on a VDU is to send the backspace control code which actually only moves the cursor back, a space which then over-writes the character previously present, and a further backspace to re-position the cursor over the wiped character.

If you are in control of the display itself which means you should really know the cursor location at any given time, then you perform much the same operation - set the cursor to one position to the left (unless it is on the margin already), write a blank to that location, and if in doing so you moved the cursor position, set it back again.

Go Up