Interfacing Keyboard, LEDs, and Seven-Segment Displays
Building Real Input/Output Hardware
Open interactive version (quiz + challenge)Real-world analogy
What is it?
This lesson covers the practical interfacing of common I/O devices to the 8086 through the 8255 PPI: matrix keyboard scanning (row-by-row with debouncing), LED driving (direct port output with running light patterns), seven-segment display encoding (lookup tables mapping digits to segment patterns), and multiplexed multi-digit displays (time-division scanning that creates the illusion of simultaneous display).
Real-world relevance
Every calculator, microwave oven, elevator panel, and gas pump uses these exact techniques. The seven-segment display in your alarm clock uses multiplexing — only one digit is actually lit at any instant, switching thousands of times per second. ATM keypads use matrix scanning identical to what we implement here. These are among the most universally used interfacing patterns in all of electronics.
Key points
- Matrix Keyboard Scanning — A matrix keyboard arranges switches in rows and columns. A 4x4 matrix gives 16 keys using only 8 lines (4 rows + 4 columns) instead of 16 separate wires. To scan: drive one row LOW at a time, then read all columns. If a column reads LOW, the key at that row-column intersection is pressed. This row-by-row scanning happens so fast that it catches every keypress.
- Key Debouncing — Mechanical switches bounce — when pressed, the contact rapidly opens and closes for a few milliseconds before settling. Without debouncing, one press might register as 2-5 presses. Software debouncing adds a short delay (10-20ms) after detecting a press, then re-checks. If the key is still pressed, it is a valid press. This simple technique eliminates false triggers.
- LED Driving via 8255 — LEDs are the simplest output device. Connect each LED (with a current-limiting resistor, typically 330 ohm) to an 8255 output port pin. Writing a 1 to a bit turns that LED ON; writing 0 turns it OFF. With 8 bits on Port A, you can control 8 LEDs independently. Patterns like running lights, binary counters, or status indicators are easy to implement.
- Seven-Segment Display Basics — A seven-segment display has 7 LED segments (a-g) plus a decimal point (dp), arranged to form digits 0-9 and some letters. Each segment is controlled by one bit. For common-cathode displays, HIGH lights a segment. For common-anode, LOW lights it. A lookup table maps each digit (0-9) to the corresponding 7-bit pattern.
- Driving a Single Seven-Segment Display — Connect the 7 segments (a-g) to 7 output pins of an 8255 port. To display a digit, look up its bit pattern in a table and write it to the port. The lookup table is stored in memory as an array of bytes. The digit value (0-9) is used as an index to fetch the correct pattern.
- Multiplexed Multi-Digit Display — To display multiple digits (e.g., 4 digits) without using 4 separate ports, we use multiplexing. Only one digit is ON at any time, but we switch between digits so fast (>100 Hz per digit) that persistence of vision makes them all appear lit simultaneously. One port sends the segment data, another port selects which digit is active.
- Complete Keyboard-to-Display System — The ultimate interfacing exercise: scan a keyboard for input, decode the key, look up the seven-segment pattern, and display it. Port B reads the keyboard matrix, Port A drives the display. The main loop continuously scans keys and updates the display, creating a responsive interactive system entirely driven by the 8255.
- Current Limiting and Hardware Considerations — Each LED segment draws about 10-20mA. The 8255 output pins can source/sink limited current (typically 2.5mA). For real hardware, you need buffer drivers (like 74LS245) between the 8255 and the LEDs, or use transistor switches for each digit in multiplexed mode. Current-limiting resistors (220-330 ohm) prevent LED burnout. Always calculate the total current budget before building.
Code example
; =============================================
; Keyboard → 7-Segment Display System
; =============================================
;
; 8255 at base 80h
; Port A (80h) = 7-segment output
; Port B (81h) = 4x4 keyboard (rows out, cols in)
; Control (83h)
;
; Configure 8255:
MOV AL, 82h ; PA=out, PB=in, Mode 0
OUT 83h, AL
;
; Segment lookup table:
SEG_TBL DB 3Fh,06h,5Bh,4Fh,66h,6Dh,7Dh,07h,7Fh,6Fh
; 0 1 2 3 4 5 6 7 8 9
;
MAIN:
; --- Scan keyboard ---
MOV AL, 0FEh ; row 0 active (LOW)
OUT 81h, AL
NOP ; settling time
IN AL, 81h ; read columns
AND AL, 0F0h
CMP AL, 0F0h
JNE GOT_KEY_R0 ; key in row 0
;
MOV AL, 0FDh ; row 1
OUT 81h, AL
NOP
IN AL, 81h
AND AL, 0F0h
CMP AL, 0F0h
JNE GOT_KEY_R1 ; key in row 1
;
JMP MAIN ; no key, rescan
;
GOT_KEY_R0:
; Decode column and map to digit 0-3
; (column detection logic here)
MOV BL, 0 ; example: key = 0
JMP DISPLAY_IT
;
GOT_KEY_R1:
MOV BL, 4 ; example: key = 4
;
DISPLAY_IT:
; Debounce: wait 20ms
MOV CX, 5000
DBNC: LOOP DBNC
;
; Lookup segment pattern
LEA SI, SEG_TBL
MOV BH, 0
MOV AL, [SI+BX] ; get pattern for digit
OUT 80h, AL ; display on 7-segment
JMP MAIN ; back to scanningLine-by-line walkthrough
- 1. Title comment for the keyboard-to-display system
- 2. Separator line
- 3. Blank line
- 4. System description: 8255 base address 80h
- 5. Port A at 80h drives the seven-segment display (output)
- 6. Port B at 81h reads the 4x4 keyboard matrix (input)
- 7. Control register at 83h
- 8. Blank line
- 9. Configure 8255: control word 82h means PA=output, PB=input, Mode 0
- 10. Write the control word to initialize the 8255
- 11. Blank line
- 12. Segment lookup table: 10 bytes mapping digits 0-9 to segment patterns
- 13. Comment showing which byte corresponds to which digit
- 14. Blank line
- 15. MAIN label: start of keyboard scanning loop
- 16. Load 0FEh (11111110) to drive row 0 LOW
- 17. Output to Port B to activate row 0
- 18. NOP gives the signal time to settle on the wires
- 19. Read back Port B to check which columns are LOW (key pressed)
- 20. AND with F0h isolates the column bits (upper nibble)
- 21. Compare with F0h — if all columns HIGH, no key in this row
- 22. If not equal, a key was detected in row 0 — jump to handler
- 23. Blank line
- 24. Load 0FDh (11111101) to drive row 1 LOW
- 25. Output to Port B to activate row 1
- 26. NOP for settling time
- 27. Read columns again
- 28. Isolate column bits
- 29. Compare for key press
- 30. If key found in row 1, jump to that handler
- 31. Blank line
- 32. No key detected in any row, jump back to MAIN and rescan
- 33. Blank line
- 34. Handler for key in row 0 — decode column to determine exact key
- 35. Comment: column detection logic maps the pattern to a key number
- 36. Example: BL=0 means the key maps to digit 0
- 37. Jump to display routine
- 38. Blank line
- 39. Handler for key in row 1 — example key = digit 4
- 40. Blank line
- 41. DISPLAY_IT label: show the digit on the seven-segment display
- 42. Debounce delay: load counter for approximately 20ms
- 43. DBNS label: LOOP decrements CX and repeats until zero — creating the delay
- 44. Blank line
- 45. Load address of segment lookup table into SI
- 46. Clear BH so BX = the digit value (0-9)
- 47. Fetch the segment pattern from the table using BX as index
- 48. Output the pattern to Port A, lighting the appropriate segments
- 49. Jump back to MAIN to scan for the next keypress
Spot the bug
; Multiplexed 2-digit display
; Port A = segments, Port B = digit select
;
MOV AL, 80h
OUT 83h, AL ; all output mode
;
; Display digit 0 (tens)
MOV AL, [SEG_TBL+3] ; pattern for '3'
OUT 80h, AL
MOV AL, 0FEh ; select digit 0
OUT 81h, AL
CALL DELAY
;
; Display digit 1 (ones) — BUG HERE
MOV AL, 0FDh ; select digit 1
OUT 81h, AL
MOV AL, [SEG_TBL+7] ; pattern for '7'
OUT 80h, AL
CALL DELAYNeed a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- Keyboard Interfacing with 8255 (Neso Academy)
- Seven Segment Display Interfacing with 8086 (GeeksforGeeks)
- Multiplexed Display Explained (Ben Eater)
- LED and Keyboard Interfacing with 8255 (TutorialsPoint)