قد تختلف أسماء بعض المكونات في Tinkercad عن الأسماء المستخدمة في الوحدة.
استخدم الجدول التالي عند البحث عن المكوّن داخل المحاكي:
| الاسم في Tinkercad | الاسم المستخدم في الوحدة |
|---|---|
| Soil Moisture Sensor | Water Level Detection Sensor |
| Piezo | Passive Buzzer |
| Micro Servo | Servo Motor |
| Tilt Sensor | Tilt Ball Switch |
| PIR Motion Sensor | HC-SR501 PIR Motion Sensor |
| Photoresistor | Photoresistor / LDR |
| Keyboard 4x4 | Membrane Keypad |
لماذا بعض المكونات ليست مطابقة تمامًا؟
لأن Tinkercad لا يوفر دائمًا نفس القطعة المستخدمة في هذه الوحدة، لذلك نستخدم مكوّنًا يؤدي وظيفة مشابهة أو يعتمد على نفس الفكرة البرمجية.
مثال على ذلك:
analogRead().في هذه الوحدة سنتعامل مع مجموعة من الحساسات والوحدات المختلفة، ونطبق عليها عمليات القراءة والكتابة التي تعلمناها سابقًا.
ثم نتعلم كيفية إضافة المكتبات البرمجية واستخدامها مع المكونات التي تحتاج إليها.

بنهاية الوحدة، يُتوقع القدرة على:
تعلمنا في الوحدة السابقة أربع عمليات أساسية:
في هذه الوحدة سنستخدم هذه العمليات مع مكونات مختلفة.
قبل كتابة الكود، اسأل:
Tilt Ball Switch مفتاح تتغير حالته عند تغيير اتجاهه أو إمالته.
يعطي حالتين فقط:
HIGH
أو
LOW
لذلك نتعامل معه كـ:

التوصيل:
يوصل أحد طرفي Tilt Switch بالمنفذ D2 والطرف الآخر بـ GND.
الكود:
const int tiltPin = 2;
void setup()
{
pinMode(tiltPin, INPUT_PULLUP);
Serial.begin(9600);
}
void loop()
{
int state = digitalRead(tiltPin);
Serial.println(state);
delay(200);
}
غيّر اتجاه الحساس ولاحظ تغير القراءة في Serial Monitor.
الحساس:
HC-SR501 PIR Motion Sensor
يستخدم لاكتشاف الحركة.
أهم طرف للإشارة هو:
OUT
وتكون حالته:
إذن نستخدم:

التوصيل:
الكود:
const int pirPin = 2;
void setup()
{
pinMode(pirPin, INPUT);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
int motion = digitalRead(pirPin);
if (motion == HIGH)
{
digitalWrite(LED_BUILTIN, HIGH);
}
else
{
digitalWrite(LED_BUILTIN, LOW);
}
}
عند اكتشاف حركة تعمل اللمبة المدمجة في لوحة أردوينو.
Photoresistor أو المقاومة الضوئية تتغير مقاومتها حسب شدة الضوء.
نريد الحصول على قيمة تتغير حسب الإضاءة:
نستخدم Photoresistor مع مقاومة 10kΩ لتكوين دائرة Voltage Divider بين 5V وGND.
يقرأ A0 الجهد المتغير عند نقطة التقاء Photoresistor مع المقاومة.

التوصيل:
يقرأ A0 الجهد المتغير عند نقطة التقاء Photoresistor مع المقاومة.
الكود:
const int lightPin = A0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
int lightValue = analogRead(lightPin);
Serial.println(lightValue);
delay(200);
}
جرّب:
ثم راقب تغير القراءة.
Water Level Detection Sensor يستخدم لاكتشاف وجود الماء أو تغير مستواه.
يعطي قيمة تتغير حسب مقدار ملامسة الماء للحساس.
لذلك يمكن قراءته باستخدام:
وتكون القراءة في أردوينو UNO ضمن المجال:

الصورة تستخدم Soil Moisture Sensor في Tinkercad بديلًا تعليميًا لحساس مستوى الماء، كما توضّح شريحة التسميات.
التوصيل:
الكود:
const int waterPin = A0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
int waterValue = analogRead(waterPin);
Serial.println(waterValue);
delay(200);
}
راقب تغير القراءة عند تغير مقدار ملامسة الماء للحساس.
يمكننا باستخدام Passive Buzzer تحديد تردد الصوت.
نستخدم:
tone();
ولإيقاف الصوت:
noTone();
ولا نحتاج إلى مكتبة برمجية خارجية.
في هذا المثال نستخدم Piezo ذا طرفين.
التوصيل:

سنكتب ترددات النغمات مباشرة داخل البرنامج.
const int buzzerPin = 8;
int melody[] = {
523, 587, 659, 698,
784, 880, 988, 1047
};
void setup()
{
}
void loop()
{
for (int i = 0; i < 8; i++)
{
tone(buzzerPin, melody[i], 500);
delay(700);
}
noTone(buzzerPin);
delay(2000);
}
القيم مثل:
523
587
659
تمثل ترددات صوتية بوحدة Hertz.
الحساس:
HC-SR04
يستخدم لقياس المسافة.
يحتوي على طرفين مهمين:
Trig
Echo
وظيفتهما:
Trig = Digital Output، وEcho = Digital Input.
إذن الحساس يستخدم:

أرقام المنافذ في الصورة مختلفة؛ التوصيل المعتمد في مثالي الوحدة هو Trig → D9 وEcho → D10، مع VCC → 5V وGND → GND.
يرسل أردوينو نبضة قصيرة إلى:
Trig
ثم يرسل الحساس موجة صوتية.
عندما ترتد الموجة من جسم، تظهر نبضة على:
Echo
نقيس زمن عودة الموجة:
التوصيل:
Trig = Digital Output، وEcho = Digital Input.
الكود:
const int trigPin = 9;
const int echoPin = 10;
void setup()
{
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.begin(9600);
}
void loop()
{
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
float distance = duration * 0.0343 / 2;
Serial.println(distance);
delay(200);
}لإرسال النبضة:
digitalWrite();
لإنشاء تأخير صغير جدًا:
delayMicroseconds();
لقياس مدة نبضة Echo:
pulseIn();
ثم حسبنا المسافة بأنفسنا:
float distance = duration * 0.0343 / 2;
سنعود لاحقًا إلى الحساس نفسه بعد تعلم استخدام المكتبات البرمجية.
تعرفنا سابقًا على مفهوم المكتبة البرمجية.
في هذه الوحدة سنتعلم كيفية:
المكتبة تساعدنا على التعامل مع المكونات التي تحتاج إلى خطوات برمجية أكثر تعقيدًا.
نستدعي المكتبة باستخدام:
#include <LibraryName.h>
مثال:
#include <Servo.h>
تكتب #include في بداية البرنامج، قبل:
void setup()
بعد ذلك يمكننا استخدام الدوال والأدوات التي توفرها المكتبة.
يمكن تثبيت المكتبات باستخدام:
Library Manager
داخل بيئة تطوير أردوينو.
الخطوات:

بعد تثبيت المكتبة يمكن الوصول إلى أمثلتها من:
عند استخدام مكوّن جديد:
تعاملنا سابقًا مع HC-SR04 بدون مكتبة.
كان علينا تنفيذ:
يمكن استخدام مكتبة جاهزة لتنفيذ جزء كبير من هذه التفاصيل.
من المكتبات المستخدمة لهذا الغرض:
NewPingالتوصيل:
Trig = Digital Output، وEcho = Digital Input.
نستدعي المكتبة:
#include <NewPing.h>
ثم:
const int trigPin = 9;
const int echoPin = 10;
const int maxDistance = 200;
NewPing sonar(trigPin, echoPin, maxDistance);
لقراءة المسافة:
int distance = sonar.ping_cm();
فتعطينا المكتبة المسافة بالسنتيمتر مباشرة.
التوصيل:
Trig = Digital Output، وEcho = Digital Input.
#include <NewPing.h>
const int trigPin = 9;
const int echoPin = 10;
const int maxDistance = 200;
NewPing sonar(trigPin, echoPin, maxDistance);
void setup()
{
Serial.begin(9600);
}
void loop()
{
int distance = sonar.ping_cm();
Serial.println(distance);
delay(200);
}
قارن هذا الكود بالمثال الذي كتبناه سابقًا بدون مكتبة.
نحن مسؤولون عن:
Trig
Echo
قياس الزمن
حساب المسافة
يمكن أن نكتب:
sonar.ping_cm();
وتعيد لنا المسافة مباشرة.
المكتبة لا تغير طريقة عمل الحساس.
إنما تجعل التعامل البرمجي معه أسهل.
محرك Servo يستطيع التحرك إلى زاوية محددة.
مثل:
0°
90°
180°
نستخدم مكتبة:
Servo
ونستدعيها:
#include <Servo.h>
يستخدم المثال Servo صغيرًا بدون حمل.
التوصيل:
الكود:
#include <Servo.h>
Servo myServo;
void setup()
{
myServo.attach(9);
}
void loop()
{
myServo.write(0);
delay(1000);
myServo.write(90);
delay(1000);
myServo.write(180);
delay(1000);
}إنشاء Servo باسم:
Servo myServo;
ربطه بمنفذ أردوينو:
myServo.attach(9);
تحريكه إلى زاوية:
myServo.write(90);
بفضل المكتبة أصبح التحكم في Servo باستخدام أوامر بسيطة.
لوحة المفاتيح الغشائية تحتوي مجموعة أزرار مرتبة على شكل:
Rows
صفوف
و:
Columns
أعمدة
يمكن برمجة قراءة الصفوف والأعمدة يدويًا، لكن الكود سيكون أطول.
لذلك يمكن استخدام مكتبة:
Keypad
لتسهيل معرفة الزر الذي تم ضغطه.
نستدعي المكتبة:
#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'}
};التوصيل:
ترتيب أطراف الصفوف والأعمدة قد يختلف حسب نوع الـKeypad المستخدم.

الكود الكامل:
#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};
byte colPins[cols] = {5, 4, 3, 2};
Keypad keypad = Keypad(
makeKeymap(keys),
rowPins,
colPins,
rows,
cols
);
void setup()
{
Serial.begin(9600);
}
void loop()
{
char key = keypad.getKey();
if (key)
{
Serial.println(key);
}
}عند الحصول على مكوّن جديد:
تعاملنا مع مكونات بدون مكتبات برمجية:
ثم تعلمنا:
#include.وتعاملنا باستخدام المكتبات مع:
الهدف الأساسي من الوحدة:
فهم نوع الإشارة واختيار المنفذ والدالة المناسبة، ثم معرفة متى وكيف نستخدم مكتبة برمجية.