Hello, everyone I need a little help with making a Keypad interface with a LCD (16x2) and a PIC16F88 or PIC16F84 (they have same layout). I want to implement a keypad but with a phone keypad function (see image below), also instead of # and * buttons, shift and DELETE. By phone keypad function I mean is that if "2 button" is pressed once a "2" is displayed; BUT when SHIFT is pressed and then press 2-button once an "a" is displayed and twice "b", three times a "c"...
I have most of the code finished, but i don't know how to add a SHIFT button (along with the function described) and the deleted button.
I have put the code and the simulation in a winrar file, along with a capture of the circuit.
MAIN
LCD CODE
KEYPAD CODE
I have most of the code finished, but i don't know how to add a SHIFT button (along with the function described) and the deleted button.
I have put the code and the simulation in a winrar file, along with a capture of the circuit.
MAIN
Code:
///THIS IS MAIN CODE
/*PIC16F88A interface to 3x4 Keypad and 16x2 LCD
*/
#include <16f88.h>
#fuses XT,NOLVP,NOWDT,NOPROTECT
#use delay(clock=4000000)
#include "flex_lcd.c"
#include <kbd.c>
void main()
{
char k=0; // El caracter k se guarda Character k to store keypad input
delay_ms(1);
/* Peripherals Configurations */
lcd_init(); // Turn LCD ON, along with other initialization commands
kbd_init(); // Initialize Keypad
lcd_gotoxy(1,1); // point LCD cursor to col1 row1
// lcd_putc(" "); // print on LCD
lcd_gotoxy(1,2); // point LCD cursor to col1 row2
//lcd_putc(" ");
while(1) // infinite loop
{
k = kbd_getc(); // read keypad input (if exists)
if(k!=0) // if key captured
{
lcd_putc(k); // print captured key to lcd
k=0; // reset k for another loop round
delay_ms(250); // delay between key presses
}
delay_ms(1); // delay_between read trials
}
}
LCD CODE
Code:
// flex_lcd.c
// Para los pines del LCD
#define LCD_DB4 PIN_A2
#define LCD_DB5 PIN_A3
#define LCD_DB6 PIN_A4
#define LCD_DB7 PIN_B0
#define LCD_E PIN_A1
#define LCD_RS PIN_A0
#define LCD_RW PIN_A1
// olny 6-pin interface on LCD, so[ATTACH]107114[/ATTACH] [ATTACH]107114[/ATTACH] [ATTACH]107116[/ATTACH] [ATTACH]107114[/ATTACH] [ATTACH]107116[/ATTACH]
// connect the R/W pin on the LCD to ground, and commented
// out the following line.
//#define USE_LCD_RW 1
//========================================
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // 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
0xc, // Display on
1, // Clear display
6 // Increment 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) | low);
}
#endif
//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);
#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif
if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);
delay_cycles(1);
#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif
output_low(LCD_E);
lcd_send_nibble(n >> 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
KEYPAD CODE
Code:
// Un-commented the following define to use port B
#define use_portb_kbd TRUE
// Maked sure the port used has pull-up resistors (or the LCD) on
// the column pins
#if defined use_portb_kbd
#byte kbd = getenv("SFR:PORTB")
#else
#byte kbd = getenv("SFR:PORTD")
#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:
#ifdef blue_keypad ///////////////////////////////////// For the blue keypad
#define COL0 (1 << 2)
#define COL1 (1 << 3)
#define COL2 (1 << 6)
#define ROW0 (1 << 4)
#define ROW1 (1 << 7)
#define ROW2 (1 << 1)
#define ROW3 (1 << 5)
#else ////////////////////////////////////////////////// For the black keypad
#define COL0 (1 << 5)
#define COL1 (1 << 6)
#define COL2 (1 << 7)
#define ROW0 (1 << 1)
#define ROW1 (1 << 2)
#define ROW2 (1 << 3)
#define ROW3 (1 << 4)
#endif
#define ALL_ROWS (ROW0|ROW1|ROW2|ROW3)
#define ALL_PINS (ALL_ROWS|COL0|COL1|COL2)
// Keypad layout:
char const KEYS[4][3] = {{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}};
#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 int1 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;
case 2 : set_tris_kbd(ALL_PINS&~COL2);
kbd=~COL2&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;
else if((kbd & ROW3)==0)
row=3;
last_key =KEYS[row][col];
kbd_down = TRUE;
} else {
++col;
if(col==3)
col=0;
}
}
kbd_call_count=0;
}
set_tris_kbd(ALL_PINS);
return(kchar);
}
Attachments
-
38 KB Views: 2
-
22.7 KB Views: 15
-
32.4 KB Views: 2