MC68HC908GP32 (4x4 matrix keypad program)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MC68HC908GP32 (4x4 matrix keypad program)

7,886 Views
mauricio2346
Contributor II
Hi.   i need to do a little proyect using a 4x4 matrix keypad.   i was thinking use the KBI module, but i found the way to do it without using KBI.

here is the entire code.  i wish you check it and tell me what is wrong, and how i can return an integer value from this program???

#include <hidef.h>
#include <MC68HC908GP32.h>
#include "serial.h"
#include "TIMERAPI.h"
#include "lcddrv.h"


void Inicio_uC(void);   
char Muestreo_Columnas[4]={0x07,0x0B,0x0D,0x0E};
char i, Fila_Encontrada, Columna_Encontrada,Tecla_Presionada, Salir;

void Inicio_uC(void){
    CONFIG1_COPD=1;   
    EnableInterrupts;
      PTA = 0;           
      DDRA = 0x0F;//[PTA7..PTA4]como entradas.
  }

void main(void) {
Inicio_uC();
for(;:smileywink: {
PTA=0;  //Parte baja de PTA a cero.
Salir=0;
while((PTA>>4)!=0x0F && Salir==0){  //mientras haya un cero lógico en la parte alta de PTA.

    for(i=1;i<=4;i++){      //Muestreo de las columnas
        PTA=Muestreo_Columnas[i];  //vector de posiciones
        Delayus(500);             //espera 500 us
       
    if((PTA>>4)!=0x0F){
            Fila_Encontrada=(PTA>>4);
            Columna_Encontrada=Muestreo_Columnas[i];
            Salir=1;
        }
    }
}
Tecla_Presionada=Fila_Encontrada && Muestreo_Columnas;

}


Tecla_Presionada is the final variable, in were the key position data will be store.   
 Please, help me....









Labels (1)
0 Kudos
12 Replies

1,061 Views
mauricio2346
Contributor II
thanks for your intersting ideas.  if i'm understanding, the last array of the code, RowDecode has to store every 16 posible values of the keyboard numbers (equal hex. numbers of every key?????
16 posible row values (4 row value by row... jejej).  i tested the circuit and the program, and it work fine detecting any key, but when i try to press another key... nothing happens.
i.e. when i don't push any key, the code returns 0xFF (in my case, through a little message into LCD (not push.)  when i push a key, lcd shows a kind of chinese word, it doesn't a problem but when i push another key... that chinese symbol stays in LCD.
i think Temporal isn't changing every time, even if i change Codificar_Filas values.

Temporal = Codificar_Filas[Temporal >> 4] + i;

Grettings

Mauricio.

0 Kudos

1,061 Views
bigmac
Specialist III
Hello Mauricio,
 
To explain the array structure a little more clearly, let's label the keyboard rows from 0 to 3, and let's assume that the row with the lower number takes priority over higher numbered rows.  When a single column is scanned I will assume that the upper nybble of the PTA reading for a single keypress would be as follows -
 
           PTA    Array element Array value
Row 0  0b1110xxxx     14            0
Row 1  0b1101xxxx     13            4
Row 2  0b1011xxxx     11            8
Row 3  0b0111xxxx     7            12
 
If the keys in Row 0 and Row 1 were to be simultaneously pressed, the PTA reading would become 0b1100xxxx.  This means that array element 12 (the decimal nybble value) should contain the value 0, for Row 0 precedence.  Every multiple keypress situation needs to be entered in the array, in a similar fashion.  Array element 15 (the last element) will not normally be accessed, but should contain the value 0xFF.
 
With the above values in the array, the return value from the keyscan() function should be within the decimal range 0 to 15, when a key is pressed.  The returned value should then be used to derive the information you wish to display on the LCD, perhaps a specific text message.  As a simple test, you could try adding 0x41 to the value, before sending directly to the display.
 
It is not clear whether you are releasing the first key before pressing the second key - the second keypress won't be detected unless the first key is first released.  This is because the Salir variable should contain a non-zero value up until all keys are released, and scanning will not occur unless Salir contains zero.
 
Regards,
Mac
 
0 Kudos

1,061 Views
mauricio2346
Contributor II
Hi Mac.
i did everything you suggest in your last post.  i tested everything with that program, i checked it but it doesn't work.  y came back to the previous programs, i rewrite it and it worked, but as you said, it can detect a key even if another one is pressed.  when all keys are released, with that program, PTA values changes everytime.  what you suggest to prevent this program to read a key with another key pressed??
thanks!

program:

#include<MC68HC908GP32.h>
#include "TIMERAPI.h"



byte Muestreo_Filas[4]={0x07,0x0B,0x0D,0x0E};
byte Salir;

void Key_Init(void);
byte Escanear_Teclado(void);


void Key_Init(void){
    PTAPUE =0xF0;   //Entrada de datos con Pull-Up interno
    DDRA   =0x0F;   //Configura entradas [A7...A4] y salidas [A3...A0].
    PTA    =0;      //Todas las salidas del puerto PTA a 0
}


byte Escanear_Teclado(void){
    byte i, Tecla_Pulsada, Fila, Columna;
    Key_Init();
   
if (Salir == 0) {
for (i=0;i<4;i++) {
    PTA = Muestreo_Filas[i];
    Delayus(200);               
        if ((PTA >> 4) != 0x0F) {
        Delayms(20);
        Columna=PTA;
        Fila=Muestreo_Filas[i];
        Tecla_Pulsada=Columna|Fila;
        i=4;
        return Tecla_Pulsada;
        }
        else{
        Salir=0;
        }
    }
}
}
   
   
0 Kudos

1,061 Views
bigmac
Specialist III
Hello Mauricio,
 
You do not describe the manner in which the suggested code failed, or what you observed when you tested the code.
 
Your new function  Escanear_Teclado() differs from the previous keyscan() function in two key areas -
  1. You have eliminated the test to determined whether any key is pressed, and hence the determination that all keys are released.
  2. You do not control the Salir variable to prevent multiple entry to the scanning process, once a keypress has been decoded. 
However, to a more important issue . . .
 
I have just realized that all the code posted so far has the potential to damage the MCU and/or the keypad.  This is because the columns that are not being scanned, during each cycle of the scanning process, are driven to a high output state.  The single column that is being scanned is driven to a low output state.  If two (or more) keys, within the same row, are pressed, this will result in a short circuit between two differing output states, with excessive current flow.  This may damage the MCU, and if a membrane keypad type is used, might also damage the keypad.
 
Two solutions to this problem are possible, a harware solution and a firmware solution -
 
The hardware solution is to place a series schottky diode between each MCU output and its associated keypad column connection.
 
The preferred solution is the firmware solution.  This requires that the non-scanned columns are never driven high.  This is achieved by the following code changes -
  1. All bits of the keypad port are set low, and remain so at all times, i.e. PTA = 0;
  2. Pullups are enabled on all bits of the port, i.e. PTAPUE = 0xFF;
  3. When a column is to be scanned, its corresponding DDR bit is set for output.  However, when not scanned the DDR bit must be cleared.  This will require change to the Muestreo_Filas array, and the way it is used.
Changes to the previously suggested code are shown below.
 
/* Global variables */
byte Salir = 0;
byte Tecla_Presionada;
 
const byte Muestreo_Columnas[4] = {0x08, 0x04, 0x02, 0x01};
const byte RowDecode[16] = {
...
};
 
byte keyscan(void)
{
   byte temp, i;
 
   PTA = 0;
   PTAPUE = 0xFF;  /* Enable all pullups */
 
   /* Check for any key pressed */
   DDRA = 0x0F;
   if (((PTA >> 4) != 0x0F) {
      /* Check if keypress previously decoded */
      if (Salir == 0)) {
         Debounce();  /* Key debounce delay */
         /* Commence scan for actual keypress */
         for (i = 0; i < 4; i++) {
            DDRA = Muestreo_Columnas[i];
            Delayus(500);                // Settling delay 500 us
            temp = PTA;
            if ((temp >> 4) != 0x0F) {
               DDRA = 0x0F;
               Salir = 1;  /* Flag successful decode */
               temp = RowDecode[temp >> 4] + i;
               return temp;  /* Return keypress value 0-15 */
            }
         }
      }
   }
   else
      Salir = 0;  /* All keys released */
 
   DDRA = 0x0F;
   return 0xFF;
}
 
Regards,
Mac
 
0 Kudos

1,061 Views
mauricio2346
Contributor II
Hi.   no . fortunately, y used between uC and keypad some series resistors. i never trust only in the internal resistors. anyway;
 
the way i knew when the program was working as it should, was trough a LCD.  the lcd controler support some simbols.   with both programs, i store the value of the key into a function that send data to LCD.  so, with my last program, the LCD shown a kind of japanese or chinese symbol (diferent for every key).  with your program, the LCD shown only one strange symbol, even pressing any key. 
y ckeck some of the programs you have posted and i was thinking about reset PTA after a key was pushed.  maybe it was the problem, but i correct it and nothing happens.  i think the last corrections you did are fine. i will test them.
the basic algorith and some examples i choose were taken from this website:

http://www.x-robotics.com/rutinas.htm#Teclado%20Matricial%204x4 (maybe you need some help with spanish.... jeje.
)

and from this site:

http://www.rentron.com/serkey16.htm

there it says the steps you have to follow to control it.  i read it and simplify it, trying to use only one function to control everything, detect the key, find the key and return a valid data from every single key.

thanks a lot for your help...
Mauricio!

0 Kudos

1,061 Views
PeterHouse
Contributor I
Mauricio,

I have been lurking on this topic as Bigmac has been very helpful.  I have one more thing for you to think about.

Continously scanning the columns generates a lot of electrical noise!  You can reduce this a lot if you do the following:  While you are in idle mode waiting for a keypress, Drive all the column lines high and then monitor the rows to see if they go high - when they do, you can then start your scan and do one scan to determine which key is pressed - then you put all the columns high again and wait for the rows to all go low - the key has been released - Start Over.  This way, you only scan the columns when a key is pressed and only scan once per key press.  You may have to slightly modify your hardware to make sure inputs are pulled down and you have propper current limiting.  Contact me off topic and I could send you a schematic I have used.

I have used this on several projects and it works very well and helps keep the FCC and your AM radio a lot happier.

Good Luck,

Peter House
0 Kudos

1,061 Views
bigmac
Specialist III
Hello Peter,
 
What you have suggested is exactly the intent of my posted code, except that the active logic state is low, rather than high.  This is more in keeping with use of the internal pullups within the device.
 
Regards,
Mac
 
0 Kudos

1,061 Views
PeterHouse
Contributor I
Bigmac,

If you like it "Upside Down" that is OK with me. :smileyhappy:

Peter
0 Kudos

1,061 Views
peg
Senior Contributor IV
Hi all,
 
The method suggested here by Peter is, in fact, the method used by the code I suggested to look at in my first post in this thread. It works well and is the method I (and most others) use also.
 
0 Kudos

1,061 Views
bigmac
Specialist III
Hello,
 
It seems there are a couple fundamental errors in your code -
  1. You have defined a 4-element array for the table Muestreo_Columnas.  In C, the first element of an array has an index of 0, and the fourth element an index of 3.  As the code stands, the first element would never be used and you attempt to read a non-existent fifth element.  You might alter the limits of the for-loop to correct this.
  2. I have a problem with the final line of code
    Tecla_Presionada = Fila_Encontrada && Muestreo_Columnas;
    The logical and does not make sense.  However, even if a bitwise and is used instead, this will still not produce a unique result for each of the 16 keys.  I think the row value and the column value should be in different nybbles, and then combined with a bit-wise OR.
There are also some other issues like allowing a key de-bounce period once a keypress is detected, and immediately exiting the for-loop once a keypress is decoded.
 
The 500 microsecond delay is insufficient for key de-bounce purposes - a period of 50 milliseconds would be more typical, and this should timeout before entering the for-loop where each column is scanned.  The existing delay will allow for settling time during scanning, and could probably be considerably less than 500us.
 
I have attempted to correct some of these issues in the following code -
 
void main(void) {
  Inicio_uC();
  for( ; ; ) {
    PTA = 0;  // Parte baja de PTA a cero.
    Salir = 0;
    while (((PTA >> 4) != 0x0F) && (Salir == 0)) {

      /* Keypress detected - key debounce delay here */
 
      for (i = 0; i < 4; i++) {      // Muestreo de las columnas
        PTA = Muestreo_Columnas[i];  // vector de posiciones
        Delayus(500);                // espera 500 us
       
        if ((PTA >> 4) != 0x0F) {
          Fila_Encontrada = PTA & 0xF0;
          Columna_Encontrada = Muestreo_Columnas[i];
          Salir = 1;
          i = 4;  /* Terminate for-loop */
        }
      }
      Tecla_Presionada = Fila_Encontrada | Muestreo_Columnas;
 
      /* Additional code required for keypress action */
 
    }

    /* Wait for no key pressed before allowing loop back to Salir = 0; */
 
  }
}
 
Note that Salir should remain set to 1 until it is established that no key is pressed, to avoid multiple decodes for the same keypress.  It might also be a good idea to replace the while with an if since only a single decode is required.
 
Regards,
Mac
0 Kudos

1,061 Views
mauricio2346
Contributor II
Yeah Mac, you were right.  i will make the changes  (some stupid mistakes jeje).   maybe you were wondering why i'm trying to decode a matrix keyboard without KBI module, the answer is that in the final aplication, i will use a MC68HC908JK3 (it doesn't have PORT A-KBI module).  anyway....
i tried to change the index (3 instead 4) of the array Muestreo_Columnas as you suggest me  but when i compile the program it shows an error that says:
Error: C4801: Too many initializers.
Error: Compile failed.
with mi original array's index (4) the compile results are diferent.

the code is simple but there is a line that i can't understand:

Fila_Encontrada = PTA & 0xF0;

what is the purpose to "add" 0xF0 to PTA value?

Thanks a Lot!!
Mauricio
0 Kudos

1,061 Views
peg
Senior Contributor IV
Hi Mauricio,
 
Take a look at the thermostat example in this book:
 
 
It is for HC05 and is in assembler, but is good for getting the basic concept of how to do this.
It has a debounced 4x4 matrix keypad that uses a lookup table to convert keypresses into the character on the key.
 
This manual is also a very good "how to get started with microcontrollers" book for anyone starting out.
 
A more up to date version of this sort of thing is sadly lacking from Freescales current documentation.
 
0 Kudos