🔢 کیپد ۴×۴ با آردوینو: طرز کار ماتریسی، کتابخانهی Keypad و قفل رمزدار با سروو
قفل رمزدار، ماشینحساب، منوی دستگاه یا وارد کردن دمای دلخواه ترموستات؛ هر جا کاربر باید عدد وارد کند، کیپد ۴×۴ سادهترین جواب است. این صفحهی نازک پلاستیکی ۱۶ دکمه دارد ولی فقط با ۸ سیم به آردوینو وصل میشود. در این آموزش راز این ۸ سیم را میفهمیم، با کتابخانهی Keypad یک برنامهی وارد کردن عدد مینویسیم و بعد یک قفل رمزدار با سروو میسازیم که بعد از سه رمز اشتباه قفل میشود. کیپد را در شبیهساز فارسی با کلیک ماوس فشار میدهی و همهچیز رایگان است؛ مثل تجربهای که ووکوی (Wokwi) دارد، این بار کاملاً فارسی.
کیپد ماتریسی چطور کار میکند؟
اگر هر دکمه سیم جدا داشت، ۱۶ پین لازم بود و آردوینو اونو عملاً پر میشد. ترفند کیپد این است که دکمهها را در یک ماتریس چیدهاند: چهار سیم افقی (ردیفها R1 تا R4) و چهار سیم عمودی (ستونها C1 تا C4) که از روی هم رد میشوند ولی به هم وصل نیستند. زیر هر دکمه، یک ردیف و یک ستون به هم میرسند و فشار دادن دکمه فقط همان ردیف را به همان ستون وصل میکند.
آردوینو برای پیدا کردن دکمهی فشردهشده اسکن میکند: پینهای ردیف را ورودی با پولآپ داخلی میگذارد، پس همه HIGH میخوانند. بعد ستونها را یکییکی LOW میکند و هر بار چهار ردیف را میخواند. اگر وقتی ستون ۲ پایین است، ردیف ۳ هم LOW خواند، یعنی دکمهی محل تلاقی ردیف ۳ و ستون ۲ فشرده شده، که در کیپد استاندارد عدد ۸ است. این اسکن هزاران بار در ثانیه انجام میشود و کتابخانهی Keypad همهاش را، همراه با حذف لرزش کلید (debounce)، برایت انجام میدهد.
پایهها و سیمکشی
کابل تخت کیپد هشت پایه دارد. در بیشتر کیپدهای غشایی رایج، وقتی کیپد رو به توست و کابل پایین است، از چپ به راست: R1، R2، R3، R4، C1، C2، C3، C4. ولی همهی سازندهها این ترتیب را رعایت نمیکنند؛ اگر عددها جابهجا درآمدند، بخش اشکالها را ببین.
- یک آردوینو Uno
- یک کیپد ۴×۴
- برای پروژهی دوم: یک سروو موتور و یک بازر
| پایهی کیپد | آردوینو | پایهی کیپد | آردوینو |
|---|---|---|---|
| R1 (ردیف ۱) | پین 9 | C1 (ستون ۱) | پین 5 |
| R2 (ردیف ۲) | پین 8 | C2 (ستون ۲) | پین 4 |
| R3 (ردیف ۳) | پین 7 | C3 (ستون ۳) | پین 3 |
| R4 (ردیف ۴) | پین 6 | C4 (ستون ۴) | پین 2 |
کیپد نه VCC دارد و نه GND؛ فقط همین هشت سیم. مقاومت پولآپ هم لازم نیست، چون کتابخانه پولآپ داخلی خود آردوینو را روشن میکند.
کد کامل: وارد کردن عدد
// 4x4 membrane keypad on an Arduino Uno with the Keypad library.
#include <Keypad.h>
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; // R1, R2, R3, R4
byte colPins[COLS] = {5, 4, 3, 2}; // C1, C2, C3, C4
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
String number = "";
void setup() {
Serial.begin(9600);
Serial.println("Type a number, # = enter, * = clear");
}
void loop() {
char key = keypad.getKey();
if (!key) return; // no new key this time
if (key >= '0' && key <= '9') {
number += key;
Serial.print("Typed: ");
Serial.println(number);
} else if (key == '#') {
long value = number.toInt();
Serial.print("Entered: ");
Serial.print(value);
Serial.print(" x2 = ");
Serial.println(value * 2);
number = "";
} else if (key == '*') {
number = "";
Serial.println("Cleared");
} else {
Serial.print("Command key: ");
Serial.println(key);
}
}
توضیح کد
char keys[ROWS][COLS]یک «نقشه» است: میگوید محل تلاقی هر ردیف و ستون چه حرفی است. اگر کیپدت برچسب دیگری دارد (مثلاً ۳×۴ تلفنی)، فقط همین جدول و تعداد ستونها را عوض میکنی.rowPinsوcolPinsمیگویند هر ردیف و ستون به کدام پین آردوینو رفته است. ترتیب اعداد باید دقیقاً با جدول سیمکشی یکی باشد.keypad.getKey()منتظر نمیماند: اگر دکمهی تازهای زده نشده باشد، فوراً مقدار خالی (NO_KEY) برمیگرداند. برای همین بلافاصله باif (!key) return;از این دورloopبیرون میرویم. هر فشار فقط یک بار گزارش میشود، حتی اگر دکمه را نگه داری.key >= '0' && key <= '9'چون حرفها در کامپیوتر عدد هستند و ارقام پشت سر هماند، این شرط یعنی «کلید یک رقم است».number.toInt()رشتهی «125» را به عدد ۱۲۵ تبدیل میکند تا بتوانی با آن حساب کنی. ازlongاستفاده کردهایم چونintدر اونو فقط تا ۳۲۷۶۷ جا دارد.- کلیدهای A تا D را برای فرمانها نگه داشتهایم؛ مثلاً در یک منو A یعنی بالا و B یعنی پایین.
کتابخانهی Keypad روی کامپیوتر خودت از Library Manager با جستوجوی «Keypad» (نوشتهی Mark Stanley و Alexander Brevig) نصب میشود. در شبیهساز از قبل آماده است. برای اینکه بدانی کتابخانه دقیقاً چه کاری برایت میکند، صفحهی کتابخانهها در شبیهساز را هم ببین.
پروژهی کوچک: قفل رمزدار با سروو و قفل سهبار خطا
حالا کیپد را به یک سروو وصل میکنیم که نقش زبانهی در را بازی میکند. سیم سیگنال سروو به پین 11، بازر به پین 12. رمز را وارد کن و # بزن؛ اگر درست بود در چهار ثانیه باز میماند. اگر سه بار اشتباه زدی، سی ثانیه همهچیز قفل میشود؛ همان کاری که گوشیها برای سخت کردن حدس زدن رمز میکنند. روی سریال مانیتور هم بهجای رقمها ستاره نشان میدهیم.
// Mini project: keypad door lock with a servo and a 3-try lockout.
#include <Keypad.h>
#include <Servo.h>
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
Servo lock;
const int SERVO_PIN = 11;
const int BUZZER_PIN = 12;
const String PASSWORD = "2580";
String entered = "";
int wrongTries = 0;
void setup() {
Serial.begin(9600);
lock.attach(SERVO_PIN);
lock.write(0); // 0 degrees = locked
pinMode(BUZZER_PIN, OUTPUT);
Serial.println("Enter code, then #");
}
void loop() {
char key = keypad.getKey();
if (!key) return;
tone(BUZZER_PIN, 2000, 30); // short click for every key
if (key == '*') {
entered = "";
Serial.println("Cleared");
} else if (key == '#') {
if (entered == PASSWORD) {
Serial.println("Open!");
wrongTries = 0;
lock.write(90); // open the latch
delay(4000);
lock.write(0);
Serial.println("Locked again");
} else {
wrongTries++;
Serial.print("Wrong code (");
Serial.print(wrongTries);
Serial.println("/3)");
if (wrongTries >= 3) {
Serial.println("Too many tries, wait 30 s");
tone(BUZZER_PIN, 400, 1000);
delay(30000);
wrongTries = 0;
}
}
entered = "";
} else if (entered.length() < 8) {
entered += key;
Serial.print("Code: ");
for (unsigned int i = 0; i < entered.length(); i++) Serial.print('*');
Serial.println();
}
}
entered.length() < 8 نمیگذارد کسی با زدن صدها دکمه حافظهی کوچک اونو را پر کند. مقایسهی entered == PASSWORD هم چون هر دو String هستند، متن را مقایسه میکند. یادت باشد این قفل آموزشی است: رمز داخل کد نوشته شده و با یک آهنربا یا قطع برق هم میشود سروو را دور زد. برای چرخاندن دقیقتر سروو، آموزش سروو موتور با آردوینو را بخوان؛ اگر کارت جای رمز میخواهی، قفل در با RFID نسخهی کارتی همین پروژه است.
اجرا در شبیهساز، رایگان
کیپد ۴×۴ و کتابخانهی Keypad در تینکرکد فارسی روی آردوینو اونو رایگاناند و دکمهها را با ماوس یا انگشت روی گوشی فشار میدهی. سادهترین مثال آماده «کیپد ۴×۴» است که هر کلید را چاپ میکند و نسخهی کاملتر «قفل رمزدار» با سروو. درسهایش هم درس ۳۰: کیپد ۴×۴ و درس ۳۱: قفل رمزدار هستند و ایدههای بیشتر در مقالهی ساخت قفل رمزی با آردوینو.
اشکالهای رایج
- دکمهها عدد اشتباه میدهند: ترتیب پینها با کیپد تو فرق دارد. اگر ردیفها و ستونها جابهجا شدهاند (مثلاً ۲ بهجای ۴)، جای
rowPinsوcolPinsرا عوض کن؛ اگر ترتیب برعکس است (۱ بهجای ۳)، اعداد یکی از آرایهها را برعکس بنویس. - سریال مانیتور خراب یا آپلود ناموفق است: کیپد را به پینهای 0 و 1 وصل کردهای که مال ارتباط سریالاند.
- هیچ کلیدی چاپ نمیشود: شرط
if (key)را باkey == 0اشتباه نوشتهای، یا درloopیکdelayطولانی داری که اسکن را کند میکند. - برنامهی دیگرت قفل میشود: از
waitForKey()استفاده کردهای که تا فشار دادن دکمه همهچیز را متوقف میکند.getKey()را ترجیح بده. - مقایسهی رمز همیشه غلط است: رمز را با تککوتیشن (
'1234') نوشتهای؛ متن چندحرفی باید در دابلکوتیشن باشد.
کیپد را به دزدگیر وصل کن تا با رمز مسلح شود: سنسور حرکت PIR با آردوینو. رمز وارد شده را روی صفحه نشان بده: LCD I2C با آردوینو (نمایشگر LCD I2C در شبیهساز با اشتراک Plus اجرا میشود). بقیهی ماژولها هم در بخش سنسورها و ماژولها هستند.
قفل رمزدار را رایگان اجرا کن 🔢سؤالهای رایج
کیپد ۴×۴ چند پین آردوینو را میگیرد؟
هشت پین: چهار ردیف و چهار ستون. هر پین دیجیتالی میشود، حتی A0 تا A5، ولی بهتر است پینهای 0 و 1 را که برای ارتباط سریالاند آزاد بگذاری.
چرا وقتی یک دکمه را میزنم عدد دیگری چاپ میشود؟
ترتیب پینهای ردیف و ستون در کد با سیمکشی یکی نیست. معمولاً کافی است آرایهی rowPins یا colPins را برعکس کنی یا جای دو آرایه را عوض کنی.
برای کیپد مقاومت پولآپ لازم است؟
نه. کتابخانهی Keypad خودش مقاومت پولآپ داخلی آردوینو را روی پینهای ردیف روشن میکند و به مقاومت بیرونی نیازی نیست.