View previous topic :: View next topic |
Author |
Message |
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
Keypad and LCD |
Posted: Fri Feb 08, 2008 6:42 pm |
|
|
Please could someone help me with the kbd.c, lcd.c and lcdkb drivers.
I have read numerous posts about this subject but still cannot get the keyboard to scan/work.
Prerequisites:
PIC18F4525
2x3 bespoke keypad (2 cols, 3 rows)
using picdem 2 plus
tried with and without 10k pull ups on the rows - (because of the weak pull ups). None on the columns.
The LCD works fine and displays with other programs.
my main code is:
Code: | #include <18F4525>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#include lcd.c //this is in the correct brackets but just doesn't show
#include kbd.c //this is in the correct brackets but just doesn't show
void main() {
char k;
port_b_pullups(TRUE);
kbd_init();
lcd_init();
lcd_putc("\fReady...\n");
while (TRUE) {
k=kbd_getc();
if(k!='0')
if(k=='1')
lcd_putc("\1\n");
if(k=='2')
lcd_putc("\2\n");
if(k=='3')
lcd_putc("\3\n");
if(k=='4')
lcd_putc("\4\n");
if(k=='5')
lcd_putc("\5\n");
if(k=='6')
lcd_putc("\6\n");
}
}
|
My kbd.c code has been changed for the following pin configs:
Code: | #define row0 PIN_B5
#define row1 PIN_B6
#define row2 PIN_B7
#define col0 PIN_B3
#define col1 PIN_B4
#define ALL_ROWS (ROW0|ROW1|ROW2)
#define ALL_PINS (ALL_ROWS|COL0|COL1)
// Keypad layout:
char const KEYS[3][2] =
{{'1','2'},
{'3','4'},
{'5','6'}}; |
The full kbd.c is:
Code: | // Un-comment the following define to use port B
#define use_portb_kbd (TRUE)
// Make sure the port used has pull-up resistors (or the LCD) on
// the column pins
#if defined(__PCH__)
#if defined use_portb_kbd
#byte kbd = 0xF81 // This puts the entire structure
#else
#byte kbd = 0xF83 // This puts the entire structure
#endif
#else
#if defined use_portb_kbd
#byte kbd = 6 // on to port B (at address 6)
#else
#byte kbd = 8 // on to port D (at address 8)
#endif
#endif
#if defined use_portb_kbd
#define set_tris_kbd(x) set_tris_b(x)
#else
#define set_tris_kbd(x) set_tris_d(x)
#endif
//Keypad connection: (for example column 0 is B2)
// Bx:
//Keypad connection:
#define row0 PIN_B5
#define row1 PIN_B6
#define row2 PIN_B7
#define col0 PIN_B3
#define col1 PIN_B4
#define ALL_ROWS (ROW0|ROW1|ROW2)
#define ALL_PINS (ALL_ROWS|COL0|COL1)
// Keypad layout:
char const KEYS[3][2] =
{{'1','2'},
{'3','4'},
{'5','6'}};
#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() {
}
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 : set_tris_kbd(ALL_PINS&~COL0);
kbd=~COL0&ALL_PINS;
break;
case 1 : set_tris_kbd(ALL_PINS&~COL1);
kbd=~COL1&ALL_PINS;
break;
}
if(kbd_down) {
if((kbd & (ALL_ROWS))==(ALL_ROWS)) {
kbd_down=FALSE;
kchar=last_key;
last_key='\0';
}
} else {
if((kbd & (ALL_ROWS))!=(ALL_ROWS)) {
if((kbd & ROW0)==0)
row=0;
else if((kbd & ROW1)==0)
row=1;
else if((kbd & ROW2)==0)
row=2;
last_key =KEYS[row][col];
kbd_down = TRUE;
} else {
++col;
if(col==2)
col=0;
}
}
kbd_call_count=0;
}
set_tris_kbd(ALL_PINS);
return(kchar);
} |
It compiles fine and just displays ready on the LCD. Testing with a meter I cannot see any voltage change on the column pins - as it cycles through to detect a buttton press.
Any help would be upmost appreciated as this is really annoying me now.
Carl |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Feb 08, 2008 7:29 pm |
|
|
Quote: | while (TRUE) {
k=kbd_getc();
if(k != '0')
if(k=='1')
lcd_putc("\1\n");
if(k=='2')
lcd_putc("\2\n");
if(k=='3')
lcd_putc("\3\n");
if(k=='4')
lcd_putc("\4\n");
if(k=='5')
lcd_putc("\5\n");
if(k=='6')
lcd_putc("\6\n");
}
}
|
In the code above, you are testing k against a value of '0'. What's the
hex value of a zero inside single-quotes ? Look at the CCS sample
program, ex_lcdkb.c. It's also doing a test of the k variable. What
value is it testing k against ? What should be done to fix that line in
your code ?
Also, you're testing k in an if() statement. Then you want to do six
other tests, provided that k is non-zero. You are missing a pair
of braces.
Then finally, you are sending chars to the lcd in the six if() statements.
But all the chars have a slash in front of them. What does a slash do
to the value of a char ? What type of value is the LCD expecting, and
what are you actually sending to it ? |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Feb 09, 2008 2:45 am |
|
|
Thankyou for your assistance - much appreciated. I will go through all the points you have mentioned and reply back. |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Feb 09, 2008 7:16 am |
|
|
changed the '0' to just 0 but made no difference so i thought i would just copy the lcdkb file with changes as shown:
#include <18F4525>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#include <lcd.c>
#include <kbd.c>
void main() {
char k;
port_b_pullups(TRUE);
lcd_init();
kbd_init();
lcd_putc("\fReady...\n");
while (TRUE) {
k=kbd_getc();
if(k!=0)
if(k=='*')
lcd_putc('\f');
else
lcd_putc(k);
}
}
It still didn't do anything apart from display Ready...
Can you explain what this means if(k=='*') - I cant find an explanation anywhere. Do I need to change it?
Because I'm using the weak pull_ups do I still need the 10k Pull ups on the rows?
Also when I plug in the IDC, the screen does not clear - even if I press erase target device. this is strange though, because every other program I have done, as soon as I plug in the IDC the LCD lights up every pixel like it should do?
It always compiles and I have made changes in all the three programs(lcd.c, kbd.c and lckbd.c) just to force a compile error and it does.
It cant be a problem with the LCD.
Maybe I have the keypad wrong? When I power down the PICDEM2 plus and then power up I measured the voltage on the column lines and they go from 0V to 5V when all six buttons are pressed and released . The voltage on the rows stays at 5V regardless because of the pullups.
When I program it and measure the voltages they are different.
Thankyou for any assistance you can give on this would be very much appreciated. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Feb 09, 2008 12:38 pm |
|
|
Code: |
if(k=='*')
lcd_putc('\f');
|
If the star key (asterisk) is pressed, the PIC will send '\f' to the lcd.
To find the meaning of the lcd commands, look at the comments at
the start of the LCD.c file. Here is the directory for that file:
Quote: | c:\Program Files\Picc\Drivers\lcd.c |
Also:
Post the manufacturer and part number of the keypad. Post a link
to the web page for the keypad. If you don't know that information
because the keypad came already installed on a development board,
then post the manufacturer, part number, and web page of the board. |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Feb 09, 2008 1:05 pm |
|
|
I have made a keypad by rewiring two individual 1x3 pads.
Part Number: MCAK103BSSSWPMM
It is a bank of three pushbuttons (times 2=6 buttons in total) soldered together in the conventional way:
Keypad1 Keypad2
row1 (wired to) row1 >B6 via 10k pullup
row2 (wired to) row2 >B7 via 10k pullup
row3 (wired to) row3 >B8 via 10k pullup
Col0 (not wired to Col1) >B4 No resistor
(not wired to Col0) Col1 >B5 No resistor
Therefore I do not have a '*'
I understand that the '*' is on normal keypads and when pressed it will display the next command as you have shown. obviously this can be used with all the other pads on the keypad like '1', '2' etc. I have tried these different pad variables but it still doesn't work. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Feb 09, 2008 4:07 pm |
|
|
I already had the datasheet.
Sorry I should have said. Its the fact that its not working is the problem.
I would be extremely grateful if you could help me tomorrow.
Thanks for your help
Carl |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 10, 2008 2:52 pm |
|
|
Quote: |
#define row0 PIN_B5
#define row1 PIN_B6
#define row2 PIN_B7
#define col0 PIN_B3
#define col1 PIN_B4
Keypad1 Keypad2
row1 (wired to) row1 >B6 via 10k pullup
row2 (wired to) row2 >B7 via 10k pullup
row3 (wired to) row3 >B8 via 10k pullup
Col0 (not wired to Col1) >B4 No resistor
(not wired to Col0) Col1 >B5 No resistor |
I'm starting to work on this, and I noticed an inconsistency.
You have two different sets of definitions in your posts shown above.
There are different pin numbers in each set. Also, the 2nd set
refers to a pin B8, which doesn't exist on an 18F4525.
Can you post a revised list of the wire connections between
the two keypads and the PIC ?
The keypad data sheet shows that the pinout is as follows:
Code: |
Row1 Row2 Row3 Column
o o o o |
This is with the keypad oriented as shown in the photo on the data sheet. |
|
|
Guest
|
|
Posted: Mon Feb 11, 2008 1:30 pm |
|
|
sorry i have miss-typed. the original is correct as code:
#define row0 PIN_B5
#define row1 PIN_B6
#define row2 PIN_B7
#define col0 PIN_B3
#define col1 PIN_B4 |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Mon Feb 11, 2008 1:35 pm |
|
|
so the way I have it set up is code:
Keypad1 Keypad2
row0(wired to) row0 >B5 via 10k pullup
row1 (wired to) row1 >B6 via 10k pullup
row2 (wired to) row2 >B7via 10k pullup
Col0 (not wired to Col1) >B3 No resistor
(not wired to Col0) Col1 >B4 No resistor |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Mon Feb 11, 2008 4:50 pm |
|
|
PROBLEM SOLVED.
it was the code in the end I did not have it configured correctly. Here is the code I use with LCD.C, KBD.C and LCDKB.C.
I am using this code with the PICDEM2 PLUS Board (v2002)
So LCD.C:
Code:
Code: | // As defined in the following structure the pin connection is as follows:
// D0 D8
// D1 D9
// D2 D10
// D3 D11
// D4 RS
// D5 RW
// D6 E
// LCD pins D4-D7 are not used
#use delay (clock=4000000)
// This structure is overlayed onto the data ports so that you may use
// whatever ports you desire
struct lcd_pin_map
{
boolean dummy; // PinA0 is not used
boolean enable; // PinA1
boolean rw; // PinA2
boolean rs; // PinA3
int unusedA : 4; // The rest of portA
int unusedB; // portB is not used
int unusedC; // portC is not used
int data : 4; // lower nibble of portD is used for data lines
int unusedD : 4; // The rest of portD
} lcd;
#if defined(__PCH__)
#locate lcd = 0xF80
#else
#locate lcd = 5
#endif
struct lcd_tris_map
{
boolean dummy; // PinA0 is not used
int control : 3;
int unusedA : 4; // The rest of portA
int unusedB; // portB is not used
int unusedC; // portC is not used
int data : 4; // lower nibble of portD is used for data lines
int unusedD : 4; // The rest of portD
} lcdtris;
#if defined(__PCH__)
#locate lcdtris = 0xF92
#else
#locate lcdtris = 0x85
#endif
#define set_tris_lcd(x) lcdtris.data = (x); lcdtris.control = 0;
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
// These bytes need to be sent to the LCD
// to start it up.
// The following are used for setting
// the I/O port direction register.
#define LCD_WRITE 0 // For write mode all pins are out
#define LCD_READ 15 // For read mode data pins are in
//--------------- Start of code ---------------------------------
byte lcd_read_byte() {
byte low,high;
set_tris_lcd(LCD_READ);
lcd.rw = 1;
delay_cycles(1);
lcd.enable = 1;
delay_cycles(1);
high = lcd.data;
lcd.enable = 0;
delay_cycles(1);
lcd.enable = 1;
delay_us(1);
low = lcd.data;
lcd.enable = 0;
set_tris_lcd(LCD_WRITE);
return( (high<<4>> 4);
lcd_send_nibble(n & 0xf);
}
void lcd_init() {
byte i;
set_tris_lcd(LCD_WRITE);
lcd.rs = 0;
lcd.rw = 0;
lcd.enable = 0;
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_nibble(3);
delay_ms(5);
}
lcd_send_nibble(2);
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
}
void lcd_gotoxy( byte x, byte y) {
byte 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); break;
case '\n' : lcd_gotoxy(1,2); break;
case '\b' : lcd_send_byte(0,0x10); break;
default : lcd_send_byte(1,c); break;
}
}
char lcd_getc( byte x, byte y) {
char value;
lcd_gotoxy(x,y);
lcd.rs=1;
value = lcd_read_byte();
lcd.rs=0;
return(value);
} |
KBD.c:
Code:
Code: | //Keypad connection:
#define row0 PIN_B5
#define row1 PIN_B6
#define row2 PIN_B7
#define col0 PIN_B3
#define col1 PIN_B4
// Keypad layout:
char const KEYS[3][2] =
{{'1','2'},
{'3','4'},
{'5','6'}};
#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_b(0xF0);
//output_b(0xF0);
port_b_pullups(true);
}
short int ALL_ROWS (void)
{
if(input (row0) & input (row1) & input (row2))
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);
break;
case 1:
output_high(col0);
output_low(col1);
break;
case 2:
output_high(col0);
output_high(col1);
break;
case 3:
output_low(col0);
output_low(col1);
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;
last_key =KEYS[row][col];
kbd_down = true;
}
else
{
++col;
if(col==2)
col=0;
}
}
kbd_call_count=0;
}
return(kchar);
} |
LCBKD.C:
Code:
Code: | #include <18F4525.h>
#include
#include
#fuses EC_IO,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
void main() {
char k;
port_b_pullups(TRUE);
lcd_init();
kbd_init();
lcd_putc("\fReady...\n");
while (TRUE) {
k=kbd_getc();
if(k!=0)
if(k=='1')
lcd_putc('\f');
else
lcd_putc(k);
}
} |
It all works fully -and I am very happy. THankyou for your assistance PCM Programmer. |
|
|
|