image_pdfimage_print

نظام مسح الفضاء المحيط

في هذا المشروع سنتعلم كيفية استخدام حساس الموجات الفوق صوتية (Ultrasonic) مع الأردوينو في عمل مسح للفضاء المحيط

التحكم بالـ LED من خلال Node-RED

خلال هذا المشروع، ستتعرف على كيفية استخدام الـ Node-RED للتواصل مع منافذ GPIO الخاصة بالـ Raspberry Pi.
سنقوم بإنشاء تدفق Node-RED للتحكم في LED.

getting-started-with-node-red

القطع المطلوبة :

الأدوات التي تحتاجها لهذا المشروع :

5mm Red LED

العدد :1

220 Ω resistor

مقاومة 220 اوم

العدد :1

لوح تجارب صغير

Raspberry Pi 3 Model B

Female-Male Jumper Wires

 اسلاك توصيل أنثى/ذكر (Jumper Wires Female/male)

5V 2A Switching Power Supply MicroUSB Cable

Power Supply

Samsung 8Gb Class 6 Microsd Memory Card 2

Samsung 8Gb Class 10 Microsd Memory Card

تصميم لوحة التجارب:

قم بتوصيل الـ LED إلى منفذ GPIO 17 على الـ Raspberry Pi من خلال اتباع الشكل التالي :

getting-started-with-node-red

عادة ما يكون الطرف الموجب للـ LEDأطول، وهذا الطرف موصل إلى الـ GPIO 17 على الجانب الأيسر من اللوح.

البدء مع الـ Node-RED

ابدأ من الـ Raspberry Pi ، قم بالنقر على أيقونة Raspberry (القائمة الرئيسية) ، ثم قائمة البرمجة Programming لفتح Node-RED

getting-started-with-node-red

يجب أن تشاهد نافذة تعرض معلومات حول بدء تشغيل Node-RED

getting-started-with-node-red

انتقل الآن إلى قائمة الإنترنت وافتح متصفح الويب Chromium .

getting-started-with-node-red

في المتصفح عند شريط العنوان في الأعلى قم بكتابة localhost:1880 ، ثم اضغط على Enter .  سيعرض هذا واجهة الـ Node-RED

getting-started-with-node-red

لا يحتاج جهاز الراسبيري باي إلى الاتصال بالانترنت لاستخدام Node-RED: localhost هو العنوان الذي يستخدمه الراسبيري باي للإشارة إلى نفسه و :1880 يعني ان يستخدم المنفذ 1880.

إنشاء التدفق

أولا الاتصال بمنفذ GPIO :

البرامج في الـ Node-RED تسمى تدفقات. يمكنك إنشاء العديد من التدفقات كما تريد، ويمكن تشغيلها كلها في نفس الوقت.
البلوك الملونه على الجانب الأيسر من الواجهة هي العقد. قم بالتمرير إلى اسفل القائمة وسترى بعض العقد المسمى بـ Raspberry Pi.

getting-started-with-node-red

سترى عقدتين مسمية بإسم rpi gpio هذه هي التي يتم استخدامها للتحدث إلى منافذ GPIO في الراسبيري باي. أول واحد في القائمة ، مع رمز التوت على اليسار، هو للمدخلات. مثل استخدام زر الضغط للتحكم في شيء ما. العقدة الثانية، مع رمز الراسبيري باي على اليمين، هي للمخرجات.
سيتم استخدام العقدة الخاصة بالمخرجات ، قم عقدة الإخراج إلى الصفحة الفارغة في المنتصف.

getting-started-with-node-red

انقر نقرا مزدوجا على العقدة وسيظهر مربع يتيح لك إعداد وتهيئة هذه العقدة.

أولا نقوم بتحديد منفذ الـ GPIO الذي تم استخدامه GPIO17، وتحديد القيمة الابتدائية للمنفذ low . يمكنك تغير اسم العقد هنا تم تسميتها بإسم Green LED . عند الإنتهاء ، انقر فوق تم Done.

getting-started-with-node-red

ثانيا التحكم بمخرجات المنفذ :

الآن انتقل مرة أخرى إلى قائمة العقد. لتشغيل وإيقاف الـ LED، نحن بحاجة إلى عقدة إدخال. في Node-RED، يمكننا إدخال الرسائل في التدفقلتؤدي بعد ذلك إلى حدوث أشياء نتيجة لذلك. قم بسحب عقدة الإدخال inject node للتدفق.

getting-started-with-node-red

انقر نقراً مزدوجاً فوق عقدة الإدخال inject node . استخدم القائمة المنسدلة بجانب Payload لتغير نوع البيانات إلى string . قم بكتابة القيمة 1 في مربع Payload – ستمثل هذه الرسالة قيمة 1 والتي سيتم اخراجها على المنفذ ليتم تشغيل الـ LED.
يمكنك تغير اسم العقدة إلى ON.

 

getting-started-with-node-red

كرر الخطوات السابقة لإنشاء عقدة إدخال أخرى، ولكن سيتم إخراج قيمة 0 كرسالة محمولة، وتسمية هذه العقدة OFF.

Create two inject nodes

الآن نقوم بتوصيل العقد معا لإنشاء التدفق المطلوب. من النقط الرمادية على الجانب الأيمن من عقد الإدخال نقوم بسحب سلك ربطه بعقدة الإخراج .

getting-started-with-node-red

نشر التدفق

تم الانتهاء من التدفق، حتى نتمكن من نشره. انقر على زر Deploy الأحمر الكبير أعلى يمين الشاشة. ستظهر رسالة في الأعلى تقول تم نشرها بنجاح “Successfully deployed”

getting-started-with-node-red

انقر الآن على المربع الأزرق على يسار العقدة on لإدخال الرسالة 1. تتلقى عقدة Green LED الرسالة وينبغي أن يضيء الـ LED. يجب أن تكون قادراً على إيقاف تشغيل الـ LED بالنقر على عقدة OFF.

getting-started-with-node-red

التحكم بالـ LED عبر الأوامر الصوتية

في هذا المشروع، سنقوم بتعلم كيفية تحويل الصوت إلى أوامر تحكم . وتعرف على وحدة التعرف على الصوت (Voice Recognition)، وكيفية تشغيل/ إيقاف الـ LED  باستخدام الأوامر الصوتية. هناك عدة طرق أخرى لتنفيذ التعرف على الصوت في مشروعك من خلال هاتف  android إلى   Alexa أو  Raspberry pi أو اي طريقة أخرى.

arduino-voice-recognition

القطع المطلوبة

الأدوات التي سيتم استخدامها لهذا المشروع :

arduino-voice-recognition

Voice Recognition Module v3

arduino uno r3

Arduino Uno R3

arduino-voice-recognition

Pin Male Headers

 اسلاك توصيل أنثى/ذكر (Jumper Wires Female/male)

وحدة التعرف على الصوت (Voice Recognition ) :

وحدة Voice Recognition هي عبارة عن لوحة مدمجة سهله التحكم، تستخدم للتعرف على الصوت/ الكلام للتحكم في المشاريع المختلفة.

arduino-voice-recognition

لدى وحدة V3 القدرة على تخزين ما يصل إلى 80 أمرا صوتياً لكل منها مدة  1500 milliseconds  (اي ما يقارب كلمة أو كلمتين لكل امر). يتم تخزينها  في مجموعة واحدة كبيرة مثل المكتبة. ولكن خلال عملها لا تستطيع التمييز بين الـ 80 صوتا في نفس اللحظة، لذلك يتم استيراد/استدعاء سبعة أوامر صوتية في المكتبة إلى أداة التعرف(Recognizer) . وهذا يعني أن الحد الأقصى للأوامر الصوتية هي سبع أوامر فعالة في نفس الوقت.

arduino-voice-recognition

لا تقوم هذه الوحدة بتحويل الأمر إلى نص ولكن ستقوم بمقارنة الصوت القادم من الميكروفون بمجموعة من الأصوات المسجله مسبقا. لذلك من الناحية الفنية لا توجد حواجز لغوية لاستخدام هذا المنتج. يمكنك تسجيل الأمر بأي لغة .

كما انها تحتاج إلى تهيئة وتسجيل الأصوات أولاً قبل اعطاء الأوامر الصوتية للتحكم بالمشاريع.

تصميم لوح التجارب :

هناك طريقتان لإستخدام والتحكم بهذه الوحدة، أولا باستخدام  UART أو من خلال دبابيس GPIO  المدمجة. سيتم في هذا المشروع استخدام UART.

قم بتوصيل الدارة كما هو موضح بالصورة التالية :

arduino-voice-recognition
الاردوينووحدة Voice Recognition
5v5v
2Tx
3Rx
GNDGND

 

تهيئة وحدة التعرف على الصوت (Voice Recognition )

ليتم  برمجة وحدة Voice Recognition ، والتحكم بالمختلف المشاريع عبر الأوامر الصوتية، قم بإتباع التالي :

– أولا قم بتثبيت Arduino IDE  على جهازك، يمكنك الاطلاع على درس تنصيب الأردوينو على جهازك .
– ثم قم بتنزيل مكتبة VoiceRecognitionV3  (قم بتنزيل ملف zip أو استخدم git clone https://github.com/elechouse/VoiceRecognitionV3.git command )
في حالة استخدام ملف zip ، قم باستخراج VoiceRecognitionV3.zip  إلى اردوينو Sketch\libraries ، وإذا استخدمت   gitclonecommand  قم بنسخ VoiceRecognitionV3  إلى ArduinoSketch\libraries .

  تحتاج الوحدة إلى تهئية وتخزين الأوامر الصوتية ثم استدعائها، قم بإتباع الخطوات التالية :

 1. فتح كود  File -> Examples -> VoiceRecognitionV3 -> vr_sample_train) vr_sample_train).
2. اختيار لوحة التحكم الصحيحة (Tool -> Board, UNO recommended ) ، ثم اختيار المنفذ الصحيح.
3. رفع الكود إلى لوحة الأردوينو.
4. بعد ذلك يتم فتح الشاشة التسلسلية (Serial Monitor) . واختيار الـ Baund rate = 115200  ، وتحديد الإرسال مع Newline أو Both NL & CR

 arduino-voice-recognition
الأوامر الخاصة بوحدة الـ Voice Recognition :

يتم التحقق من إعدادات وحدة الـ Voice Recognition من خلال الأمر settings ثم الضغط على ارسال send او على مفتاح Enter  .

arduino-voice-recognition

يتم تسجيل وتخزين الأوامر الصوتية على وحدة Voice Recognition بإسم معين، من خلال ادخال الأمر sigtrain 0 On ثم الضغط على ارسال send او على مفتاح Enter  :

arduino-voice-recognition

بعد ادخال الأمر السابق والضغط على ارسال send، عند طباعة “Speak now” على الشاشة التسلسلية (Serial Monitor)  ، انت بحاجة إلى نطق أمر بصوتك ( يمكنك قول اي كلمة ، يوصى باستخدام كلمات ذات صلة بالمشروع ، هنا ستكون كلمة الأمر الصوتي هو “ON” )، عند طباعة “Speak again”  على الشاشة التسلسلية (Serial Monitor) ، تحتاج إلى إعادة نطق الأمر الصوتي مرة اخرى.

إذا تمت مطابقة هذين الصوتين، سيتم طباعة “Success” على الشاشة التسلسلية (Serial Monitor), ويتم تخزين الأمر الصوتي في سجل  0 “record 0” ,  وإذا لم يتم التطابق، فكرر نطق الكلام حتى تنجح العملية.

arduino-voice-recognition

بعد ذلك نقوم بإرسال الأمر sigtrain1Off للتخزين على السجل 1 ( record 1)  مع اسم “Off” . قم بنطق كلماتك التي ترغب باستخدامها لإيقاف الـ LED .

arduino-voice-recognition

عند ارسال الأمر load 0 1 يتم استدعاء/تحميل الأوامر الصوتيه للسجل 0 و 1. كما ذكرنا مسبقا يمكنك استدعاء سبعة أصوات في نفس اللحظة.

arduino-voice-recognition

الآن يمكنك نطق الكلمات التي تم تسجيلها واختبار ما إذا تم التعرف على الصوت. يمكنك أن ترى التالي على الشاشة التسلسلية :

arduino-voice-recognition

 

برمجة الأردوينو

هنا نقوم بعرض مثال بسيط يوضح كيفية التحكم بالـ LED المدمج على لوحة الـ Arduino (الـ LED الموصل على المنفذ الرقمي 13) من خلال الأوامر الصوتية. في هذا المثال تحتاج إلى تهيئة وحدة التعرف على الاصوات أولاً (تم عرض الطريقة في الخطوة السابقة) . سيتم استخدام الأوامر التالية :

– تخزين امر صوتي لإستخدامه في تشغيل الـ LED من خلال الأمر sigtrain 0 on .
– تخزين امر صوتي لإستخدامه في إيقاف الـ LED من خلال الأمر sigtrain 1 off .

الآن نقوم بفتح الملف vr_sample_control_led  (File -> Examples -> VoiceRecognitionV3 -> vr_sample_control_led) ، والذي يحتوي على كود أدناه للتحكم بالـ LED .

#include 
#include "VoiceRecognitionV3.h"

VR myVR(2,3);    // 2:RX 3:TX, you can choose your favourite pins.

uint8_t records[7]; // save record
uint8_t buf[64];

int led = 13;

#define onRecord    (0)
#define offRecord   (1) 

void printSignature(uint8_t *buf, int len)
{
  int i;
  for(i=0; i<len; i++){ 
    if(buf>0x19 && buf<0x7F){ 
      Serial.write(buf); 
     } 
    else{ 
      Serial.print("["); 
      Serial.print(buf, HEX); 
      Serial.print("]"); 
    } 
  } 
} 
/** @brief Print signature, if the character is invisible, print hexible value instead. @param buf -->  VR module return value when voice is recognized.
             buf[0]  -->  Group mode(FF: None Group, 0x8n: User, 0x0n:System
             buf[1]  -->  number of record which is recognized. 
             buf[2]  -->  Recognizer index(position) value of the recognized record.
             buf[3]  -->  Signature length
             buf[4]~buf[n] --> Signature
*/
void printVR(uint8_t *buf)
{
  Serial.println("VR Index\tGroup\tRecordNum\tSignature");

  Serial.print(buf[2], DEC);
  Serial.print("\t\t");

  if(buf[0] == 0xFF){
    Serial.print("NONE");
  }
  else if(buf[0]&0x80){
    Serial.print("UG ");
    Serial.print(buf[0]&(~0x80), DEC);
  }
  else{
    Serial.print("SG ");
    Serial.print(buf[0], DEC);
  }
  Serial.print("\t");

  Serial.print(buf[1], DEC);
  Serial.print("\t\t");
  if(buf[3]>0){
    printSignature(buf+4, buf[3]);
  }
  else{
    Serial.print("NONE");
  }
  Serial.println("\r\n");
}

void setup()
{
  /** initialize */
  myVR.begin(9600);
  
  Serial.begin(115200);
  Serial.println("Elechouse Voice Recognition V3 Module\r\nControl LED sample");
  
  pinMode(led, OUTPUT);
    
  if(myVR.clear() == 0){
    Serial.println("Recognizer cleared.");
  }else{
    Serial.println("Not find VoiceRecognitionModule.");
    Serial.println("Please check connection and restart Arduino.");
    while(1);
  }
  
  if(myVR.load((uint8_t)onRecord) >= 0){
    Serial.println("onRecord loaded");
  }
  
  if(myVR.load((uint8_t)offRecord) >= 0){
    Serial.println("offRecord loaded");
  }
}

void loop()
{
  int ret;
  ret = myVR.recognize(buf, 50);
  if(ret>0){
    switch(buf[1]){
      case onRecord:
        /** turn on LED */
        digitalWrite(led, HIGH);
        break;
      case offRecord:
        /** turn off LED*/
        digitalWrite(led, LOW);
        break;
      default:
        Serial.println("Record function undefined");
        break;
    }
    /** voice recognized */
    printVR(buf);
  }
}

شرح الـ Code  :

اولا يتم انشاء متغير led يحتوي على المنفذ 13 الخاص بالـ led المدمج بلوحة الاردوينو.

int led = 13;

  ثم يتم تعريف اثنين من السجلات الأول  onrecord ( لتشغلي الـ   LED ) و  offrecord(لإيقاف تشغيل الـ LED ) .  قم بتغير قيمة السجلات حسب العنوان/الرقم الذي تم تخزين أوامر التشغيل والايقاف عليها. في هذا المشروع تم استخدام السجل رقم 0 و 1.

#define onRecord (0) 
#define offRecord (1) 

 في الـ ()setup ،نقوم بتهيئة وحدة  Voice Recognition ، والشاشة التسلسلية .

myVR.begin(9600); 
Serial.begin(115200); 
Serial.println("Elechouse Voice Recognition V3 Module\r\nControl LED sample");

تهيئة المنفذ الموصل بالـ LED كمخرج .

pinMode(led, OUTPUT);

التحقق ما إذا تم توصيل وحدة التعرف على الصوت بشكل صحيح إلى الأردوينو.

if(myVR.clear() == 0){ 
Serial.println("Recognizer cleared."); 
}
else{ 
Serial.println("Not find VoiceRecognitionModule."); 
Serial.println("Please check connection and restart Arduino."); 
while(1); 
}

استيراد/نسخ الأمر الصوتي الموجود في السجل 0 (onRecord) إلى recognizer .

if(myVR.load((uint8_t)onRecord) >= 0){ 
Serial.println("onRecord loaded"); 
}

استيراد/نسخ الأمر الصوتي الموجود في السجل 1 (offRecord) إلى recognizer .

if(myVR.load((uint8_t)offRecord) >= 0){ 
Serial.println("offRecord loaded");
}

في ()loop، نقوم بمحاولة استقبال الصوت من الميكروفون مع تحديد قيمة مهلة الانتظار timeout

int ret; 
ret = myVR.recognize(buf, 50);

يحتوي buf[1] على رقم السجل الذي تم مطابقته مع السجلات التي تم نسخها على recognizer. لذالك نقوم بمقارنته من السجلات التي تم انشائها onRecord و offRecord، واعتمادا على النتيجة نقوم بالتحكم بالـ LED.

switch(buf[1]){ 
case onRecord: 
/** turn on LED */ 
digitalWrite(led, HIGH); 
break; 
case offRecord: 
/** turn off LED*/ 
digitalWrite(led, LOW); 
break; 
default: 
Serial.println("Record function undefined"); 
break; 
}

وأخيراً، يتم استدعاء دالة printVR و دالة printSignature ليتم طباعة النتيجة والسجلات التي تم التطابق معها.

عند رفع الكود على الأردوينو والبدء بالتحدث سيتم طباعة التالي على الشاشة التسلسلية  :

arduino-voice-recognition

قياس مستوى الصوت باستخدام الاردوينو

 في هذا المشروع سنقوم بتعلم كيفية استخدام الأردوينو لقياس مستوى الصوت، وسيتم توضيح مستوى الصوت على مجموعة من الـ LEDs.

المكونات المطلوبة

arduino uno r3

Arduino Uno

Electret Microphone

10K Ohm Potentiometer

LM386

Capacitor 10uF 50V

100nF capacitor

Red LED

 

220 Ω resistor

220 Ohm Resistor

10K Ohm Resistor

Full size breadboard 830

Breadboard

Breadboard Jumper Wire 65 pcs

Wires

 

LM386 :

هو عبارة عن دارة متكاملة تحتوي على مكبر عمليات (Operational Amplifier) ،يقوم بتكبير الاشارة الصوتية القادمة اليه من المايكروفون

نقوم بقراءة هذه الإشارة الصوتية بعد تكبيرها عن طريق الأردوينو، الذي بدوره يقوم بتشغيل الـ LEDs حسب شدة الإشارة الصوتية.

توصيل الدارة

قم بتوصيل الدارة كما هو موضح بالصورة التالية :

قياس مستوى الصوت باستخدام الاردوينو

سنقوم ببرمجة الأردوينو بحيث يقوم بقراءة الإشارة الصوتية التي يلتقطها المايكروفون بعد تكبيرها من خلال LM386، ثم يوضح شدة الصوت على مجموعة من الـ LEDs.

قياس مستوى الصوت باستخدام الاردوينو

 

الكود البرمجي

#define LED1 3
#define LED2 4
#define LED3 5
#define LED4 6
#define LED5 7
#define LED6 8

int value;

void setup()
{
  //set pins attached to LEDs as outputs
  pinMode(LED1,OUTPUT);
  pinMode(LED2,OUTPUT);
  pinMode(LED3,OUTPUT);
  pinMode(LED4,OUTPUT);
  pinMode(LED5,OUTPUT);
  pinMode(LED6,OUTPUT);
}

void loop()
{
  value = analogRead(5); 
  
  //glow the LEDs depending on the ammount of sound detected by the electret  
  if (value > 455 && value <555)
  {//glow first LED
    Clear(4);
    Glow(4);
  } 
  else if (value > 378 && value < 624)
  {//glow 2nd LED
    Clear(5);
    Glow(5);
  }
  else if (value > 311 && value < 693)
  {//glow 3rd LED
    Clear(6);
    Glow(6);
  }
  else if (value > 244 && value < 762)
  {//glow 4th LED
    Clear(7);
    Glow(7);
  }
  else if (value > 177 && value < 831)
  {//glow 5th LED
    Clear(8);
    Glow(8);
  }
  else if (value < 177 || value > 831)
  {//glow 6th LED
    Clear(9);
    Glow(9);
  }
  
}

void Glow(int initial)//function to glow LEDs
{
  for(int i=3;i<initial;i++)	digitalWrite(i,HIGH);
}

void Clear(int initial)//function to clear LEDs
{
  for(int i=initial;i<9;i++)	digitalWrite(i,LOW);
}

شرح الكود :

في البداية نقوم بتسمية منافذ الأردوينو المستخدمة في المشروع. ونقوم بالإعلان عن المتغير value الذي سيستخدم في تخزين قيمة قراءة الإشارة الصوتية :

#define LED1 3
#define LED2 4
#define LED3 5
#define LED4 6
#define LED5 7
#define LED6 8

int value;

في الدلة ()setup ، نقوم بضبط الإعدادات اللازمة مثل ضبط المنافذ الموصله مع الـ LEDs كمخرج :

void setup()
{
  //set pins attached to LEDs as outputs
  pinMode(LED1,OUTPUT);
  pinMode(LED2,OUTPUT);
  pinMode(LED3,OUTPUT);
  pinMode(LED4,OUTPUT);
  pinMode(LED5,OUTPUT);
  pinMode(LED6,OUTPUT);
}

في الدالة ()loop ، نقوم بقراءة الإشارة الصوتية الناتجة عن المايكروفون بعد تكبيرها بواسطة LM386 :

value = analogRead(5);

بعد ذلك نقوم بإختبار القيمة المقاسه وإعتمادا على هذه القيمة نقوم بإضاءة الـ LEDs بإستخدام الدالتين Clear وGlow للتعبر عن مدى ارتفاع أو انخفاض شدة الإشارة الصوتية :

  if (value > 455 && value <555)
  {//glow first LED
    Clear(4);
    Glow(4);
  } 
  else if (value > 378 && value < 624)
  {//glow 2nd LED
    Clear(5);
    Glow(5);
  }
  else if (value > 311 && value < 693)
  {//glow 3rd LED
    Clear(6);
    Glow(6);
  }
  else if (value > 244 && value < 762)
  {//glow 4th LED
    Clear(7);
    Glow(7);
  }
  else if (value > 177 && value < 831)
  {//glow 5th LED
    Clear(8);
    Glow(8);
  }
  else if (value < 177 || value > 831)
  {//glow 6th LED
    Clear(9);
    Glow(9);
  }

نستخدم الدالة Glow لإضاءة الـ LEDs تدريجيا حسب قيمة شدة الصوت :

void Glow(int initial)//function to glow LEDs
{
  for(int i=3;i<initial;i++)	digitalWrite(i,HIGH);
}

نستخدم الدالة Clear لإطفاء الـ LEDs تدريجيا حسب قيمة شدة الصوت :

void Clear(int initial)//function to clear LEDs
{
  for(int i=initial;i<9;i++)	digitalWrite(i,LOW);
}

استخدام شاشة Nokia 5110 مع الاردوينو

في هذا المشروع سنتعلم كيفية استخدام شاشة Nokia 5110 مع الأردوينو لعرض صور ثابتة ومتحركة، وأيضا عرض الكلمات التي يتم ارسالها عن طريق الحاسوب.

استخدام شاشة جرافيك مع الاردوينو (Nokia 5110)

 

المكونات المطلوبة

arduino uno r3

Arduino Uno

nokia screen 5110

Nokia Screen 5110

220 Ω resistor

220 Ohm Resistor

 

Full size breadboard 830

Breadboard

Breadboard Jumper Wire 65 pcs

Wires

Nokia Screen 5110

تستخدم هذه الشاشة في العديد من التطبيقات، حيث كانت تستخدم في الهواتف النقالة . ويتم التحكم بها من خلال الإتصال عبر بروتوكول SPI، فهو وسيلة للربط بين المتحكمات والأجهزة الطرفية.

nokia screen 5110

كما يمكننها التحكم بها على مستوى الـ Pixels، اي انها تعطي مرونة عالية للكتابة أو الرسم عليها.

توصيلها مع الأردوينو :

هذة الشاشة تستخدم برتوكول SPI، ببساطة هو عبارة عن وسيلة لربط الاردوينو باجهزة اخرى مثل الشاشة في حالتنا. فيمكننا من ارسال البيانات اليها والتحكم فى تشغيلها من خلال هذا البروتوكول. لذلك لابد من توصيلها على منافذ الأردوينو المخصصة لذلك البروتوكول.

توصيل الدارة

نقوم بتوصيل الشاشة بالاردوينو باستخدام برتوكول الـ SPI ، ثم نقوم بإرسال الاوامر والبيانات اللازمة لعرض الصور بالشكل الذي نريده عن طريق الاردوينو.

قم بتوصيل الدارة كما هو موضح بالصورة التالية :

استخدام شاشة جرافيك مع الاردوينو (Nokia 5110)

يعمل هذا البروتوكول على ارجل محددة فى الاردوينو لذلك لا يمكننا تغيير المنافذ المستخدمة لذلك  تم توصيل الشاشة مع الأردوينو كما هو موضح بالجدول :

الطرف (بداية من اليسار)التوصيل
1Arduino Pin 6
2Arduino Pin 7
3Arduino Pin 5
4 Arduino Pin 11
5 Arduino Pin 13
6 3.3v
7 Arduino Pin 4
8 GND

سنقوم بعمل برنامج يقوم في البداية بتشغيل الصور الثابتة والمتحركة، ثم يتوقف على صورة معينة منتظرا ادخال المستخدم لرسالة ما من خلال الشاشة التسلسلية (Serial Monitor)، ليقوم بعرضها على الشاشة.

استخدام شاشة جرافيك مع الاردوينو (Nokia 5110)

البرمجة

في البداية، نقوم بإدراج المكتبة الخاصة بالـ SPI حتى نتمكن من استخدامه :

#include <SPI.h>

ثم نقوم بتسمية بعض الثوابت المستخدمة في إرسال الأوامر إلى الشاشة :

#define LCD_COMMAND  0 
#define LCD_DATA     1
#define LCD_WIDTH   84 
#define LCD_HEIGHT  48 
#define WHITE       0 
#define BLACK       1 

بعد ذلك نقوم بتمسية منافذ الأردوينو المستخدمة في توصيل الشاشة :

const int scePin = 7;   // SCE - Chip select, pin 3 on LCD.
const int rstPin = 6;   // RST - Reset, pin 4 on LCD.
const int dcPin = 5;    // DC - Data/Command, pin 5 on LCD.
const int sdinPin = 11;  // DN(MOSI) - Serial data, pin 6 on LCD.
const int sclkPin = 13;  // SCLK - Serial clock, pin 7 on LCD.
const int blPin = 9;    // LED - Backlight LED, pin 8 on LCD.

بعد ذلك قمنا بعمل مصفوفة تحتوي على قيم الحروف والرموز والأرقام الممثلة بصيغة الـ ASCII ، وهي طريقة قياسية لتمثيل الحروف والأقام وبعض الرموز. فعند عرض الحرف a فإن القيمة المكافئة له تساوي 0x16 وهكذا.

static const byte ASCII[][5] = {
   {0x00, 0x00, 0x00, 0x00, 0x00} // 0x20  
  ,{0x00, 0x00, 0x5f, 0x00, 0x00} // 0x21 !
  ,{0x00, 0x07, 0x00, 0x07, 0x00} // 0x22 "
  ,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 0x23 #
  ,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 0x24 $
  ,{0x23, 0x13, 0x08, 0x64, 0x62} // 0x25 %
  ,{0x36, 0x49, 0x55, 0x22, 0x50} // 0x26 &
  ,{0x00, 0x05, 0x03, 0x00, 0x00} // 0x27 '
  ,{0x00, 0x1c, 0x22, 0x41, 0x00} // 0x28 (
  ,{0x00, 0x41, 0x22, 0x1c, 0x00} // 0x29 )
  ,{0x14, 0x08, 0x3e, 0x08, 0x14} // 0x2a *
  ,{0x08, 0x08, 0x3e, 0x08, 0x08} // 0x2b +
  ,{0x00, 0x50, 0x30, 0x00, 0x00} // 0x2c ,
  ,{0x08, 0x08, 0x08, 0x08, 0x08} // 0x2d -
  ,{0x00, 0x60, 0x60, 0x00, 0x00} // 0x2e .
  ,{0x20, 0x10, 0x08, 0x04, 0x02} // 0x2f /
  ,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 0x30 0
  ,{0x00, 0x42, 0x7f, 0x40, 0x00} // 0x31 1
  ,{0x42, 0x61, 0x51, 0x49, 0x46} // 0x32 2
  ,{0x21, 0x41, 0x45, 0x4b, 0x31} // 0x33 3
  ,{0x18, 0x14, 0x12, 0x7f, 0x10} // 0x34 4
  ,{0x27, 0x45, 0x45, 0x45, 0x39} // 0x35 5
  ,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 0x36 6
  ,{0x01, 0x71, 0x09, 0x05, 0x03} // 0x37 7
  ,{0x36, 0x49, 0x49, 0x49, 0x36} // 0x38 8
  ,{0x06, 0x49, 0x49, 0x29, 0x1e} // 0x39 9
  ,{0x00, 0x36, 0x36, 0x00, 0x00} // 0x3a :
  ,{0x00, 0x56, 0x36, 0x00, 0x00} // 0x3b ;
  ,{0x08, 0x14, 0x22, 0x41, 0x00} // 0x3c 
  ,{0x02, 0x01, 0x51, 0x09, 0x06} // 0x3f ?
  ,{0x32, 0x49, 0x79, 0x41, 0x3e} // 0x40 @
  ,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 0x41 A
  ,{0x7f, 0x49, 0x49, 0x49, 0x36} // 0x42 B
  ,{0x3e, 0x41, 0x41, 0x41, 0x22} // 0x43 C
  ,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 0x44 D
  ,{0x7f, 0x49, 0x49, 0x49, 0x41} // 0x45 E
  ,{0x7f, 0x09, 0x09, 0x09, 0x01} // 0x46 F
  ,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 0x47 G
  ,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 0x48 H
  ,{0x00, 0x41, 0x7f, 0x41, 0x00} // 0x49 I
  ,{0x20, 0x40, 0x41, 0x3f, 0x01} // 0x4a J
  ,{0x7f, 0x08, 0x14, 0x22, 0x41} // 0x4b K
  ,{0x7f, 0x40, 0x40, 0x40, 0x40} // 0x4c L
  ,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 0x4d M
  ,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 0x4e N
  ,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 0x4f O
  ,{0x7f, 0x09, 0x09, 0x09, 0x06} // 0x50 P
  ,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 0x51 Q
  ,{0x7f, 0x09, 0x19, 0x29, 0x46} // 0x52 R
  ,{0x46, 0x49, 0x49, 0x49, 0x31} // 0x53 S
  ,{0x01, 0x01, 0x7f, 0x01, 0x01} // 0x54 T
  ,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 0x55 U
  ,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 0x56 V
  ,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 0x57 W
  ,{0x63, 0x14, 0x08, 0x14, 0x63} // 0x58 X
  ,{0x07, 0x08, 0x70, 0x08, 0x07} // 0x59 Y
  ,{0x61, 0x51, 0x49, 0x45, 0x43} // 0x5a Z
  ,{0x00, 0x7f, 0x41, 0x41, 0x00} // 0x5b [
  ,{0x02, 0x04, 0x08, 0x10, 0x20} // 0x5c \
  ,{0x00, 0x41, 0x41, 0x7f, 0x00} // 0x5d ]
  ,{0x00, 0x41, 0x41, 0x7f, 0x00} // 0x5d ]
  ,{0x04, 0x02, 0x01, 0x02, 0x04} // 0x5e ^
  ,{0x40, 0x40, 0x40, 0x40, 0x40} // 0x5f _
  ,{0x00, 0x01, 0x02, 0x04, 0x00} // 0x60 `
  ,{0x20, 0x54, 0x54, 0x54, 0x78} // 0x61 a
  ,{0x7f, 0x48, 0x44, 0x44, 0x38} // 0x62 b
  ,{0x38, 0x44, 0x44, 0x44, 0x20} // 0x63 c
  ,{0x38, 0x44, 0x44, 0x48, 0x7f} // 0x64 d
  ,{0x38, 0x54, 0x54, 0x54, 0x18} // 0x65 e
  ,{0x08, 0x7e, 0x09, 0x01, 0x02} // 0x66 f
  ,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 0x67 g
  ,{0x7f, 0x08, 0x04, 0x04, 0x78} // 0x68 h
  ,{0x00, 0x44, 0x7d, 0x40, 0x00} // 0x69 i
  ,{0x20, 0x40, 0x44, 0x3d, 0x00} // 0x6a j 
  ,{0x7f, 0x10, 0x28, 0x44, 0x00} // 0x6b k
  ,{0x00, 0x41, 0x7f, 0x40, 0x00} // 0x6c l
  ,{0x7c, 0x04, 0x18, 0x04, 0x78} // 0x6d m
  ,{0x7c, 0x08, 0x04, 0x04, 0x78} // 0x6e n
  ,{0x38, 0x44, 0x44, 0x44, 0x38} // 0x6f o
  ,{0x7c, 0x14, 0x14, 0x14, 0x08} // 0x70 p
  ,{0x08, 0x14, 0x14, 0x18, 0x7c} // 0x71 q
  ,{0x7c, 0x08, 0x04, 0x04, 0x08} // 0x72 r
  ,{0x48, 0x54, 0x54, 0x54, 0x20} // 0x73 s
  ,{0x04, 0x3f, 0x44, 0x40, 0x20} // 0x74 t
  ,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 0x75 u
  ,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 0x76 v
  ,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 0x77 w
  ,{0x44, 0x28, 0x10, 0x28, 0x44} // 0x78 x
  ,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 0x79 y
  ,{0x44, 0x64, 0x54, 0x4c, 0x44} // 0x7a z
  ,{0x00, 0x08, 0x36, 0x41, 0x00} // 0x7b {
  ,{0x00, 0x00, 0x7f, 0x00, 0x00} // 0x7c |
  ,{0x00, 0x41, 0x36, 0x08, 0x00} // 0x7d }
  ,{0x10, 0x08, 0x08, 0x10, 0x08} // 0x7e ~
  ,{0x78, 0x46, 0x41, 0x46, 0x78} // 0x7f DEL
};

بعد ذلك نقوم بالإعلان عن المصفوفة displayMap ، وهي تمثل الـ Pixels الموجودة في الشاشة. فعند وضع قيمة 0 في إحدى قيم المصفوفة، نقوم بذلك بإطفاء الـ Pixel المكافئة له على الشاشة. وعند وضع قيمة 255 نقوم بإضاءة الـ Pixel المكافئة :

byte displayMap[LCD_WIDTH * LCD_HEIGHT / 8] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0,
  0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, 0xFE, 0x1E, 0x0E, 0x02, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
  0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF8,
  0xF8, 0xF0, 0xF8, 0xFE, 0xFE, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xF8, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xF3, 0xE0, 0xE0, 0xC0, 
  0xC0, 0xC0, 0xE0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 
  0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03,
  0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};

نقوم بإنشاء مصفوفة xkcdSandwich التي يقوم الأردوينو بإرسالها إلى الشاشة فتقوم برسم صورة معينة سنراها عندما نكمل كتابة الكود ويتم رفعه إلى الأردوينو :

char xkcdSandwich[504] = {
0xFF, 0x8D, 0x9F, 0x13, 0x13, 0xF3, 0x01, 0x01, 0xF9, 0xF9, 0x01, 0x81, 0xF9, 0xF9, 0x01, 0xF1,
0xF9, 0x09, 0x09, 0xFF, 0xFF, 0xF1, 0xF9, 0x09, 0x09, 0xF9, 0xF1, 0x01, 0x01, 0x01, 0x01, 0x01,
0xF9, 0xF9, 0x09, 0xF9, 0x09, 0xF9, 0xF1, 0x01, 0xC1, 0xE9, 0x29, 0x29, 0xF9, 0xF1, 0x01, 0xFF,
0xFF, 0x71, 0xD9, 0x01, 0x01, 0xF1, 0xF9, 0x29, 0x29, 0xB9, 0xB1, 0x01, 0x01, 0x01, 0xF1, 0xF1,
0x11, 0xF1, 0xF1, 0xF1, 0xE1, 0x01, 0xE1, 0xF1, 0x51, 0x51, 0x71, 0x61, 0x01, 0x01, 0xC1, 0xF1,
0x31, 0x31, 0xF1, 0xFF, 0xFF, 0x00, 0x01, 0x01, 0x01, 0x01, 0x60, 0xE0, 0xA0, 0x01, 0x01, 0x81,
0xE1, 0x61, 0x60, 0xC0, 0x01, 0xE1, 0xE1, 0x21, 0x21, 0xE0, 0xC1, 0x01, 0xC1, 0xE1, 0x20, 0x20,
0xFC, 0xFC, 0xE0, 0xE0, 0xC1, 0xE1, 0xE0, 0xC1, 0xE0, 0xE1, 0x01, 0xFC, 0xFC, 0x21, 0x21, 0xE1,
0xC1, 0xE5, 0xE4, 0x01, 0xC1, 0xE0, 0x20, 0x21, 0x20, 0x00, 0x01, 0xFD, 0xFD, 0x21, 0x20, 0xE0,
0x00, 0x00, 0x01, 0x01, 0xC0, 0x61, 0x31, 0x31, 0x21, 0x20, 0xC0, 0x81, 0x01, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02,
0x03, 0x01, 0x00, 0x01, 0x03, 0xF2, 0x1A, 0x0B, 0x08, 0x0B, 0x1B, 0x10, 0x60, 0xE3, 0x03, 0x00,
0x01, 0x03, 0x02, 0x02, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x03,
0x03, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x00, 0x01, 0x03, 0x02, 0x02, 0x03, 0x01, 0x00, 0x03,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x80, 0x80, 0x80, 0x80, 0x60, 0x3F, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x01, 0x01, 0x02, 0x03, 0x3E, 0xE8, 0xF8, 0xF0, 0xD0, 0x90,
0x18, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x38, 0xFF,
0x0C, 0x38, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
0x5F, 0x8F, 0x84, 0x05, 0x07, 0x06, 0x0C, 0x0E, 0x0E, 0x0C, 0x14, 0x34, 0x68, 0x88, 0xD8, 0x70,
0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x10, 0x10, 0x10, 0xF0, 0xE0, 0x00, 0xF0, 0xF0, 0x00, 0x80,
0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x20, 0x38,
0x0E, 0x01, 0xC0, 0x3F, 0xE0, 0x00, 0x00, 0x03, 0x0E, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xB6, 0xED, 0xC0, 0xC0,
0xC0, 0xE0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xE1, 0xE1, 0xC1,
0xEF, 0xBB, 0x83, 0x86, 0x88, 0xB0, 0x80, 0x80, 0x80, 0x8F, 0x90, 0x90, 0x90, 0x9F, 0x8F, 0x80,
0x9F, 0x9F, 0x87, 0x8D, 0x98, 0x80, 0x8C, 0x9E, 0x92, 0x92, 0x9F, 0xC0, 0xC7, 0xFF, 0xB8, 0x8F,
0x80, 0x90, 0x90, 0xC0, 0xF0, 0x8E, 0x81, 0x80, 0x81, 0x8F, 0xB8, 0xE0, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, 
};

في الدالة ()setup، نقوم بوضع الإعدادات اللازمة للمشروع مثل تشغيل الشاشة وضبط إعداداتها اللازمة مثل الوضوح وإظهار بعض الصور المتحركة.
وايضا نقوم بتشغيل الشاشة التسلسلية (Serial Monitor) التي سنستخدمها في إرسال الأحرف والكلمات لعرضها على الشاشة لاحقا. حيث سنقوم بالككتابه على الشاشة بعد أن تنتهي من عرض الصور المتحركة.

void setup()
{
  Serial.begin(9600);

  lcdBegin(); // This will setup our pins, and initialize the LCD
  setContrast(55); // Pretty good value, play around with it

  updateDisplay(); // with displayMap untouched, SFE logo
  delay(2000);

  lcdFunTime(); // Runs a 30-second demo of graphics functions

  // Wait for serial to come in, then clear display and go to echo
  while (!Serial.available())
    ;
  clearDisplay(WHITE);
  updateDisplay();
}

في الدله ()loop، تقوم بإنتظار المستخدم إدخال الحروف أو الكلمات إلى الشاشة التسلسلية (Serial Monitor) ، ليقوم الأردوينو بإرسالها إلى الشاشة ليتم كتابتها. نقوم بعمل إختبار على ماتم ادخاله من قبل المستخدم. فمثلا إذا ادخل المستخدم الرمز ~ فإنه عبارة عن أمر لمسح الشاشة.

void loop()
{
  static int cursorX = 0;
  static int cursorY = 0;

  if (Serial.available())
  {
    char c = Serial.read();

    switch (c)
    {
    case '\n': // New line
      cursorY += 8;
      break;
    case '\r': // Return feed
      cursorX = 0;
      break;
    case '~': // Use ~ to clear the screen.
      clearDisplay(WHITE);
      updateDisplay();
      cursorX = 0; // reset the cursor
      cursorY = 0;
      break;
    default:
      setChar(c, cursorX, cursorY, BLACK);
      updateDisplay();
      cursorX += 6; // Increment cursor
      break;
    }
    // Manage cursor
    if (cursorX >= (LCD_WIDTH - 4)) 
    { // If the next char will be off screen...
      cursorX = 0; // ... reset x to 0...
      cursorY += 8; // ...and increment to next line.
      if (cursorY >= (LCD_HEIGHT - 7))
      { // If the next line takes us off screen...
        cursorY = 0; // ...go back to the top.
      }
    }
  }
}

باقي الدوال المستخدمة متقدمة بعض الشئ، يكفي فقط أن تعرف أنها تقوم بإرسال البيانات إلى الشاشة بشكل معين لتتمكن من عرض الصور أو الكلمات. وهي الدوال المستخدمة داخل الدالتين ()setup، و ()loop .

إذا كنت تريد تغيير ما يظهر على الشاشة، فلا حاجة إلى تغيير هذه الدوال، فقط قم بعمل التغير الذي تريده داخل الداليتين ()loop، و ()setup.

void lcdFunTime()
{
  clearDisplay(WHITE); 
  randomSeed(analogRead(A0));
  const int pixelCount = 100;
  for (int i=0; i<pixelCount; i++)
  {
    setPixel(random(0, LCD_WIDTH), random(0, LCD_HEIGHT));
    updateDisplay();
    delay(10);
  }
  setStr("full of stars", 0, LCD_HEIGHT-8, BLACK);
  updateDisplay();
  delay(1000);
  for (int i=0; i<5; i++)
  {
    invertDisplay(); 
    delay(200);
    invertDisplay();
    delay(200);
  }
  delay(2000);
  clearDisplay(WHITE); 
  int x0 = LCD_WIDTH/2;
  int y0 = LCD_HEIGHT/2;
  for (float i=0; i<2*PI; i+=PI/8)
  {
    const int lineLength = 24;
    int x1 = x0 + lineLength * sin(i);
    int y1 = y0 + lineLength * cos(i);
    setLine(x0, y0, x1, y1, BLACK);
    updateDisplay();
    delay(100);
  }
  for (int j=0; j<2; j++)
  {
    for (int i=255; i>=0; i-=5)
    {
      analogWrite(blPin, i);
      delay(20);
    }
    for (int i=0; i<256; i+=5)
    {
      analogWrite(blPin, i);
      delay(20);
    }
  }
  clearDisplay(WHITE); 
  for (int x=0; x<LCD_WIDTH; x+=8)
  { 
    setRect(0, 0, x, LCD_HEIGHT, 1, BLACK);
    updateDisplay();
    delay(10);
  }
  for (int x=0; x<LCD_WIDTH; x+=8)
  { 
    setRect(0, 0, x, LCD_HEIGHT, 1, WHITE);
    updateDisplay();
    delay(10);
  }
  for (int x=0; x<12; x++)
  { 
    setRect(0, 0, x, LCD_HEIGHT, 1, 1);
    setRect(11, 0, x+12, LCD_HEIGHT, 1, BLACK);
    setRect(23, 0, x+24, LCD_HEIGHT, 1, BLACK);
    setRect(35, 0, x+36, LCD_HEIGHT, 1, BLACK);
    setRect(47, 0, x+48, LCD_HEIGHT, 1, BLACK);
    setRect(59, 0, x+60, LCD_HEIGHT, 1, BLACK);
    setRect(71, 0, x+72, LCD_HEIGHT, 1, BLACK);
    updateDisplay();
    delay(10);
  }
  setRect(25, 10, 45, 30, 0, WHITE);
  setRect(35, 20, 55, 40, 0, WHITE);
  setLine(25, 10, 35, 20, WHITE);
  setLine(45, 30, 55, 40, WHITE);
  setLine(25, 30, 35, 40, WHITE);
  setLine(45, 10, 55, 20, WHITE);
  updateDisplay();
  delay(2000);
  clearDisplay(WHITE);
  for (int i=0; i<20; i++)
  {
    int x = random(0, LCD_WIDTH);
    int y = random(0, LCD_HEIGHT);
    setCircle(x, y, i, BLACK, 1);
    updateDisplay();
    delay(100);
  }
  delay(2000);
  setStr("Modern Art", 0, 10, WHITE);
  updateDisplay();
  delay(2000);
  setBitmap(xkcdSandwich);
  updateDisplay();
}

void setPixel(int x, int y)
{
  setPixel(x, y, BLACK); 
}

void clearPixel(int x, int y)
{
  setPixel(x, y, WHITE); 
}

void setPixel(int x, int y, boolean bw)
{
  if ((x >= 0) && (x < LCD_WIDTH) && (y >= 0) && (y < LCD_HEIGHT))
  {
    byte shift = y % 8;

    if (bw) 
      displayMap[x + (y/8)*LCD_WIDTH] |= 1<<shift;
    else   
      displayMap[x + (y/8)*LCD_WIDTH] &= ~(1<<shift);
  }
}

void setLine(int x0, int y0, int x1, int y1, boolean bw)
{
  int dy = y1 - y0; // Difference between y0 and y1
  int dx = x1 - x0; // Difference between x0 and x1
  int stepx, stepy;
  if (dy < 0)
  {
    dy = -dy;
    stepy = -1;
  }
  else
    stepy = 1;

  if (dx < 0)
  {
    dx = -dx;
    stepx = -1;
  }
  else
    stepx = 1;

  dy <<= 1; 
  dx <<= 1; 
  setPixel(x0, y0, bw); 
  if (dx > dy) 
  {
    int fraction = dy - (dx >> 1);
    while (x0 != x1)
    {
      if (fraction >= 0)
      {
        y0 += stepy;
        fraction -= dx;
      }
      x0 += stepx;
      fraction += dy;
      setPixel(x0, y0, bw);
    }
  }
  else
  {
    int fraction = dx - (dy >> 1);
    while (y0 != y1)
    {
      if (fraction >= 0)
      {
        x0 += stepx;
        fraction -= dy;
      }
      y0 += stepy;
      fraction += dx;
      setPixel(x0, y0, bw);
    }
  }
}

void setRect(int x0, int y0, int x1, int y1, boolean fill, boolean bw)
{
  if (fill == 1)
  {
    int xDiff;

    if(x0 > x1)
      xDiff = x0 - x1; 
    else
      xDiff = x1 - x0;

    while(xDiff > 0)
    {
      setLine(x0, y0, x0, y1, bw);

      if(x0 > x1)
        x0--;
      else
        x0++;

      xDiff--;
    }
  }
  else 
  {
    setLine(x0, y0, x1, y0, bw);
    setLine(x0, y1, x1, y1, bw);
    setLine(x0, y0, x0, y1, bw);
    setLine(x1, y0, x1, y1, bw);
  }
}

void setCircle (int x0, int y0, int radius, boolean bw, int lineThickness)
{
  for(int r = 0; r < lineThickness; r++)
  {
    int f = 1 - radius;
    int ddF_x = 0;
    int ddF_y = -2 * radius;
    int x = 0;
    int y = radius;

    setPixel(x0, y0 + radius, bw);
    setPixel(x0, y0 - radius, bw);
    setPixel(x0 + radius, y0, bw);
    setPixel(x0 - radius, y0, bw);

    while(x < y)
    {
      if(f >= 0)
      {
        y--;
        ddF_y += 2;
        f += ddF_y;
      }
      x++;
      ddF_x += 2;
      f += ddF_x + 1;

      setPixel(x0 + x, y0 + y, bw);
      setPixel(x0 - x, y0 + y, bw);
      setPixel(x0 + x, y0 - y, bw);
      setPixel(x0 - x, y0 - y, bw);
      setPixel(x0 + y, y0 + x, bw);
      setPixel(x0 - y, y0 + x, bw);
      setPixel(x0 + y, y0 - x, bw);
      setPixel(x0 - y, y0 - x, bw);
    }
    radius--;
  }
}

void setChar(char character, int x, int y, boolean bw)
{
  byte column; 
  for (int i=0; i<5; i++) 
  {
    column = ASCII[character - 0x20];
    for (int j=0; j<8; j++) 
    {
      if (column & (0x01 << j)) 
        setPixel(x+i, y+j, bw);
      else
        setPixel(x+i, y+j, !bw);
    }
  }
}

void setStr(char * dString, int x, int y, boolean bw)
{
  while (*dString != 0x00) 
  {
    setChar(*dString++, x, y, bw);
    x+=5;
    for (int i=y; i<y+8; i++)
    {
      setPixel(x, i, !bw);
    }
    x++;
    if (x > (LCD_WIDTH - 5)) 
    {
      x = 0;
      y += 8;
    }
  }
}

void setBitmap(char * bitArray)
{
  for (int i=0; i<(LCD_WIDTH * LCD_HEIGHT / 8); i++)
    displayMap = bitArray;
}

void clearDisplay(boolean bw)
{
  for (int i=0; i<(LCD_WIDTH * LCD_HEIGHT / 8); i++)
  {
    if (bw)
      displayMap = 0xFF;
    else
      displayMap = 0;
  }
}

void gotoXY(int x, int y)
{
  LCDWrite(0, 0x80 | x);  
  LCDWrite(0, 0x40 | y);  
}

void updateDisplay()
{
  gotoXY(0, 0);
  for (int i=0; i < (LCD_WIDTH * LCD_HEIGHT / 8); i++)
  {
    LCDWrite(LCD_DATA, displayMap);
  }
}

void setContrast(byte contrast)
{  
  LCDWrite(LCD_COMMAND, 0x21);
  LCDWrite(LCD_COMMAND, 0x80 | contrast); 
  LCDWrite(LCD_COMMAND, 0x20);
}

void invertDisplay()
{
  
  LCDWrite(LCD_COMMAND, 0x20);
  LCDWrite(LCD_COMMAND, 0x08 | 0x05); 
  LCDWrite(LCD_COMMAND, 0x20); 
  for (int i=0; i < (LCD_WIDTH * LCD_HEIGHT / 8); i++)
  {
    displayMap = ~displayMap & 0xFF;
  }
  updateDisplay();
}

void LCDWrite(byte data_or_command, byte data) 
{
  digitalWrite(dcPin, data_or_command); 
  digitalWrite(scePin, LOW);
  SPI.transfer(data); //shiftOut(sdinPin, sclkPin, MSBFIRST, data);
  digitalWrite(scePin, HIGH);
}

void lcdBegin(void) 
{
  pinMode(scePin, OUTPUT);
  pinMode(rstPin, OUTPUT);
  pinMode(dcPin, OUTPUT);
  pinMode(sdinPin, OUTPUT);
  pinMode(sclkPin, OUTPUT);
  pinMode(blPin, OUTPUT);
  analogWrite(blPin, 255);

  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);
  digitalWrite(rstPin, LOW);
  digitalWrite(rstPin, HIGH);

  LCDWrite(LCD_COMMAND, 0x21); 
  LCDWrite(LCD_COMMAND, 0xB0); 
  LCDWrite(LCD_COMMAND, 0x04); 
  LCDWrite(LCD_COMMAND, 0x14);
  LCDWrite(LCD_COMMAND, 0x20); 
  LCDWrite(LCD_COMMAND, 0x0C);
}

 

استخدام الاردوينو في قياس الجهود الكهربائية

في هذا المشروع سنتعلم كيفية استخدام الاردوينو لقياس الجهود الكهربائية. يمكن استخدام هذه الفكرة لعمل Digital Voltameter أو جهاز لمعرفة حالة البطارية.

Voltameter: استخدام الاردوينو فى قياس الجهود الكهربية

 

المكونات المطلوبة

arduino uno r3

Arduino Uno

 

10K Ohm Resistor

 

1k Ohm Resistor

 

Full size breadboard 830

Breadboard

Breadboard Jumper Wire 65 pcs

Wires

شرح الدارة

تعتمد الدارة على مبدا تقسيم الجهد Voltage Divider في حساب الجهد المراد قياسه.

Servo Motor: استخدام مقاومة متغيرة للتحكم فى حركة محرك سيرفو

مثلا، لقياس الجهد على المقاومة R2 :

V(R2) = Vcc * R2 / (R1 + R2)

ملاحظة : مدى الجهود التى يمكن قياسها من 0 الى 5 فولت

توصيل الدارة :

قم بتوصيل الدارة كما هو مبين بالشكل التالي :

Voltameter: استخدام الاردوينو فى قياس الجهود الكهربية

Voltameter: استخدام الاردوينو فى قياس الجهود الكهربية

سيتم قياس جهد ما عن طريق توصيل طرفى القياس على الجهد المراد. لذلك، سنقوم بكتابه برنامج بحيث يتم تشغيل الشاشة التسلسلية Serial monitor لعرض الجهد المقاس عليها.

Voltameter: استخدام الاردوينو فى قياس الجهود الكهربية

 

الكود البرمجي

// Max Voltage ( reference voltage ) 
float vPow = 5.0; 
// first resistor 10K ohm 
float r1 = 10000; 
// second resistor 1k Ohm 
float r2 = 1000;

void setup() {
 Serial.begin(9600);
 Serial.println("--------------------");
 Serial.println("DC VOLTMETER");
 Serial.print("Maximum Voltage: ");
 Serial.print((int)(vPow / (r1 / (r1 + r2))));
 Serial.println("V");
 Serial.println("--------------------");
 Serial.println("");
 
 delay(2000);   //wait 2000 ms before starting
}

void loop() {
 float v = (analogRead(0) * vPow) / 1024.0;
 float v2 = v / (r1 / (r1 + r2));
 
 Serial.print("Voltage (Volts) = ");
 Serial.println(v2);
}

شرح الكود :

في البداية نقوم بالإعلان عن المتغيرات التي سيتم استخدامها في البرمجة. سيتم استخدام المتغير vPow لتسجيل قيمة الجهد المرجعي المستخدم في هذه الحالة 5 فولت. والمتغير r1 لتسجيل قيمة المقاومة الأولى المستخدمة في الـ Voltage Divider . والمتغير r2 لتسجيل قيمة المقاومة الثانية المستخدمة في voltage Divider.

// Max Voltage ( reference voltage )
float vPow = 5.0;
// first resistor 10K ohm
float r1 = 10000;
// second resistor 1k Ohm
float r2 = 1000;

في الدالة ()setup نقوم بضبط الإعدادات، وهي تشغيل الشاشة التسلسلية لنستطيع عرض قيمة الجهد المقاس.كما نقوم بعرض اقصى قيمة يمكن قياسها ومن ثم الإنتظار لمدة ثانيتين قبل البدء في الحسابات ( من الممكن اهمال هذا التأخير الزمني).

void setup() {
 Serial.begin(9600);
 Serial.println("--------------------");
 Serial.println("DC VOLTMETER");
 Serial.print("Maximum Voltage: ");
 Serial.print((int)(vPow / (r1 / (r1 + r2))));
 Serial.println("V");
 Serial.println("--------------------");
 Serial.println("");
 
 delay(2000);   //wait 2000 ms before starting
}

في الدالة ()loop، نقوم بقراءة قيمة الجهد على المقاومة 10k ohm، ثم عن طريق استخدام قانون Voltage Divider نقوم بحساب الجهد الكلي وعرضة على الشاشة التسلسلية.

void loop() {
 float v = (analogRead(0) * vPow) / 1024.0;
 float v2 = v / (r1 / (r1 + r2));
 
 Serial.print("Voltage (Volts) = ");
 Serial.println(v2);
}

مشغل موسيقى بإستخدام الأردوينو

سنقوم في هذا المشروع بعمل مشغل موسيقى mp3 باستخدام الاردوينو و موديول DFPlayer Mini الذي يستخدم كارت ذاكرة يمكننا من وضع الموسيقى التي نريد تشغيلها .

Mp3 Player: مشغل اغانى باستخدام الاردينو

 

المكونات المطلوبة

arduino uno r3

Arduino Uno

 

 

Full size breadboard 830

Breadboard

Breadboard Jumper Wire 65 pcs

Wires

 

DFPlayer Mini MP3 Module :

هو عبارة عن موديول يحتوي على بطاقة ذاكرة ويمكنه تشغيل الملفات الصوتية الموجودة به. ويمكننا التحكم بتشغيلها عن طريق الأردوينو.

Mp3 Player: مشغل اغانى باستخدام الاردينو

سنقوم بتحميل ملفات الصوتيات على بطاقة الذاكرة (SD Card) ، ثم نقوم بوضعه داخل الموديول واعتمادا على الكود البرمجي الذي يتم رفعه على الأردوينو سنتحكم بتشغيل هذه الملفات.

ليتم عمل هذه الدارة بشكل صحيح نحتاج إلى بطاقة ذاكرة نقوم بعمل Format لها. ثم نقوم بإنشاء مجلد جديد بإسم mp3 نضع فيه الملفات الصوتية.

Mp3 Player: مشغل اغانى باستخدام الاردينو
ملاحظة : الملفات الصوتية ذات الإمتداد mp3 هي التي تعمل فقط مع هذا الموديول.

يجب ان نقوم باعادة تسمية الملفات الصوتية بالشكل التالى :

0001.mp3 – 0002.mp3 – ……….. – 0100.mp3

 

Mp3 Player: مشغل اغانى باستخدام الاردينو

توصيل الدارة :

قم بتوصيل الدارة كما هو موضح بالصورة التالية :

Mp3 Player: مشغل اغانى باستخدام الاردينو

سنقوم بكتابة كود ليتم تشغيل الملفات الصوتية الموجودة على بطاقة الذاكرة بالترتيب والمدة الذي يتم تحديدها في البرمجة.

Mp3 Player: مشغل اغانى باستخدام الاردينو

الكود البرمجي :

قم برفع الكود التالي إلى الأردوينو :

#include <DFPlayer_Mini_Mp3.h>
#include <SoftwareSerial.h>


void setup () {
 Serial.begin (9600);
 mp3_set_serial (Serial); //set Serial for DFPlayer-mini mp3 module 
 mp3_set_volume (10);
}

void loop () {        

 mp3_play (1); //play 0001.mp3
 delay (10000); //10 sec, time delay to allow 0001.mp3 to finish playing

 mp3_play (2);
 delay (5000);

 mp3_play (5);
 delay (5000);

 mp3_play (20); //play 0020.mp3
 delay (9000);
}

 

شرح الكود البرمجى

في البداية سنحتاج الى تحميل مكتبة الموديول من الرابط .
ثم نقوم باضافتة الى مكتبات الاردوينو :

#include <DFPlayer_Mini_Mp3.h>
#include <SoftwareSerial.h>

في الدالة ()setup، نقوم بتشغيل بروتوكول التسلسلي، الذي سيتم استخدامه لإرسال الأوامر بين الأردوينو وموديول الـ Mp3 .

void setup () {
 Serial.begin (9600);
 mp3_set_serial (Serial); //set Serial for DFPlayer-mini mp3 module 
 mp3_set_volume (10);
}

في الدالة ()loop، نقوم بإعطاء ترتيب الملفات الصوتية المراد تشغيلها. فمثلا، نبدأ بتشغيل الملف الصوتي  0001.mp3 وننتظر 10 ثوان قبل البدء في الملف التالي وهكذا.

void loop () {        

 mp3_play (1); //play 0001.mp3
 delay (10000); //10 sec, time delay to allow 0001.mp3 to finish playing

 mp3_play (2);
 delay (5000);

 mp3_play (5);
 delay (5000);

 mp3_play (20); //play 0020.mp3
 delay (9000);
}

لاحظ انة اذا لم نضع تاخير زمنى سيقوم الاردوينو بارسال الاوامر تلقائيا بدون انتظار تشغيل و انتهاء الملف الصوتي.  لذلك يجب عليك ان تضع التاخير الزمنى المناسب لكل ملف صوتي

ساعة رقمية باستخدام الاردوينو

في هذا المشروع سنتعلم كيفية استخدام الأردوينو لعمل ساعة رقمية. سنقوم بعرض الوقت على شاشة الـ LCD والتحكم في ضبط الوقت من خلال مفاتيح الـ Push Buttons.

ساعة رقمية باستخدام الاردوينو

المكونات المطلوبة

arduino uno r3

Arduino Uno

16×2 LCD

10K Ohms Resistors

Push Buttons

220 Ω resistor

220 Ohm Resistor

Full size breadboard 830

Breadboard

Breadboard Jumper Wire 65 pcs

Wires

الشاشة LCD

استخدام-حساس-الموجات-فوق-الصوتية-مع-ال
تعمل الشاشة في احد الحالات التالية:

استقبال الأوامر من الأردوينو وتنفيذها، مثلا : أمر تهيئة ومسح الشاشة :

lcd.begin(16,2);
lcd.clear();

استقبال المعلومات من الأردوينو وعرضها، مثلا : كتابة جملة معينة :

lcd.print("Hello");

 

توصيل الدارة :

قم بتوصيل الدارة كما هو موضح بالصورة التالية :

ساعة رقمية باستخدام الاردوينو

سنقوم بعمل كود يقوم على حساب التوقيت لتعمل الساعة بشكل صحيح، حيث سيقوم بحساب مرور 60 ثانية ليقوم بزيادة عدد الدقائق وهكذا ايضا مع الساعات. سيتم استخدام مفاتيح الضغط ليقوم البرنامج بمراقبتها في البداية ليتم ضبط التوقيت الصحيح.

ساعة رقمية باستخدام الاردوينو

 

الكود البرمجي

قم برفع الكود التالي على الأردوينو :

#include <LiquidCrystal.h>

#define HOUR_BUTTON 6
#define MINUTE_BUTTON 7
#define TICK_LENGTH 60000
#define CHECK_TIME 250


LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

unsigned int minute = 0;
unsigned int hour = 01;
unsigned long previousMillis = 0;
unsigned char am = 1;

void setup() {
  // put your setup code here, to run once:
  lcd.begin(16, 2);
  pinMode(HOUR_BUTTON, INPUT);
  pinMode(MINUTE_BUTTON, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  checkTick();
  lcd.setCursor(0,0);
  lcd.print("Time:");
  lcd.setCursor(6,1);
  lcd.print(hour);
  lcd.print(":");
  lcd.print(minute);
  if(am == 1) lcd.print(" AM");
  else lcd.print(" PM");
}

void checkTick() {
   unsigned long currentMillis = millis();
   
   if ((unsigned long)(currentMillis - previousMillis) >= TICK_LENGTH) {
      tick();
      previousMillis = currentMillis;
   }
   if((unsigned long)(currentMillis - previousMillis) >= CHECK_TIME){
      readHourButton();
      readMinuteButton();
   }
}

void tick() {
  minuteUp();
}

  
void readHourButton() {
  if (digitalRead(HOUR_BUTTON) == HIGH) {
    delay(200);
    hourUp();
  }
}

void readMinuteButton() {
  if (digitalRead(MINUTE_BUTTON) == HIGH) {
    delay(200);
    minuteUp();
  }
}

void hourUp() {
  hour = hour + 1;
  if (hour > 12) {
    lcd.clear();
    hour = 1;
    if(am == 1) am = 0;
    else am = 1;
  }
}

void minuteUp() {
  minute = minute + 1;
  if (minute > 59) {
    minute = 0;
    hourUp();
  }
}

شرح الكود :

في البداية نقوم بإضافة مكتبة شاشة الـ LCD وتسمية منافذ الأردوينو المستخدمة مع مفاتيح الضبط :

#include <LiquidCrystal.h>

#define HOUR_BUTTON 6
#define MINUTE_BUTTON 7

ثم نقوم نقوم بالإعلان عن بعض الثوابت التي سيتم استخدامها لاحقا :

#define TICK_LENGTH 60000
#define CHECK_TIME 250

بعد ذلك نقوم بالإعلان عن بعض المتغيرات. يستخدم المتغير minute لحفظ الدقائق. والمتغير hour لحفظ الساعات. والمتغير am لتسجيل ما إذا كان التوقيت صباحا أم مساءاً. وسيتم تسجيل الوقت الخاص بأخر مرة تم حساب التوقيت في المتغير previousMillis .

unsigned int minute = 0;
unsigned int hour = 01;
unsigned long previousMillis = 0;
unsigned char am = 1;

في الدالة ()setup قمنا بضبط الاعدادات اللازمة للمشروع مثل ضبط ارجل الاردوينو كمخارج للمفاتيح وتشغيل الشاشة LCD :

void setup() {
  // put your setup code here, to run once:
  lcd.begin(16, 2);
  pinMode(HOUR_BUTTON, INPUT);
  pinMode(MINUTE_BUTTON, INPUT);
}

في الدلة ()loop، نقوم بحساب عدد الثوان التي مرت، فإذا كانت 60 ثانية نقوم بزيادة عدد الدقائق في المتغير minute. كما نقوم بإختبار الدقائق التي مرت، فعند مرور 60 دقيقة نقوم بزيادة عدد الساعات في المتغير hour. ثم نقوم بالنهاية بعرض الدقائق والساعات على شاشة الـ LCD.

أيضا اثناء الإختبار نقوم بإختبار المفاتيح إذا ما تم الضغط عليها ام لا عبر استدعاء الدالة ()checkTick . فإذا تم الضغط على مفتاح الدقائق نقوم بزيادة عدد الدقائق في المتغير minute، ويعمل بنفس الطريقة عند الضغط على مفتاح الساعات.

void loop() {
  // put your main code here, to run repeatedly:
  checkTick();
  lcd.setCursor(0,0);
  lcd.print("Time:");
  lcd.setCursor(6,1);
  lcd.print(hour);
  lcd.print(":");
  lcd.print(minute);
  if(am == 1) lcd.print(" AM");
  else lcd.print(" PM");
}

سنقوم بعمل عدد من الدوال المستخدمة في المشروع :

الدالة ()checkTick ، في كل مرة يتم استدعائها تقوم بحفظ الوقت الذي مضى منذ عمل Reset للأردوينو. ثم تتم مقارنة الوقت الحالي بقيمة مسبقة فإذا اصبح الفارق بين التوقيتين يتعدى الـ TICK_LENGTH الذي تم تحديده في أول البرنامج، فهذا يعني انه قد مرة دقيقة فنقوم بزيادتها بإستخدام الدالة ()tick. ثم نقوم بتسجيل هذا التوقيت لإستخدامه مرة ارخى لمعرفة هل مر دقيقة أخرى ام لا.

 unsigned long currentMillis = millis();
   
   if ((unsigned long)(currentMillis - previousMillis) >= TICK_LENGTH) {
      tick();
      previousMillis = currentMillis;
   }

ايضا يتم التحقق ما إذا تعدى الفارق في التوقيت قيمة CHECK_TIME ، فعندها نقوم بقراءة المفاتيح المستخدمة في تعديل التوقيت.

   if((unsigned long)(currentMillis - previousMillis) >= CHECK_TIME){
      readHourButton();
      readMinuteButton();
   }

الدالة ()tick، تقوم بإستدعاء الدالة ()minuteUp، والتي بدورها تقوم بزيادة عداد الدقائق.

void tick() {
  minuteUp();
}

 

الدالة ()readHourtButton تقوم بقراءة المفتاح الخاص بتعديل خانة الساعات فإذا تم الضغط عليه تقوم بتشغيل الدالة ()hourUp التي تقوم بزيادة عداد الساعات.

void readHourButton() {
  if (digitalRead(HOUR_BUTTON) == HIGH) {
    delay(200);
    hourUp();
  }
}

الدالة readMinuteButton() تقوم بقراءة المفتاح الخاص بتعديل خانة الدقائق فإذا تم الضغط عليه تقوم بإستدعاء دالة ()minuteUp التي تقوم بزيادة عداد الدقائق.

void readMinuteButton() {
  if (digitalRead(MINUTE_BUTTON) == HIGH) {
    delay(200);
    minuteUp();
  }
}

الدالة hourUp() في كل مرة يتم إستعداء هذه الدالة تقوم بزيادة عداد الساعات بمقدار واحد وعمل اختبار اذا كان التوقيت تغير من الصباح إلى المساء .

void hourUp() {
  hour = hour + 1;
  if (hour > 12) {
    lcd.clear();
    hour = 1;
    if(am == 1) am = 0;
    else am = 1;
  }
}

الداله minuteUp() في كل مرة يتم إستدعائها تقوم بزيادة عداد الدقائق بمقدار واحد وعمل اختبار اذا وصل عداد الدقائق الى 60 تقوم بتصفير عداد الدقائق و زيادة عداد الساعات بمقدار واحد .

void minuteUp() {
  minute = minute + 1;
  if (minute > 59) {
    minute = 0;
    hourUp();
  }
}

نظام الحماية ضد السرقة

في هذا المشروع سنتعلم كيفية استخدام حساس الحركة PIR Sensor مع الاردوينو لعمل نظام انذار ضد السرقة.

Anti-Thief System: نظام انذار باستخدام PIR Sensor مع الاردوينو

المكونات المطلوبة

arduino uno r3

Arduino Uno

PIR Sensor

 

Buzzer

 

LED

 

220 Ω resistor

220 Ohm Resistor

 

Full size breadboard 830

Breadboard

Breadboard Jumper Wire 65 pcs

Wires

حساس الحركة PIR Sensor

يعمل الحساس على قياس مقدار التغير في الاشعه تحت الحمراء الصادرة عن الاجسام و في حالتنا الانسان. ولكن لا يقوم الحساس بقياس كمية الأشعة الصادرة من الإنسان بل التغير الحادث لهذه الأشعة، وهكذا يشعر الحساس بوجود حركة.

Anti-Theft System: نظام انذار باستخدام PIR Sensor مع الاردوينو

عند تحرك الشخص امام الحساس يحدث تغيير في كمية الأشعة تحت الحمراء التي يستقبلها الحساس، فيعطى إشارة بأن هناك شخص امامه.

عناصر الحساس :

Anti-Theft System: نظام انذار باستخدام PIR Sensor مع الاردوينو

يتم توصيله إلى الأردوينو كما هو موضح بالجدول :

الطرف (بداية من اليسار)التوصيل
1GND
2Output To Arduino
3VCC

توصيل الدارة

قم بتوصيل الدارة كما هو موضح بالصورة التالية :

Anti-Theft System: نظام انذار باستخدام PIR Sensor مع الاردوينو

سنقوم بكتابه برنامج، بحيث يقوم الحساس بإلتقاط ما إذا كان هناك حركة ام لا، , وعند الكشف عن وجود حركة يقوم بإرسال اشارة إلى الأردوينو الذي يقوم بدوره بتشغيل الـ Buzzer وإضاءة الـ LED للتنبيه.

Anti-Theft System: نظام انذار باستخدام PIR Sensor مع الاردوينو

 

الكود البرمجي

// led
#define LED 13
// pir
#define INPUT 2
// buzzer
#define SPEAKER 10

int pirFlag = 0;
int val = 0;


void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(INPUT, INPUT);
  pinMode(SPEAKER, OUTPUT);
  Serial.begin(9600);
}


void loop()
{
  val = digitalRead(INPUT);
  // test this val
  if (val == HIGH){
    digitalWrite(LED, HIGH);
    tone(SPEAKER, 160, 300);
    delay(300);
    if (pirFlag == 0){
	Serial.println("Motion detected!");
	pirFlag = 1;
    }
  }	
  else{
    digitalWrite(LED, LOW);
    noTone(SPEAKER);
    if (pirFlag == 1){
	Serial.println("Motion ended!");
	pirFlag = 0;
    }
  }
}

شرح الكود :

في البداية، نقوم بتسمية منافذ الأردوينو المستخدمة في المشروع، من أجل تسهيل عملية التعامل معها. ثم نقوم بالإعلان عن المتغيرات التي سنحتاج استخدامها في البرنامج.

سيتم استخدام المتغير pirFlag لتسجيل حالة الحساس. نقوم بوضع قيمة ابتدائية للحالة وهي 0. والمتغير val يستخدم لتسجيل الإشارة القادمة من الحساس إلى الأردوينو حسب وجود حركة ام لا.

// led
#define LED 13
// pir
#define INPUT 2
// buzzer
#define SPEAKER 10

int pirFlag = 0;
int val = 0;

في الدالة ()setup، قمنا بضبط المنافذ المستخدمة إما مدخله أو مخرجة. يتم ضبط الـ LED والـ Buzzer كمخرج، والمنفذ الموصل مع الـحساس كمدخل.

ويتم تفعيل الاتصال التسلسلي من أجل الطباعة على الشاشة التسلسلية Serial Monitor عند الكشف عن وجود حركة.

void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(INPUT, INPUT);
  pinMode(SPEAKER, OUTPUT);
  Serial.begin(9600);
}

في دالة الـ ()loop، نقوم بقراءة الإشارات القادمة من الحساس واختبارها. إذا كانت الإشارة High اي انه تم الكشف عن وجود حركة، نقوم بتشغيل ال LED والـ Buzzer . ثم نقوم بتحقق من الحالة المسجله في المتغير PirFlag إذا كانت 0 نقوم بطباعة رسالة تدل على وجود حركة على الشاشة التسلسلية وتغير قيمة المتغير pirFlag إلى 1 .

val = digitalRead(INPUT);
  // test this val
  if (val == HIGH){
    digitalWrite(LED, HIGH);
    tone(SPEAKER, 160, 300);
    delay(300);
    if (pirFlag == 0){
	Serial.println("Motion detected!");
	pirFlag = 1;
    }
  }	

في حال كانت الإشاءة القادمة من الحساس LOW اي انه لم يتم الكشف عن وجود حركة، نقوم بإيقاف تشغيل الـ LED و الـ Buzzer . والتحقق من الحالة المسجله لدى الـ pirFlag إذا كانت 1 اي انه كانت هناك حركة وتوقفت فنقوم بالطباعة على الشاشة التسلسلية رساله تدل على وقف الحركة، وتغير قيمة المتغير pirFlag إلى 0 .

  else{
    digitalWrite(LED, LOW);
    noTone(SPEAKER);
    if (pirFlag == 1){
	Serial.println("Motion ended!");
	pirFlag = 0;
    }
  }

تستخدم الدالة tone() لتوليد اشارات يكمننا من سماعها عن طريق سماعه او Buzzer

tone(SPEAKER, 160, 300);

noTone(SPEAKER);
tone(المدة الزمنية , التردد ,اسم الرجل)
noTone(اسم الرجل)

 

بث فيديو مباشر عبر شبكة الإنترنت

خلال هذا المشروع، سنتعلم كيفية  بث فيديو مباشر على صفحة الويب بإستخدام الراسبيري باي. يمكن دمج هذا المشروع مع العديد من المشاريع كمشروع الروبوت لمشاهدة كل ما يشاهده الروبوت عبر شبكة الإنترنت أو مع أنظمة المراقبة أو مع أي تطبيق آخر يحتاج إلى كاميرا.

raspberry-pi-webcam-server

القطع المطلوبة :

raspberry-pi-iot-intruder-alert-system

 كاميرا للراسبري باي (raspberry pi camera module) أو USB webcam

8Gb Microsd 

 راسبيري باي (Raspberry Pi 3 Model B)

كيفية إعداد خادم كاميرا الويب :

أولا، سوف تحتاج إلى تثبيت نظام الراسبيان على الراسبيري باي. إذا لم تكن قد فعلت ذلك قم بالإطلاع على درس تهيئة بطاقة الذاكرة.

في هذا المشروع سنقوم باستخدام حزمة الحركة (Motion) .

للبدء، سنقوم بإستخدام الـ Termial  لتحديث الراسبيري باي إلى أحدث إصدار.

sudo apt-get update
sudo apt-get upgrade

إعتمادا على إصدار الـ Raspbian الذي تستخدمه سوف تحتاج إلى القيام ببعض الخطوات المختلفة.

إصدار  Raspbian Jessie :

نبدأ بإزالة المكتبات التي قد تتعارض مع الحزم الأحدث. قد تكون موجودة أو غير موجودة على نسختك من الراسبيان.

sudo apt-get remove libavcodec-extra-56 libavformat56 libavresample2 libavutil54

قم بتنزيل وتثبيت الحزم التالية عن طريق إدخال الأوامر التالية  على الـ Terminal

wget https://github.com/ccrisan/motioneye/wiki/precompiled/ffmpeg_3.1.1-1_armhf.deb
sudo dpkg -i ffmpeg_3.1.1-1_armhf.deb

الآن نحن بحاجة إلى تثبيت الحزم التالية :

sudo apt-get install curl libssl-dev libcurl4-openssl-dev libjpeg-dev libx264-142 libavcodec56 libavformat56 libmysqlclient18 libswscale3 libpq5

بعد تثبيت تلك الحزم، يمكننا الآن الحصول على أحدث نسخة من برنامج Motion وتثبيته. للقيام بذلك قم بتشغيل الأوامر التالية:

wget https://github.com/Motion-Project/motion/releases/download/release-4.0.1/pi_jessie_motion_4.0.1-1_armhf.deb
sudo dpkg -i pi_jessie_motion_4.0.1-1_armhf.deb

إصدار Raspbian Stretch :

أولا قم بتثبيت الحزم التالية. الأمر التالي يعمل على الإصدارين من Raspbian Stretch .

sudo apt-get install libmariadbclient18 libpq5 libavcodec57  libavformat57 libavutil55 libswscale4

بعد ذلك، قم بتنزيل ملف motion deb من GitHub وتثبيته بإستخدام dpkg.

sudo wget https://github.com/Motion-Project/motion/releases/download/release-4.0.1/pi_stretch_motion_4.0.1-1_armhf.deb
sudo dpkg -i pi_stretch_motion_4.0.1-1_armhf.deb

هذا كل ماعليك القيام به للإنتقال إلى إعداد motion بحيث يتم تشغيلها على الراسبيري باي الخاص بك.

إعداد Motion :

الآن نحن بحاجة إلى إجراء بعض التعديلات على ملف motion.conf ، قم بفتح الملف عبر الأمر التالي :

sudo nano /etc/motion/motion.conf

قم بالبحث عن الأسطر التالية، ثم قم بتغييرها إلى ما يلي :

daemon on
stream_localhost off
output_pictures off
ffmpeg_output_movies off
stream_maxrate 100
framerate 100
width 640
height 480

الآن نحن بحاجة إلى إعداد الـ daemon، أولا نحن بحاجة إلى تحرير ملف الـ Motion.

sudo nano /etc/default/motion

ابحث عن السطر التالي وقم بتغييره إلى ما يلي :

start_motion_daemon=yes

بمجرد الإنتهاء من ذلك، قم بحفظ الملف والخروج منه عن طريق الضعط على ctrl+x ثم Y

تأكد الآن من توصيل الكاميرا، وتشغيلها عبر الأمر التالي:

sudo service motion start

إذا كنت بحاجة إلى إيقاف البث، ببساطة قم بتشغيل الأمر التالي:

sudo service motion stop

الآن يمكنك مشاهدة البث المباشر عبر صفحة الويب بإستخدام عنوان الـ IP Address الخاص بالراسبيري باي. قم بفتح المتصفح واستخدام IP address للراسبيري باي كما يلي :

YourIPAddress:8081

إذا لم يتم تحميل صفحة الويب حاول إعادة تشغيل الخدمة عبر الأمر التالي :

sudo service motion restart

 

raspberry-pi-webcam-server

إذا كنت تستخدم كاميرا الراسبيري باي، ستحتاج إلى القياب ببعض الخطوات الإضافية المذكورة بالقسم القادم.

خطوات إضافية لمستخدمي كاميرا الراسبيري باي

إذا كنت ترغب في استخدام وحدة كاميرا الراسبيري باي سوف تحتاج إلى القيام ببعض الخطوات الإضافية لإعدادها.

تثبيت الجهاز :

أولا قم بتوصيل الكاميرا إلى لوحة الراسبيري باي بالطريقة الصحيحة كما هو موضح بالصورة التالية :

raspberry-pi-webcam-server

إعداد البرنامج :

لجعل كاميرا الراسبيري باي تعمل، ستحتاج للقيام ببعض الخطوات الإضافية.

تأكد من تفعيل كاميرا الراسبيري باي. بعد توصيل الكاميرا إلى لوحة الراسبيري باي ، من قائمة البدء ثم preferences قم بفتح Raspberry Pi Configuration Tool

raspberry-pi-webcam-server

تأكد من أن الكاميرا مفعلة كما هو موضح بالصوة أدناه :

raspberry-pi-webcam-server

إذا لم تكن مفعلة قم بتفعيلها عن طريق اختيار (Enable) ،   ثم قم بإعادة تشغيل نظام الراسبيري باي.

الآن قم بفتح ملف modules عن طريق إدخال الأمر التالي عبر الـ Terminal.

sudo nano /etc/modules

قم بإدخال السطر التالي في الجزء السفلي من الملف إذا لم يكن موجودا بالفعل، وبمجرد الإنتهاء قم بحفظ والخروج من الملف عبر الضغط على ctrl+x ثم y .

bcm2835-v4l2

الآن قم بإعادة تشغيل الراسبيري باي. بعد ذلك، يجب أن تكون قادر على الوصول إلى صفحة الويب التي تعرض البث المباشر عبر عنوان IP الخاص بالراسبيري باي

YourIPAddress:8081

 

raspberry-pi-webcam-server

 

هنا خادم كاميرا الراسبيري باي يمكن الوصول إليها داخل الشبكة المحلية. إذا كنت ترغب في السماح بالوصول الخارجي إليها قم بتباع التعليمات الموجودة في القسم التالي .

الإعدادات للوصول من خارج الشبكة  للبث :

من أجل تمكين الوصول الخارجي إلى خادم الراسبيري باي، سوف تحتاج إلى تغيير بعض الإعدادات في جهاز الـ Router . ومع ذلك تم تصميم أجهزة الـ routers بشكل مختلف لذلك قد تحتاج إلى البحث عن التعليمات الخاصة بجهاز الـ router الخاص بك.

ملاحظة: فتح منفذ (Port) على شبكة الإنترنت يمكن أن يتسبب في مخاطر أمنية .

 – أولا ، انتقل إلى صفحة router adimn (بالعادة يكون العنوان 192.168.1.1 أو 192.168.1.254)

raspberry-pi-webcam-server

 – بعد ذلك، قم بإدخال اسم المستخدم وكلمة المرور. الإفتراضي تكون admin , adimn.

– ثم قم بالذهاب إلى Advanced ، ثم Nat ، ثم قم بالضغط على Port Mapping .

– هنا قم بإدخال التالي :

Protocol : TCP/UDP ■
External start port: 8081 ■
External end port: 8081 ■
(Internal host: (Address of your Pi ■
Internal port: 8081 ■
Enable: Enable ■

raspberry-pi-webcam-server

يجب أن تكون الآن قادر على الإتصال ببث الـ webcam على الراسبيري باي من خارج الشبكة. قد تحتاج إلى إعادة تشغيل الـ Router لتصبح التغييرات مفعلة.

إذا لم تتمكن من الإتصال من خارج الشبكة المحلية، يمكنك تجربة ما يلي :

– تحقق من إعدادات جهاز router الخاص بك وتأكد من صحتها.
– تحقق من عنوان الـ IP انه لم يتغير . يمكنك إعداد Dynamic dns لمواجهة هذا.
– إعادة تشغيل الـ router .

جهاز للتحكم وقياس درجة الحرارة

 في هذا المشروع سنقوم بعمل جهاز لمراقبة وقياس درجة الحرارة . سيتم قياس درجة الحرارة بإستخدام حساس درجة الحرارة LM35، وعرض درجة الحرارة الحالية والمطلوبة من خلال شاشة العرض.

جهاز لقياس و التحكم فى درجة الحرارة باستخدام LM35

المكونات المطلوبة

arduino uno r3

Arduino Uno

LM35 Temperature Sensor

LM35

HD44780

LCD 16×2

220 Ω resistor

مقاومة 220 اوم

10K Ohms Resistors

Push Buttons

Full size breadboard 830

Breadboard

Breadboard Jumper Wire 65 pcs

Wires

الشاشة LCD

استخدام-حساس-الموجات-فوق-الصوتية-مع-ال
تعمل الشاشة في احد الحالات التالية:

استقبال أمر من الأردوينو وتنفيذه، على سبيل المثال : أمر التهيئة ومسح الشاشة:

lcd.begin(16,2);
lcd.clear();

استقبال معلومات من الأردوينو وعرضها، على سبيل المثال : كتابة جملة معينة :

lcd.print("Hello");
 للإطلاع على المزيد حول شاشة الـ LCD قم بالإطلاع على درس التحكم بشاشة LCD

حساس الحرارة LM35

LM35 Temperature Sensor

هو عبارة عن عنصر إلكتروني يتأثر بالحرارة ويعطي خرج كهربائي على شكل فولت يمكننا قياسه. أي أن الجهد الكهربائي الناتج منه يتناسب طرديا مع درجة الحرارة فكلما كانت درجة الحرارة عالية كلما كانت الفولتية الناتجة منه عالية.

توصيله في الدارة :

مُخرج هذا الحساس يكون قيمة تناظرية (Analog) ، اي نحتاج إلى توصيله على أحد المنافذ التناظرية (Analog) في الأردوينو. الأطراف التناظرية في الأردوينو من A0 إلى A5 .

جهاز لقياس و التحكم فى درجة الحرارة باستخدام LM35

الطرف (بداية من اليسار)التوصيل
1Vcc
2Output To Arduino
3Ground

ملاحظة هامة :

يجب التدقيق في عملية التوصيل، لأنه في حال توصيل الأطراف بشكل خاطىء قد يتسبب في تلف العنصر. ولاحظ عند توصيل العنصر يتم وضعه بحيث تكون الناحية المسطحة مواجهة لنا.

شرح الدارة

قم بتوصيل الدارة كما هو موضح بالصورة التالية :

جهاز لقياس و التحكم فى درجة الحرارة باستخدام LM35

سيقوم الحساس LM35 بقياس درجة الحرارة بإستمرار وعرضها على شاشة الـ LCD وبإستخدام مفتاح التحكم (Push Buttons) يمكننا التحكم في رفع أو خفض درجة الحرارة المطلوبة في المكان.

جهاز لقياس و التحكم فى درجة الحرارة باستخدام LM35

الكود البرمجي :

قم بكتابة الكود التالي ورفعه على الأردوينو :

#include <LiquidCrystal.h>
#define tempPin A0 
#define tup 10 
#define tdown 9
 
float temp; 
int defC = 23; 
int upstate = 0; 
int downstate = 0; 

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2); 
  lcd.setCursor(0, 0); 
  lcd.print("Config.."); 
  delay(900);
  lcd.clear(); 
  pinMode(tup, INPUT); 
  pinMode(tdown, INPUT); 
}

void loop() {
  upstate = digitalRead(tup); 
  downstate = digitalRead(tdown); 
  int tvalue = analogRead(tempPin);  
  
  if (upstate == HIGH) { 
    defC = defC + 1; 
  }
  if (downstate == HIGH) { 
    defC = defC - 1; 
  }
  temp = tvalue * 0.48828;

  lcd.setCursor(0, 0);
  lcd.print("Current ");
  lcd.print (temp);  
  lcd.print ('C');
  
  lcd.setCursor (0, 1); 
  lcd.print ("Desired "); 
  lcd.print (defC);
  lcd.print ('C');

  delay(200);
}

شرح الكود :

في البداية، نقوم بإضافة المكتبة الخاصة بشاشة الـ LCD :

#include <LiquidCrystal.h>

ثم نقوم بتسمية منافذ الأردوينو المستخدمة في المشروع :

#define tempPin A0 
#define tup 10 
#define tdown 9

بعد ذلك، نقوم بالإعلان عن المتغيرات التي سيتم استخدامها في البرنامج لتسجيل قيم درجات الحرارة :

float temp; 
int defC = 23; 
int upstate = 0; 
int downstate = 0;

يتم تسجيل درجة الحرارة الناتجة من حساس الحرارة على المتغير temp. واستخدام المتغير defC لتسجيل درجة الحرارة المطلوبة. والمتغير upstate لتسجيل حالة المفتاح الأول الخاص برفع درجة الحرارة المطلوبة. والمتغير downstate لتسجيل حالة المفتاح الثاني الخاص بخفض درجة الحرارة المطلوبة.

ثم نقوم بإنشاء المتغير الخاص بشاشة الـ LCD وتحديد الأرجل التي سيتم توصيلها مع الأردوينو :

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

في الدالة ()setup، نقوم بضبط الإعدادات اللازمة، كإعدادات شاشة الـ LCD وضبط المفاتيح (Push Buttons) كمخرج :

void setup() {
  lcd.begin(16, 2); 
  lcd.setCursor(0, 0); 
  lcd.print("Config.."); 
  delay(900);
  lcd.clear(); 
  pinMode(tup, INPUT); 
  pinMode(tdown, INPUT); 
}

في الدالة ()loop، نقوم بقراءة المفاتيح (Push Buttons) ، وقراءة قيمة الجهد الناتج من الحساس :

  upstate = digitalRead(tup); 
  downstate = digitalRead(tdown); 
  int tvalue = analogRead(tempPin);

ثم نقوم بإختبار ما إذا تم الضغط على المفاتيح. فعند الضغط على مفتاح زيادة درجة الحرارة المطلوبة نقوم بإضافة 1 إلى درجة الحرارة المسجلة في المتغير defC. ويتم العكس عند الضغط على مفتاح خفض درجة الحرارة المطلوبة :

   if (upstate == HIGH) { 
    defC = defC + 1; 
  }
  if (downstate == HIGH) { 
    defC = defC - 1; 
  }

ونقوم بإستخدام قيمة الجهد الناتج من الحساس لإيجاد قيمة درجة الحرارة عن طريق المعادلة التالية :

   temp = tvalue * 0.48828;

وأخيرا، يتم عرض درجة الحرارة الحالية وأيضا درجة الحرارة المطلوبة على شاشة الـ LCD :

  lcd.setCursor(0, 0);
  lcd.print("Current ");
  lcd.print (temp);  
  lcd.print ('C');
  
  lcd.setCursor (0, 1); 
  lcd.print ("Desired "); 
  lcd.print (defC);
  lcd.print ('C');

  delay(200);

نظام الأمن للصندوق بإستخدام الاردوينو

في هذا المشروع سنتعلم كيف نستخدم المقاومة الضوئية (LDR (Light Dependent Resistor مع الاردوينو لعمل صندوق امان يقوم بإصدار صوت انذار عند فتحه.

 

خزانة امان باستخدام الاردوينو

 

المكونات المطلوبة

 

arduino uno r3

Arduino Uno

Piezo sounder
220 Ω resistor
Full size breadboard 830

Breadboard

Breadboard Jumper Wire 65 pcs

Wires

 

Buzzer

 هو عبارة عن طنان كهربائي يقوم بتحويل الطاقة الكهربائية إلى صوت مسموع. سنقوم بإستخدامه في هذا المشروع لاصدار صوت انذار عند فتح الصندوق .

عمل-بيانو-بسيط-باستخدام-اردوينو

المقاومة الضوئية LDR :

هي عبارة عن مقاومة تتأثر وتتغير قيمتها بتغير شدة الاضاءة المعرضة لها. فعند الظلام تكون قيمتها كبيرة جدا تصل الى 2 ميجا اوم، وفي الضوء الساطع تكون قيمتها صغيرة تصل إلى 200 اوم.

سنقوم بإستخدامها في المشروع لمعرفة اذا كان الصندوق مقفل ام مفتوح. فإذا كان مفتوح نقوم بتشغيل الانذار ويتوقف عندما يتم اغلاق الصندوق.

توصيل الدارة

قم بتوصيل الدارة كما هو موضح بالصورة التالية :

خزانة امان باستخدام الاردوينو

يقوم البرنامج بمراقبة شدة الاضاءة في الصندوق عن طريق المقاومة الضوئية. طالما كان الصندوق مقفل تكون شدة الاضاءة ضعيفة جدا فلا يعمل الانذار و بمجرد فتح الصندوق خزانة يعمل الانذار .

خزانة امان باستخدام الاردوينو

 

الكود البرمجي

#define LED 13
#define BUZZER 3

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(BUZZER, OUTPUT);
}

void loop() {
  int sensorValue = analogRead(A0);
  if (sensorValue > 700) {
    digitalWrite(LED, HIGH);
    digitalWrite(BUZZER, HIGH);
  }
  else{
    digitalWrite(LED, LOW);
    digitalWrite(BUZZER, LOW);
  }
}

شرح الكود :

في البداية، نقوم بتسمية منافذ الأردوينو المستخدمة في المشروع، من أجل تسهيل عملية التعامل معها.

#define LED 13
#define BUZZER 3

وفي الدالة ()setup نقوم بضبط الاعدادات اللازمة فى المشروع مثل ضبط الليد والـ Buzzer كمخرج

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(BUZZER, OUTPUT);
}

في دالة ()loop نقوم بقياس قراءة المقاومة الضوئية و نختبر القيمة المقاسه، فإذا تعدت قيمة معينة دل ذلك على أن الصندوق مفتوح ويتم تشغيل الانذار.

  int sensorValue = analogRead(A0);
  if (sensorValue > 700) {
    digitalWrite(LED, HIGH);
    digitalWrite(BUZZER, HIGH);
  }

غير ذلك يتم ايقاف الإنذار .

else{
    digitalWrite(LED, LOW);
    digitalWrite(BUZZER, LOW);
  }