التحكم بالشاشة الكرستالية باستخدام الاردوينو ووحدة البلوتوث

مقدمة

وسائل التحكم عن بُعد هي أجهزة إلكترونية يكون التحكم فيها يدويًا للتحكم في جهاز آخر، وذلك عبر إشارات مثل الأشعة تحت الحمراء أو إشارات الراديو اللاسلكية أو البلوتوث، في هذا الدرس سنتعلم كيفية التحكم بالشاشة الكرستالية عن بعد باستخدام الاردوينو ووحدة البلوتوث.

arduino-bluetooth-remote-lcd-display

المواد والأدوات

التحكم بالشاشة الكرستالية

1× اردوينو اونو

التحكم بالشاشة الكرستالية

1× سلك الاردوينو

التحكم بالشاشة الكرستالية

 1× شاشة كرستالية

التحكم بالشاشة الكرستالية

 حزمة أسلاك توصيل (ذكر- ذكر)

arduino-bluetooth-remote-lcd-display

حزمة أسلاك توصيل (ذكر – أنثى)

arduino-bluetooth-remote-lcd-display

1× 2C / IIC Serial Interface Module

arduino-bluetooth-remote-lcd-display

1× لوحة تجارب حجم صغير

دولار نينجا

40 رأس دبوس

arduino-bluetooth-remote-lcd-display

1× هاتف بنظام اندرويد

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

لمعرفة المزيد حول الشاشة الكرستالية يمكنك الرجوع للدرس التحكم بالشاشة الكرستالية LCD.

للمزيد حول وحدة البلوتوث يمكنك الرجوع للدرس التالي نظام التحكم في الإضاءة عبر البلوتوث.arduino-bluetooth-remote-lcd-display

البرمجة

قبل رفع الكود البرمجي للوحة الاردوينو افصل السلكان Tx و Rx وبعد رفع الكود أعد الأسلاك كما كانت.

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
String inData;
void setup() 
{
Serial.begin(9600);
lcd.begin();
lcd.clear();
}

void loop()
{
int i=0;
char commandbuffer[150];
if(Serial.available()){
delay(3000);
while( Serial.available() && i< 150) {
commandbuffer[i++] = Serial.read();
}
commandbuffer[i++]='\0';
}
if(i>0)
Serial.println((char*)commandbuffer);
lcd.print((char*)commandbuffer);
delay(4000);
lcd.clear();
}

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

سنقوم في البداية باستدعاء مكتبة (LiquidCrystal_I2C.h) الخاصة بوحدة i2c والتي تحتوي على مجموعة أوامر برمجية نحتاجها في المشروع.

ثم نضيفها للاردوينو IDE.

بتتبع المسار التالي:

Sketch > Include libraries > Add ZIP library 

ونضيف المجلد الذي قمنا بتحميله.

#include <LiquidCrystal_I2C.h>

نعرف عنوان وحدة i2c.

LiquidCrystal_I2C lcd(0x27, 16, 2);

في المتغير inData سيتم تخزين البيانات المقروءة من كلمات وجمل .

String inData;

في الدالة ()setup سيتم تهيئة الشاشة الكرستالية استعدادًا لطباعة الجمل والكلمات عليها.

void setup() 
{
Serial.begin(9600);
lcd.begin();
lcd.clear();
}

في الدالة ()loop سيتم قراءة البيانات من وحدة البلوتوث وسيتم طباعتها على الشاشة الكرستالية.

void loop()
{
int i=0;
char commandbuffer[150];
if(Serial.available()){
delay(3000);
while( Serial.available() && i< 150) {
commandbuffer[i++] = Serial.read();
}
commandbuffer[i++]='\0';
}
if(i>0)
Serial.println((char*)commandbuffer);
lcd.print((char*)commandbuffer);
delay(4000);
lcd.clear();
}

برنامج BlueTerm

حمّل برنامج BlueTerm المجاني على جهازك المحمول من متجر GooglePlay.

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

arduino-bluetooth-remote-lcd-display

انقر الزر اليمين من الهاتف المحمول ستظهر هذه الخيارات اختر Connect device.

arduino-bluetooth-remote-lcd-display

اختر نوع وحدة البلوتوث المستخدمة في هذا الدرس استخدمنا HC-06.التحكم بالشاشة الكرستالية

بعد اكتمال عملية الربط يمكن الآن التحكم بالشاشة الكرستالية عن طريق الاردوينو ووحدة البلوتوث.

اختبر صحة خطواتك.

 لا تنسَ فصل مصدر الطاقة بعد الانتهاء من استخدام النظام.




اصنع منبه رسائل البريد الإلكتروني باستخدام الاردوينو

مقدمة

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

منبه رسائل البريد الإلكتروني

المواد والأدوات

arduino-unread-gmail-email-notifier

1× اردوينو اونو

منبه رسائل البريد الإلكتروني

1× سلك الاردوينو

 

منبه رسائل البريد الإلكتروني

حزمة أسلاك توصيل (ذكر – أنثى)

arduino-unread-gmail-email-notifier

 1× ثنائي مشع للضوء أحمر (LED)

منبه رسائل البريد الإلكتروني

 شاشة كرستالية

منبه رسائل البريد الإلكتروني

I2C / IIC Serial Interface Module

شفرة

1× 40 رأس دبوس

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

للمزيد حول الشاشة الكرستالية يمكنك الرجوع للدرس التحكم بالشاشة الكرستالية LCD.

وصَل دائرة منبه رسائل البريد الإلكتروني كما في الشكل: 
 منبه رسائل البريد الإلكتروني

تفعيل IMAP

 افتح المتصفح الخاص بك وسجّل دخول على حسابك في Gmail.

أعلى يمين الصفحة انقر على العلامة الظاهرة بالصورة.

The Settings gear in Gmail

اختر See all settings.

The "See All Settings" button in Gmail

اختر أيقونة Forwarding and POP/IMAP.

Gmail settings with the Forwarding and POP/IMAP tab highlighted

في قسم IMAP access, اختر Enable IMAP.

وفي قسم POP download اختر Enable POP for all email.

The Enable IMAP option

احفظ التغييرات الجديدة.

كود اردوينو IDE

ارفع الكود البرمجي التالي على لوحة الاردوينو باستخدام برنامج اردوينو IDE.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

int val = 0; 
byte led = 13;

void setup(){
Serial.begin(9600); 
pinMode(led, OUTPUT); 
lcd.begin(); 
lcd.backlight(); 
}

void loop()
{
if(Serial.available()) 
if (val = Serial.read() - '0')
{
lcd.setCursor(1, 0); 
lcd.print("You've messages"); 
digitalWrite(led, val);
}
else
{
lcd.setCursor(1, 0); 
lcd.print("No new messages"); 
digitalWrite(led, val);
}
}

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

في البداية سنقوم بكتابة المكتبات الضرورية في مشروع صناعة منبه رسائل البريد الإلكتروني مثل <Wire.h> و <LiquidCrystal_I2C.h>.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

في هذه الأسطر سيتم تهيئة المتغير val الذي سيحمل معلومات عن رسائل البريد الإلكتروني والمتغير led تم ربطه مع لوحة الاردوينو بالمنفذ 13.

int val = 0; 
byte led = 13;

في الدالة ()setup سيتم تهيئة الشاشة الكرستالية والثنائي المشع للضوء.

void setup()
{
Serial.begin(9600); 
pinMode(led, OUTPUT); 
lcd.begin(); 
lcd.backlight(); 
}

في الدالة ()loop سيتم تحديث البريد الإلكتروني بشكل مستمر للبحث عن رسائل جديدة.

إذا كان هناك رسائل جديدة سيعمل الثنائي المشع للضوء وسينطبع على الشاشة رسالة You’ve messages.

وإذا لم يكن هناك رسائل سينطفئ الثنائي المشع للضوء وسنطبع على الشاشة No new messages.

void loop()
{
if(Serial.available()) 
if (val = Serial.read() - '0')
{
lcd.setCursor(1, 0); 
lcd.print("You've messages"); 
digitalWrite(led, val);
}
else
{
lcd.setCursor(1, 0); 
lcd.print("No new messages"); 
digitalWrite(led, val);
}
}

 كود البايثون

في البداية عليك تنصب برنامج Python 2.7 يمكنك الرجوع للدرس التالي لمعرفة كيفية تنصيبه تنصيب Python 2.7.

انقر بالسهم اليمين على Command Prompt واختر من القائمة Run as administrator.

arduino-unread-gmail-email-notifier

ادخل على مسار برنامج البايثون.

(هذا السطر قابل للتغيير بناء على موقع برنامج البايثون في جهازك)

cd C:\python27

حدّث Pip من خلال كتابة الأمر التالي.

pip install --upgrade pip

حمّل مكتبة pyserial.

pip install pyserial

افتح برنامج IDLE (Python) من قائمة File اختر New File التالي.

منبه رسائل البريد الإلكتروني

اكتب الكود البرمجي لكن عليك قراءة شرح الكود البرمجي قبل رفعه للوحة الاردوينو.

import imaplib, serial #import modules

ser = serial.Serial('COM3', 9600) #create serial object, enter in the proper port 
obj = imaplib.IMAP4_SSL('imap.gmail.com') #create imap object, set to gmail
obj.login('Your Email', 'Password') #enter in gmail credentials

#runs continuously 
while 1: 
obj.select() #refresh 
val = len(obj.search(None, 'UnSeen')[1][0].split()) #generate a value of 1 or 0
#print "The val is: %s\n" % val #print value to monitor
ser.write(str(val)) #write value to serial port

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

في البداية سيتم استدعاء المكتبات الضرورية مثل imaplib و serial.

import imaplib, serial #import modules

عليك تحرير هذا السطر وكتابة المنفذ المستخدم هنا تم استعمال المنفذ COM3.

ser = serial.Serial('COM3', 9600) #create serial object, enter in the proper port 

ادخل البريد الإلكتروني الخاص بك هنا Your Email  وكلمة السر هنا Password.

obj.login('Your Email', 'Password') #enter in gmail credentials

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

while 1: 
obj.select() #refresh 
val = len(obj.search(None, 'UnSeen')[1][0].split()) #generate a value of 1 or 0
#print "The val is: %s\n" % val #print value to monitor
ser.write(str(val)) #write value to serial port

 ارفع الكود البرمجي على لوحة الاردوينو من قائمة Run انقر على Run module.

يمكنك اختبار منبه رسائل البريد الإلكتروني بعد رفع الكود البرمجي.

 لا تنسَ فصل مصدر الطاقة بعد الانتهاء من استخدام النظام.




التحكم بالحاسوب باستخدام الاردوينو والهاتف الذكي

مقدمة

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

المواد والأدوات

smartphone-controlled-mouse

1× اردوينو اونو

smartphone-controlled-mouse

1× سلك الاردوينو

التحكم بالحاسوب عن بعد

موديول بلوتوث من النوع HC-06

التحكم بالحاسوب

حزمة أسلاك توصيل (ذكر – أنثى)

التحكم بالحاسوب

1× هاتف بنظام اندرويد

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

للمزيد حول وحدة البلوتوث يمكنك الرجوع للدرس التالي نظام التحكم في الإضاءة عبر البلوتوث.

التحكم بالحاسوب

كود اردوينو IDE

قبل رفع الكود البرمجي للوحة الاردوينو عد للدائرة الكهربائية وافصل السلكين المربوطين بالمنافذ A4 و A5.

بعد ذلك ارفع الكود البرمجي للوحة الاردوينو وبعد اكتمال عملية الرفع أعد الأسلاك كما كانت.

int datareceived[5] {0,0,0,0};          // To store byte from phone
int in_byte = 0;
int array_index = 0;
int l_prev=0,r_prev=0; // previous status of mouse left and right click 
void setup() {
Serial.begin (9600); // starts the serial monitor
}
 int height=0,width=0;
void loop() {
  int clicks=0;
  int sensitivity=20;       // you can adjust the sensitivity
  int xpos=0,ypos=0;
if (Serial.available() > 0) {  //recieve byte from phone
  in_byte= Serial.read(); //store in byte into a variable
  if (in_byte == (255)) { // if the variable is 0 stet the array inxed to 0.
    array_index = 0;
  }
  datareceived[array_index] = in_byte;  //store number into array
  array_index = array_index +1;
  
if(datareceived[1]>=110)
xpos=map(datareceived[1],110,172,0,sensitivity);       // When moved right
if(datareceived[1]<=70)
xpos=map(datareceived[1],60,1,0,-sensitivity);        // When moved left
if(datareceived[2]>=110)
ypos=map(datareceived[2],110,255,0,sensitivity);     // When moved down
if(datareceived[2]<=60)
ypos=map(datareceived[2],70,1,0,-sensitivity);       // When moved up


if(datareceived[3]==1 && l_prev==0)      // TO recognise a single button press
  clicks=1;
else if(datareceived[3]==2 && r_prev==0)
clicks=2;
else if(datareceived[3]==3 || datareceived[3]==4)
clicks=datareceived[3];  //  scroll

l_prev=datareceived[3];
r_prev=datareceived[3];

if(xpos!=0 or ypos!=0 or clicks!=0)       // when either of the joystick is moved or the button is pressed or scrolled
{
height=height+ypos;
width=width+xpos;
if(height>=799)
height=799;
if(height<=0)
height=0;
if(width>=1279)
width=1279;
if(width<=0)
width=0;
Serial.print(width);
Serial.print(":");
Serial.print(height);
Serial.print(":");
Serial.println(clicks);
clicks=0;
}
}
}

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

في المصفوفة datareceived ستخزن البيانات التي ستتم قراءتها من الهاتف الذكي وستكون قيمتها الابتدائية=0.

int datareceived[5] {0,0,0,0};          // To store byte from phone

في المتغيرين l_prev و r_prev=0 سيتم تخزين القيم الابتدائية لحالة الحركة ليمين ويسار الحاسوب =0.

int l_prev=0,r_prev=0; // previous status of mouse left and right click 

في دالة ()void loop:

المتغير sensitivity=20 يمثل حساسية الحركة والانتقال من مكان لآخر يمكنك تغيير القيمة.

 متغير xpos يشير إلى موقع السهم على محور x في شاشة الكمبيوتر وقيمته الابتدائية = 0.

متغير ypos يشير إلى موقع السهم على محور y في شاشة الكمبيوتر وقيمته الابتدائية = 0.

 int sensitivity=20;       // you can adjust the sensitivity
 int xpos=0,ypos=0;

في المصفوفة datareceived سيتم تخزين القيم المقروءة من الهاتف الذكي وتحديثها بشكل مستمر.

  datareceived[array_index] = in_byte;  //store number into array

بعد قراءة البيانات من الهاتف الذكي سيتم تحديد وجهة الحركة للسهم.

إذا كانت القيم المقروءة >=110 ستكون حركة السهم لليمين.

إذا كانت القيم المقروءة <=70 ستكون حركة السهم لليسار.

إذا كانت القيم المقروءة >=110 ستكون حركة السهم للأسفل. 

إذا كانت القيم المقروءة <=60 ستكون حركة السهم للأعلى.

if(datareceived[1]>=110)
xpos=map(datareceived[1],110,172,0,sensitivity);       // When moved right
if(datareceived[1]<=70)
xpos=map(datareceived[1],60,1,0,-sensitivity);        // When moved left
if(datareceived[2]>=110)
ypos=map(datareceived[2],110,255,0,sensitivity);     // When moved down
if(datareceived[2]<=60)
ypos=map(datareceived[2],70,1,0,-sensitivity);       // When moved up

هنا سيتم تحديد النقر هل هو لزر اليسار أو لزر اليمين.

if(datareceived[3]==1 && l_prev==0)      // TO recognise a single button press
  clicks=1;
else if(datareceived[3]==2 && r_prev==0)
clicks=2;
else if(datareceived[3]==3 || datareceived[3]==4)

هنا سيتم تحديد مكان الانتقال إما لأعلى أو أسفل الصفحة.

clicks=datareceived[3];  //  scroll

برنامج MIT App Inventor

حمّل تصميم واجهة المستخدم والكود البرمجي من هنا.

من المتصفح افتح موقع MIT App Inventor.

أنشئ حساب على الموقع ثم انقر علي Create Apps.

التحكم بالحاسوب عن بعد

من قائمة Project اختر Import projects (.aia) from my computer ثم انقر على الملف الذي حملته مسبقًا ويحتوي على واجهة المستخدم والكود البرمجي.

التحكم بالحاسوب عن بعد

من قائمة Connect اختر Al companion

التحكم بالحاسوب عن بعد

سيظهر كود ورمز مكون من 6 حروف.

حمّل تطبيق MIT App Inventor على جهازك الذكي.

يمكنك ادخال الرمز في المستطيل أو النقر على scan QR code ومسح الكود السابق.

ثم انقر على connect with code.
التحكم بالحاسوب عن بعد

ستظهر هذه الواجهة انقر على Bluetooth Connect.smartphone-controlled-mouse

اختر نوع وحدة البلوتوث من القائمة النوع المستخدم في هذا الدرس HC-06.التحكم بالحاسوب عن بعد

ستظهر كلمة Connected في حال اكتمال عملية الاتصال.

شرح لطريقة استعمال الواجهة.

التحكم بالحاسوب عن بعد

كود البايثون

في البداية عليك تنصب برنامج Python 3 يمكنك الرجوع للدرس التالي لمعرفة كيفية تنصيبه تنصيب Python 3.

انقر بالسهم اليمين على Command Prompt واختر من القائمة Run as administrator.

التحكم بالحاسوب عن بعد

ادخل على مسار برنامج البايثون.

(هذا السطر قابل للتغيير بناء على موقع برنامج البايثون في جهازك)

cd C:\Program Files (x86)\Python39-32

حدّث Pip من خلال كتابة الأمر التالي.

python -m pip install --upgrade pip

حمّل مكتبة فأرة الحاسوب.

python –m pip install mouse

حمّل مكتبة pyserial.

python -m pip install pyserial

افتح برنامج IDLE (Python 3.9 32-bit) من قائمة File اختر New File التالي.

smartphone-controlled-mouse

الصق الكود البرمجي وارفعه للوحة الاردوينو من قائمة Run انقر على Run module.

import mouse, sys
import time 
import serial

mouse.FAILSAFE=False
ArduinoSerial=serial.Serial('com3',9600)  #Specify the correct COM port
time.sleep(1)                             #delay of 1 second

while 1:
   data=str(ArduinoSerial.readline().decode('ascii'))
   (x,y,z)=data.split(":")  # read the x and y axis data
   (x,y)=(int(x),int(y))   # convert to int
   mouse.move(x,y)         # move the cursor to desired coordinates
   if '1' in z:                       
      mouse.click(button="left")     #clicks mouse button
   elif '2' in z:
      mouse.click(button="right")
   elif '3' in z:
      mouse.wheel(delta=-1)       # Scroll down
   elif '4' in z:
      mouse.wheel(delta=1)       # Scroll up
  

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

افتح صفحة جديدة في IDLE Python وقم باستدعاء المكتبات المطلوبة mouse, sys serial python و time.

import mouse, sys
import time 
import serial

حدد المنفذ COM المستخدم في الاتصال مع الاردوينو، لديك وقم بتعديل الأمر في السطر التالي حسب رقم المنفذ.

(يمكنك تعيينه عن طريق برنامج اردوينو IDE من قائمة Port).

ArduinoSerial=serial.Serial('com3',9600)  #Specify the correct COM port

هنا تتم قراءة القيم من المنافذ التناظرية A0 و A1 وسيتم تحريك السهم في أماكن مختلفة على الشاشة بناء على هذه القيم.

while 1:
   data=str(ArduinoSerial.readline().decode('ascii'))
   (x,y,z)=data.split(":")  # read the x and y axis data
   (x,y)=(int(x),int(y))   # convert to int
   mouse.move(x,y)         # move the cursor to desired coordinates

بناء على القراءات سيتم تحديد حركة السهم إما للأعلى أو للأسفل أو لليمين أو لليسار.

   if '1' in z:                       
      mouse.click(button="left")     #clicks mouse button
   elif '2' in z:
      mouse.click(button="right")
   elif '3' in z:
      mouse.wheel(delta=-1)       # Scroll down
   elif '4' in z:
      mouse.wheel(delta=1)       # Scroll up

يمكنك التحكم بالحاسوب عن بعد باستخدام الاردوينو وهاتفك الذكي بعد رفع الكود البرمجي.

اختبر صحة خطواتك.

 لا تنسَ فصل مصدر الطاقة بعد الانتهاء من استخدام النظام.




لعبة X/O باستخدام الاردوينو والشاشة الكرستالية

مقدمة

تستخدم الشاشة في تطبيقات مختلفة في حياتنا اليومية لعرض البيانات والاحصائيات وعرض الصور والفيديوهات المصورة، ستتعلم في هذا الدرس كيف تبرمج لعبة X/O باستخدام الاردوينو والشاشة الكرستالية مقاس 2.8 انش.

لعبة X/O

المواد والأدوات

arduino-game-x-o-on-the-tft-display

1× اردوينو اونو

arduino-game-x-o-on-the-tft-display

1× سلك الاردوينو

لعبة X/O

شاشة كرستالية “2.8

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

قم بتثبيت الشاشة الكرستالية كما هو ظاهر بالصور عليك الانتباه للمنافذ يجب توصيلها في مكانها  الصحيح على لوحة الاردوينو.لعبة X/O

لعبة X/O

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

قبل رفع الكود البرمجي للوحة الاردوينو عليك تحميل المكتبات الضرورية للمشروع.

من خلال الرابط التالي:

أولا مكتبة Touchscreen 

ثانيا مكتبة Elegoo_GFX

ثالثا مكتبة Elegoo_TFTLCD

#include <TouchScreen.h>
#include <Elegoo_GFX.h>
#include <Elegoo_TFTLCD.h>
#include <avr/pgmspace.h>

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4


#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF

#define YP A2
#define XM A3
#define YM 8
#define XP 9

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 400);
Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

const unsigned char x_bitmap[]PROGMEM={
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x3,0xff,0xff,0xc0,0x1,0xff,0xff,0xe0,0x0,
0x1,0xff,0xff,0xe0,0x1,0xff,0xff,0xc0,0x0,
0x1,0xff,0xff,0xf0,0x3,0xff,0xff,0xc0,0x0,
0x0,0xff,0xff,0xf0,0x7,0xff,0xff,0x80,0x0,
0x0,0xff,0xff,0xf8,0x7,0xff,0xff,0x80,0x0,
0x0,0x7f,0xff,0xf8,0xf,0xff,0xff,0x0,0x0,
0x0,0x3f,0xff,0xfc,0xf,0xff,0xfe,0x0,0x0,
0x0,0x3f,0xff,0xfe,0x1f,0xff,0xfe,0x0,0x0,
0x0,0x1f,0xff,0xfe,0x1f,0xff,0xfc,0x0,0x0,
0x0,0x1f,0xff,0xff,0x3f,0xff,0xfc,0x0,0x0,
0x0,0xf,0xff,0xff,0x7f,0xff,0xf8,0x0,0x0,
0x0,0xf,0xff,0xff,0xff,0xff,0xf8,0x0,0x0,
0x0,0x7,0xff,0xff,0xff,0xff,0xf0,0x0,0x0,
0x0,0x3,0xff,0xff,0xff,0xff,0xe0,0x0,0x0,
0x0,0x3,0xff,0xff,0xff,0xff,0xe0,0x0,0x0,
0x0,0x1,0xff,0xff,0xff,0xff,0xc0,0x0,0x0,
0x0,0x1,0xff,0xff,0xff,0xff,0xc0,0x0,0x0,
0x0,0x0,0xff,0xff,0xff,0xff,0x80,0x0,0x0,
0x0,0x0,0xff,0xff,0xff,0xff,0x80,0x0,0x0,
0x0,0x0,0x7f,0xff,0xff,0xff,0x0,0x0,0x0,
0x0,0x0,0x3f,0xff,0xff,0xfe,0x0,0x0,0x0,
0x0,0x0,0x3f,0xff,0xff,0xfe,0x0,0x0,0x0,
0x0,0x0,0x1f,0xff,0xff,0xfc,0x0,0x0,0x0,
0x0,0x0,0x1f,0xff,0xff,0xfc,0x0,0x0,0x0,
0x0,0x0,0x1f,0xff,0xff,0xfc,0x0,0x0,0x0,
0x0,0x0,0x3f,0xff,0xff,0xfe,0x0,0x0,0x0,
0x0,0x0,0x3f,0xff,0xff,0xfe,0x0,0x0,0x0,
0x0,0x0,0x7f,0xff,0xff,0xff,0x0,0x0,0x0,
0x0,0x0,0xff,0xff,0xff,0xff,0x80,0x0,0x0,
0x0,0x0,0xff,0xff,0xff,0xff,0x80,0x0,0x0,
0x0,0x1,0xff,0xff,0xff,0xff,0xc0,0x0,0x0,
0x0,0x1,0xff,0xff,0xff,0xff,0xc0,0x0,0x0,
0x0,0x3,0xff,0xff,0xff,0xff,0xe0,0x0,0x0,
0x0,0x3,0xff,0xff,0xff,0xff,0xe0,0x0,0x0,
0x0,0x7,0xff,0xff,0xff,0xff,0xf0,0x0,0x0,
0x0,0xf,0xff,0xff,0xff,0xff,0xf8,0x0,0x0,
0x0,0xf,0xff,0xff,0xff,0xff,0xf8,0x0,0x0,
0x0,0x1f,0xff,0xff,0x7f,0xff,0xfc,0x0,0x0,
0x0,0x1f,0xff,0xfe,0x3f,0xff,0xfc,0x0,0x0,
0x0,0x3f,0xff,0xfc,0x3f,0xff,0xfe,0x0,0x0,
0x0,0x3f,0xff,0xfc,0x1f,0xff,0xfe,0x0,0x0,
0x0,0x7f,0xff,0xf8,0x1f,0xff,0xff,0x0,0x0,
0x0,0xff,0xff,0xf8,0xf,0xff,0xff,0x80,0x0,
0x0,0xff,0xff,0xf0,0x7,0xff,0xff,0x80,0x0,
0x1,0xff,0xff,0xe0,0x7,0xff,0xff,0xc0,0x0,
0x1,0xff,0xff,0xe0,0x3,0xff,0xff,0xc0,0x0,
0x3,0xff,0xff,0xc0,0x3,0xff,0xff,0xe0,0x0,
0x3,0xff,0xff,0xc0,0x1,0xff,0xff,0xe0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
};
//x = 0 :blue
//x = 1 :red
int x = 0;
int rturn = 0;


int a;
int ab;
int b;
int bb;
int c;
int cb;
int d;
int db;
int e;
int eb;
int f;
int fb;
int g;
int gb;
int h;
int hb;
int i;
int ib;

void setup() {
tft.reset();
tft.begin(0x9341);
tft.fillScreen(BLACK);
tft.setRotation(1);
Serial.begin(9600);
tft.setCursor(60, 110);
tft.setTextColor(RED);
tft.setTextSize(3);
tft.println("X-O Game");
delay(2000);
tft.setCursor(5, 178);
tft.setTextColor(GREEN);
tft.setTextSize(1);
tft.println("In this game, there are two players : Player O");
tft.setCursor(5, 187);
tft.println("and Player X. Each turn, they can put pads on a");
tft.setCursor(5, 196);
tft.println("grid. You win once three of your pads are aligned.");

delay(1000);
tft.fillScreen(BLACK);
tft.drawLine(113, 10, 113, 230, WHITE);
tft.drawLine(208, 10, 208, 230, WHITE);
tft.drawLine(30, 80, 290, 80, WHITE);
tft.drawLine(30, 160, 290, 160, WHITE);
pinMode(13, OUTPUT);
}

void loop()
{
returning:

if(rturn==1){
tft.fillScreen(BLACK);
tft.drawLine(113, 10, 113, 230, WHITE);
tft.drawLine(208, 10, 208, 230, WHITE);
tft.drawLine(30, 80, 290, 80, WHITE);
tft.drawLine(30, 160, 290, 160, WHITE);
rturn = 0;
x = 0;
a = 0;
ab = 0;
b = 0;
bb = 0;
c = 0;
cb = 0;
d = 0;
db = 0;
e = 0;
eb = 0;
f = 0;
fb = 0;
g = 0;
gb = 0;
h = 0;
hb = 0;
i = 0;
ib = 0;
}
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
if (p.z > ts.pressureThreshhold) {
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);

if(p.y < 380){
if(p.x < 400){
if(x==0){
tft.fillCircle(70, 45, 25, YELLOW);
x=x+1;
a = 1;
delay(10);
}
else if(x==1){
drawX(35, 10);
x=x-1;
ab = 1;
delay(10);
}
}
else if(p.x < 650 && p.x > 400){
if(x==0){
tft.fillCircle(160, 45, 25, YELLOW);
x=x+1;
b = 1;
delay(10);
}
else if(x==1){
drawX(130, 10);
x=x-1;
bb = 1;
delay(10);
}}
else if(p.x > 650){
if(x==0){
tft.fillCircle(250, 45, 25, YELLOW);
x=x+1;
c = 1;
delay(10);
}
else if(x==1){
drawX(220, 10);
x=x-1;
cb = 1;
delay(10);
}
}
}
else if(p.y > 380 && p.y < 650){
if(p.x < 400){
if(x==0){
tft.fillCircle(70, 120, 25, YELLOW);
x=x+1;
d = 1;
delay(10);
}
else if(x==1){
drawX(35, 90);
x=x-1;
db = 1;
delay(10);
}
}
else if(p.x < 650 && p.x > 400){
if(x==0){
tft.fillCircle(160, 120, 25, YELLOW);
x=x+1;
e = 1;
delay(10);
}
else if(x==1){
drawX(130, 90);
x=x-1;
eb = 1;
delay(10);
}
}
else if(p.x > 650){
if(x==0){
tft.fillCircle(250, 120, 25, YELLOW);
x=x+1;
f = 1;
delay(10);
}
else if(x==1){
drawX(220, 90);
x=x-1;
fb = 1;
delay(10);
}
}
}
else if(p.y > 650){
if(p.x < 400){
if(x==0){
tft.fillCircle(70, 195, 25, YELLOW);
x=x+1;
g = 1;
delay(10);
}
else if(x==1){
drawX(35, 160);
x=x-1;
gb = 1;
delay(10);
}
}else if(p.x < 650 && p.x > 400){
if(x==0){
tft.fillCircle(160, 195, 25, YELLOW);
x=x+1;
h = 1;
delay(10);
}
else if(x==1){
drawX(130, 160);
x=x-1;
hb = 1;
delay(10);
}
}
else if(p.x > 650){
if(x==0){
tft.fillCircle(250, 195, 25,YELLOW );
x=x+1;
i = 1;
delay(10);
}
else if(x==1){
drawX(220, 160);
x=x-1;
ib = 1;
delay(10);
}
}
}
delay(500);
if(a==1 && b==1 && c==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(d==1 && e==1 && f==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(g==1 && h==1 && i==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}if(a==1 && d==1 && g==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(b==1 && e==1 && h==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(c==1 && f==1 && i==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}if(c==1 && e==1 && g==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(a==1 && e==1 && i==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}if(ab==1 && bb==1 && cb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(db==1 && eb==1 && fb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(gb==1 && hb==1 && ib==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(ab==1 && db==1 && gb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(bb==1 && eb==1 && hb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(cb==1 && fb==1 && ib==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(cb==1 && eb==1 && gb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(ab==1 && eb==1 && ib==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(a||ab==1){
if(b||bb==1){
if(c||cb==1){
if(d||db==1){
if(e||eb==1){
if(f||fb==1){
if(g||gb==1){
if(h||hb==1){
if(i||ib==1){
tft.fillScreen(BLACK);
tft.setCursor(65, 100);
tft.setTextColor(GREEN);
tft.setTextSize(3);
tft.println("No winner.");
delay(2000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
}
}
}
}
}
}
}
}
}
}
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
{
int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t byte;
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
if(i & 7) byte <<= 1;
else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
if(byte & 0x80) tft.drawPixel(x+i, y+j, color);
}
}
}
void drawX(int x, int y)
{drawBitmap(x,y,x_bitmap,65,65,RED);
}

يتم تنزيل المكتبات من خلال شريط القوائم في برنامج arduino IDE

لعبة X/O

أو من خلال فك الضغط عن ملفات المكتبات و نقلها إلى الملف التالي الموجود بجهازك  C:\Program Files (x86)\Arduino

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

 

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

#include <TouchScreen.h>
#include <Elegoo_GFX.h>
#include <Elegoo_TFTLCD.h>
#include <avr/pgmspace.h>

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

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

هنا يتم تعريف الألوان المستخدمة في الشاشة.

#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

في الدالة ()setup يتم تهيئة الشاشة لطباعة النصوص والرموز المستخدمة في لعبة X/O وأيضًا توضيح الألوان المستخدمة لطباعة النصوص والرموز يمكنك تحرير الألوان حسب ما تراه جيد ومناسب لك.

في البداية سينطبع على الشاشة X-O Game ثم بعد ذلك ستبدأ اللعبة.

void setup() {
  
tft.reset();
tft.begin(0x9341);
tft.fillScreen(BLACK);
tft.setRotation(1);

Serial.begin(9600);

tft.setCursor(60, 110);
tft.setTextColor(RED);
tft.setTextSize(3);
tft.println("X-O Game");
delay(2000);


tft.setCursor(5, 178);
tft.setTextColor(GREEN);
tft.setTextSize(1);
tft.println("In this game, there are two players : Player BLUE");
tft.setCursor(5, 187);
tft.println("and Player RED. Each turn, they can put pads on a");
tft.setCursor(5, 196);
tft.println("grid. You win once three of your pads are aligned.");

delay(9000);


tft.fillScreen(BLACK);

tft.drawLine(113, 10, 113, 230, WHITE);
tft.drawLine(208, 10, 208, 230, WHITE);

tft.drawLine(30, 80, 290, 80, WHITE);
tft.drawLine(30, 160, 290, 160, WHITE);

  pinMode(13, OUTPUT);

}

في الدالة ()loop سيتم عرض الشاشة الخاصة باللعبة بالألوان والرموز التي تم تحديدها في الكود البرمجي.

سيتم استخدام الدائرة الصفراء لتمثيل O وسيتم استخدام حرف X الأزرق لتمثيل X.

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

سيتم عرض النتيجة مباشرة بعد اكتمال كل التسع رموز أو في حالة فوز أحد الأطراف قبل اكتمال التسع رموز سيتم إيقاف اللعبة وإعلان الفائز.


#define WHITE   0xFFFF
void loop() 
{

returning:
if(rturn==1){
tft.fillScreen(BLACK);
tft.drawLine(113, 10, 113, 230, WHITE);
tft.drawLine(208, 10, 208, 230, WHITE);\tft.drawLine(30, 80, 290, 80, WHITE);
tft.drawLine(30, 160, 290, 160, WHITE);
rturn = 0;
x = 0;

a = 0;
ab = 0;
b = 0;
bb = 0;
c = 0;
cb = 0;
d = 0;
db = 0;
e = 0;
eb = 0;
f = 0;
fb = 0;
g = 0;
gb = 0;
h = 0;
hb = 0;
i = 0; 
ib = 0;
}


digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);

if (p.z > ts.pressureThreshhold) {

pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);

if(p.y < 380){

if(p.x < 400){
if(x==0){
tft.fillCircle(70, 45, 25, YELLOW);
x=x+1;
a = 1;
delay(10);
}
else if(x==1){
drawX(35, 10);
x=x-1;
ab = 1;
delay(10);
}
}

else if(p.x < 650 && p.x > 400){
if(x==0){
tft.fillCircle(160, 45, 25, YELLOW);
x=x+1;
b = 1;
delay(10);
}
else if(x==1){
drawX(130, 10);
x=x-1;
bb = 1;
delay(10);
}

}

else if(p.x > 650){
if(x==0){
tft.fillCircle(250, 45, 25, YELLOW);
x=x+1;
c = 1;
delay(10);
}
else if(x==1){
drawX(220, 10);
x=x-1;
cb = 1;
delay(10);
}

}
}



else if(p.y > 380 && p.y < 650){

if(p.x < 400){ 
if(x==0){
tft.fillCircle(70, 120, 25, YELLOW);
x=x+1;
d = 1;
delay(10);
}
else if(x==1){
drawX(35, 90);
x=x-1;
db = 1;
delay(10);
}

}
else if(p.x < 650 && p.x > 400){
if(x==0){
tft.fillCircle(160, 120, 25, YELLOW);
x=x+1;
e = 1;
delay(10);
}
else if(x==1){
drawX(130, 90);
x=x-1;
eb = 1;
delay(10);
}

}
else if(p.x > 650){
if(x==0){
tft.fillCircle(250, 120, 25, YELLOW);
x=x+1;
f = 1;
delay(10);
}
else if(x==1){
drawX(220, 90);
x=x-1;
fb = 1;
delay(10);
}

}

}
else if(p.y > 650){
if(p.x < 400){ 
if(x==0){
tft.fillCircle(70, 195, 25, YELLOW);
x=x+1;
g = 1;
delay(10);
}
else if(x==1){
drawX(35, 160);
x=x-1;
gb = 1;
delay(10);
}

}
else if(p.x < 650 && p.x > 400){
if(x==0){
tft.fillCircle(160, 195, 25, YELLOW);
x=x+1;
h = 1;
delay(10);
}
else if(x==1){
drawX(130, 160);
x=x-1;
hb = 1;
delay(10);
}

}
else if(p.x > 650){
if(x==0){
tft.fillCircle(250, 195, 25,YELLOW );
x=x+1;
i = 1;
delay(10);
}
else if(x==1){
drawX(220, 160);
x=x-1;
ib = 1;
delay(10);
}

}

}
delay(500);
if(a==1 && b==1 && c==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
} 
if(d==1 && e==1 && f==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
} 
if(g==1 && h==1 && i==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(a==1 && d==1 && g==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
} 
if(b==1 && e==1 && h==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
} 
if(c==1 && f==1 && i==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(c==1 && e==1 && g==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(a==1 && e==1 && i==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(GREEN);
tft.setTextSize(2);
tft.println("Player O Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(ab==1 && bb==1 && cb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(db==1 && eb==1 && fb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(gb==1 && hb==1 && ib==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(ab==1 && db==1 && gb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(bb==1 && eb==1 && hb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(cb==1 && fb==1 && ib==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(cb==1 && eb==1 && gb==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(ab==1 && eb==1 && ib==1){
tft.fillScreen(BLACK);
tft.setCursor(80, 110);
tft.setTextColor(YELLOW);
tft.setTextSize(3);
tft.println("Victory !");
tft.setCursor(72, 140);
tft.setTextColor(RED);
tft.setTextSize(2);
tft.println("Player X Win !");
delay(3000);
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
if(a||ab==1){
if(b||bb==1){
if(c||cb==1){
if(d||db==1){
if(e||eb==1){
if(f||fb==1){
if(g||gb==1){
if(h||hb==1){
if(i||ib==1){
tft.fillScreen(BLACK); 
tft.setCursor(65, 100);
tft.setTextColor(GREEN);
tft.setTextSize(3);
tft.println("No winner."); 
delay(2000); 
tft.fillScreen(BLACK);
tft.setCursor(20, 110);
tft.setTextColor(CYAN);
tft.setTextSize(2);
tft.println("Ready for another game ?");
delay(2000);
tft.setCursor(100, 140);
tft.setTextColor(MAGENTA);
tft.setTextSize(2);
tft.println("Loading");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading.");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading..");
delay(800);
tft.setCursor(100, 140);
tft.println("Loading...");
delay(800);
rturn = 1;
goto returning;
}
}
}
}
}
} 
}
}
}

}
}
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
{
int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t byte;
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
if(i & 7) byte <<= 1;
else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
if(byte & 0x80) tft.drawPixel(x+i, y+j, color);
}
}
}

void drawX(int x, int y)
{

drawBitmap(x,y,x_bitmap,65,65,RED);
}

يمكنك رفع الكود البرمجي على لوحة الاردوينو باستخدام برنامج اردوينو IDE.

اختبر لعبة X/O.

لا تنسَ فصل مصدر الطاقة بعد الانتهاء من استخدام اللعبة.




حساب سرعة دراجة هوائية باستخدام اردوينو

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

speed-meter-bike/

المواد و الأدوات

في هذا الدرس تحتاج إلى الأدوات التالية

اردوينو اونو 1X
I2C / IIC Serial Interface Module 1X
سلك اردوينو 1X
شاشة كرستالية 1X
لوحة تجارب 1X
مستشعر مفتاح الاتصال المغناطيسي 1X
مقاومة 10 كيلو أوم 1X
ضغاط التحكم  1X
مجموعة أسلاك توصيل 1X

 

 

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

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

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

//librarys
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4); 
//definition of variables
long previous, triptime, time, impulses;
float speedometer, dist, aspeed;
int screen=1;
//If you have other circuit of wheel you need change it
float radius=2;
void setup() {
lcd.init(); // initialize the lcd 
// Print a message to the LCD.
lcd.setCursor(1,0);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
lcd.print("Bike speedometer");
delay(1000);
lcd.setCursor(5, 1);
lcd.print("V 1.0");
delay(4000);
lcd.clear();
delay(500);
lcd.setCursor(0, 0);
lcd.print("Dist:");
}
void loop() {
int aa=analogRead (A0);
Serial.println (aa); 
//if wheel turns
if(analogRead(A0)>=300){
//number of turns++
impulses++;
//count turn time
time=(millis()-previous);
//count speed
speedometer=(3600000 / time) * radius/ 1000;
speedometer=(circuit / time)*3600.0;
previous=millis();
delay(100);
}
Lcd();
}
void Lcd(){
//when button is clicked
if(digitalRead (A1)==1){
lcd.clear();
screen++;
if(screen==3){
screen=1;
}
}
if(screen==1){
//displays speed
lcd.setCursor(0, 1);
lcd.print("Speed:");
lcd.setCursor(7, 1);
lcd.print(speedometer);
lcd.print("km/h");
}
if(screen== 2){
//diplays trip time
triptime=millis()/60000;
lcd.setCursor(0, 1);
lcd.print("Time:");
lcd.setCursor(7, 1);
lcd.print(triptime);
}
lcd.setCursor(0, 0);
lcd.print("Dist:");
//calculation of the distance
dist=impulses*radius/1000.00;
//dislays distance
lcd.setCursor(6,0);
lcd.print(dist);
lcd.print("km");
}

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

سنقوم في البداية باستدعاء مكتبة (LiquidCrystal_I2C) الخاصة بوحدة i2c و التي تحتوي على مجموعة أوامر برمجية نحتاجها في المشروع

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

نعرف عنوان وحدة i2c

LiquidCrystal_I2C lcd(0x27,20,4); 
//definition of variables

نعرف المتغيرات التالية و هي (previous, triptime, time, impulses, speedometer, dist, aspeed)

long previous, triptime, time, impulses;
float speedometer, dist, aspeed;

تعريف متغير (screen) و الذي يشير إلى طباعة البيانات و ستتم طباعتها على 3 شاشات شاشة تحتوي على المسافة والسرعة و شاشة تعرض المسافة و متوسط السرعة وشاشة للوقت و المسافة

int screen=1;

تحديد نصف القطر للعجلة

float radius=2.0;

تهيئة الشاشة والمنافذ

void setup() {
itialize the lcd 
lcd.init();
// Print a message to the LCD.

lcd.backlight();
lcd.setCursor(1,0);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
lcd.print("Bike speedometer ");
delay(1000);}

في دالة void loop يتم حساب سرعة دراجة هوائية حسب الوقت المعادلة بالدالة

void loop() {
int aa=analogRead (A0);
//if wheel turns
if(analogRead(A0)>=300){
//number of turns++
impulses++;
//count turn time
time=(millis()-previous);
//count speed
speedometer=(radius/ time)*3600.0;
previous=millis();
delay(100);
}

تحديد البيانات في كل شاشة و سيتم عرض 3 شاشات شاشة تظهر السرعة و شاشة تظهر متوسط السرعة وشاشة تظهر وقت الرحلة بالدقائق

Lcd();
}
void Lcd(){
//when button is clicked
if(digitalRead (A1)==1){
lcd.clear();
screen++;
if(screen==3){
screen=1;
}
}

if(screen==1){
//displays speed
lcd.setCursor(0, 1);
lcd.print("Speed:");
lcd.setCursor(7, 1);
lcd.print(speedometer);
lcd.print("km/h");
}

if(screen== 2){
//diplays trip time
triptime=millis()/60000;

lcd.setCursor(0, 1);
lcd.print("Time:");
lcd.setCursor(7, 1);
lcd.print(triptime);


}

عرض المسافة

lcd.setCursor(0, 0); 
lcd.print("Dist:"); //calculation of the distance 
dist=impulses*circuit/1000.00; //dislays distance 
lcd.setCursor(6,0);
 lcd.print(dist); 
lcd.print("km"); }

قم بتثبيت المستشعر بحيث يكون في جزء ثابت يقابل العجلة، وعلى العجلة يتم تثبيت المغناطيس في كل مرة تتحرك العجلة و يصبح المغناطيس في مقابل الحساس سيتم حساب نبضة،

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

 

 




مؤشر حالة العمل باستخدام الراسبيري باي

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

مؤشر العمل

المواد والأدوات

راسبيري باي

X1 راسبيري باي 

ذاكرة

X1 ذاكرة 8 قيقا 

lcd

X1 شاشة كرستالية 

i2c

X1 2C / IIC Serial Interface Module

لوحة تجارب

X1 لوحة تجارب 

محول طاقة راسبيري باي

1X محول طاقة 2A5V 

أسلاك توصيل

X4 أسلاك توصيل F/F

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

توصيل الدائرة مؤشر حالة العمل

الطباعة على الشاشة

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

وبعد تثبيت النظام، يمكنك تهيئة النظام من خلال الرجوع  تهيئة نظام التشغيل و يمكنك التحكم بالراسبيري  باي عن بعد من خلال الدرس 

بالبداية سنقوم بتجربة الطباعة على الشاشة حتى نتحقق من ضبط المقاومة المتغيرة الموجودة على موديول I2C

 ابدأ بتحديث النظام من خلال الأوامر التالية التي يتم كتابتها على الشاشة السوداء LXterminal

sudo apt-get update
sudo apt-get upgrade

قم بتفعيل اتصال i2c من خلال الأمر التالي

sudo raspi-config

شاشة rpi-config

قم بتحريك الأسهم للوصول الى الخيار الثالث “Interface Options”

شاشة interface option

مرر الأسهم للوصول للخيار الخامس “P5 I2C” و انقر على enter

شاشة O5

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

mkdir work

داخل ملف المشروع سنضيف المكتبة الخاصة بمديول i2c بكتابة الأمر التالي

cd work

ثم

sudo nano i2c_lcd_driver.py

قم بنسخ الكود التالي

#Caroline Dunn
#this code was modified from:
#https://www.circuitbasics.com/raspberry-pi-i2c-lcd-set-up-and-programming/


# i2c bus (0 -- original Pi, 1 -- Rev 2 Pi)
I2CBUS = 1

# LCD Address
ADDRESS = 0x27

import smbus
from time import sleep

class i2c_device:
def __init__(self, addr, port=I2CBUS):
self.addr = addr
self.bus = smbus.SMBus(port)

# Write a single command
def write_cmd(self, cmd):
self.bus.write_byte(self.addr, cmd)
sleep(0.0001)

# Write a command and argument
def write_cmd_arg(self, cmd, data):
self.bus.write_byte_data(self.addr, cmd, data)
sleep(0.0001)

# Write a block of data
def write_block_data(self, cmd, data):
self.bus.write_block_data(self.addr, cmd, data)
sleep(0.0001)

# Read a single byte
def read(self):
return self.bus.read_byte(self.addr)

# Read
def read_data(self, cmd):
return self.bus.read_byte_data(self.addr, cmd)

# Read a block of data
def read_block_data(self, cmd):
return self.bus.read_block_data(self.addr, cmd)


# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80

# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00

# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00

# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00

# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00

En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit

class lcd:
#initializes objects and lcd
def __init__(self):
self.lcd_device = i2c_device(ADDRESS)

self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x02)

self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)


# clocks EN to latch command
def lcd_strobe(self, data):
self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
sleep(.0005)
self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
sleep(.0001)

def lcd_write_four_bits(self, data):
self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
self.lcd_strobe(data)

# write a command to lcd
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xF0))
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))

# write a character to lcd (or character rom) 0x09: backlight | RS=DR<
# works!
def lcd_write_char(self, charvalue, mode=1):
self.lcd_write_four_bits(mode | (charvalue & 0xF0))
self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0))

# put string function with optional char positioning
def lcd_display_string(self, string, line=1, pos=0):
if line == 1:
pos_new = pos
elif line == 2:
pos_new = 0x40 + pos
elif line == 3:
pos_new = 0x14 + pos
elif line == 4:
pos_new = 0x54 + pos

self.lcd_write(0x80 + pos_new)

for char in string:
self.lcd_write(ord(char), Rs)

# clear lcd and set to home
def lcd_clear(self):
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_RETURNHOME)

# define backlight on/off (lcd.backlight(1); off= lcd.backlight(0)
def backlight(self, state): # for state, 1 = on, 0 = off
if state == 1:
self.lcd_device.write_cmd(LCD_BACKLIGHT)
elif state == 0:
self.lcd_device.write_cmd(LCD_NOBACKLIGHT)

# add custom characters (0 - 7)
def lcd_load_custom_chars(self, fontdata):
self.lcd_write(0x40);
for char in fontdata:
for line in char:
self.lcd_write_char(line)

ثم حفظ و الخروج من الملف عن طريق Ctrl +S ثم Ctrl+ x

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

sudo nano test.py

ثم أدخل الكود البرمجي

import i2c_lcd_driver #imports functions from i2c_lcd_driver.py file

mylcd = i2c_lcd_driver.lcd()

mylcd.lcd_clear() #clear the LCD screen
mylcd.lcd_display_string("Welcome", 1) #Display text on Line 1 of the LCD screen
mylcd.lcd_display_string("lets get started", 2) #Display text on Line 2 of the LCD screen

تحتاج لضبط الشاشة من خلال المقاومة المتغيرة على الميديول لتظهر العبارة التي قمنا بطباعتها

مؤشر حالة العمل

انشاء صفحة الويب

مؤشر حالة العمل

سيتم كتابة الكود البرمجي الخاص بصفحة الويب على بلغة html

داخل ملف سيت تسميته terminals

cd work

ثم

mkdir templates

ثم

sudo nano lcd.html

ثم قم باضافة الكود التالية

<!DOCTYPE html>
<!--Section 1 START-->
<html>
<body>

<h1>Status Indicator</h1>

<p>This page allows you to select the text of your LCD status indicator.</p>

<p id="demo"></p>

<button onclick="availableFunc()">Available</button>
<br>
<button onclick="busyFunc()">Busy</button>
<br>
<button onclick="awayFunc()">Away</button>
<br>
<button onclick="meetingFunc()">In a meeting</button>
<br>
<button onclick="phoneFunc()">On the phone</button>
<br>
<button onclick="emailFunc()">Sending emails</button>
<br>
<button onclick="videoFunc()">On a video call</button>
<br>
<button onclick="clearFunc()">Clear Display</button>

<!--Section 1 END-->

<script>
///////////////// Section 2 START////////////////////
var available = "http://0.0.0.0:5000/api/available";
var busy = "http://0.0.0.0:5000/api/busy";
var away = "http://0.0.0.0:5000/api/away";
var meeting = "http://0.0.0.0:5000/api/meeting";
var phone = "http://0.0.0.0:5000/api/phone";
var email = "http://0.0.0.0:5000/api/email";
var video = "http://0.0.0.0:5000/api/video";
var clear = "http://0.0.0.0:5000/api/clear";
///////////////// Section 2 END////////////////////
///////////////// Section 3 START////////////////////
function availableFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", available);
document.getElementById("demo").innerHTML = "Status set to Available";
xmlhttp.send();
}
function busyFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", busy);
document.getElementById("demo").innerHTML = "Status set to Busy";
xmlhttp.send();
}
function awayFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", away);
document.getElementById("demo").innerHTML = "Status set to Away";
xmlhttp.send();
}
function meetingFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", meeting);
document.getElementById("demo").innerHTML = "Status set to in a meeting";
xmlhttp.send();
}
function phoneFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", phone);
document.getElementById("demo").innerHTML = "Status set to on the phone";
xmlhttp.send();
}
function emailFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", email);
document.getElementById("demo").innerHTML = "Status set to sending to emails";
xmlhttp.send();
}
function videoFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", video);
document.getElementById("demo").innerHTML = "Status set to on a video call";
xmlhttp.send();
}
function clearFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", clear);
document.getElementById("demo").innerHTML = "Clear Status Screen";
xmlhttp.send();
}
///////////////// Section 3 END////////////////////
</script>

</body>
</html>

لمحة عن الكود البرمجي

<!DOCTYPE html>
<!--Section 1 START-->
<html>
<body>

سيتم طباعة النصوص التالية في بداية صفحة الويب

<h1>Status Indicator</h1>

<p>This page allows you to select the text of your LCD status indicator.</p>

هنا سيتم اظهار الحالة التي تم اختيارها

<p id="demo"></p>

عرض مفاتيح اختيار الحالة

<button onclick="availableFunc()">Available</button>
<br>
<button onclick="busyFunc()">Busy</button>
<br>
<button onclick="awayFunc()">Away</button>
<br>
<button onclick="meetingFunc()">In a meeting</button>
<br>
<button onclick="phoneFunc()">On the phone</button>
<br>
<button onclick="emailFunc()">Sending emails</button>
<br>
<button onclick="videoFunc()">On a video call</button>
<br>
<button onclick="clearFunc()">Clear Display</button>

<!--Section 1 END-->

ارسال البيانات المدخلة إلى الراسبيري باي

يتم كتابة رقم الIP الخاص بالراسبيري باي بدلا من 0.0.0.0.

<script>
///Replace 0.0.0.0 with your Raspberry Pi's internal IP address below

var available = "http://0.0.0.0:5000/api/available"; 
var busy = "http://0.0.0.0:5000/api/busy"; 
var away = "http://0.0.0.0:5000/api/away"; 
var meeting = "http://0.0.0.0:5000/api/meeting"; 
var phone = "http://0.0.0.0:5000/api/phone"; 
var email = "http://0.0.0.0:5000/api/email"; 
var video = "http://0.0.0.0:5000/api/video"; 
var clear = "http://0.0.0.0:5000/api/clear";

اظهار الحالة في رأس الصفحة في خانة (Demo)

function availableFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", available);
document.getElementById("demo").innerHTML = "Status set to Available";
xmlhttp.send();
}
function busyFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", busy);
document.getElementById("demo").innerHTML = "Status set to Busy";
xmlhttp.send();
}
function awayFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", away);
document.getElementById("demo").innerHTML = "Status set to Away";
xmlhttp.send();
}
function meetingFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", meeting);
document.getElementById("demo").innerHTML = "Status set to in a meeting";
xmlhttp.send();
}
function phoneFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", phone);
document.getElementById("demo").innerHTML = "Status set to on the phone";
xmlhttp.send();
}
function emailFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", email);
document.getElementById("demo").innerHTML = "Status set to sending to emails";
xmlhttp.send();
}
function videoFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", video);
document.getElementById("demo").innerHTML = "Status set to on a video call";
xmlhttp.send();
}
function clearFunc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", clear);
document.getElementById("demo").innerHTML = "Clear Status Screen";
xmlhttp.send();
}
///////////////// Section 3 END////////////////////
</script>

</body>
</html>

 

برمجة البايثون

 سيتم اضافة كود البرمجي داخل ملف (Work) الذي تم عمله لمشروع مؤشر حالة العمل

cd work

الشكل التالي يمثل توزيع الملف الذي تم انشاؤه

ملف مؤشر حالة العمل

ثم

sudo nano status.py

ثم نكتب الأمر التالي

#!/usr/bin/env python

import i2c_lcd_driver
from time import sleep
from flask import Flask, jsonify, make_response, request, render_template
from datetime import datetime
mylcd = i2c_lcd_driver.lcd()

app = Flask(__name__)
#app.config['SERVER_NAME']= 'caroline.local'

def currentTime():
dateraw=datetime.now()
timeFormat=dateraw.strftime("%-I:%M %p")
return timeFormat

def switchTH() :
mylcd.lcd_clear()
mylcd.lcd_display_string("Welcome to", 1)
sleep(1)

def switchAvailable() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Status:Available", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchBusy() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Status: Busy", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchAway() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Status: Away", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchMeeting() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("In a meeting", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchPhone() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("On the phone", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchGrading() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Grading papers", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchEmail() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Sending Emails", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchVideo() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("On a video call", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)



def switchClear() :
mylcd.lcd_clear()
sleep(1)

# API TH
@app.route('/api/th', methods=['GET'])
def apiTH() :
switchTH()
return jsonify({})

# API switchAvailable
@app.route('/api/available', methods=['GET'])
def apiavailable() :
switchAvailable()
return jsonify({})

# API Busy
@app.route('/api/busy', methods=['GET'])
def apiBusy() :
switchBusy()
return jsonify({})

# API Away
@app.route('/api/away', methods=['GET'])
def apiAway() :
switchAway()
return jsonify({})

# API switchMeeting
@app.route('/api/meeting', methods=['GET'])
def apiMeeting() :
switchMeeting()
return jsonify({})

# API switchPhone
@app.route('/api/phone', methods=['GET'])
def apiPhone() :
global globalLastCalledApi
globalLastCalledApi = '/api/Phone'
switchPhone()
return jsonify({})


# API switchEmail
@app.route('/api/email', methods=['GET'])
def apiEmail() :
switchEmail()
return jsonify({})

# API switchVideo
@app.route('/api/video', methods=['GET'])
def apiVideo() :
switchVideo()
return jsonify({})

# API clear
@app.route('/api/clear', methods=['GET'])
def apiClear() :
switchClear()
return jsonify({})

@app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error': 'Not found'}), 404)

@app.route('/')
def index():
#url_for('html', filename='lcd.html')
return render_template('lcd.html')

if __name__ == '__main__':
app.debug = True
app.run(host='0.0.0.0')

شرح الأمر البرمجي

في البداية سيتم استدعاء المكتبات المطلوبة

#!/usr/bin/env python
import i2c_lcd_driver
from time import sleep
from flask import Flask, jsonify, make_response, request, render_template
from datetime import datetime
mylcd = i2c_lcd_driver.lcd()

تعريف دالة الوقت

def currentTime():
dateraw=datetime.now()
timeFormat=dateraw.strftime("%-I:%M %p")
return timeFormat

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

def switchTH() :
mylcd.lcd_clear()
mylcd.lcd_display_string("Welcome ", 1)
sleep(1)

نعرف 8 دوال للحالات التي قد يختار المستخدم من بينها

def switchAvailable() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Status:Available", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchBusy() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Status: Busy", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchAway() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Status: Away", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchMeeting() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("In a meeting", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchPhone() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("On the phone", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchGrading() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Grading papers", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchEmail() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("Sending Emails", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

def switchVideo() :
cT=currentTime()
mylcd.lcd_clear()
mylcd.lcd_display_string("On a video call", 1)
mylcd.lcd_display_string("as of "+cT, 2)
sleep(1)

نعرف API  للحالات الثمانية التي تم تعريفها

# API TH
@app.route('/api/th', methods=['GET'])
def apiTH() :
switchTH()
return jsonify({})

# API switchAvailable
@app.route('/api/available', methods=['GET'])
def apiavailable() :
switchAvailable()
return jsonify({})

# API Busy
@app.route('/api/busy', methods=['GET'])
def apiBusy() :
switchBusy()
return jsonify({})

# API Away
@app.route('/api/away', methods=['GET'])
def apiAway() :
switchAway()
return jsonify({})

# API switchMeeting
@app.route('/api/meeting', methods=['GET'])
def apiMeeting() :
switchMeeting()
return jsonify({})

# API switchPhone
@app.route('/api/phone', methods=['GET'])
def apiPhone() :
global globalLastCalledApi
globalLastCalledApi = '/api/Phone'
switchPhone()
return jsonify({})


# API switchEmail
@app.route('/api/email', methods=['GET'])
def apiEmail() :
switchEmail()
return jsonify({})

# API switchVideo
@app.route('/api/video', methods=['GET'])
def apiVideo() :
switchVideo()
return jsonify({})

# API clear
@app.route('/api/clear', methods=['GET'])
def apiClear() :
switchClear()
return jsonify({})

 

اكتب ip الخاص بالراسبيري باي في مربع url على المتصفح مع رقم المنفذ ليتم ظهور صفحة الويب  كالتالي (0.0.0.0:5000)

 




الحصالة الذكية باستخدام الاردوينو ومستشعر تجنب الحواجز

مقدمة

في هذا الدرس ستتعلم كيف تصنع حصالة ذكية تقوم بحساب العملات المعدنية باستخدام الاردوينو ومستشعر تجنب الحواجز بالأشعة تحت الحمراء.coin-sorting-counting-machine-arduino

المواد والأدوات

الحصالة الذكية

اردوينو اونو

الحصالة الذكية

مستشعر تجنب الحواجز بالأشعة تحت الحمراء

arduino-usb-lead-blue

x1 سلك الاردوينو

حصالة ذكية

شاشة كرستالية (LCD 2×16)

حصالة ذكية

1× لوحة تجارب – حجم كبير

حصالة ذكية

 1× مقاومة متغيرة

اسلاك توصيل

 حزمة أسلاك توصيل (ذكر- أنثى)

الحصالة الذكية

 حزمة أسلاك توصيل (ذكر- ذكر)

شفرة

1× 40 رأس دبوس

الحصالة الذكية

1× هيكل الحصالة

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

للمزيد حول مستشعر تجنب الحواجز بالأشعة تحت الحمراء يمكنك الرجوع للدرس إضاءة ذكية باستخدام مستشعر تجنب الحواجز بالأشعة تحت الحمراء.

وللمزيد حول الشاشة الكرستالية يمكنك الرجوع للدرس التحكم بالشاشة الكرستالية LCD.

coin-sorting-counting-machine-arduino

هيكل الحصالة الذكية

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

coin-sorting-counting-machine-arduino

الحصالة الذكية

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

بعد ذلك ثبت الدائرة الكهربائية على الهيكل.الحصالة الذكية

الحصالة الذكية

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

ارفع كود الحصالة الذكية على لوحة الاردوينو باستخدام برنامج اردوينو (IDE).

#include "EEPROMex.h"
#include <LiquidCrystal.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const float coinA = A0; 
const int coinB = A1;
const int coinC = A2;

float irA=0;
int irB,irC = 0;
float cntA=0;
float cntB,cntC,cnttotal = 0;

void setup() 
{
Serial.begin(9600); 
pinMode(coinA ,INPUT);
pinMode(coinB ,INPUT);
pinMode(coinC,INPUT);

lcd.begin(16, 2);
lcd.write(EEPROM.read(5));
}

void loop() 
{
irA =digitalRead(coinA); 
irB =digitalRead(coinB); 
irC=digitalRead(coinC); 

if(irA ==LOW){cntA+=0.50; delay(600);}
if(irB ==LOW){cntB+=1; delay(600);}
if(irC ==LOW){cntC+=2; delay(600);}
cnttotal =cntA+cntB+cntC;

EEPROM.write(5,cnttotal);
Serial.println(EEPROM.read(5));
lcd.setCursor(0,0);
lcd.print("Total :");
lcd.setCursor(0,1);
lcd.print(cnttotal);
}

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

هذه الأسطر تستدعي المكتبات الضرورية للدرس مثل مكتبة الشاشة الكرستالية <LiquidCrystal.h> و مكتبة “EEPROMex.h” التي تستخدم لكتابة وقراءة الأرقام.

يمكنك تحميل المكتبات من هنا.

يتم تنزيل المكتبات من خلال شريط القوائم في برنامج arduino IDE.

لعبة X/O

أو من خلال فك الضغط عن ملفات المكتبات ونقلها إلى الملف التالي الموجود بجهازك  C:\Program Files (x86)\Arduino

#include "EEPROMex.h"
#include <LiquidCrystal.h>

بعد ذلك تم انشاء المتغيرات اللازمة مثل المتغيرات الخاصة بالشاشة الكرستالية.

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

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

المتغير coinA من النوع float يستخدم لتخزين القيم المقروءة من المنفذ A0.

المتغير coinB من النوع int يستخدم لتخزين القيم المقروءة من المنفذ A1.

المتغير coinC من النوع int يستخدم لتخزين القيم المقروءة من المنفذ A2.

const float coinA = A0; 
const int coinB = A1;
const int coinC = A2;

سيتم تعيين القيم الابتدائية لكل مستشعرات تجنب الحواجز = 0.

وسيتم تعيين القيمة الابتدائية للمجموع الكلي لكل مستشعرات تجنب الحواجز = 0.

float irA=0;
int irB,irC = 0;
float cntA=0;
float cntB,cntC,cnttotal = 0;

في الدالة ()setup يتم تهيئة الشاشة الكرستالية وجعل المتغير coinA و coinB و coinC كمدخلات لقراءة القيم من المستشعرات.

void setup() 
{
Serial.begin(9600); 
pinMode(coinA ,INPUT);
pinMode(coinB ,INPUT);
pinMode(coinC,INPUT);

lcd.begin(16, 2);
lcd.write(EEPROM.read(5));
}

في الدالة ()loop يتم تخزين القيم المقروءة من المستشعرات الثلاث.

المدخل coinA قيمته تخزن في المتغير irA.

المدخل coinB قيمته تخزن في المتغير irB.

المدخل coinC قيمته تخزن في المتغير irC.

void loop() 
{
irA =digitalRead(coinA); 
irB =digitalRead(coinB); 
irC =digitalRead(coinC);

هنا سيتم حساب العملات في كل مستشعر.

وبعد ذلك يتم جمع القيم من كل المستشعرات وتخزينها في cnttotal.

if(irA ==LOW){cntA+=0.50; delay(600);}
if(irB ==LOW){cntB+=1; delay(600);}
if(irC ==LOW){cntC+=2; delay(600);}
cnttotal =cntA+cntB+cntC;

سيتم طباعة Total متبوعة بالمجموع الكلي للعملات المعدنية.

EEPROM.write(5,cnttotal);
Serial.println(EEPROM.read(5));
lcd.setCursor(0,0);
lcd.print("Total :");
lcd.setCursor(0,1);
lcd.print(cnttotal);
}

يمكنك اختبار الحصالة الذكية بعد رفع الكود البرمجي.

 لا تنسَ فصل مصدر الطاقة بعد الانتهاء من استخدام النظام.




مقياس تدفق الماء و التحكم بالكمية باستخدام الاردوينو

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

تدفق الماء


المواد و الأدوات*

اردوينو

X1 أردوينو أونو 

مرحل

X1 مرحل 

سلك الاردوينو

X1 سلك الأردوينو 

مفتاح

X8 ضغاط التحكم 

لوحة تجارب

X2 لوحة تجارب 

حساس التدفق

X1 حساس التدفق 

مقاومة

X8 مقاومة 10 كيلو أوم

مقاومة 220

1X مقاومة 220 أوم

مقاومة متغيرة

X1 مقاومة متغيرة 

صمام ملف

X1 ملف صمام 

وصلة  تيار ثابت

X1 وصلة تيار ثابت 

محول طاقة

X1 مصدر طاقة 24 فولت

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

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

 

حساس التدفق

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

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

مستشعر التدفق

ويحتوي المستشعر على 3 أسلاك باللون الأحمر والأصفر والأسود. يستخدم السلك الأحمر للجهد الذي يتراوح من 5 فولت إلى 18 فولت والسلك الأسود متصل بـ GND. يستخدم السلك الأصفر للإخراج (نبضات)، والتي يمكن قراءتها بواسطة المتحكم ، كذلك يظهر على المستشعر سهم يشير إلى مسار الماء

مستشعر التدفق

فكرة المشروع

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

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

ثانيًا: مفتاح تحديد الوحدة يمكن قياس الكمية بوحدة مليلتر أو لتر، إذا كان في حالة 0يعني أنه على وحدة مليلتر. وحالة 1 يعني لتر

ثالثا: متاح إعادة ضبط الكمية المعينة إلى 0، حيث تُظهر الشاشة SP   والتي تعني الكمية التي يعمل النظام للوصول لها والتي تم تحديدها من قبل المستخدم.

رابعًا: زر إعادة ضبط عداد الكمية المعبئة إلى 0، لبدء تعبئة جديدة، حيث تظهر الشاشة CNT والتي تشير لكمية الماء التي تم تعبئتها

خامسًا: مفاتيح تعين كمية الماء، وهي أربع مفاتيح +1,+10,+100,+1000.

 

تحديد عدد نبضات لتر واحد من الماء

 مواصفات المنتج أن 450 نبضة للتر واحد من الماء لكن للوصول لقراءة دقيقة سنقوم بعملية الوزن ،عن طريق أخذ قراءة عدد النبضات عند تمرير لتر واحد من الماء

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

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13); //Pines arduino to lcd

//-------Pins-----//
int Relay = 1; //Solenoid valve open/close
int start_stop = 2; //Start/Stop button
const int sensor_pulse = 16; //Sensor pulse
int rst_cnt = 3; // Reset counter button
//---------Storage debounce function-----//
boolean currentstart_stop = LOW; 
boolean laststart_stop =LOW; 
boolean lastsensor_pulse = LOW;
boolean currentsensor_pulse = LOW;
boolean lastrst_cnt = LOW;
boolean currentrst_cnt = LOW;
boolean RelayState = LOW; 

int counter = 0;

void setup() {
pinMode(Relay, OUTPUT);
lcd.begin(16, 2);
lcd.setCursor(5, 0);
lcd.print("COUNTER");
lcd.setCursor(0, 1);
lcd.print("PULSES");

}
//----Debouncing function----//
boolean debounce(boolean last, int pin)
{
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}

void loop() { 
currentstart_stop = debounce(laststart_stop, start_stop); //Debounce for Start/Stop Button
currentsensor_pulse = debounce(lastsensor_pulse, sensor_pulse); //Debounce for Sensor pulse Button
currentrst_cnt = debounce(lastrst_cnt, rst_cnt); //Debounce for reset counter Button

//-----Start/Stop toggle function----//
if (currentstart_stop == HIGH && laststart_stop == LOW){

if (RelayState == HIGH){ //Toggle the state of the Relay
digitalWrite(Relay, LOW);
RelayState = LOW;


} 
else{
digitalWrite(Relay, HIGH);
RelayState = HIGH;
}
}

laststart_stop = currentstart_stop;

if (lastsensor_pulse== LOW && currentsensor_pulse == HIGH){
counter=counter+ 1;
}
lastsensor_pulse = currentsensor_pulse;

lcd.setCursor(7, 1);
lcd.print(counter);

if(RelayState == LOW){ //Reset counter while sistem is not running
if (currentrst_cnt == HIGH && lastrst_cnt == LOW){//Reset Counter
lcd.setCursor(6, 1); // Clear CNT area
lcd.print(" ");
counter= 0; 

}
lastrst_cnt = currentrst_cnt; 
}

}// end void loop

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

استدعاء مكتبة الشاشة الكرستالية، و تعريف المنافذ للشاشة

 #include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13); //Pines arduino to lcd

تعريف منافذ الحساس تم توصيله مع منفذ A2= 16، و تسمية المتغير sensor_pulse، كذلك تعريف منفذ مفتاح التحكم بتشغيل النظام و هو المنفذ رقم 3 و منفذ مفتاح التحكم بتصفير العداد و هو المنفذ رقم 2

//-------Pins-----//
int Relay = 17; //Solenoid valve open/close
int start_stop = 2; //Start/Stop button
const int sensor_pulse = 16; //Sensor pulse
int rst_cnt = 3; // Reset counter button

تعين الحالة الابتدائية للمتغرات

boolean currentstart_stop = LOW; 
boolean laststart_stop =LOW; 
boolean lastsensor_pulse = LOW;
boolean currentsensor_pulse = LOW;
boolean lastrst_cnt = LOW;
boolean currentrst_cnt = LOW;
boolean RelayState = LOW; 

int counter = 0;

في دالة void setup نقوم بتهيئة الشاشة وتعريف منافذ الادخال و الاخراج

void setup() {
pinMode(Relay, OUTPUT);
lcd.begin(16, 2);
lcd.setCursor(5, 0);
lcd.print("COUNTER");
lcd.setCursor(0, 1);
lcd.print("PULSES");

}
//----Debouncing function----//
boolean debounce(boolean last, int pin)
{
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}

في دالة void loop يتم حساب عدد النبضات و عرضها على الشاشة الكرستالية

void loop() { 
currentstart_stop = debounce(laststart_stop, start_stop); //Debounce for Start/Stop Button
currentsensor_pulse = debounce(lastsensor_pulse, sensor_pulse); //Debounce for Sensor pulse Button
currentrst_cnt = debounce(lastrst_cnt, rst_cnt); //Debounce for reset counter Button

//-----Start/Stop toggle function----//
if (currentstart_stop == HIGH && laststart_stop == LOW){

if (RelayState == HIGH){ //Toggle the state of the Relay
digitalWrite(Relay, LOW);
RelayState = LOW;


} 
else{
digitalWrite(Relay, HIGH);
RelayState = HIGH;
}
}

laststart_stop = currentstart_stop;
if (lastsensor_pulse== LOW && currentsensor_pulse == HIGH){
counter=counter+ 1;
}
lastsensor_pulse = currentsensor_pulse;
lcd.setCursor(7, 1);
lcd.print(counter);
if(RelayState == LOW){ //Reset counter while sistem is not running
if (currentrst_cnt == HIGH && lastrst_cnt == LOW){//Reset Counter
lcd.setCursor(6, 1); // Clear CNT area
lcd.print(" ");
counter= 0; 
}
lastrst_cnt = currentrst_cnt; 
}
}// end void loop

قم بحفض القيمة لكل لتر من الماء ليتم تعديلها في الشفرة البرمجية للمشروع

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

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13); //Pines arduino to lcd

//-------Pins-----//
int Relay = 17; //Solenoid valve open/close
int start_stop = 2; //Start/Stop button
int rst_sp = 3; // Reset Set Point Button
int rst_cnt = 4; // Reset counter button
int unit = 5; // Change Unit Button
const int sensor_pulse =16; // Sensor Pulse In
//----Analog as Input-----//
int add_one =6; // +1 Button
int add_ten = 7; // +10 Button
int add_cien = 14; // +100 Button
int add_mil = 15; // +1000 Buton

//-----Variables for debouncing-----//
boolean currentstart_stop = LOW; 
boolean laststart_stop =LOW; 
boolean lastsensor_pulse = LOW;
boolean currentsensor_pulse = LOW;
boolean lastunit = LOW;
boolean currentunit = LOW;
boolean lastrst_sp = LOW;
boolean currentrst_sp = LOW;
boolean lastrst_cnt = LOW;
boolean currentrst_cnt = LOW;
boolean lastadd_one = LOW;
boolean currentadd_one = LOW;
boolean lastadd_ten = LOW;
boolean currentadd_ten = LOW;
boolean lastadd_cien = LOW;
boolean currentadd_cien = LOW;
boolean lastadd_mil = LOW;
boolean currentadd_mil = LOW;

//-----Storage state for toggle function---//
boolean unitState = LOW; //storage for the current state of the unit
boolean RelayState = LOW; //storage for the current state of the Relay (off/on)

//-------You have to put your pulses x liters here-----//
float cal_1=2.5; //Calibrate ml x pulse (cal_1 = 1000/400)
int cal_2= 400; //Calibrate pulses x liters
//-----------------------------------------------------//

float counter_1 = 0.0; 
int counter_2= 0; 
int TotalCount_1= 0;
int TotalCount_2= 0;
int set_point_1= 0; 
int set_point_2= 0;

void setup(){
lcd.begin(16, 2);
pinMode(Relay, OUTPUT); 
pinMode(add_one, INPUT); 
pinMode(add_ten, INPUT); 
pinMode(add_cien, INPUT); 
pinMode(add_mil, INPUT);

lcd.setCursor(0,0); //Show "SP" on the LCD
lcd.print("SP"); 
lcd.setCursor(0,1); //Show "CNT" on the LCD
lcd.print("CNT"); 

}
//----Debouncing function for all buttons----//
boolean debounce(boolean last, int pin)
{
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}

void loop(){
//-----Debounce Buttons-----//
currentstart_stop = debounce(laststart_stop, start_stop); //Debounce for Start/Stop Button
currentsensor_pulse = debounce(lastsensor_pulse, sensor_pulse); //Debounce for Sensor
currentunit = debounce(lastunit, unit); //Debounce for unit Button
currentrst_sp = debounce(lastrst_sp, rst_sp); //Debounce for reset set point Button
currentrst_cnt = debounce(lastrst_cnt, rst_cnt); //Debounce for reset counter Button
currentadd_one = debounce(lastadd_one, add_one); //Debounce for +1 Button
currentadd_ten = debounce(lastadd_ten, add_ten); //Debounce for +10 Button
currentadd_cien = debounce(lastadd_cien, add_cien); //Debounce for +100 Button
currentadd_mil = debounce(lastadd_mil, add_mil); //Debounce for +1000 Button


//-----Start/Stop toggle function----//
if (currentstart_stop == HIGH && laststart_stop == LOW){

if (RelayState == HIGH){ //Toggle the state of the Relay
digitalWrite(Relay, LOW);
RelayState = LOW;
} 
else{
digitalWrite(Relay, HIGH);
RelayState = HIGH;
}
}

laststart_stop = currentstart_stop;

//-------Unit toggle function----//
if(RelayState == LOW){ //You only can change unit while system is not running! 

//------ Lt/ml unit toggle function----//
if (currentunit == HIGH && lastunit == LOW){
lcd.setCursor(4, 1); //Clear lcd(CNT area) between unit change,keeping last count
lcd.print(" ");
lcd.setCursor(3,0); //Clear lcd (SP area) between unit change, keeping last SP
lcd.print(" ");

if (unitState == HIGH){ //Toggle the state of the unit (L/ml)
digitalWrite(unit, LOW);
unitState = LOW;
}
else{
digitalWrite(unit, HIGH);
unitState = HIGH; 
}
}
lastunit = currentunit;
}
//------Print unit state-----//
if(unitState==HIGH){ //Unit state HIGH = L 
lcd.setCursor(14,0);
lcd.print("Lt");
lcd.setCursor(14, 1);
lcd.print("Lt");

}
else { //Unit state LOW = ml
lcd.setCursor(14,0);
lcd.print("Ml");
lcd.setCursor(14,1);
lcd.print("Ml");
}//End Print unit state

//--------------------------// 
//------------Ml Counter-----//
//---------------------------//
if(unitState==LOW){ // LOW= Ml state

//-----------------------//
//-----Settings----------//
//----------------------//

if(RelayState == LOW){ // You only can change settings while system is not running!

//-----Adders Buttons (set point_1)---//

if (currentadd_ten == HIGH && lastadd_ten == LOW){ // Add +10
set_point_1 = set_point_1 +10;
}
lastadd_ten = currentadd_ten;

if (currentadd_cien == HIGH && lastadd_cien == LOW){ // Add +100
set_point_1 = set_point_1 +100;
}
lastadd_cien = currentadd_cien;

if (currentadd_mil == HIGH && lastadd_mil == LOW){ // Add +1000
set_point_1 = set_point_1 +1000;
}
lastadd_mil = currentadd_mil; 

//-------Reset Buttons----//
if (currentrst_sp == HIGH && lastrst_sp == LOW){ //Reset Set Point
lcd.setCursor(3, 0); // Clear SP area
lcd.print(" ");
set_point_1 = 0;
}
lastrst_sp = currentrst_sp;
if (currentrst_cnt == HIGH && lastrst_cnt == LOW){//Reset Counter
lcd.setCursor(4, 1); // Clear CNT area
lcd.print(" ");
counter_1= 0; 
TotalCount_1= 0;
}
lastrst_cnt = currentrst_cnt;
}//-----End Settings-----//

//----Start Counter------//
if(RelayState == HIGH){ // Only counts while relay is HIGH
if (lastsensor_pulse== LOW && currentsensor_pulse == HIGH){
counter_1 = counter_1 + cal_1;
}
}
lastsensor_pulse = currentsensor_pulse;

//-------Counter function-----//
if(counter_1 >= 10){
TotalCount_1 = TotalCount_1 + 10;
counter_1=0; //Counter reset
}

lcd.setCursor(3, 0); //Show set point
lcd.print(set_point_1);
lcd.setCursor(4, 1); // Show counter
lcd.print(TotalCount_1);

//--Stop Counter.You can´t start if set point is lower or equal to counter--//
if(RelayState==HIGH){
if(set_point_1 <= TotalCount_1){ 
RelayState = LOW;
digitalWrite(Relay, LOW);
//***********************************************Autoreset
lcd.setCursor(4, 1); // Clear CNT area
lcd.print(" ");
counter_1= 0; 
TotalCount_1= 0; 
}
}
}//End unit state LOW (ml)

//--------------------------// 
//------------Lt Counter-----//
//---------------------------//

if(unitState== HIGH){ //HIGH = Lt state

//-----------------------//
//-----Settings----------//
//----------------------//

if(RelayState == LOW){ // You only can change settings while system is not running!

//-----Adders Buttons (set point_2)---//
if (currentadd_one == HIGH && lastadd_one == LOW){ // Add +1 
set_point_2 = set_point_2 +1;
}
lastadd_one = currentadd_one;

if (currentadd_ten == HIGH && lastadd_ten == LOW){ // Add +10
set_point_2 = set_point_2 +10;
}
lastadd_ten = currentadd_ten;

if (currentadd_cien == HIGH && lastadd_cien == LOW){ // Add +100
set_point_2 = set_point_2 +100;
}
lastadd_cien = currentadd_cien;

if (currentadd_mil == HIGH && lastadd_mil == LOW){ // Add +1000
set_point_2 = set_point_2 +1000;
}
lastadd_mil = currentadd_mil; 

//-------Reset Buttons----//
if (currentrst_sp == HIGH && lastrst_sp == LOW){ //Reset Set Point
lcd.setCursor(3, 0); // Clear SP area
lcd.print(" ");
set_point_2 = 0;
}
lastrst_sp = currentrst_sp;
if (currentrst_cnt == HIGH && lastrst_cnt == LOW){//Reset Counter
lcd.setCursor(4, 1); // Clear CNT area
lcd.print(" ");
counter_2= 0; 
TotalCount_2= 0;
}
lastrst_cnt = currentrst_cnt;
}//-----End Settings-----//

//----Start Counter------//
if(RelayState == HIGH){ // Only counts while relay is HIGH
if (lastsensor_pulse== LOW && currentsensor_pulse == HIGH){
counter_2 = counter_2 + 1;
}
}
lastsensor_pulse = currentsensor_pulse;

//-------Counter function-----//
if(counter_2 == cal_2){
TotalCount_2 = TotalCount_2 + 1;
counter_2 = 0; //Counter reset
}

lcd.setCursor(3, 0); //Show set point
lcd.print(set_point_2);
lcd.setCursor(4, 1); // Show counter
lcd.print(TotalCount_2);

//--Stop Counter.You can´t start if set point is lower or equal to counter--//
if(RelayState==HIGH){
if(set_point_2 <= TotalCount_2){
RelayState = LOW;
digitalWrite(Relay, LOW);
//*****************************Autoreset
lcd.setCursor(4, 1); // Clear CNT area
lcd.print(" ");
counter_2= 0; 
TotalCount_2= 0; 
} 
}


}//End unit state HIGH (L)




}//End Void Loop

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

استدعاء مكتبة الشاشة الكرستالية و تعريف منافذها

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13); //Pines arduino to lcd

تعريف منافذ مفاتيح النظام

//-------Pins-----//
int Relay = 17; //Solenoid valve open/close
int start_stop = 2; //Start/Stop button
int rst_sp = 3; // Reset Set Point Button
int rst_cnt = 4; // Reset counter button
int unit = 5; // Change Unit Button
const int sensor_pulse =16; // Sensor Pulse In
//----Analog as Input-----//
int add_one =6; // +1 Button
int add_ten = 7; // +10 Button
int add_cien = 14; // +100 Button
int add_mil = 15; // +1000 Buton

تعريف متغيرات

//-----Variables for debouncing-----//
boolean currentstart_stop = LOW; 
boolean laststart_stop =LOW; 
boolean lastsensor_pulse = LOW;
boolean currentsensor_pulse = LOW;
boolean lastunit = LOW;
boolean currentunit = LOW;
boolean lastrst_sp = LOW;
boolean currentrst_sp = LOW;
boolean lastrst_cnt = LOW;
boolean currentrst_cnt = LOW;
boolean lastadd_one = LOW;
boolean currentadd_one = LOW;
boolean lastadd_ten = LOW;
boolean currentadd_ten = LOW;
boolean lastadd_cien = LOW;
boolean currentadd_cien = LOW;
boolean lastadd_mil = LOW;
boolean currentadd_mil = LOW;

//-----Storage state for toggle function---//
boolean unitState = LOW; //storage for the current state of the unit
boolean RelayState = LOW; //storage for the current state of the Relay (off/on)

هنا يتم تعديل الأمر البرمجي بناء على عدد النبضات التي وجدتها في كود الموازنة، حيث تقوم بقسمة عدد النبضات على 1000 لتعين متغير cal_1 و متغسر cal_2 يساوي عدد النبضات

//-------You have to put your pulses x liters here-----//
float cal_1=2.5; //Calibrate ml x pulse (cal_1 = 1000/400)
int cal_2= 400; //Calibrate pulses x liters
//-----------------------------------------------------//

float counter_1 = 0.0;
int counter_2= 0;
int TotalCount_1= 0;
int TotalCount_2= 0;
int set_point_1= 0;
int set_point_2= 0;

في دالة void setup يتم تهيئة الشاشة

void setup(){
lcd.begin(16, 2);
pinMode(Relay, OUTPUT);
pinMode(add_one, INPUT);
pinMode(add_ten, INPUT);
pinMode(add_cien, INPUT);
pinMode(add_mil, INPUT);

lcd.setCursor(0,0); //Show "SP" on the LCD
lcd.print("SP");
lcd.setCursor(0,1); //Show "CNT" on the LCD
lcd.print("CNT");

}
//----Debouncing function for all buttons----//
boolean debounce(boolean last, int pin)
{
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}


دالة الvoid loop لبدء النظام

 

void loop(){
//-----Debounce Buttons-----//
currentstart_stop = debounce(laststart_stop, start_stop); //Debounce for Start/Stop Button
currentsensor_pulse = debounce(lastsensor_pulse, sensor_pulse); //Debounce for Sensor
currentunit = debounce(lastunit, unit); //Debounce for unit Button
currentrst_sp = debounce(lastrst_sp, rst_sp); //Debounce for reset set point Button
currentrst_cnt = debounce(lastrst_cnt, rst_cnt); //Debounce for reset counter Button
currentadd_one = debounce(lastadd_one, add_one); //Debounce for +1 Button
currentadd_ten = debounce(lastadd_ten, add_ten); //Debounce for +10 Button
currentadd_cien = debounce(lastadd_cien, add_cien); //Debounce for +100 Button
currentadd_mil = debounce(lastadd_mil, add_mil); //Debounce for +1000 Button

//-----Start/Stop toggle function----//
if (currentstart_stop == HIGH && laststart_stop == LOW){

if (RelayState == HIGH){ //Toggle the state of the Relay
digitalWrite(Relay, LOW);
RelayState = LOW;
}
else{
digitalWrite(Relay, HIGH);
RelayState = HIGH;
}
}

laststart_stop = currentstart_stop;

//-------Unit toggle function----//
if(RelayState == LOW){ //You only can change unit while system is not running!

//------ Lt/ml unit toggle function----//
if (currentunit == HIGH && lastunit == LOW){
lcd.setCursor(4, 1); //Clear lcd(CNT area) between unit change,keeping last count
lcd.print(" ");
lcd.setCursor(3,0); //Clear lcd (SP area) between unit change, keeping last SP
lcd.print(" ");

if (unitState == HIGH){ //Toggle the state of the unit (L/ml)
digitalWrite(unit, LOW);
unitState = LOW;
}
else{
digitalWrite(unit, HIGH);
unitState = HIGH;
}
}
lastunit = currentunit;
}

الشرط التالي لتغير الوحدة

//------Print unit state-----//
if(unitState==HIGH){ //Unit state HIGH = L
lcd.setCursor(14,0);
lcd.print("Lt");
lcd.setCursor(14, 1);
lcd.print("Lt");

}
else { //Unit state LOW = ml
lcd.setCursor(14,0);
lcd.print("Ml");
lcd.setCursor(14,1);
lcd.print("Ml");
}//End Print unit state

//--------------------------//
//------------Ml Counter-----//
//---------------------------//
if(unitState==LOW){ // LOW= Ml state

//-----------------------//
//-----Settings----------//
//----------------------//

يمكن تغير الإعدادات اذا كان النظام لايعمل

if(RelayState == LOW){ // You only can change settings while system is not running!

//-----Adders Buttons (set point_1)---//

if (currentadd_ten == HIGH && lastadd_ten == LOW){ // Add +10
set_point_1 = set_point_1 +10;
}
lastadd_ten = currentadd_ten;

if (currentadd_cien == HIGH && lastadd_cien == LOW){ // Add +100
set_point_1 = set_point_1 +100;
}
lastadd_cien = currentadd_cien;

if (currentadd_mil == HIGH && lastadd_mil == LOW){ // Add +1000
set_point_1 = set_point_1 +1000;
}
lastadd_mil = currentadd_mil;

الشرط التالي لتحديد عمل مفتاح اعادة الضبط

//-------Reset Buttons----//
if (currentrst_sp == HIGH && lastrst_sp == LOW){ //Reset Set Point
lcd.setCursor(3, 0); // Clear SP area
lcd.print(" ");
set_point_1 = 0;
}
lastrst_sp = currentrst_sp;
if (currentrst_cnt == HIGH && lastrst_cnt == LOW){//Reset Counter
lcd.setCursor(4, 1); // Clear CNT area
lcd.print(" ");
counter_1= 0;
TotalCount_1= 0;
}
lastrst_cnt = currentrst_cnt;
}//-----End Settings-----//

//----Start Counter------//
if(RelayState == HIGH){ // Only counts while relay is HIGH
if (lastsensor_pulse== LOW && currentsensor_pulse == HIGH){
counter_1 = counter_1 + cal_1;
}
}
lastsensor_pulse = currentsensor_pulse;

دالة العداد

//-------Counter function-----//
if(counter_1 >= 10){
TotalCount_1 = TotalCount_1 + 10;
counter_1=0; //Counter reset
}

lcd.setCursor(3, 0); //Show set point
lcd.print(set_point_1);
lcd.setCursor(4, 1); // Show counter
lcd.print(TotalCount_1);

//--Stop Counter.You can´t start if set point is lower or equal to counter--//
if(RelayState==HIGH){
if(set_point_1 <= TotalCount_1){
RelayState = LOW;
digitalWrite(Relay, LOW);
//***********************************************Autoreset
lcd.setCursor(4, 1); // Clear CNT area
lcd.print(" ");
counter_1= 0;
TotalCount_1= 0;
}
}
}//End unit state LOW (ml)

//--------------------------//
//------------Lt Counter-----//
//---------------------------//

if(unitState== HIGH){ //HIGH = Lt state

//-----------------------//
//-----Settings----------//
//----------------------//

if(RelayState == LOW){ // You only can change settings while system is not running!

//-----Adders Buttons (set point_2)---//
if (currentadd_one == HIGH && lastadd_one == LOW){ // Add +1
set_point_2 = set_point_2 +1;
}
lastadd_one = currentadd_one;

if (currentadd_ten == HIGH && lastadd_ten == LOW){ // Add +10
set_point_2 = set_point_2 +10;
}
lastadd_ten = currentadd_ten;

if (currentadd_cien == HIGH && lastadd_cien == LOW){ // Add +100
set_point_2 = set_point_2 +100;
}
lastadd_cien = currentadd_cien;

if (currentadd_mil == HIGH && lastadd_mil == LOW){ // Add +1000
set_point_2 = set_point_2 +1000;
}
lastadd_mil = currentadd_mil;

//-------Reset Buttons----//
if (currentrst_sp == HIGH && lastrst_sp == LOW){ //Reset Set Point
lcd.setCursor(3, 0); // Clear SP area
lcd.print(" ");
set_point_2 = 0;
}
lastrst_sp = currentrst_sp;
if (currentrst_cnt == HIGH && lastrst_cnt == LOW){//Reset Counter
lcd.setCursor(4, 1); // Clear CNT area
lcd.print(" ");
counter_2= 0;
TotalCount_2= 0;
}
lastrst_cnt = currentrst_cnt;
}//-----End Settings-----//

//----Start Counter------//
if(RelayState == HIGH){ // Only counts while relay is HIGH
if (lastsensor_pulse== LOW && currentsensor_pulse == HIGH){
counter_2 = counter_2 + 1;
}
}
lastsensor_pulse = currentsensor_pulse;

//-------Counter function-----//
if(counter_2 == cal_2){
TotalCount_2 = TotalCount_2 + 1;
counter_2 = 0; //Counter reset
}

lcd.setCursor(3, 0); //Show set point
lcd.print(set_point_2);
lcd.setCursor(4, 1); // Show counter
lcd.print(TotalCount_2);

//--Stop Counter.You can´t start if set point is lower or equal to counter--//
if(RelayState==HIGH){
if(set_point_2 <= TotalCount_2){
RelayState = LOW;
digitalWrite(Relay, LOW);
//*****************************Autoreset
lcd.setCursor(4, 1); // Clear CNT area
lcd.print(" ");
counter_2= 0;
TotalCount_2= 0;
}
}

}//End unit state HIGH (L)




}//End Void Loop



عرض أوقات الصلاة على الشاشة باستخدام الاردوينو

مقدمة

في هذا الدرس ستتعلم كيف تعرض أوقات الصلاة على شاشة Oled باستخدام الاردوينو.arduino-smart-prayer-times-display

المواد والأدوات

أوقات الصلاة

1× اردوينو اونو

أوقات الصلاة

1× سلك الاردوينو

أوقات الصلاة

 حزمة أسلاك توصيل (ذكر- ذكر)

arduino-smart-prayer-times-display

1× وحدة الوقت الحقيقي (RTC)

arduino-smart-prayer-times-display

1× شاشة (OLED)


arduino-smart-prayer-times-display

لوحة تجارب حجم وسط

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

للمزيد حول الشاشة (OLED) يمكنك الرجوع للدرس  شاشة عرض (OLED) Display.

وللمزيد حول وحدة الوقت الحقيقي يمكنك الرجوع للدرس استخدام DS3231 RTC Module مع الاردوينو.arduino-smart-prayer-times-display

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

بالبداية عليك تحميل المكتبات التالية.

 Streaming.h  و “mainroutines.h” و <U8g2lib.h>

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

#include <Wire.h>
#include <RTClib.h>
#include <Streaming.h>
#include <SoftwareSerial.h>
#include <U8g2lib.h>
#include "mainroutines.h"

const unsigned int text1_y0=30, text2_y0=60, text2_x1=0, text2_x2=58;
char text1[8], text2[6], todaydate[9];
int displaypage=0;
const uint8_t BTTX = 3;
const uint8_t BTRX = 2;
int quartsec, OldDay, OldMinute, OldSecond, dayMinutes, NextSalat;
int i;
DateTime now;
char time[9];

U8G2_SSD1306_128X64_NONAME_2_HW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA); 
SoftwareSerial BTSerial(BTRX, BTTX);

struct FLAGS {
unsigned Recalcule : 1;
unsigned CheckTime : 1;
unsigned seconde : 1;
unsigned SeqAthan : 1;
unsigned Toggles : 1;
unsigned demiseconde: 1;
unsigned heures : 1;
unsigned displayPageTog : 1;
};
struct FLAGS Flags;

void setup()
{
Serial.begin(115200);
BTSerial.begin(9600);
BTSerial.listen();
u8g2.begin();
u8g2.setFont(u8g2_font_logisoso24_tr);
u8g2.setFontMode(0);


u8g2.firstPage();
do {
u8g2.drawUTF8(0,text1_y0,"SalatTime");
u8g2.drawUTF8(0,text2_y0,"L. Baghli");
} 
while ( u8g2.nextPage() );

Wire.begin();
rtc.begin();
if (! rtc.isrunning()) {
Serial.println(F("RTC NOT running!"));
rtc.adjust(DateTime(2021,8, 24, 16,8, 0));
}

Serial.flush();
STinit();
Flags.Recalcule=1;
Flags.heures=0;
Flags.CheckTime=0;
Flags.displayPageTog=0;
cli();
TCCR1A = 0;
TCCR1B = (0<<WGM13) | (1<<WGM12) | 4;
OCR1A = 15625;
TIMSK1 = 1<<OCIE1A;
TIFR1 = 0;
TCNT1 = 0;
sei();
}
void CheckTime()
{
now = rtc.now();
Flags.Toggles = !Flags.Toggles;
if (OldSecond != now.second()) {
if (++displaypage>5) displaypage=0;
OldSecond = now.second();
Serial << now.day() << F("/")<< now.month() << F("/")<<now.year()
<< F(" ")<< now.hour() << F(":")<<now.minute() << F(":")<<now.second() << endl;
}
if (OldDay != now.day()) Flags.Recalcule = 1;
if ((OldMinute != now.minute()) && (Flags.Recalcule == 0))
{
if ((SalatT.m[NextSalat]==now.minute()) && (SalatT.h[NextSalat]==now.hour()))
{// Athan
Flags.SeqAthan = 1;
}
else Flags.SeqAthan = 0;
OldMinute = now.minute();
dayMinutes = now.hour()*60+now.minute();
for (i=4; i>=0; i--)
if (SalatT.h[i]*60 + SalatT.m[i] >= dayMinutes)
{
NextSalat = i;
Serial << F("SalatT.m[")<< i <<F("] =") << SalatT.m[i] << endl;
}
}
}
void MaJRTC(int * dt)
{
if ((dt[0]<1) || (dt[0]>31)) return;
if ((dt[1]<1) || (dt[1]>12)) return;
if ((dt[2]<2000) || (dt[2]>2099)) return;
if ((dt[3]<0) || (dt[3]>23)) return;
if ((dt[4]<0) || (dt[4]>59)) return;
if ((dt[5]<0) || (dt[5]>59)) return;
rtc.adjust(DateTime(dt[2], dt[1], dt[0], dt[3], dt[4], dt[5]));
}
ISR(TIMER1_COMPA_vect) {
if (Flags.SeqAthan)
{
Flags.Toggles = !Flags.Toggles;
}
if (++quartsec == 4) quartsec = 0;
Flags.CheckTime = 1; // check time chaque 1/4 seconde
Flags.displayPageTog = 1; // page affichée chaque 1/4 seconde
if (quartsec == 0) {
Flags.seconde = 1;
}
}
void DisplayPages()
{
switch(displaypage)
{
case 0: sprintf( text1, "Fajr");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[0],SalatT.m[0] );
break;
case 1: sprintf( text1, "Duhr");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[1],SalatT.m[1] );
break;
case 2: sprintf( text1, "Asr");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[2],SalatT.m[2] );
break;
case 3: sprintf( text1, "Mgrb");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[3],SalatT.m[3] );
break;
case 4: sprintf( text1, "Isha");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[4],SalatT.m[4] );
break;
for (int i=0; i<8; i++) text1[i] = todaydate[i];
sprintf( text2, "");
break;
}
sprintf( time, "%02hhu:%02hhu:%02hhu", now.hour(), now.minute(), now.second() );
u8g2.firstPage();
do {
u8g2.drawUTF8(0,text1_y0,time);
u8g2.drawUTF8(text2_x1,text2_y0, text1);
u8g2.drawUTF8(text2_x2,text2_y0, text2);
} while ( u8g2.nextPage() );
}
void loop()
{
if (Flags.CheckTime) {
CheckTime();
Flags.CheckTime = 0;
}
if (Flags.Recalcule) {
ComputeSalatTime();
OldDay = now.day();
sprintf( todaydate, "%02hhu/%02hhu/%02hhu", now.day(),now.month(),now.year()%100 );
todaydate[8]=0;
OldMinute = 61;
OldSecond = 61;
Flags.Recalcule = 0;
}
if (Flags.displayPageTog) {
DisplayPages();
Flags.displayPageTog = 0;
}
}

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

هنا تم استدعاء المكتبات التي سنستخدمها لعرض أوقات الصلاة على الشاشة.

#include <Wire.h>
#include <RTClib.h>
#include <Streaming.h>
#include <SoftwareSerial.h>
#include <U8g2lib.h>
#include "mainroutines.h"

هنا يتم تعريف المتغيرات التي سنستخدمها لتخزين النص الذي سينطبع على الشاشة.

char text1[8], text2[6], todaydate[9];

ربط المنافذ في الشاشة OLED بحيث يكون المنفذ SCL مع المنفذ SCL الموجود في وحدة الوقت والمنفذ SDA مع المنفذ SDA في وحدة الوقت.

U8G2_SSD1306_128X64_NONAME_2_HW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA);

يتم تقسيم الجهد 5V BTTX يحمل القيمة 3 و BTRX يحمل القيمة 2.

const uint8_t BTTX = 3;
const uint8_t BTRX = 2;

في الدالة ()setup يتم تهيئة الشاشة استعدادًا لطباعة الوقت وحساب أوقات الصلاة.

void setup()
{
Serial.begin(115200);
BTSerial.begin(9600);
BTSerial.listen();
u8g2.begin();
u8g2.setFont(u8g2_font_logisoso24_tr);
u8g2.setFontMode(0);
u8g2.firstPage();
do {
u8g2.drawUTF8(0,text1_y0,"SalatTime");
u8g2.drawUTF8(0,text2_y0,"L. Baghli");
} 
while ( u8g2.nextPage() );
Wire.begin();
rtc.begin();
if (! rtc.isrunning()) {
Serial.println(F("RTC NOT running!"));
rtc.adjust(DateTime(2021,8, 24, 16,8, 0));
}

 هذا السطر لابد من تعديله حسب التاريخ والوقت الحالي لديك و كتابة الوقت بالثواني و الدقائق و الساعة ، و التاريخ اليوم و الشهر والسنة

rtc.adjust(DateTime(2021,8, 24, 16,8, 0));  

هنا يتم تهيئة المتغيرات التي تستخدم لحساب أوقات الصلاة.

STinit();
Flags.Recalcule=1;
Flags.heures=0;
Flags.CheckTime=0;
Flags.displayPageTog=0;

في الدالة ()CheckTime يتم حساب الوقت وطباعته على الشاشة كل ثانية.

void CheckTime()
{
now = rtc.now();
Flags.Toggles = !Flags.Toggles;
if (OldSecond != now.second()) {
if (++displaypage>5) displaypage=0;
OldSecond = now.second();
Serial << now.day() << F("/")<< now.month() << F("/")<<now.year()
<< F(" ")<< now.hour() << F(":")<<now.minute() << F(":")<<now.second() << endl;
}
if (OldDay != now.day()) Flags.Recalcule = 1;
if ((OldMinute != now.minute()) && (Flags.Recalcule == 0))
{
if ((SalatT.m[NextSalat]==now.minute()) && (SalatT.h[NextSalat]==now.hour()))
{
Flags.SeqAthan = 1;
}
else Flags.SeqAthan = 0;
OldMinute = now.minute();
dayMinutes = now.hour()*60+now.minute();
for (i=4; i>=0; i--)
if (SalatT.h[i]*60 + SalatT.m[i] >= dayMinutes)
{
NextSalat = i;
Serial << F("SalatT.m[")<< i <<F("] =") << SalatT.m[i] << endl;
}
}
}

هنا يتم برمجة وحدة الوقت بحيث الساعات باليوم تكون 24 والدقائق 60 دقيقة للساعة و60 ثانية بالدقيقة.

void MaJRTC(int * dt)
{
if ((dt[0]<1) || (dt[0]>31)) return;
if ((dt[1]<1) || (dt[1]>12)) return;
if ((dt[2]<2000) || (dt[2]>2099)) return;
if ((dt[3]<0) || (dt[3]>23)) return;
if ((dt[4]<0) || (dt[4]>59)) return;
if ((dt[5]<0) || (dt[5]>59)) return;
rtc.adjust(DateTime(dt[2], dt[1], dt[0], dt[3], dt[4], dt[5]));
}
ISR(TIMER1_COMPA_vect) 
{
if (Flags.SeqAthan)
{
Flags.Toggles = !Flags.Toggles;
}
if (++quartsec == 4) quartsec = 0;
Flags.CheckTime = 1; 
Flags.displayPageTog = 1; 
if (quartsec == 0) {
Flags.seconde = 1;
}
}

هنا سيتم برمجة الشاشة لتحتوي على ست شاشات مختلفة في المحتوى.

الأولى: عرض موعد صلاة الفجر.

الثانية: عرض موعد صلاة الظهر.

الثالثة: عرض موعد صلاة العصر.

الرابعة: عرض صلاة المغرب.

الخامسة: عرض صلاة العشاء.

السادسة: عرض تاريخ اليوم.

void DisplayPages()
{
switch(displaypage)
{
case 0: sprintf( text1, "Fajr");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[0],SalatT.m[0] );
break;
case 1: sprintf( text1, "Duhr");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[1],SalatT.m[1] );
break;
case 2: sprintf( text1, "Asr");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[2],SalatT.m[2] );
break;
case 3: sprintf( text1, "Mgrb");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[3],SalatT.m[3] );
break;
case 4: sprintf( text1, "Isha");
sprintf( text2, "%02hhu:%02hhu", SalatT.h[4],SalatT.m[4] );
break;
for (int i=0; i<8; i++) text1[i] = todaydate[i];
sprintf( text2, "");
break;
}
sprintf( time, "%02hhu:%02hhu:%02hhu", now.hour(), now.minute(), now.second() );
u8g2.firstPage();
do {
u8g2.drawUTF8(0,text1_y0,time);
u8g2.drawUTF8(text2_x1,text2_y0, text1);
u8g2.drawUTF8(text2_x2,text2_y0, text2);
} while ( u8g2.nextPage() );
}

في الدالة ()loop سيتم تحديث الوقت وموعد الصلاة والتاريخ بشكل مستمر.

void loop()
{
if (Flags.CheckTime) {
CheckTime();
Flags.CheckTime = 0;
}
if (Flags.Recalcule) {
ComputeSalatTime();
OldDay = now.day();
sprintf( todaydate, "%02hhu/%02hhu/%02hhu", now.day(),now.month(),now.year()%100 );
todaydate[8]=0;
OldMinute = 61;
OldSecond = 61;
Flags.Recalcule = 0;
}
if (Flags.displayPageTog) {
DisplayPages();
Flags.displayPageTog = 0;
}
}

حمّل الملفات التالية التي تحتوي على الدوال المهمة؛ لحساب أوقات الصلاة بناء على موقعك الجغرافي.

mainroutines.cpp

و

mainroutines.h

انقر على Add File أضف الملفات اللذان قمت بتحميلهما.arduino-smart-prayer-times-displayبعد إضافتهما يمكنك التعديل عليهما اذهب إلى الملف mainroutines.cpp.

حرر الأسطر التالية لكي تناسب منطقة السكن لديك.

ادخل على هذا الرابط وضع منطقة السكن لديك (استخدم نسخة Expert).

عدّل []CountryName و []TownName و TimeZoneTown و Convention  و DST بناء على البيانات التي عرضها.

استخدم هذا الرابط لعرض خريطة منطقة السكن لديك.

انسخ وعدل قيم latitude و longitude الموجودة في الكود البرمجي.

في هذا الدرس استخدمنا البيانات الخاصة بمدينة الرياض.

/** change your town */
	const char CountryName[] PROGMEM =  "Arabie Saoudite";
	const char TownName[] PROGMEM = ""Ar Riyad";
	const double latitude = 24.6498255*deg2rd;
	const double longitude = 46.7687988*deg2rd;
	const int TimeZoneTown = 3;
	const int Convention =  5;
	const int DST = 0;

بعد تعديل الكود البرمجي يمكنك رفع الكود إلى لوحة الاردوينو.

يمكنك اختبار صحة خطواتك.

 لا تنسَ فصل مصدر الطاقة بعد الانتهاء من استخدام النظام.




فعّل مساعد جوجل الافتراضي على الراسبيري باي

مقدمة

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

المواد والأدوات

google-assistant

 1× راسبيري باي

google-assistant

 1× سلك (HDMI)

مساعد جوجل

1× محول تيار (5V-2A)

مساعد جوجل

1× سلك ايثرنت

مساعد جوجل

 1× كرت ذاكرة

google-assistant

1× مايكروفون

google-assistant

1× مكبر صوت

تهيئة حساب جوجل

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

اتبع الخطوات التالية لتسجيل وإعداد مشروع على منصة الأحداث

قم بتسجيل الدخول إلى منصة الأحداث باستخدام حساب جيميل (Gmail)

انقر على مشروع جديد New project.

  مساعد جوجل

ستظهر لك نافذة الشروط والأحكام، وتحديد الدولة، اختر الموافقة والاستمرار  (Agree and continue).

google-assistant

ثم ستظهر نافذة لتحديد اسم المشروع وتعيين البلد واللغة، قم بكتابة اسم المشروع وعين اللغة والبلد وانقر على انشئ مشروعًا (Create project)

مساعد جوجل

بعد الانتهاء من إنشاء مشروع في منصة الأحداث ستحتاج لتمكين Google Embedded Assistant API بالخطوات التالية:

في نافذة تبويب جديدة انتقل إلى منصة جوجل السحابية.

قم بتحديد مشروعك الذي قمت بإنشائه في الخطوة السابقة عن طريق النقر على “Select project” ثم “All”

بعد التأكد من أنك حددت مشروعك انقرعلى تمكين Enable.

google-assistant

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

لتحديد جهازك عد إلى منصة الأحداث. ستجد في نهاية الصفحة ظهور الجملة التالية “Are you looking for device registration” انقر على Click here.

google-assistant

 

سيتم نقلك إلى النافذة التالية، انقر فوق الزر “Register Model” للمتابعة.

مساعد جوجل

سيتم نقلك إلى النافذة التالية والتي تتطلب اسم المنتج و الشركة المصنعة، يجب ملء الفراغات في النافذة، نحن كتبنا اسم و شركة مصنعة من اختيارانا

 من قائمة Device type اختر Speaker ثم انقر على (Register model).

google-assistant

بعد أن قمت بتسجيل النموذج ستحصل على ملف الاعتماد و الذي يسمح لك بإجراء اتصال بخدمة مساعد قوقل  قم بتنزيل الملف على جهازك  بالنقر على التحميل Download OAuth 2.0 credentials. ستحتاج إليه في قسم تهيئة الراسبيري باي ثم انقر على Next.

google-assistant

 

يمكنك أن تحدد السمات التي تحتاجها في مشروعك بوضع علامة  (صح) مقابل السمة التي يحتاجها المشروع أو جلب جميع السمات بوضع علامة صح أمام All 7 traits.

ثم انقر على Save Traits.

google-assistant عد إلى منصة جوجل السحابية.

اظهر قائمة التنقل من خلال النقر على الثلاث شرطات في أعلى يسار الصفحة.

ثم اختر APIs & Services وانقر على OAuth consent screen.

مساعد جوجل

السماح للمستخدمين باستعمال النظام.

انقر على External ثم Create.

google-assistant

من قائمة User support email اختر البريد الإلكتروني على Gmail.

google-assistant

انزل أسفل الصفحة دوّن البريد الإلكتروني مرة أخرى ثم انقر على Save and continue.

google-assistant

في الصفحة التالية انقر على Save and continue.

google-assistant

انقر على Save and continue.

google-assistant

انقر على Back to Dashboard.

google-assistant

انقر على Publish app ثم confirm.

google-assistant

افتح صفحة الأنشطة الخاصة بك على جوجل.

انقر على Web & App Activity.

google-assistant

فعّل Web & App Activity.

ثم انقر على Turn on.

مساعد جوجلمساعد جوجل

فعّل الخيارين التاليين وانقر على I agree للموافقة على الشروط والأحكام.

google-assistant

توصيل القطع

وصّل المايكروفون مع لوحة الراسبيري باي كما في الشكل.

google-assistant

وصّل مكبر الصوت مع لوحة الراسبيري باي كما في الشكل.

google-assistant

تهيئة الراسبيري باي

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

وبعد تثبيت النظام، يمكنك تهيئة النظام من خلال الرجوع  للدرس الثاني تهيئة نظام التشغيل

افتح الشاشة السوداء LXterminal للبدء باستخدام الراسبيري باي.

مساعد جوجل

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

sudo apt-get update
sudo apt-get upgrade

ثم أعد تشغيل الراسبيري باي.

reboot

انشيء مجلد جديد باسم googleassistant.

mkdir googleassistant

ادخل إلى المجلد googleassistant.

cd googleassistant

في هذا السطر سنقوم بتعديل الملف التالي credentials.json.

sudo nano credentials.json

افتح ملف OAuth 2.0 Credentials  الذي قمت بتحميله مسبقًا في قسم تهيئة حساب جوجل وانسخ محتواه والصقه في ملف credentials.json كما في الشكل.

google-assistant

اضغط من لوحة المفاتيح على زر Ctrl + x لحفظ التعديلات.

ثم اضغط على زر Y للتأكيد على حفظ التعديلات.

أخيرًا اضغط على الشاشة السوداء. Enter للعودة إلى

اكتب السطر التالي حتى تقوم بتحميل الحزمة اللازمة.

sudo apt install python3-dev python3-venv python3-pip libssl-dev libffi-dev libportaudio2

حمّل مكتبة Google assistant.

sudo python3 -m pip install --upgrade google-assistant-library

حمّل مكتبة google-assistant-sdk[samples].

sudo python3 -m pip install --upgrade google-assistant-sdk[samples]

حمّل مكتبة google-auth-oauthlib[tool].

sudo python3 -m pip install --upgrade google-auth-oauthlib[tool]

سنستخدم google-oauthlib-tool لتفعيل الكود والأدوات اللازمة.

google-oauthlib-tool --client-secrets credentials.json \
--scope https://www.googleapis.com/auth/assistant-sdk-prototype \
--scope https://www.googleapis.com/auth/gcm \
--save --headless

ستواجهك رسالة بهذا الشكل انسخ الرابط الذي في الأسفل والصقه في المتصفح.

مساعد جوجل

بعد ذلك سجل دخولك على البريد الإلكتروني Gmail.

انقر على السماح Allow.

google-assistant

 انقر على السماح Allow.

google-assistant

انقر على السماح Allow.

google-assistant

انسخ الكود الذي سيظهر لك بهذا الشكل.

google-assistant

الصق الكود أسفل الرابط كما في الشكل.

google-assistant

عد إلى منصة جوجل السحابية.

اتبع المسار التالي حتى تحصل على ID الخاص بمشروعك.

مساعد جوجل

عد إلى منصة الأحداث.

حتى تحصل على ID الخاص بالجهاز.

google-assistant

google-assistant

هذا السطر يحتاج تعديل.

<projectid> ضع مكانه ID الخاص بمشروعك.

<deviceid> ضع مكانه ID الخاص بالجهاز.

googlesamples-assistant-pushtotalk --project-id <projectid> --device-model-id <deviceid>

يمكنك الآن اختبار مساعد قوقل الخاص بك.

لا تنسَ فصل وحدة الطاقة بعد الانتهاء من استخدام النظام.

 




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

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

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

 

المواد والأدوات

اردوينو

X1 اردوينو

Full-size-breadboard-830-2-640x480

X1 لوحة تجارب 

شاشة عرض 7 مقاطع - 4أرقام

X1 سبعة مقاطع 4-أرقام

أسلاك توصيل

مجموعة أسلاك توصيل(M/M)

10 ohm resistors

X4 مقاومة 10 كيلو أوم 

مفتاح

X1 ضغاط التحكم 

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

X1 سلك أردوينو

زنبرك

X10 زنبرك

وحدة سبع مقاطع – أربع ارقام

تستخدم وحدات العرض في كثير من المشاريع التي تتطلب عرض معلومات رقمية مثل درجة الحرارة، والوقت. يوجد شاشات عرض مكونة من 7 وحدات لتشكل رقم واحد تحتوي على 10 دبابيس، 7 منها للقطاعات، وواحد للنقطة، و2 دبابيس لمصدر الطاقة إما GND أو VCC حسب نوع الشاشة – قطب موجب مشترك Common Anode أو قطب سالب مشترك Common Cathode-
من ناحية أخرى، لا تحتوي الشاشة المكونة من 4 أرقام على 40 دبوس، بل تحتوي على 12 دبوس فقط: 7 للمقاطع وواحد للنقطة ودبابيس اختيار مكونة من 4 أرقام تحدد الرقم الذي سيكون نشطًا لعرض الحرف الذي أرسله Arduino على دبابيس قطعة 7 + 1.
يتم ترتيب المقاطع السبعة بطريقتين: إما أن يتم تجميع كل قطب سالب في دبوس واحد (GND)، وهذا النوع يسمى سالب مشترك Common Cathode، أو يتم تجميع كل قطب موجب في دبوس واحد (Vcc)، وهذا النوع يسمى قطب موجب مشترك Common Anode. وبالمثل، فإن الأجزاء المكونة من 7 أرقام والمكونة من 4 أرقام هي إما قطب موجب مشترك Common Anode أو قطب سالب مشترك Common Cathode، وبالتالي توجد أربعة دبابيس مشتركة للأرقام الأربعة.

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

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

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

 

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

نهاية أطراف الأسلاك يتم توصيلها مع الحلقات في الهيكل بحيث تكون أصغر حلقة موصله مع A 0  والتي تليها مع A1  والأخيرة مع A2

الهيكل

فكرة المشروع وضع ثلاث حلقات مكونه من مادة موصلة على قاعدة، كل حلقة متصلة مع خط الطاقة 5 فولت بالاردوينو، تنفصل عنها 3 حلقات باستخدام الزنبرك موصلة مع منافذ الأردوينو

  إذا استطاع اللاعب إصابة الهدف تتلامس الحلقات ويتم حساب النقاط ومن ثم عرضها على شاشة السبع وحدات أربع أرقام

في هذا الشكل يظهر توزيع الزنبركات والحلقات المتصلة على القاعدة الأساسية

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

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

 

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

#define aPin 2 
#define bPin 1 
#define cPin 4 
#define dPin 5 
#define ePin 6 
#define fPin 7 
#define gPin 8 

#define c1Pin 9 // Common pin for digit 1
#define c2Pin 10 // Common pin for digit 2
#define c3Pin 11 // Common pin for digit 3
#define c4Pin 12 // Common pin for digit 4

#define c1 A0
#define c2 A1
#define c3 A2
#define bt_reset A3
long Counter=0;
int flag1=0, flag2=0, flag3=0, timer=0;
int Common = 0; //<Common=1; for Common anode> <Common=0; for Common cathode>
int On, Off, Off_C; 
int DTime = 4; // Display timer

void setup(){ // put your setup code here, to run once

pinMode(c1, INPUT);
pinMode(c2, INPUT);
pinMode(c3, INPUT);
pinMode(bt_reset, INPUT);

pinMode(aPin, OUTPUT);
pinMode(bPin, OUTPUT);
pinMode(cPin, OUTPUT);
pinMode(dPin, OUTPUT);
pinMode(ePin, OUTPUT); 
pinMode(fPin, OUTPUT);
pinMode(gPin, OUTPUT);
pinMode(c1Pin, OUTPUT);
pinMode(c2Pin, OUTPUT);
pinMode(c3Pin, OUTPUT);
pinMode(c4Pin, OUTPUT);


if(Common==1){On=0, Off=1, Off_C=0;} //for Common anode
else{On=1, Off=0, Off_C=1;} //for Common cathode

// Indicate that system is ready
for (int i = 9; i >=0; i--) {
showNumber(i);
digitalWrite(c1Pin, Common);
digitalWrite(c2Pin, Common);
digitalWrite(c3Pin, Common);
digitalWrite(c4Pin, Common);
delay(1000); 
} 
}

void loop(){

if(digitalRead (c1) == 1){
if(flag1==0){ flag1=1;
Counter = Counter+30;
if(Counter>9999){Counter=0;} 
}}
else{flag1=0;}

if(digitalRead (c2) == 1){ 
if(flag2==0){ flag2=1;
Counter = Counter+20;
if(Counter<0){Counter=9999;} 
} 
}else{flag2=0;}
if(digitalRead (c3) == 1){ 
if(flag2==0){ flag2=1;
Counter = Counter+10;
if(Counter<0){Counter=9999;} 
} 
}else{flag3=0;}

if(digitalRead (bt_reset) == 1){ 
Counter=0;
if(timer<200){timer=timer+1;}
if(timer==200){

} 
}else{timer=0;}


showNumber((Counter/1000)%10);
digitalWrite(c1Pin, Common);
delay(DTime);
digitalWrite(c1Pin, Off_C);

showNumber((Counter/100)%10);
digitalWrite(c2Pin, Common);
delay(DTime);
digitalWrite(c2Pin, Off_C);

showNumber((Counter/10)%10);
digitalWrite(c3Pin, Common);
delay(DTime);
digitalWrite(c3Pin, Off_C);

showNumber(Counter%10);
digitalWrite(c4Pin, Common);
delay(DTime);
digitalWrite(c4Pin, Off_C);

}


void showNumber(int x){

switch(x){
case 1: one(); break;
case 2: two(); break;
case 3: three(); break;
case 4: four(); break;
case 5: five(); break;
case 6: six(); break;
case 7: seven(); break;
case 8: eight(); break;
case 9: nine(); break;
default: zero(); break;
}
}

void one(){
digitalWrite( aPin, Off); // 
digitalWrite( bPin, On); // |
digitalWrite( cPin, On); // |
digitalWrite( dPin, Off); // |
digitalWrite( ePin, Off); // |
digitalWrite( fPin, Off);
digitalWrite( gPin, Off);
}

void two(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // | 
digitalWrite( cPin, Off); // ____|
digitalWrite( dPin, On); // | 
digitalWrite( ePin, On); // |____
digitalWrite( fPin, Off);
digitalWrite( gPin, On);
}

void three(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // |
digitalWrite( cPin, On); // ____|
digitalWrite( dPin, On); // |
digitalWrite( ePin, Off); // ____|
digitalWrite( fPin, Off); 
digitalWrite( gPin, On);
}

void four(){
digitalWrite( aPin, Off); // 
digitalWrite( bPin, On); // | |
digitalWrite( cPin, On); // |____|
digitalWrite( dPin, Off); // |
digitalWrite( ePin, Off); // |
digitalWrite( fPin, On);
digitalWrite( gPin, On);
}

void five(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, Off); // |
digitalWrite( cPin, On); // |____
digitalWrite( dPin, On); // |
digitalWrite( ePin, Off); // ____|
digitalWrite( fPin, On); 
digitalWrite( gPin, On);
}

void six(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, Off); // |
digitalWrite( cPin, On); // |____
digitalWrite( dPin, On); // | |
digitalWrite( ePin, On); // |____|
digitalWrite( fPin, On);
digitalWrite( gPin, On);
}

void seven(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // |
digitalWrite( cPin, On); // |
digitalWrite( dPin, Off); // |
digitalWrite( ePin, Off); // |
digitalWrite( fPin, Off);
digitalWrite( gPin, Off);
}

void eight(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // | |
digitalWrite( cPin, On); // |____|
digitalWrite( dPin, On); // | |
digitalWrite( ePin, On); // |____|
digitalWrite( fPin, On); 
digitalWrite( gPin, On); 
}

void nine(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // | |
digitalWrite( cPin, On); // |____|
digitalWrite( dPin, On); // |
digitalWrite( ePin, Off); // ____|
digitalWrite( fPin, On); 
digitalWrite( gPin, On);
}

void zero(){ 
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // | |
digitalWrite( cPin, On); // | |
digitalWrite( dPin, On); // | |
digitalWrite( ePin, On); // |____|
digitalWrite( fPin, On); 
digitalWrite( gPin, Off); 
}

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

نعرف منافذ شاشة السبع مقاطع اربع أرقام

#define aPin 2
#define bPin 1
#define cPin 4
#define dPin 5
#define ePin 6
#define fPin 7
#define gPin 8
#define c1Pin 9 // Common pin for digit 1
#define c2Pin 10 // Common pin for digit 2
#define c3Pin 11 // Common pin for digit 3
#define c4Pin 12 // Common pin for digit 4

نعرف الخطوط الثلاثة الخاسة بحلقات هدف الرماية

#define c1 A0
#define c2 A1
#define c3 A2

نعرف زر تصفير حساب النقط

#define bt_reset A3

نعرف متغير لحساب النقاط باسم counter

long Counter=0;

نعرف متغير باسم common نعطيه قيمة 1 اذا كان شاشة السبع مقاطع اربع أرقاب ذات قطب موجب مشترك و 0 اذا كانت ذات قطب سابي مشترك

int flag1=0, flag2=0, flag3=0, timer=0;
int Common = 0; //<Common=1; for Common anode> <Common=0; for Common cathode>
int On, Off, Off_C;
int DTime = 4; // Display timer

في دالة void setup نعرف منافذ الدخل والخرج

void setup(){ // put your setup code here, to run once

pinMode(c1, INPUT);
pinMode(c2, INPUT);
pinMode(c3, INPUT);
pinMode(bt_reset, INPUT);

pinMode(aPin, OUTPUT);
pinMode(bPin, OUTPUT);
pinMode(cPin, OUTPUT);
pinMode(dPin, OUTPUT);
pinMode(ePin, OUTPUT);
pinMode(fPin, OUTPUT);
pinMode(gPin, OUTPUT);
pinMode(c1Pin, OUTPUT);
pinMode(c2Pin, OUTPUT);
pinMode(c3Pin, OUTPUT);
pinMode(c4Pin, OUTPUT);


if(Common==1){On=0, Off=1, Off_C=0;} //for Common anode
else{On=1, Off=0, Off_C=1;} //for Common cathode

في بداية تشغيل البرنامج و للتأكد من أن جميع وحدات شاشة العرض في جميع الأرقام تعمل بشكل صحيح يتم اظهار عد تنازلي على الشاشة من 9 الى 0 على كل رقم

for (int i = 9; i >=0; i--) {
showNumber(i);
digitalWrite(c1Pin, Common);
digitalWrite(c2Pin, Common);
digitalWrite(c3Pin, Common);
digitalWrite(c4Pin, Common);
delay(1000);
}
}

في بداية دالة voide loop نحدد الشرط اذا قرأ الأردوينو المنفذ الخاص بالدائرة الداخلية على أنه 1 يتم اضافة قيمة 30 نقطة لمتغير النقاط counter

void loop(){

if(digitalRead (c1) == 1){
if(flag1==0){ flag1=1;
Counter = Counter+30;
if(Counter>9999){Counter=0;}
}}
else{flag1=0;}

اذا قرأ الأردوينو اشارة 1 من المنفذ A1 سيتم اضافة 20 نقطة

if(digitalRead (c2) == 1){
if(flag2==0){ flag2=1;
Counter = Counter+20;
if(Counter<0){Counter=9999;}
}

اذا قرأ الأردوينو اشارة 1 من المنفذ A2 سيتم اضافة 10 نقطة

}else{flag2=0;}
if(digitalRead (c3) == 1){
if(flag2==0){ flag2=1;
Counter = Counter+10;
if(Counter<0){Counter=9999;}
}
}else{flag3=0;}

اذا قرأ الأردوينو اشارة 1 من المنفذ A3 تصفير عداد النقاط أي عند الضغط على ضغاط التحكم

if(digitalRead (bt_reset) == 1){
Counter=0;
if(timer<200){timer=timer+1;}
if(timer==200){

}
}else{timer=0;}

الدوال التالية لتعريف الأرقام من 0- 9


void one(){
digitalWrite( aPin, Off); //
digitalWrite( bPin, On); // |
digitalWrite( cPin, On); // |
digitalWrite( dPin, Off); // |
digitalWrite( ePin, Off); // |
digitalWrite( fPin, Off);
digitalWrite( gPin, Off);
}

void two(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // |
digitalWrite( cPin, Off); // ____|
digitalWrite( dPin, On); // |
digitalWrite( ePin, On); // |____
digitalWrite( fPin, Off);
digitalWrite( gPin, On);
}

void three(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // |
digitalWrite( cPin, On); // ____|
digitalWrite( dPin, On); // |
digitalWrite( ePin, Off); // ____|
digitalWrite( fPin, Off);
digitalWrite( gPin, On);
}

void four(){
digitalWrite( aPin, Off); //
digitalWrite( bPin, On); // | |
digitalWrite( cPin, On); // |____|
digitalWrite( dPin, Off); // |
digitalWrite( ePin, Off); // |
digitalWrite( fPin, On);
digitalWrite( gPin, On);
}

void five(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, Off); // |
digitalWrite( cPin, On); // |____
digitalWrite( dPin, On); // |
digitalWrite( ePin, Off); // ____|
digitalWrite( fPin, On);
digitalWrite( gPin, On);
}

void six(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, Off); // |
digitalWrite( cPin, On); // |____
digitalWrite( dPin, On); // | |
digitalWrite( ePin, On); // |____|
digitalWrite( fPin, On);
digitalWrite( gPin, On);
}

void seven(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // |
digitalWrite( cPin, On); // |
digitalWrite( dPin, Off); // |
digitalWrite( ePin, Off); // |
digitalWrite( fPin, Off);
digitalWrite( gPin, Off);
}

void eight(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // | |
digitalWrite( cPin, On); // |____|
digitalWrite( dPin, On); // | |
digitalWrite( ePin, On); // |____|
digitalWrite( fPin, On);
digitalWrite( gPin, On);
}

void nine(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // | |
digitalWrite( cPin, On); // |____|
digitalWrite( dPin, On); // |
digitalWrite( ePin, Off); // ____|
digitalWrite( fPin, On);
digitalWrite( gPin, On);
}

void zero(){
digitalWrite( aPin, On); // ____
digitalWrite( bPin, On); // | |
digitalWrite( cPin, On); // | |
digitalWrite( dPin, On); // | |
digitalWrite( ePin, On); // |____|
digitalWrite( fPin, On);
digitalWrite( gPin, Off);
}



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

مقدمة

يمكن أن يكون تحديد سرعة حركة الأجسام مفيدًا وضروريًا في العديد من التطبيقات، ويمكن استخدام وسائل متنوعة لتحديد السرعة، في هذا الدرس ستتعلم طريقة قياس السرعة والمسافة باستخدام  الاردوينو وحساس الموجات فوق الصوتية.

قياس السرعة والمسافة

المواد والأدوات

speed-measurement-using-hc-sr04-ultrasonic-sensor

1× اردوينو اونو

speed-measurement-using-hc-sr04-ultrasonic-sensor

1× سلك الاردوينو

speed-measurement-using-hc-sr04-ultrasonic-sensor

1× لوحة تجارب – حجم كبير

قياس السرعة والمسافة

 شاشة كرستالية (LCD 2×16)

قياس السرعة والمسافة

1× مقاومة متغيرة

قياس السرعة والمسافة

 حزمة أسلاك توصيل (ذكر- ذكر)

قياس السرعة والمسافة

1× حساس المسافة (HC-SR04)

قياس السرعة والمسافة

مقاومة 220 Ω

قياس السرعة والمسافة

 1× ثنائي مشع للضوء أحمر (LED)

شفرة

1× 40 رأس دبوس

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

للمزيد حول حساس الموجات الفوق صوتية يمكنك الرجوع للدرس التالي حساس الموجات فوق الصوتية.

لمعرفة المزيد حول الشاشة الكرستالية يمكنك الرجوع للدرس التحكم بالشاشة الكرستالية LCD

لابد من تلحيم المنافذ مع الشاشة الكرستالية، للمزيد حول اللحام يمكنك الرجوع للدرس تعلم كيفية التلحيم – تلحيم القطع باللوحة الإلكترونية

قياس السرعة والمسافة

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

ارفع الكود البرمجي التالي على لوحة الاردوينو باستخدام برنامج اردوينو (IDE).

#include <LiquidCrystal.h>
const int RS = 2, EN = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7;
LiquidCrystal lcd(RS,EN,D4,D5,D6,D7);

// defines pins numbers
const int trigPin = 9;
const int echoPin = 10;

// defines variables
long duration;
int distance1=0;
int distance2=0;
double Speed=0;
int distance=0;

void setup() 
{
lcd.begin(16, 2);// LCD 16X2
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(8 , OUTPUT);
Serial.begin(9600); // Starts the serial communication
}


void loop() 
{
//calculating Speed
distance1 = ultrasonicRead(); //calls ultrasoninicRead() function below

delay(1000);//giving a time gap of 1 sec

distance2 = ultrasonicRead(); //calls ultrasoninicRead() function below

//formula change in distance divided by change in time
Speed = (distance2 - distance1)/1.0; //as the time gap is 1 sec we divide it by 1.

//Displaying Speed
Serial.print("Speed in cm/s :"); 
Serial.println(Speed);
lcd.setCursor(0,1);
if (Speed<0)
{
lcd.print("Speed cm/s ");
lcd.print("0"); 
}
if (Speed>0)
{
lcd.print("Speed cm/s ");
lcd.print(Speed); 
}
// LED indicator
if (distance >0 && distance <5) 
{
digitalWrite( 8 , HIGH);
delay(50); // waits for a second
}
if (distance > 5 && distance <10 ) 
{
digitalWrite( 8 , HIGH);
delay(50); // waits for a second
digitalWrite( 8 , LOW); // sets the LED off
delay(50); // waits for a second
}
if (distance >10 && distance < 20) 
{
digitalWrite( 8 , HIGH);
delay(210); // waits for a second
digitalWrite( 8 , LOW); // sets the LED off
delay(210); // waits for a second
}
if (distance >20 && distance < 35) 
{
digitalWrite( 8 , HIGH);
delay(610); // waits for a second
digitalWrite( 8 , LOW); // sets the LED off
delay(610); // waits for a second
}
}
float ultrasonicRead ()
{
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
//calculating distance
distance= duration*0.0340 / 2;
// Prints the distance on the Serial Monitor
Serial.print("Distance in cm : ");
Serial.println(distance);
lcd.setCursor(0,0);
lcd.print("Dist. in cm ");
lcd.print(distance);
lcd.print(" ");
return distance;
}

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

هذا السطر يستدعي مكتبة الشاشة الكرستالية.

هذا السطر يستدعي مكتبة الشاشة الكرستالية.

نستطيع تحميلها بتتبع المسار التالي:

Sketch > Include libraries > Manage libraries

ثم نكتب بخانة البحث Liquid crystal by Arduino

ثم نضغط على Install.

#include <LiquidCrystal.h>

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

const int RS = 2, EN = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7;
LiquidCrystal lcd(RS,EN,D4,D5,D6,D7);

هذه الأسطر توضح منافذ الاردوينو التي ستستخدمها لربط حساس المسافة في هذا المشروع المنفذ رقم 9 مع triqPin في الحساس والمنفذ رقم 10 مع echoPin.

// defines pins numbers
const int trigPin = 9;
const int echoPin = 10;

هنا يتم تهيئة المتغيرات التي سيتم تخزين فيها قيم المسافة والسرعة وسيتم وضع القيمة الابتدائية لكل من المسافة والسرعة=0.

// defines variables
long duration;
int distance1=0;
int distance2=0;
double Speed=0;
int distance=0;

في الدالة ()setup يتم تهيئة الشاشة الكرستالية وحساس المسافة وتهيئة المنفذ 8 مع الثنائي المشع للضوء الأحمر.

void setup() 
{
lcd.begin(16, 2);// LCD 16X2
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode( 8 , OUTPUT);
Serial.begin(9600); // Starts the serial communication
}

في الدالة ()loop يتم قياس السرعة والمسافة بشكل مستمر وبعد كل قراءة سيتم طباعة القيم المقروءة من الحساس على الشاشة الكرستالية .

إذا كانت المسافة:

أكبر من الصفر وأصغر من 5 فسيعمل الثنائي المشع للضوء.

وإذا كانت المسافة أكبر من 5 وأصغر من 10 أو أكبر من 10 وأصغر من 20 أو كانت أكبر من 20 وأصغر من 35 فسيعمل الثنائي المشع أقل من ثانية ثم ينطفيء لمدة أقل من ثانية وهكذا.

void loop() 
{
//calculating Speed
distance1 = ultrasonicRead(); //calls ultrasoninicRead() function below

delay(1000);//giving a time gap of 1 sec

distance2 = ultrasonicRead(); //calls ultrasoninicRead() function below

//formula change in distance divided by change in time
Speed = (distance2 - distance1)/1.0; //as the time gap is 1 sec we divide it by 1.

//Displaying Speed
Serial.print("Speed in cm/s :"); 
Serial.println(Speed);
lcd.setCursor(0,1);
if (Speed<0)
{
lcd.print("Speed cm/s ");
lcd.print("0"); 
}
if (Speed>0)
{
lcd.print("Speed cm/s ");
lcd.print(Speed); 
}
// LED indicator
if (distance >0 && distance <5) 
{
digitalWrite( 8 , HIGH);
delay(50); // waits for a second
}
if (distance > 5 && distance <10 ) 
{
digitalWrite( 8 , HIGH);
delay(50); // waits for a second
digitalWrite( 8 , LOW); // sets the LED off
delay(50); // waits for a second
}
if (distance >10 && distance < 20) 
{
digitalWrite( 8 , HIGH);
delay(210); // waits for a second
digitalWrite( 8 , LOW); // sets the LED off
delay(210); // waits for a second
}
if (distance >20 && distance < 35) 
{
digitalWrite( 8 , HIGH);
delay(610); // waits for a second
digitalWrite( 8 , LOW); // sets the LED off
delay(610); // waits for a second
}
}
float ultrasonicRead ()
{
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
//calculating distance
distance= duration*0.0340 / 2;
// Prints the distance on the Serial Monitor
Serial.print("Distance in cm : ");
Serial.println(distance);
lcd.setCursor(0,0);
lcd.print("Dist. in cm ");
lcd.print(distance);
lcd.print(" ");
return distance;
}

يمكنك اختبار نظام قياس السرعة والمسافة بعد رفع الكود البرمجي على لوحة الاردوينو.

 لا تنسَ فصل مصدر الطاقة بعد الانتهاء من استخدام النظام.