Understanding the Keypad Idea
In the heart of every simple keypad or keyboard is a simple idea: the matrix. Instead of wiring each key directly to the microcontroller. Which requires a lot of pins. Keys are arranged in a grid of columns and rows.
When a key is pressed, it connects a row with a column. By scanning rows and columns, the microcontroller can detect which key is being pressed.
For example, a 4×4 matrix allows 16 keys to be controlled with only 8 pins. This is the principle behind calculators, numpads, and even full keyboards.
The Problem With 4×4 and Diodes' Role
Key matrices have a well-known challenge: ghosting.
Ghosting usually happens when pressing multiple keys at the same time, creating "phantom" key presses. This occurs because current flows in unintended paths across the matrix.
And the solution is easy using "diodes."
A 1N4148 diode is placed in series with each switch.
The function of the diode is to allow current to pass in only one direction.
With diodes, each key press is isolated, and ghosting is eliminated.
So the typical wiring for each key looks like this:
Row → Diode (1N4148) → Switch → Column
Looking something like this:
Building a Webpage to Showcase the Keypad
To better explain the role of diodes and how keypads work, I created with the help of AI a code to showcase how the keypad works.
Here's the code:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>4×4 Keypad Matrix with Diodes — Interactive Wiring & Print</title>
<style>
:root{--bg:#0f1724;--card:#0b1220;--accent:#38bdf8;--muted:#9aa6b2}
html,body{height:100%;margin:0;font-family:Inter,ui-sans-serif,system-ui,Segoe UI,Roboto,"Helvetica Neue",Arial}
body{background:linear-gradient(180deg,#031025 0%, #071528 60%);color:#e6eef6;display:flex;gap:20px;align-items:flex-start;padding:24px}
.wrap{max-width:1100px;margin:0 auto;width:100%}
.top{display:flex;justify-content:space-between;align-items:center;gap:12px}
h1{font-size:20px;margin:0}
p.lead{margin:6px 0 0;color:var(--muted);font-size:13px}
.layout{display:grid;grid-template-columns:420px 1fr;gap:18px;margin-top:18px}
.card{background:linear-gradient(180deg,rgba(255,255,255,0.02),rgba(0,0,0,0.02));padding:16px;border-radius:10px;box-shadow:0 6px 18px rgba(2,6,23,0.6)}
.kbd {display:grid;grid-template-columns:repeat(4,1fr);gap:12px;}
.key{background:linear-gradient(180deg,#0f1728,#081122);border-radius:8px;padding:14px;text-align:center;cursor:pointer;border:1px solid rgba(255,255,255,0.03);user-select:none}
.key:active{transform:translateY(1px)}
.key.on{box-shadow:0 6px 18px rgba(56,189,248,0.12), inset 0 -2px 6px rgba(0,0,0,0.6);border-color:rgba(56,189,248,0.22)}
.legend{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px}
.legend .item{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:13px}
.wire{width:28px;height:6px;border-radius:4px;background:linear-gradient(90deg,#3dd5ff,#0072ff);box-shadow:0 2px 6px rgba(0,115,255,0.22)}
.diode{font-weight:700;color:#ffd89b;padding:6px 8px;border-radius:6px;background:linear-gradient(180deg,#261f00,#1a1400);}
svg{width:100%;height:auto}
.controls{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
button.btn{background:transparent;border:1px solid rgba(255,255,255,0.06);padding:8px 10px;border-radius:8px;color:var(--muted);cursor:pointer}
button.btn.primary{border-color:rgba(56,189,248,0.22);color:var(--accent)}
.panel{padding:12px;border-radius:8px;background:linear-gradient(180deg,rgba(255,255,255,0.01),transparent)}
.pins{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.pin{padding:6px 8px;border-radius:6px;background:rgba(255,255,255,0.02);font-size:13px}
.status{margin-top:12px;color:var(--muted);font-size:13px}
.wiring{font-family:monospace;background:#011225;padding:12px;border-radius:6px;margin-top:12px;color:#bfe9ff}
.download{margin-top:8px}
@media(max-width:900px){.layout{grid-template-columns:1fr;}}
</style>
</head>
<body>
<div class="wrap">
<div class="top">
<div>
<h1>4×4 Keypad Matrix — Diagram & Wiring (with diodes)</h1>
<p class="lead">Click keys to toggle. The diagram shows where to place diodes and how to wire rows & columns for a microcontroller scan.</p>
</div>
<div style="text-align:right;color:var(--muted);font-size:13px">Printable, single-file HTML</div>
</div>
<div class="layout">
<div class="card">
<div style="display:flex;gap:12px;align-items:center">
<div style="flex:1">
<div style="font-size:13px;color:var(--muted)">Keypad (4 rows × 4 columns)</div>
<div class="kbd" id="kbd"></div>
<div class="legend">
<div class="item"><div class="wire"></div> Column wires</div>
<div class="item"><div style="width:6px;height:6px;border-radius:3px;background:#ffd89b"></div> Diode direction (arrow points from col→row)</div>
<div class="item"><div class="diode">D</div> Diode at each switch</div>
</div>
</div>
</div>
<div class="controls">
<button class="btn primary" id="clear">Clear all</button>
<button class="btn" id="random">Random press</button>
<button class="btn" id="simulate">Simulate scan</button>
<button class="btn" id="export">Export PNG</button>
</div>
<div class="status" id="status">Pressed: none</div>
</div>
<div class="card">
<div class="panel">
<h3 style="margin:0 0 8px 0">Wiring & Explanation</h3>
<p style="margin:0;color:var(--muted);font-size:13px">This layout shows a typical 4×4 keypad matrix. Each button connects one column line to one row line when pressed. To avoid "ghosting" when multiple keys are pressed, place a diode on each key so current can flow only in the scanning direction (from driven column into row input). In the sample diagram the diodes are oriented from column → switch → row.</p>
<div class="pins">
<div class="pin">COL0 → MCU pin: C0 (drive)</div>
<div class="pin">COL1 → MCU pin: C1</div>
<div class="pin">COL2 → MCU pin: C2</div>
<div class="pin">COL3 → MCU pin: C3</div>
<div class="pin">ROW0 → MCU pin: R0 (read)</div>
<div class="pin">ROW1 → MCU pin: R1</div>
<div class="pin">ROW2 → MCU pin: R2</div>
<div class="pin">ROW3 → MCU pin: R3</div>
</div>
<div class="wiring" id="wiring">/* Wiring will show here after simulation */</div>
<div style="font-size:13px;color:var(--muted);margin-top:8px">Notes:
<ul style="margin:6px 0 0 18px;color:var(--muted)">
<li>Use small signal diodes (1N4148 or similar) or Schottky (SS14) for lower drop.</li>
<li>Diode orientation: from column (driven) to row (read). So the diode anode connects to column, cathode to switch/row side.</li>
<li>Give rows pull-ups or configure MCU input with pull-up; drive columns low one-by-one to scan.</li>
</ul>
</div>
</div>
</div>
</div>
<div style="margin-top:18px;display:flex;gap:12px;flex-wrap:wrap">
<div class="card" style="width:100%">
<h3 style="margin:0 0 8px 0">Schematic (visual)</h3>
<svg id="schem" viewBox="0 0 900 420" xmlns="http://www.w3.org/2000/svg">
<!-- Column pins left -->
<g id="cols" transform="translate(40,40)">
<!-- labels -->
<g id="colLabels" transform="translate(0,0)">
<text x="0" y="-6" fill="#9aa6b2" font-size="13">Columns (drive)</text>
<g transform="translate(0,20)">
<text x="0" y="0" font-size="13" fill="#bde9ff">C0</text>
<text x="0" y="60" font-size="13" fill="#bde9ff">C1</text>
<text x="0" y="120" font-size="13" fill="#bde9ff">C2</text>
<text x="0" y="180" font-size="13" fill="#bde9ff">C3</text>
</g>
</g>
<!-- column vertical wires -->
<g id="colWires" transform="translate(50,0)">
<rect x="0" y="0" width="6" height="260" rx="3" fill="#0072ff" opacity="0.08" />
</g>
</g>
<!-- keypad switches grid -->
<g transform="translate(160,20)" id="grid">
<!-- rows/cols spacing 80 -->
<!-- draw diodes and switches programmatically via JS -->
</g>
<!-- row pins right -->
<g id="rows" transform="translate(680,40)">
<text x="0" y="-6" fill="#9aa6b2" font-size="13">Rows (read)</text>
<g transform="translate(0,20)">
<text x="40" y="0" font-size="13" fill="#bde9ff">R0</text>
<text x="40" y="60" font-size="13" fill="#bde9ff">R1</text>
<text x="40" y="120" font-size="13" fill="#bde9ff">R2</text>
<text x="40" y="180" font-size="13" fill="#bde9ff">R3</text>
</g>
<g transform="translate(20,12)">
<rect x="0" y="0" width="6" height="260" rx="3" fill="#00e676" opacity="0.06" />
</g>
</g>
</svg>
</div>
</div>
</div>
<script>
// Build 4x4 keypad UI and SVG schematic wiring
const kbd = document.getElementById('kbd');
const status = document.getElementById('status');
const wiring = document.getElementById('wiring');
const gridSvg = document.getElementById('grid');
const totalR = 4, totalC = 4;
const keys = [];
function makeKeyLabel(r,c){
const labelMap = [ ['1','2','3','A'],['4','5','6','B'],['7','8','9','C'],['*','0','#','D'] ];
return labelMap[r][c] || (r+","+c);
}
for(let r=0;r<totalR;r++){
for(let c=0;c<totalC;c++){
const btn = document.createElement('div');
btn.className='key';
btn.dataset.r=r;btn.dataset.c=c;
btn.textContent = makeKeyLabel(r,c);
btn.addEventListener('click', ()=>{ btn.classList.toggle('on'); updateStatus(); updateSchematic(); });
kbd.appendChild(btn);
keys.push(btn);
}
}
document.getElementById('clear').addEventListener('click', ()=>{keys.forEach(k=>k.classList.remove('on')); updateStatus(); updateSchematic();});
document.getElementById('random').addEventListener('click', ()=>{keys.forEach(k=>{ if(Math.random()>0.7) k.classList.add('on'); else k.classList.remove('on');}); updateStatus(); updateSchematic();});
function pressedList(){
return keys.filter(k=>k.classList.contains('on')).map(k=>`(${k.dataset.r},${k.dataset.c})`);
}
function updateStatus(){
const list = pressedList();
status.textContent = list.length ? ('Pressed: '+list.join(' ')) : 'Pressed: none';
}
// Build SVG grid with diodes and switches
function updateSchematic(){
gridSvg.innerHTML='';
const cell = 80;
for(let r=0;r<totalR;r++){
for(let c=0;c<totalC;c++){
const x = c*cell; const y = r*cell;
// group
const g = document.createElementNS('http://www.w3.org/2000/svg','g');
g.setAttribute('transform',`translate(${x},${y})`);
// diode symbol (anode left, cathode triangle pointing right -> bar)
const diode = document.createElementNS('http://www.w3.org/2000/svg','g');
diode.innerHTML = `
<polygon points="-30,28 -12,18 -12,38" fill="#ffd89b" opacity="0.95"></polygon>
<rect x="-12" y="24" width="22" height="8" fill="#ffd89b"></rect>
<line x1="-42" y1="28" x2="-30" y2="28" stroke="#ffd89b" stroke-width="3" stroke-linecap="round"></line>
<line x1="10" y1="28" x2="22" y2="28" stroke="#9aa6b2" stroke-width="2" stroke-linecap="round"></line>
`;
g.appendChild(diode);
// switch circle
const circle = document.createElementNS('http://www.w3.org/2000/svg','circle');
circle.setAttribute('cx',20);
circle.setAttribute('cy',28);
circle.setAttribute('r',14);
circle.setAttribute('fill','#042331');
circle.setAttribute('stroke','rgba(255,255,255,0.04)');
circle.setAttribute('data-r',r);
circle.setAttribute('data-c',c);
// label
const text = document.createElementNS('http://www.w3.org/2000/svg','text');
text.setAttribute('x',20);text.setAttribute('y',32);text.setAttribute('font-size',12);text.setAttribute('text-anchor','middle');text.setAttribute('fill','#bde9ff');
text.textContent = makeKeyLabel(r,c);
g.appendChild(circle);
g.appendChild(text);
// connection lines: from left (col) to diode anode, from diode cathode to switch, from switch to right (row)
const lineA = document.createElementNS('http://www.w3.org/2000/svg','line');
lineA.setAttribute('x1',-50);lineA.setAttribute('y1',28);lineA.setAttribute('x2',-42);lineA.setAttribute('y2',28);lineA.setAttribute('stroke','#3dd5ff');lineA.setAttribute('stroke-width','4');lineA.setAttribute('stroke-linecap','round');
g.appendChild(lineA);
const lineB = document.createElementNS('http://www.w3.org/2000/svg','line');
lineB.setAttribute('x1',22);lineB.setAttribute('y1',28);lineB.setAttribute('x2',70);lineB.setAttribute('y2',28);lineB.setAttribute('stroke','#00e676');lineB.setAttribute('stroke-width','4');lineB.setAttribute('stroke-linecap','round');
g.appendChild(lineB);
// highlight if pressed
const idx = r*totalC + c;
const pressed = keys[idx].classList.contains('on');
if(pressed){ circle.setAttribute('fill','#082a2d'); circle.setAttribute('stroke','#38bdf8'); }
gridSvg.appendChild(g);
}
}
// Update wiring text: show which R lines read active when scanning each column.
// Simple simulated scan: for each column, assume MCU drives that column low and reads rows that are connected via pressed keys (through diode). We'll report rows detected per column.
const detected = [];
for(let c=0;c<totalC;c++){
const rowsHit = new Set();
for(let r=0;r<totalR;r++){
const idx = r*totalC + c;
if(keys[idx].classList.contains('on')) rowsHit.add(r);
}
detected.push({col:c,rows:Array.from(rowsHit).sort()});
}
let text = 'Scan result (for each column driven):\n';
detected.forEach(d=>{
text += `COL${d.col}: ` + (d.rows.length ? d.rows.map(x=>'R'+x).join(', ') : 'none') + '\n';
});
wiring.textContent = text;
}
document.getElementById('simulate').addEventListener('click', ()=>{ updateSchematic(); alert('Simulation complete. See the wiring box that lists which row lines would be seen when driving each column.'); });
// Export as PNG (basic) by drawing the SVG to canvas
document.getElementById('export').addEventListener('click', ()=>{
const svg = document.querySelector('svg');
const xml = new XMLSerializer().serializeToString(svg);
const svg64 = btoa(unescape(encodeURIComponent(xml)));
const b64start = 'data:image/svg+xml;base64,'+svg64;
const img = new Image();
img.onload = ()=>{
const c = document.createElement('canvas');
c.width = img.width; c.height = img.height;
const ctx = c.getContext('2d');
ctx.fillStyle='#021022'; ctx.fillRect(0,0,c.width,c.height);
ctx.drawImage(img,0,0);
const png = c.toDataURL('image/png');
const a = document.createElement('a'); a.href=png; a.download='keypad-schematic.png'; a.click();
}
img.src = b64start;
});
// init
updateStatus(); updateSchematic();
</script>
</body>
</html>
Just copy it in a code editor, save it as index.html and view it. And if you don't want to test it yourself, here's a demo.
Using AI as a Circuit Builder
Instead of manually drawing every switch and diode, I experimented with using AI to build a webpage that you can build with diodes and switches.
Here's the code also if you want to test it yourself:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Circuit Builder</title>
<style>
body {
margin: 0;
display: flex;
flex-direction: column;
height: 100vh;
background: #0f1724;
color: #fff;
font-family: sans-serif;
}
#canvas {
flex: 1;
background: #011225;
border: 2px solid #38bdf8;
}
#toolbar {
display: flex;
justify-content: space-around;
background: #111;
padding: 10px;
}
button {
flex: 1;
margin: 0 5px;
padding: 12px;
font-size: 16px;
border: none;
border-radius: 8px;
background: #38bdf8;
color: #000;
font-weight: bold;
}
button:active {
background: #0ea5e9;
}
</style>
</head>
<body>
<svg id="canvas" xmlns="http://www.w3.org/2000/svg"></svg>
<div id="toolbar">
<button onclick="addSwitch()">SW</button>
<button onclick="addDiode()">Diode</button>
<button onclick="addWire()">Wire</button>
<button onclick="rotateSelected()">Rotate</button>
</div>
<script>
const svg = document.getElementById('canvas');
let selected = null;
let dragging = false;
let offset = {x:0,y:0};
function makeDraggable(el) {
el.addEventListener('mousedown', startDrag);
el.addEventListener('touchstart', startDrag);
}
function startDrag(e) {
selected = e.currentTarget;
dragging = true;
let pt = getPoint(e);
const transform = selected.transform.baseVal.consolidate();
const matrix = transform ? transform.matrix : svg.createSVGMatrix();
offset.x = pt.x - matrix.e;
offset.y = pt.y - matrix.f;
e.preventDefault();
}
function drag(e) {
if (!dragging || !selected) return;
let pt = getPoint(e);
let angle = parseInt(selected.dataset.rot||0);
selected.setAttribute('transform',
`translate(${pt.x - offset.x},${pt.y - offset.y}) rotate(${angle})`);
}
function endDrag() { dragging = false; }
function getPoint(e) {
let ctm = svg.getScreenCTM().inverse();
let point = svg.createSVGPoint();
if (e.touches && e.touches[0]) {
point.x = e.touches[0].clientX;
point.y = e.touches[0].clientY;
} else {
point.x = e.clientX;
point.y = e.clientY;
}
return point.matrixTransform(ctm);
}
// Create components
function addSwitch() {
let g = createGroup();
let c = document.createElementNS("http://www.w3.org/2000/svg","circle");
c.setAttribute("r","25");
c.setAttribute("fill","#042331");
c.setAttribute("stroke","#38bdf8");
c.setAttribute("stroke-width","3");
let t = document.createElementNS("http://www.w3.org/2000/svg","text");
t.setAttribute("x","0");
t.setAttribute("y","5");
t.setAttribute("text-anchor","middle");
t.setAttribute("fill","#fff");
t.textContent = "SW";
g.appendChild(c);
g.appendChild(t);
svg.appendChild(g);
}
function addDiode() {
let g = createGroup();
let poly = document.createElementNS("http://www.w3.org/2000/svg","polygon");
poly.setAttribute("points","-20,-15 0,0 -20,15");
poly.setAttribute("fill","#ffd89b");
let rect = document.createElementNS("http://www.w3.org/2000/svg","rect");
rect.setAttribute("x","0");
rect.setAttribute("y","-12");
rect.setAttribute("width","10");
rect.setAttribute("height","24");
rect.setAttribute("fill","#ffd89b");
g.appendChild(poly);
g.appendChild(rect);
svg.appendChild(g);
}
function addWire() {
let g = createGroup();
let line = document.createElementNS("http://www.w3.org/2000/svg","line");
line.setAttribute("x1","0");
line.setAttribute("y1","0");
line.setAttribute("x2","80");
line.setAttribute("y2","0");
line.setAttribute("stroke","#3dd5ff");
line.setAttribute("stroke-width","5");
g.appendChild(line);
svg.appendChild(g);
}
function createGroup() {
let g = document.createElementNS("http://www.w3.org/2000/svg","g");
g.setAttribute("class","draggable");
g.setAttribute("transform","translate(100,100)");
g.dataset.rot = 0;
makeDraggable(g);
return g;
}
function rotateSelected() {
if (!selected) return;
let angle = parseInt(selected.dataset.rot||0);
angle = (angle+45)%360;
selected.dataset.rot = angle;
const transform = selected.transform.baseVal.consolidate();
const matrix = transform ? transform.matrix : svg.createSVGMatrix();
selected.setAttribute('transform',
`translate(${matrix.e},${matrix.f}) rotate(${angle})`);
}
// Drag listeners
svg.addEventListener('mousemove', drag);
svg.addEventListener('touchmove', drag);
svg.addEventListener('mouseup', endDrag);
svg.addEventListener('touchend', endDrag);
</script>
</body>
</html>
Final Thoughts
This project shows how traditional electronics (key matrices + diodes) and modern AI tools can blend together. The AI helps design and explain, while the diodes solve the practical problem of ghosting.