PS2 Keyboard Interface with PIC16F877A

In this project, an interface between a PS2 keyboard and PIC16F877A is implemented. The main goal of this project is to use a computer keyboard with any instrument without needing a computer. keyboards are basically connected via either USB or PS2. In this project, PS2 Keyboard is interfaced with PIC16F877A. PS2 connector has 6-pin Mini-DIN connector used to connect keyboard to a PC compatible computer system. these 6-pins are:

  • Data

  • Clock

  • +Vcc

  • GND

  • The other two pins are not used.

The first 4 pins are the necessary pins needed to perform a valid communication between the keyboard and the MCU. +Vcc and GND must connected to a 7805 voltage regulator, and the Data and clock lines should be connected to the MCU.


The data and clock waveform are shown in Fig.(1). The first waveform represents the clock signal and the second one represents the data.  As can be noticed, there is a data bit at every falling edge. By using the capture function in PIC MC, we can get the ASCII code of each key and display it on the character LCD.

// Author: Abdullah M. Zyarah

#include <16f877a.h>
#use     delay(clock=20MHZ)
#include <LCD420-d.c>
#fuses   hs,nowdt,nocpd,nolvp,noprotect

#byte intcon=0x0b                  // to turn off the interrupt flag
#byte portb=0x06
#byte portd=0x08                   // for data display
#bit  ex_int_f=intcon.1            // external interrupt flag bit
#bit  data_line=portb.1            // data line is RB1

short  data;                       // a variable to store the incoming data
char   j=0,x=1,m=0,letter=0;

/* The interrupt routine has the following:
1- a variable (j) to count the number of input bits (11 bits)
at the press, and 22 bits at the press+release, so the total will be 33bit.
2- a variable (letter) to hold the required data bit, "ASCII of letters".
3- a variable (m) to count the number of data bits in letter.

void clock_int()
    if(j==33)                // number of the sent data bits (press11+release(11+11)
    j=0;                     // clear to receive a data from new button
    if((j>=2)&&(j<=9))        // extract the data (start bit (1)+data bits(8)+party and stop(2))
        if(x==data)            // making a mask, and save it in a letter
                case 0x1C:

                case 0x1B:
                case 0x23:

                case 0x2B:

                case 0x34:

                case 0x33:

                case 0x3B:

                case 0x42:

                case 0x4B:

                case 0x4C:

                case 0x15:

                case 0x1D:

                case 0x24:

                case 0x2D:

                case 0x2C:

                case 0x35:

                case 0x3C:

                case 0x43:

                case 0x44:

                case 0x4D:

                case 0x54:
                case 0x5B:

                case 0x16:

                case 0x1E:

                case 0x26:

                case 0x25:

                case 0x2E:

                case 0x36:

                case 0x3D:

                case 0x3E:

                case 0x46:

                case 0x45:

                case 0x1A:

                case 0x22:

                case 0x21:

                case 0x2A:

                case 0x32:

                case 0x31:

                case 0x3A:

                case 0x49:

                case 0x4A:

                case 0x66:

                case 0x5A:

                case 0x29:
                lcd_putc(" ");


void main()
    ext_int_edge(H_To_L);            // interrupt on high to low event
    enable_interrupts(int_ext);        // enable the external interrupt