for Microchip PIC16F84 (without
LCD)
Introduction
Possible Applications
Concept
How it works
Specifications
Features
Limitations
AT Keyboard Theory
Keyboard Scan Codes
Keyboard to Host Protocol
Keyboard Commands
Host to Keyboard Protocol
Host Commands
Project Resources
Available PIC Assembler
Code
Schematic, Data Sheets, Pinout
User-specific Customization
Sometimes you only need a simple and cheap RS232 terminal to get sufficient control over a PC or a RS232 device. There is no need, no space or even no power to place a monitor, a computer case and a keyboard. Maybe there exists also the problem, that the PC or the device is located somewhere else and you want to interact with it over a short distance.
The cheapest way to obtain a complete user interface is the
use of standard components, such as LCD modules and PC keyboards.
A standard PC keyboard costs about US$12, a 2 lines by 40 characters
dot matrix LCD module around US$20.
To connect these items to the serial port by cable, a microcontroller
and a RS232 level shifter are necessary. For longer distance control,
there exists also the possibility to interconnect the terminal
with the other device by a wireless physical transmission layer.
The RS232 terminal for instance is very convenient in conjunction with a PC based Juke-Box playing MP3 files. You only need a command line programmable MP3 player (or a player with a supplied Active-X interface) and a software-based connection between player and RS232 port. This software 'connection' could be realized using Visual Basic and the often supplied Active-X interfaces of the various Windows based MP3 players.
Another possible area for applications is PC observed access control. Therefore, the RS232 terminal is placed at the entrance to the supervised area.
A further enhancement to be able to satisfy todays needs for
network-based communication would be a complete TCP/IP
based communication layer together with an Ethernet front-end.
Then it would be possible to control simple Ethernet appliances,
e.g. your coffee maker, electrical rolling shutters, autonomous
net-based lawn mower,... ;-) by this remote terminal. Brave new
world ...
The routine below contains no support for an LCD display. It only shows the complete fetch and decoding of AT keyboard scan patterns and RS232 transmission of ASCII characters to the RS232 client. If you want a PIC 16F84 based solution with additional LCD, have a look at the keyboard v2xx project.
The problem with the PIC 16F84 is the lack of RS232 hardware. The whole keyboard scan pattern fetch, decode and RS232 data transmission is done by software. Additional RS232 data reception has also to be carried out by software - based on interrupts - but is not implemented within this project. The current implementation features a preemptive interrupt-based keyboard scan pattern acquisition.
A picture of my workplace taken by my webcam.
Any key stroke on the local keyboard will send the corresponding
scan patterns from the keyboard to the PIC microcontroller. Afterwards,
the microcontroller converts the keyboard scan patterns to ASCII
characters and transmits them to the RS232 target device.
The keyboard scan code capture is done by an interrupt service
routine. The event, which triggers the interrupt is a falling
edge on the keyboard clock line (PORTB,0). Keyboard scan pattern
acquisition takes place at the keyboard data line (PORTA,4). After
11 clocks (i.e. 11 external interrupts on RB0/INT), the interrupt
service routine has completely captured an 8 bit element of the
entire scan pattern and sets a ready flag. The decoding of this
8 bit element is then carried out during normal operation mode,
activated by a valid ready flag whilst keeping the keyboard stalled
(keyboard clock line low).
The fact, that the scan pattern acquisition is carried out using an interrupt service routine and the decoding thereof is done during normal operation mode allows for performing other tasks concurrently: That's why I call the acquisition routine preemptive. It does not block the processor while acquiring data.
Only RS232 transmission is supported by this program, since PORTB,0 interrupt is already used by the keyboard clock line. There exists no possibility to implement also RS232 reception using my modules m_rsxxx.asm, because they require PORTB,0 as well and are laid out as non-preemptive data acquisition routines (see also 'Limitations').
For dedicated code adaptations, please refer to the section
'User-specific Customization'
below.
Processor: | Microchip PIC 16F84 |
Clock Frequency: | 4 MHz crystal |
Throughput: | 1 MIPS |
RS232 Baud Rate: | 9600 baud, 8 bit, no parity, 1 stopbit |
Code Size of entire Program: | 523 instruction words |
Keyboard Routine Features: | Capability of uni-directional communication between microcontroller and keyboard |
Acquisition Methodology: | Preemptive, interrupt-based keyboard scan pattern acquisition, decoding to ASCII characters during normal operation mode activated by ready flag |
Required Hardware: | AT keyboard, PS/2 connector, MAX232 |
Required Software: | RS232 terminal software (or Excel 97 RS232 Debug Interface) |
To visualize the ASCII data sent by this microcontroller application, use a terminal program like the Windows Hyperterminal. Below an example session, which proves the correct functionality of the keyboard interface. This terminal program and the Excel 97 RS232 Debug Interface have been used to debug the interface during implementation time.
Example of a session using the Windows HyperTerminal. The
entire contents was sent by the PIC controller.
In case you want RS232 reception and keyboard decoding simultaneously
on a single PIC 16X84, you'll have to configure either the keyboard
clock line or the RS232 reception data line (both targeting PORTB,0
interrupt) to another separate interrupt source (e.g. PORTB,4
- PORTB,7 change interrupt) and to alter the RS232 data fetch
routine to a preemptive one. But then you'll also run into troubles
by using the LCD modules, because they are written to work on
entire 8 bit ports (such as PORTB on 16X84, and PORTC & PORTD
on 16X74).
So if you really appreciate to run the RS232 terminal entirely
on a PIC 16X84 - from a technical perspective it is possible
- you'll have to rewrite the LCD modules and the software RS232
reception routine. Be aware that there won't be a lot of code
space remaining for other enhancements after putting all terminal
related stuff onto the 16X84.
A workaround to get RS232 reception on the PIC 16X84 using this software could be a solution based on polling. But make sure you are polling fast enough, also in worst case.
Important note from Jason Plumb: «Hey, First, lemme say that I like your site and thank you for providing excellent reference material for us home-hobbyist microcontroller geeks. I am currently working on a music/noise project that uses a PS/2 keyboard interfaced to a PIC16F84, and I used your page at http://www.electronic-engineering.ch/microchip/projects/keyboard/v1xx/keyboard_v1xx.html heavily as a reference when designing hardware and writing code. Anyway, I just thought that I would mention that I ran into a problem that I have since solved. The problem involved sending bytes *TO* the keyboard from the PIC (in order to light NumLock and ScrollLock). Your "Host To Keyboard Protocol" section indicates that the keyboard will take the data line low for a clock after the byte is sent to create an ACK bit. Apparently, the PS/2 keyboard that I have (generic $10 comp-USA brand) doesn't send an ACK bit, but rather sends a whole byte. If my code attempted to wait for the ACK bit, it hung indefinitely. I changed the wait to look for a byte (by calling my existing function) and everything worked perfectly. I stumbled on this idea by looking at other online references (most notably, some Linux kernel code at http://www.mscs.mu.edu/~georgec/Classes/207.1998/14Minix_book/S/src%20kernel%20keyboard.c.html#307). I have seen this ACK *byte* mentioned elsewhere too. I *think* the keyboard sends back 0xFA as an ACK byte, but I have not personally confirmed this. Perhaps your excellent documentation could just use a quick note of clarification so that other don't run into the same problem. Maybe something as simple as: "NOTE: Some keyboards send an ACK byte (value 0xFA) instead of an ACK bit.". Thanks again, |
Note from the author:
The comment above refers to bi-directional communication between PIC microcontroller and AT keyboard, i.e. to the source code of the AT Keyboard Interface V2.xx and higher versions. The bi-directional communication between host and keyboard is designed to support both Ack bits and Ack bytes.
A corresponding PIC assembler code example is shown below:
;*** switch keyboard LEDs on (default status) *** KBDcmd 0xED ; keyboard LEDs' control command KBDexp 0xFA ; expect keyboard acknowledge (FA) movfw KBDleds ; load keyboard LEDs' status KBDcmdw ; send keyboard LEDs' control data KBDexp 0xFA ; expect keyboard acknowledge (FA)
However, some AT keyboards may behave different and may need code adaptations to get bi-directional communication working properly.
A complete functional description and timing diagram of the
AT keyboard is available at Craig Peacock's website. Please refer
to his website Interfacing the PC's Keyboard for an excellent
and comprehensive description of all features and commands of
the AT keyboard. At this place, I want to thank Craig Peacock
for his outstanding work with his website.
Below I only want to sketch the most important technical aspects
to be known when interfacing a PC's keyboard. Small parts of the
introduction below are more or less copied from Craig Peacock's
tutorial.
The diagram below shows the scan codes assigned to the individual
keys for the english keyboard layout. The keys' corresponding
scan codes are the numbers on the keys, for example the scan code
of the ESC key is 0x76. All scan codes are shown in hexadecimal
representation.
The scan code assignments are quite random (thanks to IBM and
other early computer manufacturers) and appear to be really weird
sometimes, for instance the break key. In many cases the easiest
way to convert the scan code to ASCII characters would be to use
a lookup table. Below are the scan codes shown for the extended
part of the keyboard and the numeric keypad.
Cite of Craig Peacock: "How about E1,14,77,E1,F0,14,F0,77! Now that can't be a valid scan code? Wrong again. It happens to be sent when you press the pause/break key. Don't ask me why they have to make it so long! Maybe they were having a bad day or something?"
By the way, AT stands for Advanced Technology...
The AT keyboard sends different scan codes on pressing, holding and releasing of each button. An example is given at the table below:
Press & Hold Down Scan Code | Release Scan Code | |
Normal Scan Code | 73 | F0 73 |
Extended Scan Code | E0 4A | E0 F0 4A |
All scan patterns can easily be visualized and verified with the
AT Scan Code Debug Routine
and the RS232
Debug Interface.
The data transfer is implemented as bi-directional protocol: The keyboard can send data to the host (microcontroller) and the host can send commands and data to the keyboard. The host has the ultimate priority over the direction. It can at anytime (although not recommended) send a command to the keyboard.
The keyboard is free to send data to the host when both KBD data and KBD clock lines are high (idle). The serial clock is generated by the keyboard, but the host can also use it as a clear-to-send line: If the host takes the KBD clock line low, the keyboard will buffer any data until the KBD clock is released, i.e. goes high. Should the host take also the KBD data line low, then the keyboard will prepare to accept a command from the host.
The transmission of data in the forward direction, i.e. keyboard
to host, is done with a frame of 11 bits. The first bit is a start
bit (logic 0) followed by 8 data bits (LSB first), one parity
bit (odd parity) and a stop bit (logic 1). Each bit has to be
read on the falling edge of the clock.
AT keyboard to host protocol, with odd parity bit
Once the host commands are sent from
the host to the keyboard, the keyboard commands must be
sent from the keyboard to the host. If you think this way, you
must be correct. Below details of some of
the commands which the keyboard is able to send.
FA
Acknowledge
AA
Power on self test passed (BAT completed)
EE
See echo command (host commands)
FE
Resend - upon receipt of the resend command the host should re-transmit
the last byte sent.
00
Error or buffer overflow
FF
Error or buffer overflow
The host to keyboard protocol is initiated by taking the KBD
data line low. However to prevent the keyboard from sending data
at the same time that you attempt to send the keyboard data, it
is common to take the KBD clock line low for more than 60 us.
This is more than one bit length. Then the KBD data line is taken
low, while the KBD clock line is released. The keyboard will start
generating a clock signal on its KBD clock line. This process
can take up to 10 ms. After the first falling edge has been
detected, you can load the first data bit on the KBD data line.
This bit will be read into the keyboard on the next falling edge,
after which you can place the next bit of data. This process is
repeated for all 8 data bits. After the data bits comes an odd
parity bit.
Host to AT keyboard protocol, with odd parity bit and acknowledge
Odd parity = NOT(XOR(bits[0..7]))
Once the parity bit has been sent and the KBD data line is
in a idle state (high) for the next clock cycle, the keyboard
will acknowledge the reception of the new data. The keyboard does
this by taking the KBD data line low for the next clock transition.
If the KBD data line is not idle after the 10th bit (start, 8
data bits, and parity bit), the keyboard will continue to send
a KBD clock signal until the KBD data line becomes idle (Note: see also Limitations).
These commands are sent by the host to the keyboard. The most common command would be the setting/resetting of the status indicators (i.e. the Num lock, Caps Lock & Scroll Lock LEDs). The more common and useful commands are shown below.
ED
Set status LED's - This command can be used to turn on and off
the Num Lock, Caps Lock & Scroll Lock LED's. After sending
ED, keyboard will reply with ACK (FA) and wait for another byte
which determines their status. Bit 0 controls the Scroll Lock,
bit 1 the Num Lock and bit 2 the Caps lock. Bits 3 to 7 are ignored.
EE
Echo - upon sending an echo command to the keyboard, the keyboard
should reply with an echo (EE).
F0
Set scan code set. Upon sending F0, keyboard will reply with ACK
(FA) and wait for another byte, 01-03 which determines the scan
code used. Sending 00 as the second byte will return the scan
code set currently in use.
F3
Set typematic repeat rate. Keyboard will acknowledge command with
FA and wait for a second byte, which determines the typematic
repeat rate.
F4
Keyboard enable - clears the keyboard's output buffer, enables
keyboard scanning and returns an acknowledgment.
F5
Keyboard disable - resets the keyboard, disables keyboard scanning
and returns an acknowledgment.
FE
Resend - upon receipt of the re-send command, the keyboard will
re-transmit the last byte sent.
FF
Reset - resets the keyboard.
Please refer to Craig Peacock's website for more information:
Interfacing
the PC's Keyboard
Main File | Main Keyboard Decode Lookup Table | SHIFT Keyboard Decode Lookup Table | HEX Files |
Latest version: kbd_1xx.asm |
English 'codepage' (QWERTY) View: eng_main.html Download: eng_main.asm |
English 'codepage' (QWERTY) View: eng_shif.html Download: eng_shif.asm |
QWERTY 'codepage': QWERTZ 'codepage': |
Modified Swiss German 'codepage' (QWERTZ) View: ger_main.html Download: ger_main.asm |
Modified Swiss German 'codepage' (QWERTZ) View: ger_shif.html Download: ger_shif.asm |
||
The above programs need additional include files (modules) to get successfully assembled: m_bank.asm, m_wait.asm, m_rs096.asm | |||
For those, who are not familiar with interfacing a PIC to the RS232 using a MAX232: RS232-Interface.pdf (9.7 kB) |
AT Keyboard Specification (PDF, 189 kB)
The schematic of the AT keyboard interface using the PIC 16F84: Keyboard_V1xx.pdf.
You don't know how a dot matrix LCD is working? Have a look at my data sheets page.
Download ASCII Character Map: ASCII-Map.pdf
You can get the pinout and a description of the various keyboard
connectors <here>.
This section covers important details of the code structure. For a high level view, please refer to the section 'How it works' above.
Basically, I have written this keyboard project in such a way that it is completely customizable depending on your programming/PIC assembler skills. Have a look at some parts of the 'AT Keyboard Lookup Table', e.g. the QWERTY one:
goto _ALT | ; ALT (set/clear ALT flag) |
goto _SHIFT | ; SHIFT (set/clear SHIFT flag) |
retlw 0 | ; |
goto _CTRL | ; CTRL (set/clear CTRL flag) |
DT "q1" | ; DT: MPASM directive to create a table (retlw x) |
goto _CRLF | ; CR, LF 0x5A |
The simple lookup table decoding is done with retlw x and DT x. The more sophisticated decoding is done with subroutines, i.e. goto _XYZ. This means that for a ENTER/RETURN key hit on the keyboard, the subroutine _CRLF is executed (carriage return, line feed) and for ALT, CTRL, SHIFT and CAPS_LOCK, the corresponding flags are set. Because the keyboard sends slightly different scan patterns for both, key hit and key release, there is need for a key release handling. This is done with the so-called release flag. So for every single character typed, the interrupt service routine is called twice (due to two different scan codes for hit and release) and the scan pattern decoding routine is executed twice.
#define RELflag FLAGreg,0x00 | ; release flag (0xF0) |
#define SHIflag FLAGreg,0x01 | ; shift flag (0x12 / 0x59) |
#define SPEflag FLAGreg,0x02 | ; special code flag (0xE0) |
#define CAPflag FLAGreg,0x03 | ; caps lock flag (0x0D) |
#define ALTflag FLAGreg,0x04 | ; ALT flag (0x11) |
#define CTRLflag FLAGreg,0x05 | ; CTRL flag (0x14) |
#define KBDflag FLAGreg,0x06 | ; keyboard data reception flag |
There are these four main code blocks:
If you want to implement your application-specific handlers, e.g. for CTRL-X, you should focus on the fourth code block and on the look-up tables. To save code space, I've implemented the two look-up tables (main and shift) as follows:
If you apply changes to the existing code, you may need to change the ORG directives in order to realign the assembler code properly.
Last updated: 30.12.2004