Sie sind auf Seite 1von 22

2x16 LCD And 4x4 Keypad Interfacing With 8051 in Assembly Language

Microcontrollers are just silicon wafers until we tell them what to do, program them according to our requirement. Similarly any user interface is incomplete without an Input. One, two pushbuttons can be easily interfaced however if more user inputs are required it can take up a lot of I/O lines. So here is a small tutorial to interface a 4x4 Matrix Keypad and displaying the key pressed on a LCD . The microcontroller used is AT89C51 and the coding has been done in assembly language. The 4x4 Keypad has 16 keys and requires a single PORT or 8 I/O lines. Port 3 has been designed to handle keypad, LCD Data Bus D7-D0 is connected to PORT 1, while (Enable) EN is connected to P2.0 (Register Select Command or Data Register) RS is connected to P2.1 (Read/Write) RW is connected to P2.2 The LCD is based on Hitachi HD44780 Controller and datasheet is present online. Working: To check for the keystroke, a polling method has been used.

PORT 3.0 Key 1 PORT3.1 Key 5 PORT3.2 Key 9 PORT3.3 Key 13 PORT3.4 Key 14 PORT3.5 Key 15 PORT3.6 Key 16 PORT3.7 Key 10 Key 11 Key 12 Key 6 Key 7 Key 8 Key 2 Key 3 Key 4

The connections are similar as shown over here. Now consider this, if I select the first column only, it has 4 keys, 1, 5,9,13. If a change of value (i.e. Binary 1 or 0) is made any one of these keys, it can be decoded and suitable message is displayed on the LCD. This is exactly what happens. Initially all the I/O lines are pulled high, then during Key Scan, every column linked is held low for a little time. If during that time a Key is pressed in that column a row I/O lines is also held low, thus the keystroke can be captured. The obvious question would be what if we press the key on a particular column and at that particular moment that column has not been pulled low, thus making no signal changes? The answer is simple, the microcontroller runs quite fast, even a convention 89c51 in which the internal frequency= external frequency clock/12 can achieve 2 MIPS at 24MHz. That is 2 Million instructions Per Second. This method is not foolproof, it has a drawback, while the Key Scan, It cannot perform other cumbersome operations which may take time and a Key Stroke could be missed. The program will work very well for small operations like activating a small relay or LED when a Key is pressed, but for people who want their systems to be near to perfect they may utilize other method.

Circuit Diagram:

Each I/O line on PORT 1 should be pulled high with 4.7K Resistors

Program: EN equ P2.0 RS equ P2.1 RW equ P2.2 mov A,#38H lcall command mov A,#0EH lcall command mov A,#06H lcall command mov a,#82H lcall command lcall disp mov a,#02H lcall command lcall delay1 ; Function Disp Called ; Setting DDRAM Address to Home position ; Entry Mode ; Display On ; Setting Up the LCD

; Displays BOTSKOOL SHOBHIT ON FIRST LINE OF LCD mov a,#'B' lcall datw NOP mov a,#'0' lcall datw

NOP mov a,#'T' lcall datw mov a,#'S' lcall datw NOP mov a,#'K' lcall datw NOP mov a,#'0' lcall datw NOP mov a,#'0' lcall datw NOP mov a,#'L' lcall datw NOP mov a,#' ' lcall datw NOP mov a,#'S' lcall datw NOP mov a,#'H' lcall datw

NOP mov a,#'O' lcall datw NOP mov a,#'B' lcall datw NOP mov a,#'H' lcall datw NOP mov a,#'I' lcall datw NOP mov a,#'T' lcall datw MOV A,#255 ; Moving Value 255 to PORT 3 MOV P3,A ; Keypad Scan Begins sd: lcall delay1 lcall key1 lcall delay lcall key2 lcall delay lcall key3 lcall delay

lcall key4 lcall delay lcall sd

; Function to Send Commands to LCD command: clr RW clr RS setB EN MOV P1,A lcall delay clr EN RET

; Function to Clear the DDRAM Content clear: mov A,#01H lcall command lcall delay mov A,#02H ; Set The DDRAM Address to Home Position lcall command lcall delay RET

; Function to Display Data on LCD Screen datw: SETB RS clr RW SETB EN MOV P1,A lcall delay clr EN RET

;Function to Display The Key Pressed datw1: lcall delay1 lcall disp lcall delay1 MOV A,R7 lcall datw RET

; Generating Small Delay delay: mov r0,#255 loop: DJNZ r0,loop; RET

; Generating a Bigger Delay

delay1: mov r1,#255 loop1: mov r3,#120 loop2: djnz r3,loop2 djnz r1,loop1 RET

; Checking for Key Press on The First Column of 4x4 Matrix

KEY1: MOV A,r5 MOV r6,A clr p3.4

MOV A,p3 ANL A,#0FH MOV r2,A cjne r2,#14,n1 MOV r7,#'1' lcall datw1 lcall delay1

n1: cjne r2,#13,n2 mov r7,#'5' lcall datw1 lcall delay1

n2: cjne r2,#11,n3 mov r7,#'9' lcall datw1 lcall delay1 n3: cjne r2,#7,n4 mov r7,#'D' lcall datw1 lcall delay1 n4: lcall delay1 SETB P3.4 RET

; Checking for Key Press on the Second Column of 4x4 Matrix KEY2: clr p3.5 MOV A,p3 ANL A,#0FH MOV r2,A

cjne r2,#14,q1 mov r7,#'2' lcall datw1 lcall delay1 q1: cjne r2,#13,q2 mov r7,#'6' lcall datw1

lcall delay1 q2: cjne r2,#11,q3 mov r7,#65; A=65 lcall datw1 lcall delay1 q3: cjne r2,#7,q4 mov r7,#'E' lcall datw1 lcall delay1 q4: lcall delay SETB p3.5 RET

; Checking for Key Press On The Third Column of 4x4 Matrix

KEY3: clr p3.6 MOV A,p3 ANL A,#0FH MOV r2,A

cjne r2,#14,w1 mov r7,#'3' lcall datw1 lcall delay1 w1: cjne r2,#13,w2

mov r7,#'7' lcall datw1 lcall delay1 w2: cjne r2,#11,w3 mov r7,#'B' lcall datw1 lcall delay1 w3: cjne r2,#7,w4 mov r7,#'F' lcall datw1 lcall delay1 w4: lcall delay1 SETB p3.6 RET

; Checking for Key Press on the Fourth Column of 4x4 Matrix KEY4: clr p3.7 MOV A,p3 ANL A,#0FH MOV r2,A cjne r2,#14,e1 mov r7,#'4' lcall datw1 lcall delay1 e1: cjne r2,#13,e2

mov r7,#'8' lcall datw1 lcall delay1 e2: cjne r2,#11,e3 mov r7,#'C' lcall datw1 lcall delay1 e3: cjne r2,#7,e4 mov r7,#'G' lcall datw1 lcall delay1 e4: lcall delay1 SETB p3.7 RET

disp: mov a,#0c0H lcall command ; Setting DDRAM Address on Second Line

; Clearing the Previous Key Pressed Information from Screen mov a,#' ' lcall datw mov a,#' ' lcall datw mov a,#' ' lcall datw

mov a,#' ' lcall datw mov a,#' ' lcall datw mov a,#' ' lcall datw

mov a,#0c0H lcall command

; Setting DDRAM Address on Second Line To Display Key Pressed

; Display "KEY" and Pressed Information mov a,#' ' lcall datw mov a,#'K' lcall datw mov a,#'E' lcall datw mov a,#'Y' lcall datw mov a,#' ' lcall datw RET END

The code was written when I was learning assembly language myself and therefore the code is not optimized, but it is easy to understand if someone is willing to check the instruction set. People who want to optimize the code may wish to look into the DPTR Register and Addressing Modes Theory.

A View of the Simulation

The 5-12V DC Input had to be removed in this diagram, because that cannot be accepted as the Power Source in the Simulation.

Programming in C: /* Calci.c calculator program for Mini51 The program simulates the calculator. The calculator supports basic operations like addition,multiplication and division. The calculator supports floating point arithmetic. */ #include <Intel\8052.h> #include <macros31.h> #include <stdio.h> #include <standard.h> #include "kbd.h" #include "lcd.h" /* global variables */ unsigned char operator ; float f1, f2, fr; #define #define MAX_COL_NUM MAX_ROW_NUM 15 2

#define #define #define

CR

0x0d

FORM_FEED 12 BACKSPACE 8

unsigned char g_byRow = 0 ; unsigned char g_byCol = 0 ; unsigned char putchar (unsigned char ch) { if (ch == CR) { // CR will move the current position back to first column // and next row (if available) // Press ENTER within SPJTerminal window to send CR g_byCol = 0 ; if (g_byRow < MAX_ROW_NUM) g_byRow ++ ; } else if (ch == FORM_FEED) { // FORM_FEED will clear the entire display // and move current position back to first row, first column // Press Ctrl.L within SPJTerminal window to send FORM_FEED lcd_cmd(0x80) ; for(ch = 0 ; ch < 16 ; ch ++) lcd_dat(' ') ; lcd_cmd(0xc0) ; for(ch = 0 ; ch < 16 ; ch ++) lcd_dat(' ') ; g_byRow = 0 ;

g_byCol = 0 ; ch = FORM_FEED ; } else if (ch == BACKSPACE) { if (g_byCol) { g_byCol -- ; if (g_byRow == 0) lcd_cmd(0x80 + g_byCol) ; else lcd_cmd(0xc0 + g_byCol) ; lcd_dat(' ') ; } } else { if (g_byRow == 0) lcd_cmd(0x80 + g_byCol) ; else lcd_cmd(0xc0 + g_byCol) ; lcd_dat(ch) ; g_byCol ++ ; if (g_byCol > MAX_COL_NUM) { g_byCol = 0 ; if (g_byRow < MAX_ROW_NUM) g_byRow ++ ; } }

return(ch) ; } unsigned char getchar () { while(!kbhit) {} kbhit = 0 ; return(scancode) ; } void main () { TH0 = 0xb1 ; // for interrupt every 10 ms (assuming P89C51RD2 @ 12 MHz) TL0 = 0xe0 ; TMOD = 0x21 ; TCON = 0x55 ; IE = 0x82 ; lcd_init() ; while(1) { putchar(FORM_FEED) ; printf("Num1> "); scanf("%f",&f1) ; port putchar(FORM_FEED) ; printf("Operator> ") ; scanf("%c",&operator); putchar(FORM_FEED) ; printf("Num2> ") ; scanf("%f",&f2) ; port putchar(FORM_FEED) ; // get the second number from serial // get the operator from the serial port // get the first number from serial // infinite loop // enable timer0 interrupt // t0 = 16 bit timer, t1 = 8 bit auto-reload timer

switch(operator) calculations { case case case case '+' '-' '*' '/' : : : :

// according to the operator do the

fr = f1 + f2 ; break ; fr = f1 - f2 ; break ; fr = f1 * f2 ; break ; fr = f1 / f2 ; break ;

default :

printf("Illegal operator") ;

// if none of the above operators are present then the // entered operator is an illegal operator } // end of switch // send the answer to the serial port // show 6 places after decimal point printf("\r= %.6f",fr) ; getchar() ; } }Bottom of Form // end of while

Das könnte Ihnen auch gefallen