Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

keypad help...

Status
Not open for further replies.

jrz126

Active Member
Hey gang,
I'm trying to interface a 4x4 keypad to a 16f877A and Im having some problems. I'm familar with the scanning routine and whatnot, I'm just having difficulty reading in the pins.

I have pins B4-B7 connected as my outputs, and pins B0-B3 as my inputs, which have pullup resistors as well.

I dont know how to read in just the lower half of port B, I have my code set up like this:
Code:
   set_tris_b(0x0F);   //upper half is output

   output_bit( PIN_B7, 0);
   output_bit( PIN_B6, 0);
   output_bit( PIN_B5, 0);
   output_bit( PIN_B4, 0); 
   while(1)
   {
   row=input_b();
   printf("row %i\n\r",row);
   delay_ms(1100);
   }

does that look ok?
 
You use AND to mask off the bits you don't need, in assembler the command would be 'ANDLW 0x0F' - I'm presuming your code is C?, as it has curly brackets.
 
You either AND the lower half like Nigel suggested (with a binary value of 00001111) or read your compiler's documentation to find the ready-made function(s) to access individual bits.

What compiler are you using?
 
jrz126 said:
Hey gang,
I'm trying to interface a 4x4 keypad to a 16f877A and Im having some problems. I'm familar with the scanning routine and whatnot, I'm just having difficulty reading in the pins.

I have pins B4-B7 connected as my outputs, and pins B0-B3 as my inputs, which have pullup resistors as well.

You need to read one row at a time. To read a row you set one column bit to zero. In your case the column bits are bits 4 to 7 of port b.

Something like this should work. (I'm guessing at the syntax.)

Code:
    for (i = 0; i<=3; i++) {
      output_b = ~(16<<i);
      Row = input_b && 15;
      printf("row %i\n\r",row);
    }

The second line sets 1 bit at a time to zero.
The third line reads port b and discards the top bits.

The value in Row is inverted - the bit is cleared if the key is pressed.

HTH

Mike.
 
I tried anding the lower half, but it would cause the micro to freeze after printing 1 value.

We're using the CCS-PIC compiler in my microcontrollers class. This is a 'side project' though.

I'm going to have some freetime to work on it this afternoon.

EDIT:
I was able to play with it some more, it turns out that the compiler will read the entire port even if it is masked, I'm able to just read in each pin individually.
here's the routine I came up with...(if anyone feels like making it alittle simpler, feel free...)
Code:
#include <16F877.h>
#use delay(clock=10000000) //External clock 10MHz
#fuses HS, NOWDT //High speed, no watchdog timer
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#include <stdio.h>

int read_columns();
void main()
{
int column;


 set_tris_b(0x0F);
 output_bit( PIN_B7, 0);
 output_bit( PIN_B6, 0);
 output_bit( PIN_B5, 0);
 output_bit( PIN_B4, 0);
 printf("test\n\r");
   while(1)      
   {
   column=read_columns();
 
  output_bit( PIN_B7, 1);
   if(column!=read_columns())
   {
   printf("row 1 col %i\n\r",column);
   } 
   output_bit( PIN_B7, 0);
  output_bit( PIN_B6, 1);
   if(column!=read_columns())
   {
   printf("row 2 col %i\n\r",column);
   }  
  output_bit( PIN_B6, 0);
  output_bit( PIN_B5, 1);
    if(column!=read_columns())
   {
   printf("row 3 col %i\n\r",column);
   }   
  output_bit( PIN_B5, 0);
  output_bit( PIN_B4, 1);
     if(column!=read_columns())
   {
   printf("row 4 col %i\n\r",column);
   } 
  
  output_bit( PIN_B4, 0);
  

   delay_ms(500);

   }

}

int read_columns()
{
int colcom=0;
    if (input(PIN_B3)==0) //col1
      colcom=1;
    if (input(PIN_B2)==0) //col2
      colcom=2;  
    if (input(PIN_B1)==0) //col3
      colcom=3;
    if (input(PIN_B0)==0) //col1
      colcom=4;
  // printf("colcom %i\n\r",colcom);
  return colcom;
}
 
jrz126 said:
it turns out that the compiler will read the entire port even if it is masked

It will do, even in assembler, you read the entire port, then mask off the bits you don't require, it's a VERY common, standard, technique - and is all that's possible in most processors.
 
You still have your bits the wrong way round. Because you have pullup resistors, you have to put a zero on the row that you wish to read and a one on all others. Your code should read:-

Code:
 set_tris_b(0x0F); 
 output_bit( PIN_B7, 1); 
 output_bit( PIN_B6, 1); 
 output_bit( PIN_B5, 1); 
 output_bit( PIN_B4, 1); 
 printf("test\n\r"); 
   while(1)      
   { 
   column=read_columns(); 
  
  output_bit( PIN_B7, 0); 
   if(column!=read_columns()) 
   { 
   printf("row 1 col %i\n\r",column); 
   } 
   output_bit( PIN_B7, 1); 
  output_bit( PIN_B6, 0); 
   if(column!=read_columns()) 
   { 
   printf("row 2 col %i\n\r",column); 
   }  
ETC

As for simplification, you could simply write the bits in one go.
I.E.



Code:
void main() 
{ 
 set_tris_b(0x0F); 
   while(1)      
   {
  output_b = 0x7f; // = 01111111 in binary 
   if(read_columns()!=0) 
   { 
   printf("row 1 col %i\n\r",column); 
   } 
  output_b = 0xbf; // = 10111111 in binary 
   if(read_columns()!=0) 
   { 
   printf("row 1 col %i\n\r",column); 
   } 
  output_b = 0xdf; // = 11011111 in binary 
   if(read_columns()!=0) 
   { 
   printf("row 1 col %i\n\r",column); 
   } 
  output_b = 0xef; // = 11101111 in binary 
   if(read_columns()!=0) 
   { 
   printf("row 1 col %i\n\r",column); 
   } 

ETC
I'm assuming that output_b will write to port b.

HTH

Mike.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top