|
|
View previous topic :: View next topic |
Author |
Message |
jab351c
Joined: 27 Nov 2006 Posts: 9
|
keypad scan problem |
Posted: Mon Nov 27, 2006 3:33 pm |
|
|
I can not seem to get my 4x4 matrix keypad scan to work. I am not a very strong programmer but here is the modified code I was trying with no success at all. I am using the pic18F4620 and the keypad is hooked upto port D0-D7.
#include <18F4620.h> //Identify Microcontroller
#device adc=10 //Identify ADC Bit Width
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOMCLR //Setup Programmer Oscillator Value
//and make Master Clear Pin an
//Input Pin
#use delay(clock=4000000) //Setup C-Code Oscillator Value
#use fast_io(d) //Leave the State of Port-D (all bits)
//the same until changed, again
#use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7, stream=HT) //Set RS232 HperTerminal Communication Parameters
#use rs232(baud=2400, xmit=PIN_C5, rcv=PIN_C0, invert, stream=BB) //Set RS232 Board-to-Board Communication Parameters
#use I2C(master, SCL=PIN_C3, SDA=PIN_C4) //Set I2C Communication Parameters
#include <lcd_flex.c>
//=============================
//Keypad connection:
#define row0 PIN_D4
#define row1 PIN_D5
#define row2 PIN_D6
#define row3 PIN_D7
#define col0 PIN_D0
#define col1 PIN_D1
#define col2 PIN_D2
#define col3 PIN_D3
// Keypad layout:
char const KEYS[4][4] =
{{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
#define KBD_DEBOUNCE_FACTOR 33 // Set this number to apx n/333 where
// n is the number of times you expect
// to call kbd_getc each second
void kbd_init()
{
set_tris_d(0xF0);
output_d(0xF0);
port_b_pullups(true);
}
short int ALL_ROWS (void)
{
if(input (row0) & input (row1) & input (row2) & input (row3))
return (0);
else
return (1);
}
char kbd_getc()
{
static byte kbd_call_count;
static short int kbd_down;
static char last_key;
static byte col;
byte kchar;
byte row;
kchar='\0';
if(++kbd_call_count>KBD_DEBOUNCE_FACTOR)
{
switch (col)
{
case 0:
output_low(col0);
output_high(col1);
output_high(col2);
output_high(col3);
break;
case 1:
output_high(col0);
output_low(col1);
output_high(col2);
output_high(col3);
break;
case 2:
output_high(col0);
output_high(col1);
output_low(col2);
output_high(col3);
break;
case 3:
output_high(col0);
output_high(col1);
output_high(col2);
output_low(col3);
break;
}
if(kbd_down)
{
if(!ALL_ROWS())
{
kbd_down=false;
kchar=last_key;
last_key='\0';
}
}
else
{
if(ALL_ROWS())
{
if(!input (row0))
row=0;
else if(!input (row1))
row=1;
else if(!input (row2))
row=2;
else if(!input (row3))
row=3;
last_key =KEYS[row][col];
kbd_down = true;
}
else
{
++col;
if(col==4)
col=0;
}
}
kbd_call_count=0;
}
return(kchar);
}
//===========================
void main()
{
char k;
kbd_init();
lcd_putc(0x0c);
lcd_gotoxy(1,1);
printf(lcd_putc,"Starting ...");
while(TRUE)
{
k=kbd_getc();
if(k!=0)
{
if(k=='*')
printf(lcd_putc,"%c", '*');
else
printf(lcd_putc,"%c", k);
}
}
}
Any help is appreciated
thanks a lot,
Jeff |
|
|
Ttelmah Guest
|
|
Posted: Mon Nov 27, 2006 4:01 pm |
|
|
Without looking too far at the code, some little comments.
I notice in your 'init', you setup the tris on port D, (and your port defintions are on port D), yet you set the pullups on port B. On port D, you will need to use external pullup resistors to support a keyboard matrix. Port B is normally used, since it has built in programmable pullups. Suspicion here is you are trying to modify code that was written for port B. Have you added the resistors that will be needed to support operation on the other port?. I not, then this is the problem.
Second generic comment. As you are usng fixed I/O, you can save a lot of work, by using port I/O, rather than bit I/O in places. For instance, on the 'ALLRows' function:
Code: |
short int ALL_ROWS (void) {
if (input_d() & 0xF0) return (FALSE);
else return (TRUE);
}
|
Similarly the outputs can all be set by just using the portwide output to output a byte, rather than the four separate bitwise outputs.
Though the code is rather more complex than it needs to be, I'd suspect the hardware is the problem. Add pullup resistors if the are not present, and then see if it works.
Best Wishes |
|
|
jab351c
Joined: 27 Nov 2006 Posts: 9
|
|
Posted: Mon Nov 27, 2006 5:11 pm |
|
|
I do have external pull up resistors present on my board and I eliminated the pull up on port b. But my LCD is not clearing and is showing solid blocks for the characters in the entire first row. This is leading me to believe that there may be something wrong with the code involving my LCD. My LCD driver code is definitely correct though because displaying stuff on the LCD was not a problem before. Any more suggestions?
thanks
Jeff |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Nov 27, 2006 5:22 pm |
|
|
Did you get the driver from here ?
http://www.ccsinfo.com/forum/viewtopic.php?t=28022&start=14
That driver doesn't use fast i/o. It also doesn't use set_tris_x().
You've added those.
You should follow the driver code in the post above.
Don't make any changes to it, other than changing the pin list
at the top of the file to use pins on Port D.
Also, what port is your LCD connected to ? Don't try to run
the LCD on the same port as the keypad with these drivers.
They're not written to allow doing this. |
|
|
jab351c
Joined: 27 Nov 2006 Posts: 9
|
|
Posted: Mon Nov 27, 2006 7:09 pm |
|
|
PCM Programmer,
I have commented out the stuff that you mentioned. My LCD is on ports a and b. The driver file for my LCD works for other applications and can be seen here:
[
// flex_lcd.c
#define LCD_DB4 PIN_B0
#define LCD_DB5 PIN_B1
#define LCD_DB6 PIN_B2
#define LCD_DB7 PIN_B3
#define LCD_E PIN_A5
#define LCD_RS PIN_A4
//#define LCD_RW PIN_A2
// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.
//#define USE_LCD_RW 1
//========================================
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0xC0 // LCD RAM address for the 2nd line
int8 const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
0x0c, // Clear Display
0x14, // Increment cursor
0x0F // Blinking cursor
};
//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
output_bit(LCD_DB4, !!(nibble & 1));
output_bit(LCD_DB5, !!(nibble & 2));
output_bit(LCD_DB6, !!(nibble & 4));
output_bit(LCD_DB7, !!(nibble & 8));
delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}
//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.
#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3
retval = 0;
output_high(LCD_E);
delay_cycles(1);
retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
output_low(LCD_E);
return(retval);
}
#endif
//---------------------------------------
// Read a byte from the LCD and return it.
#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;
output_high(LCD_RW);
delay_cycles(1);
high = lcd_read_nibble();
low = lcd_read_nibble();
return( (high<<4>> 4);
lcd_send_nibble(n & 0xf);
}
//----------------------------
void lcd_init(void)
{
int8 i;
output_low(LCD_RS);
#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif
output_low(LCD_E);
delay_ms(15);
for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);
// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 60 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_LCD_RW
delay_ms(5);
#endif
}
}
//----------------------------
void lcd_gotoxy(int8 x, int8 y)
{
int8 address;
if(y != 1)
address = lcd_line_two;
else
address=0;
address += x-1;
lcd_send_byte(0, 0x80 | address);
}
//-----------------------------
void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1,2);
break;
case '\b':
lcd_send_byte(0,0x10);
break;
default:
lcd_send_byte(1,c);
break;
}
}
//------------------------------
#ifdef USE_LCD_RW
char lcd_getc(int8 x, int8 y)
{
char value;
lcd_gotoxy(x,y);
// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));
output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);
return(value);
}
#endif
]
Here is my actual source file after the changes and it still does not work. My LCD is not clearing so it may be a problem with that section of code. Your help is really appreciated.
[
#include <18F4620.h> //Identify Microcontroller
#device adc=10 //Identify ADC Bit Width
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOMCLR //Setup Programmer Oscillator Value
//and make Master Clear Pin an
//Input Pin
#use delay(clock=4000000) //Setup C-Code Oscillator Value
//#use fast_io(d) //Leave the State of Port-D (all bits)
//the same until changed, again
#use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7, stream=HT) //Set RS232 HperTerminal Communication Parameters
#use rs232(baud=2400, xmit=PIN_C5, rcv=PIN_C0, invert, stream=BB) //Set RS232 Board-to-Board Communication Parameters
#use I2C(master, SCL=PIN_C3, SDA=PIN_C4) //Set I2C Communication Parameters
#include <lcd_flex.c>
//=============================
//Keypad connection:
#define row0 PIN_D0
#define row1 PIN_D1
#define row2 PIN_D2
#define row3 PIN_D3
#define col0 PIN_D4
#define col1 PIN_D5
#define col2 PIN_D6
#define col3 PIN_D7
// Keypad layout:
char const KEYS[4][4] =
{{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
#define KBD_DEBOUNCE_FACTOR 33 // Set this number to apx n/333 where
// n is the number of times you expect
// to call kbd_getc each second
void kbd_init()
{
//set_tris_d(0xF0);
//output_d(0xF0);
//port_b_pullups(true);
}
short int ALL_ROWS (void)
{
if(input (row0) & input (row1) & input (row2) & input (row3))
return (0);
else
return (1);
}
char kbd_getc()
{
static byte kbd_call_count;
static short int kbd_down;
static char last_key;
static byte col;
byte kchar;
byte row;
kchar='\0';
if(++kbd_call_count>KBD_DEBOUNCE_FACTOR)
{
switch (col)
{
case 0:
output_low(col0);
output_high(col1);
output_high(col2);
output_high(col3);
break;
case 1:
output_high(col0);
output_low(col1);
output_high(col2);
output_high(col3);
break;
case 2:
output_high(col0);
output_high(col1);
output_low(col2);
output_high(col3);
break;
case 3:
output_high(col0);
output_high(col1);
output_high(col2);
output_low(col3);
break;
}
if(kbd_down)
{
if(!ALL_ROWS())
{
kbd_down=false;
kchar=last_key;
last_key='\0';
}
}
else
{
if(ALL_ROWS())
{
if(!input (row0))
row=0;
else if(!input (row1))
row=1;
else if(!input (row2))
row=2;
else if(!input (row3))
row=3;
last_key =KEYS[row][col];
kbd_down = true;
}
else
{
++col;
if(col==4)
col=0;
}
}
kbd_call_count=0;
}
return(kchar);
}
//===========================
void main()
{
char k;
kbd_init();
lcd_putc(0x0c);
lcd_gotoxy(1,1);
printf(lcd_putc,"Starting ...");
while(TRUE)
{
k=kbd_getc();
if(k!=0)
{
if(k=='*')
printf(lcd_putc,"%c", '*');
else
printf(lcd_putc,"%c", k);
}
}
}
]
thanks,
Jeff |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Nov 27, 2006 8:47 pm |
|
|
I don't think the posted program will work. You're missing a call to
the lcd_init() function at the start of main(). Add the line shown in
bold below:
Quote: |
void main()
{
char k;
kbd_init();
lcd_init()
lcd_putc(0x0c);
|
Quote: | I do have external pull up resistors present on my board |
Do you have the pullups on the Row pins ? That's where they should be.
You can use 4.7K or 10K resistors. You need one on each pin.
The other end of each resistor should connect to +5v. They should
be placed on the pins shown in bold below:
Quote: |
//Keypad connection:
#define row0 PIN_D4
#define row1 PIN_D5
#define row2 PIN_D6
#define row3 PIN_D7
|
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|