Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] 3x4 Keypad with PIC 16F1937 problem

Status
Not open for further replies.

lordgarth6

Newbie level 4
Newbie level 4
Joined
Apr 25, 2012
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Visit site
Activity points
1,332
i cant seem to get this keypad to work with a pic 16F1937 on portD using any code that isnt made by 'flowcode' software package or are test routines

http://www.matrixmultimedia.com/resources/files/datasheets/EB014-30-1.pdf for data sheet on my keypad that is an 'E-block' module and how it is wired


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 3x4 Keypad with PIC 16F1937 in MikroC
#include"7_seg_Lib.h"
 
const char Column[5]={0x10,0x20,0x40,0x80};
 
void main() {
char Keypad=255,x=0;
TRISB=0x00;   // 7 seg output setup
PORTB=0xFF;   // 7 seg initial output
TRISD=0xF0;   // keypad i/o setup  b0-3 input b4-7 output
PORTD=0x00;  // keypad  initial output
  while(1)
  { 
   Delay_ms(100);
      
   for(x=0;x<4;x++){   // loop
      PORTD=Column[x]; // change column output
      if(PORTD.B0==1){  // if column 1 is high
        if(PORTD.B4==1) Keypad=1; // if row 1 is high
        else if(PORTD.B5==1) Keypad=4;        // if row 2 is high
        else if(PORTD.B6==1) Keypad=7;      // if row 3 is high
        else Keypad=0x2A;            // *   default
      }
      else if(PORTD.B1==1){  // if column 2 is high
        if(PORTD.B4==1) Keypad=2; // if row 1 is high
        else if(PORTD.B5==1) Keypad=5;       // if row 2 is high 
        else if(PORTD.B6==1) Keypad=8;      // if row 3 is high
        else Keypad=0;  // default
      }
      else if(PORTD.B2==1){  // if column 3 is high
        if(PORTD.B4==1) Keypad=2;  // if row 1 is high
        else if(PORTD.B5==1) Keypad=6;    // if row 2 is high   
        else if(PORTD.B6==1) Keypad=9;  // if row 3 is high      
        else Keypad=0x23;            // #   default
      }
     else Keypad=255; // default value
    }
    if(Keypad==255) Keypad='G';  // to test if it was my 7 seg code rthat was wrong
    PORTB=output_seg('a',4,Keypad); // output to 7 seg
    }
}

 

You have PORTD directions reversed. A '1' in the TRISD register makes it an input and '0' makes it an output. Your code is trying to write to the inputs and read from the outputs instead of the other way around.

The code itself is very ineffiicent because all the lines are executed every time it loops.

Brian.
 

am i still getting mixed up here? if so that explains why this still won't work. thanks for the help :) iv got this code working on a PIC 16f877a so why wont it on the PIC 16F1937


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* 3x4 Keypad with PIC 16F1937 in MikroC */
#include"7_seg_Lib.h"
const char Column[5]={0x01,0x02,0x04,0x08};
 
void main() {
char Keypad=255,x=0;
TRISB=0x00;           /* 7 seg output setup */ 
PORTB=0xff;           /* 7 seg initial output */
TRISD=0xF0;           /* keypad i/o setup  b0-3 OUT b4-7 IN */
PORTD=0x00;           /* keypad  initial output */
  while(1)            
  { 
   Delay_ms(100);
      
   for(x=0;x<4;x++){  /* loop  for all column*/
      PORTD=Column[x];   /* change column output */
      if(PORTD.B0==1){   /* if column 1 is high */
        if(PORTD.B4==1){ Keypad=1;         break;}    /* if row 1 is high */
        else if(PORTD.B5==1){ Keypad=4;    break;}    /* if row 2 is high */
        else if(PORTD.B6==1){ Keypad=7;    break;}    /* if row 3 is high */
        else if(PORTD.B7==1){ Keypad='S';  break;}    /* s for * [*=0x2A] */ 
      }
      Delay_ms(10);
      if(PORTD.B1==1){  /* if column 2 is high */
        if(PORTD.B4==1){ Keypad=2;         break;}  /* if row 1 is high */
        else if(PORTD.B5==1){ Keypad=5;    break;}  /* if row 2 is high */ 
        else if(PORTD.B6==1){ Keypad=8;    break;}  /* if row 3 is high */
        else if(PORTD.B7==1){ Keypad=0;    break;}  /* if row 4 is high */
      }
      Delay_ms(10);
      if(PORTD.B2==1){   /* if column 3 is high */
        if(PORTD.B4==1){ Keypad=3;         break;}  /* if row 1 is high */
        else if(PORTD.B5==1){ Keypad=6;    break;}  /* if row 2 is high */ 
        else if(PORTD.B6==1){ Keypad=9;    break;}  /* if row 3 is high */
        else if(PORTD.B7==1){ Keypad='H';  break;}  /* h for # [#=0x23] */
      }
      else Keypad=255;      /* Default */
    }                                   
    if(Keypad==255) Keypad='G'; 
    PORTB=output_seg('a',1,Keypad);
    }
}

 
Last edited:

The code looks like it should work on both devices so the problem is almost certainly to do with some missing configuration in the 16F1937. I do not have a data sheet here to check but look at the functions of the pins and make sure you have them in digital mode and any internal peripherals on PORTD are disabled.

Note that your code is still rather inefficient because it has to use a look-up table to find the signal to drive the columns. The table look up has to take place four times in each pass of the loop and the compiler has to generate code (and possibly use temporary variables) to do this. If instead you hard code the drive signals it only takes two machine instructions, one to reset the previous bit and one to set the new one.

Brian.
 
ok cheers, i'll look for things to disable on portD of this chip. [https://ww1.microchip.com/downloads/en/DeviceDoc/41364E.pdf] i cant seem to find all the stuff that i should disable :(
Is their some general rules that i should follow to make any future code more efficient, or some link to where i could learn such things. Also is their any rules for general good coding practice.
thanks for your help
 
Last edited:

I think the best way to learn efficient coding, at least in control programs, is to study assembly language. It gives good insight as to how compilers work. For example in your program, the line "PORTD=Column[x];" makes the compiler build code to calculate the table offset from variable X then do a look-up, possibly switching banks and almost certainly using 'hidden' variables as well. If you coded as "PORTD.B0 = 0; PORTD.B1 = 1;" it would produce only two instructions "bcf PORTD,0" and "bsf PORTD,1" which would run faster and use far les memory.

There are no rules about how you do it but understanding assembly language will reveal the most efficient algoriths for simple operations. When it comes to high level math routines, the assembly language becomes difficult to follow so it's better to just assume the C routines work as the manual states.

Brian.
 
ok i will look into assembly a lot more than what i have done in the past. also managed to get the code working with a few minor glitches, found out that the pins on the port im using are default analogue so i changed that. thank you very much for ur help brian.
 

The high level like C langauge cann't access PC counter , So Assembly langauge is prefer to pre setup, I think so.

Why you donn't use 74C922 encoder chip to link between 3x4 keypads and The PIC CHIP .

Port scan like in PC Computer is make loosing time because Ex. we can gennerate table for change to the other langauge in the next time in memory of Microcontroller . Againts the patent of the encoder !!!!!!!!!!!!!!
 

My data sheet for the 74C922 is 21 years old and I'm sure it was available before then, it is now an old and obsolete device.

If you want to reduce the time lost to scanning the keypad, arrange it so that in it's idle (waiting for a key to be pressed state) it sets all the column drives high and use the 'interrupt on change' facility on the PIC to detect when ANY key has been pressed. In the interrupt routine, do a normal scan to find out which key it was then go back to the idle state again. If that isn't possible due to hardware constraints, wire a diode to each of the inputs from the keypad so they form a simple OR gate and use that signal to trigger an external interrupt.

Brian.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top