|
| قسم الميكروكنترولر والروبوت ودوائر الاتصال بالحاسب الالي قسم المتحكمات الـ microcontroller و المعالجات microprocessor و التحكم الرقمي بالكمبيوتر CNC والانظمة الآلية والروبوت Robots |
|
|
|
||||||
|
التحكم فى السفن سيجمنت والمشغل MAX7219 بواسطة الاردوينو مع المكتبة LedControl : ![]() سوف نستحدم الوحدة (الموديول) المكون من الدائرة المتكاملة MAX7219 مع شاشة عرض سفن سيجمنت مكونة من حتى ثمانى أرقام digits والمبينة أدناه . يمكن توصيل حتى ثمانى وحدات على التتالى cascade . هناك مكتبة مطلوبة ليتم تضمينها للعمل مع هذه الوحدة وتسمى LedControl ، يتم تحميلها من الرابط أدناه وثبيتها فى بيئة تطوير الاردوينو . https://github.com/wayoda/LedControl التوصيل : المديول به 5 أطراف للتوصيل وهى سهلة التوصيل . يتوفر الموديول مع خيار للتتالي cascading مع المزيد من الموديولات من نوعه ، وبالتالي تشكيل شاشة أكبر. لنفكر فقط في وحدة واحدة للبساطة. يتم إجراء الاتصالات على النحو التالي : VCC- 5v of arduino GND- gnd of arduino Din- pin 12 CS(Load)-pin 10 Clk-pin 11 Dout is connected to the Din of the next module. ![]() |
| F.Abdelaziz |
| مشاهدة ملفه الشخصي |
| زيارة موقع F.Abdelaziz المفضل |
| البحث عن كافة المشاركات المكتوبة بواسطة F.Abdelaziz |
| اعلانات |
| F.Abdelaziz |
| مشاهدة ملفه الشخصي |
| زيارة موقع F.Abdelaziz المفضل |
| البحث عن كافة المشاركات المكتوبة بواسطة F.Abdelaziz |
| اعلانات اضافية ( قم بتسجيل الدخول لاخفائها ) | |
|
|
|
||||||
|
تدريب : كود:
//We always have to include the library
#include "LedControl.h"
/*
Now we need a LedControl to work with.
***** These pin numbers will probably not work with your hardware *****
pin 12 is connected to the DataIn
pin 11 is connected to the CLK
pin 10 is connected to LOAD
We have only a single MAX72XX.
*/
LedControl lc=LedControl(12,11,10,1);
/* we always wait a bit between updates of the display */
unsigned long delaytime=500;
void setup() {
/* The MAX72XX is in power-saving mode on startup, we have to do a wakeup call */
lc.shutdown(0,false);
/* Set the brightness to a medium values */
lc.setIntensity(0,8);
/* and clear the display */
lc.clearDisplay(0);
}
void hello(){
lc.setChar(0,0,'H',false);
lc.setChar(0,1,'E',false);
lc.setChar(0,2,'L',false);
lc.setChar(0,3,'L',false);
lc.setChar(0,4,'0',false);
lc.setChar(0,5,'.',false);
lc.setChar(0,6,'.',false);
lc.setChar(0,7,'.',false);
delay(delaytime+1000);
lc.clearDisplay(0);
delay(delaytime);
lc.setDigit(0,0,1,false);
delay(delaytime);
lc.setDigit(0,1,2,false);
delay(delaytime);
lc.setDigit(0,2,3,false);
delay(delaytime);
lc.setDigit(0,3,4,false);
delay(delaytime);
lc.setDigit(0,4,5,false);
delay(delaytime);
lc.setDigit(0,5,6,false);
delay(delaytime);
lc.setDigit(0,6,7,false);
delay(delaytime);
lc.setDigit(0,7,8,false);
delay(1500);
lc.clearDisplay(0);
delay(delaytime);
}
void loop() {
hello();
}
النتائج : ![]() |
|
||||||
|
تدريب : قراءة مدخل تناظرى والعرض على السفن سيجمنت والمشغل MAX7219 : كود:
#include "LedControl.h"
LedControl lc=LedControl(12,11,10,1);
void setup() {
Serial.begin(9600);
lc.shutdown(0,false);
lc.setIntensity(0,8);
lc.clearDisplay(0);
}
void loop() {
int adc = analogRead(A0);
lc.setDigit(0,0,adc/1000,false);//thousands : 1023/1000 = 1
lc.setDigit(0,1,(adc/100)%10,false);// hundreds : (1023/100) %10 = (10)%10 = 0
lc.setDigit(0,2,(adc/10)%10,false);// tens : (1023/10) %10 = (102) %10 = 2
lc.setDigit(0,3,adc%10,false);// ones : 1023%10 = 3
Serial.println(adc);
delay(100);
}
النتيجة : ![]() تعديل البرنامج لقياس درجة الحرارة باستخدام الحساس LM35 : كود:
#include "LedControl.h"
LedControl lc=LedControl(12,11,10,1);
void setup() {
Serial.begin(9600);
lc.shutdown(0,false);
lc.setIntensity(0,8);
lc.clearDisplay(0);
}
void loop() {
int adc = analogRead(A0);
adc = adc* 0.489; // transfer factor
lc.setDigit(0,0,adc/100,false);//digit 0 , hundred , 150/100 = 1
lc.setDigit(0,1,(adc/10)%10,false);// digit 1 , ten , 150 /10 =15 %10 =5
lc.setDigit(0,2, adc%10,false);// digit 2 , one , 150 %10 =0
//lc.setDigit(0,3,adc%10,false);// digit 3
lc.setRow(0,3,0x4E);//Addr 0 , Position 3 ,Value “C”
Serial.println(adc);
delay(100);
}
النتيجة : ![]() تعديل البرنامج بحيث لا تظهر الأصفار على الشمال : كود:
#include "LedControl.h"
LedControl lc=LedControl(12,11,10,1);
void setup() {
Serial.begin(9600);
lc.shutdown(0,false);
lc.setIntensity(0,8);
lc.clearDisplay(0);
}
void loop() {
int adc = analogRead(A0);//Reading
int temp = adc* 0.489; // Change reading to temperature (0-150 degrees)
int hundred = temp /100;// digit 0
int ten = (temp /10)%10;// digit 1
int one = temp %10;// digit 2
if(temp <100)
lc.setChar(0,0,' ',false); // Print space char in digit 0
else
lc.setDigit(0,0, hundred,false);//Print hundred digit
if(temp <10)
lc.setChar(0,1,' ',false); // Print space char in digit 1
else
lc.setDigit(0,1, ten,false);//Print ten digit
lc.setDigit(0,2, one,false);// digit 2 , Print one digit
lc.setRow(0,3,0x4E);// digit 3 , Addr 0 , Position 3 ,Value “C” , print ‘C’
Serial.println(temp);
delay(100);
}
النتيجة : ![]() ![]() |
|
||||||
|
ساعة Clock باستخدام الاردوينو وشاشة مكونة من أربعة وحدات سفن سيجمنت بنظام الانتخاب Multiplexing وساعة التوقيت الحقيقى DS3231 يدور هذا التدريب حول إنشاء ساعة رقمية عن طريق "انتخاب" multiplexing ما بين أربعة وحدات سقن سيجمنت باستخدام Arduino UNO وعرض الوقت بتنسيق HH: MM . الدائرة الكهربية : ![]() البرمجة : سيتم شرح كيفية أخذ الوقت (بالساعة hour والدقيقة minute) من وحدة ساعة الوقت الحقيقى RTC بتنسيق 24 ساعة 24hr ، ثم يتم تحويله إلى التنسيق المناسب لعرضه في شاشة العرض السفن سيجمنت المكونة من 4 أرقام . لربط الموديول DS3231 RTC مع Arduino UNO ، يتم استخدام ناقل I2C من Arduino UNO. يتم تضمين مكتبة تسمى <DS3231.h> في البرنامج للوصول إلى دوال الإعداد setting وقراءة الوقت والتاريخ وبيانات درجة الحرارة وما إلى ذلك. قم بتنزيل المكتبة وتثبيتها فى بيئة تطوير الاردوينو . نظرًا لأن وحدة RTC تستخدم واجهة I2C ، يتم استخدام المكتبة <wire.h> أيضًا في البرنامج. يتم أخذ الساعة hour والدقيقة minute أولاً من RTC ويتم دمجهما معًا مثل 0930 (09:30 pm) ومن ثم يتم فصل الأرقام بشكل فردى مثل الآلاف thousands والمئات hundreds والعشرات tens والآحاد units ، والأرقام الفردية يتم تحويلها إلى تنسيق ثنائي مثل الصفر 0 يحول إلى 63 (0111111) . يتم إرسال هذا الكود الثنائي إلى سجل الإزاحة ومن ثم من سجل الإزاحة إلى السفن سيجمنت من نوع الكاثود المشترك ، ليتم عرض الرقم 0 على شاشة السفن سيجمنت . وبهذه الطريقة ، يتم انتخاب multiplexed الأرقام الأربعة ويتم عرض الساعة والدقيقة. خطوات البرنامج : 1- في البداية ، يتم تضمين المكتبات الضرورية مثل مكتبة DS3231 والمكتبة Wire (مكتبة I2C). كود:
#include <Wire.h> #include<DS3231.h> 2- يتم تعريف أطراف التحكم فى السفن سيجمنت . ستلعب عناصر التحكم هذه دورًا مهمًا في انتخاب multiplexing الشاشة. كود:
#define latchPin 5 #define clockPin 6 #define dataPin 4 3- يتم الإعلان عن المتغيرات لتخزين النتيجة المحولة أو الأولية raw المأخوذة من RTC. كود:
int h; //Variable declared for hour int m; //Variable declared for minute int thousands; int hundreds; int tens; int unit; bool h24; bool PM; 4- يتم الإعلان عن كائن الفئة DS3231 مثل RTC لتبسيط الاستخدام في الأسطر . كود:
DS3231 RTC; 5- فى الدالة setup ، نظرا لأنه يتم ربط وحدة RTC مع الاردوينو باستخدام الاتصال I2C. لذلك ، تستخدم الدالة wire.begin() لبدء الاتصال I2C في العنوان الافتراضي للوحدة RTC حيث لا توجد وحدات I2C أخرى. كود:
Wire.begin(); 6- كما يتم تعريف وضع الطرف ، ما إذا كان سيتصرق كدخل أم كخرج . كود:
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
7- تعمل الدالة loop بشكل لا نهائي وتأخذ الوقت بالساعة والدقيقة من الوحدة RTC DS3231 . يشير البارامتر ‘h24’ إلى تنسيق المتغير فى شكل 24hr . كود:
8- بعد ذلك يتم الجمع بين الساعة hour والدقيقة minute كعدد واحد (مثال إذا كانت الساعة 10 والدقيقة 60 عندئذ يكون العدد 10*100=1000+60 =1060 ). كود:
int number = h*100+m; 9- يتم الحصول على الأرقام الفردية من العدد (على سبيل المثال ، العدد 1060- الواحد 1 هو الآلاف thousands ، و الصفر 0 هو المئات hundreds ، والواحد التالى 1 هو العشرات tens والصفر الذى يليه 0 هو الآحاد unit ، آخر رقم). لفصل الأرقام ، يتم استخدام معامل باقى القسمة % . على سبيل المثال ، في 1060 للحصول على 1 عندئذ 1060/1000=1.06%10=1. ومن ثم يتم تخزين الأرقام المنفصلة في متغيرات منفصلة. كود:
int thousands = number/1000%10;
int hundreds = number/100%10;
int tens = number/10%10;
int unit = number%10;
10- بعد ذلك يتم استخدام عبارة switch case لكل رقم فردي لتحويلها إلى التنسيق المناسب (تنسيق ثنائي) وإرسالها عبر مسجل الإزاحة لعرضها على السفن سيجمنت . على سبيل المثال (بالنسبة للرقم واحد “1” يتم تغييره إلى 06 (0000 0110)) . بحيث يتم إرساله عبر الإزاحة ، ويتم عرض الرقم واحد “1” على السفن سيجمنت (الصفر 0 يعنى LOW ، والواحد 1 يعنى HIGH). كود:
switch (t)
{
case 0:
unit = 63;
break;
case 1:
unit = 06;
break;
case 2:
unit =91;
break;
case 3:
unit=79;
break;
case 4:
unit=102;
break;
case 5:
unit = 109;
break;
case 6:
unit =125;
case 7:
unit = 07;
break;
case 8:
unit = 127;
break;
case 9:
unit =103;
break;
}
11- بعد ذلك ، يتم إرسال الرقم الفردي بالتنسيق الثنائي عبر الدالة "shiftout" مع MSB أولاً ويكون الطرف المشترك للرقم digit الخاص به منخفضا LOW (كاثود مشترك) ويكون طرف latch مرتفعا HIGH . كود:
digitalWrite(9, LOW);//digit thousands on , common cathode digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST,thousands); digitalWrite(latchPin, HIGH); delay(5); digitalWrite(9, HIGH); // digit thousands off البرنامج : كود:
//Four-Digit 7 Segments Multiplexing using Arduino: Display time in HH:MM
#include <Wire.h> //Library for SPI communication
#include <DS3231.h> //Library for RTC module
#define latchPin 5
#define clockPin 6
#define dataPin 4
DS3231 RTC; //Declare object RTC for class DS3231
int h; //Variable declared for hour
int m; //Variable declared for minute
int thousands;
int hundreds;
int tens;
int unit;
bool h24;
bool PM;
void setup ()
{
Wire.begin();
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop ()
{
int h= RTC.getHour(h24, PM); //To get the Hour
int m = RTC.getMinute(); //TO get the minute
int number = h*100+m; //Converts hour and minute in 4-digit
int thousands = number/1000%10; //Getting thousands digit from the 4 digit
int hundreds = number/100%10; //Getting hundreds digit from 4 digit
int tens = number/10%10; //Getting tens digit from 4-digit
int unit = number%10; //Getting last digit from 4-digit
int t= unit;
int u= tens;
int v= hundreds;
int w= thousands;
//Converting the individual digits into corresponding number for passing it through the shift register so LEDs are turned ON or OFF in seven segment
switch (t)
{
case 0:
unit = 63;//common cathod
break;
case 1:
unit = 06;
break;
case 2:
unit =91;
break;
case 3:
unit=79;
break;
case 4:
unit=102;
break;
case 5:
unit = 109;
break;
case 6:
unit =125;
case 7:
unit = 07;
break;
case 8:
unit = 127;
break;
case 9:
unit =103;
break;
}
switch (u)
{
case 0:
tens = 63;
break;
case 1:
tens = 06;
break;
case 2:
tens =91;
break;
case 3:
tens=79;
break;
case 4:
tens=102;
break;
case 5:
tens= 109;
break;
case 6:
tens =125;
case 7:
tens = 07;
break;
case 8:
tens = 127;
break;
case 9:
tens =103;
break;
}
switch (v)
{
case 0:
hundreds = 63;
break;
case 1:
hundreds = 06;
break;
case 2:
hundreds =91;
break;
case 3:
hundreds=79;
break;
case 4:
hundreds=102;
break;
case 5:
hundreds = 109;
break;
case 6:
hundreds =125;
case 7:
hundreds = 07;
break;
case 8:
hundreds = 127;
break;
case 9:
hundreds =103;
break;
}
switch (w)
{
case 0:
thousands = 63;
break;
case 1:
thousands = 06;
break;
case 2:
thousands =91;
break;
case 3:
thousands=79;
break;
case 4:
thousands=102;
break;
case 5:
thousands = 109;
break;
case 6:
thousands =125;
case 7:
thousands = 07;
break;
case 8:
thousands= 127;
break;
case 9:
thousands =103;
break;
}
digitalWrite(9, LOW);// Turinig on thousands digit
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST,thousands); // The thousand digit is sent
digitalWrite(latchPin, HIGH); // Set latch pin HIGH to store the inputs
delay(5); // delay for multiplexing
digitalWrite(9, HIGH); // Turinig off thousands digit
digitalWrite(10, LOW);
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST,hundreds ); // The hundered digit is sent
digitalWrite(latchPin, HIGH);
delay(5);
digitalWrite(10, HIGH);
digitalWrite(11, LOW);
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST,tens); // The tens digit is sent
digitalWrite(latchPin, HIGH);
delay(5);
digitalWrite(11, HIGH);
digitalWrite(12, LOW);
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST,unit); // The last digit is sent
digitalWrite(latchPin, HIGH);
delay(5);
digitalWrite(12, HIGH);
}
|
|
||||||
|
قياس الرطوبة Humidity ودرجة الحرارة Temperature باستخدام الاردوينو Arduinoوالحساس DHT11 الرطوبة ودرجة الحرارة هى بارامترات شائعة لقياس الظروف البيئية. في هذا المشروع القائم على Arduino ، سنقوم بقياس درجة الحرارة والرطوبة المحيطة وعرضها على شاشة LCD مقاس 16 × 2. يتم استخدام مستشعر درجة الحرارة والرطوبة الشائع DHT11 مع Arduino uno لتطوير مقياس حرارة thermometer مئوى Celsius ومقياس رطوبة كنسبة مئوية . يتكون هذا المشروع من ثلاثة أقسام – القسم الأول يستشعر الرطوبة ودرجة الحرارة باستخدام حساس الرطوبة ودرجة الحرارة DHT11. القسم الثاني يقرأ خرج وحدة الحساس DHT ويستخرج قيم درجة الحرارة والرطوبة إلى رقم مناسب من حيث النسبة المئوية والدرجة المئوية. والجزء الثالث من النظام يعرض الرطوبة ودرجة الحرارة على شاشة LCD . ![]() يعتمد عمل هذا المشروع على الاتصال التسلسلى لسلك مفرد . فى البداية يرسل الاردوينو إشارة بدء إلى الوحدة DHT ثم يعطي DHT إشارة استجابة تحتوي على بيانات درجة الحرارة والرطوبة. يقوم الاردوينو بالتجميع والاستخراج في شكل جزأين ، الأول هو الرطوبة والثاني هو درجة الحرارة ومن ثم إرسالها إلى شاشة LCD 16X2 . في هذا المشروع ، استخدمنا وحدة module استشعار تسمى DHT11. تتميز هذه الوحدة بتركيبة للرطوبة والحرارة مع خرج إشارة رقمية معايرة ، يعني أن وحدة الاستشعار DHT11 هي وحدة مشتركة لاستشعار الرطوبة ودرجة الحرارة والتي تعطي إشارة خرج رقمية معايرة. المستشعر DHT11 يعطينا قيمة دقيقة للغاية للرطوبة ودرجة الحرارة ويضمن موثوقية عالية والاستقرار على المدى الطويل. يحتوي هذا المستشعر على مكون لقياس الرطوبة من نوع المقاومة ومكون لقياس درجة الحرارة من النوع NTC مع متحكم 8 بت مدمج له استجابة سريعة وفعال من حيث التكلفة ومتوفر في حزمة بأربعة أطراف فى صف واحد . الوحدة DHT11 تعمل على الاتصال التسلسلى ، أي الاتصال بسلك واحد. ترسل هذه الوحدة البيانات في شكل قطار نبضات بفترة زمنية محددة. قبل إرسال البيانات إلى الاردوينو ، فإنها تحتاج إلى أمر تهيئة مع تأخير زمني . ![]() شيء مهم هو التأكد من قيمة مقاومة السحب لأعلى لأننا إذا وضعنا مستشعر DHT على مسافة أقل من 20 متر ، فمن المستحسن أن تكون قيمة مقاومة السحب لأعلى هى 5k . إذا وضع DHT على مسافة أطول من 20 متر عندئذ استخدم القيمة المناسبة لمقاومة السحب لأعلى . الدائرة الكهربية : ![]() يتم استخدام شاشة LCD لعرض درجة الحرارة والرطوبة والتي ترتبط مباشرة مع اردوينو في وضع 4 بت. يتم توصيل أطراف الشاشة المسماة RS, EN, D4, D5, D6 , D7 لأطراف الاردوينو الرقمية رقم 2, 3, 4, 5, 6 , 7 . ويتم توصيل وحدة الاستشعار DHT11 بالطرف الرقمي 12 من الاردوينو ومع مقاومة السحب لأعلى 5k . وصف البرمجة : 1- في البرمجة ، سوف نستخدم مكتبات مسبقة الصنع للمستشعر DHT11 ووحدة العرض LCD. كود:
#include<dht.h> // Including library for dht #include<LiquidCrystal.h> 2- ثم نقوم بتعريف أطراف الشاشة LCD وتعريف طرف المستشعر DHT ، وإنشاء كائن من الفئة dht ، وإعلان حرف درجة الحرارة : كود:
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
#define dht_dpin 12
dht DHT;
byte degree[8] =
{
0b00011,
0b00011,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000
};
3- ويتم تهيئة كل الأشياء فى دالة الإعداد setup . كود:
void setup()
{
lcd.begin(16, 2);
lcd.createChar(1, degree);
lcd.clear();
lcd.print(" Humidity ");
lcd.setCursor(0,1);
lcd.print(" Measurement ");
delay(2000);
lcd.clear();
}
4- بعد ذلك في الدالة loop وباستخدام الدالة dht ، يقرأ المستشعر DHT بالدالة DHT.read11، ثم باستخدام بعض دوال dht (DHT.humidity , DHT.temperature ) ، نستخلص الرطوبة ودرجة الحرارة ونعرضها على شاشة LCD. كود:
void loop()
{
DHT.read11(dht_dpin);
lcd.setCursor(0,0);
lcd.print("Humidity: ");
lcd.print((int)DHT.humidity); // printing Humidity on LCD
lcd.print("%");
lcd.setCursor(0,1);
lcd.print("Temperature:");
lcd.print((int)DHT.temperature); // Printing temperature on LCD
lcd.write(1); // lcd.print((char)223);
lcd.print("C");
delay(500);
}
البرنامج : كود:
#include<dht.h> // Including library for dht
#include<LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
#define dht_dpin 12
dht DHT;
byte degree[8] =
{
0b00011,
0b00011,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000
};
void setup()
{
lcd.begin(16, 2);
lcd.createChar(1, degree);
lcd.clear();
lcd.print(" Humidity ");
lcd.setCursor(0,1);
lcd.print(" Measurement ");
delay(2000);
lcd.clear();
}
void loop()
{
DHT.read11(dht_dpin);
lcd.setCursor(0,0);
lcd.print("Humidity: ");
lcd.print((int)DHT.humidity); // printing Humidity on LCD , DHT.humidity returns humidity in percent
lcd.print(" %");
lcd.setCursor(0,1);
lcd.print("Temperature:");
lcd.print((int)DHT.temperature); // Printing temperature on LCD,DHT.temperature returns the temperature in Celsius
lcd.write(1);
lcd.print("C");
delay(500);
}
مثال مع العرض على المنفذ التسلسلى : ![]() كود:
#include "dht.h"
#define dht_dpin 12 // sensor Pin
dht DHT;
void setup(){
Serial.begin(9600);
delay(500);//Delay to let system boot
Serial.println("DHT11 Humidity & temperature Sensor\n\n");
delay(1000);//Wait before accessing Sensor
}//end "setup()"
void loop(){
//Start of Program
DHT.read11(dht_dpin);
Serial.print("Current humidity = ");
Serial.print(DHT.humidity); // DHT.humidity returns humidity in percent
Serial.print("% ");
Serial.print("temperature = ");
Serial.print(DHT.temperature); // DHT.temperature returns the temperature in Celsius
Serial.println("C ");
delay(5000);//Wait 5 seconds before accessing sensor again.
//Fastest should be once every two seconds.
}// end loop()
|
|
||||||
|
مقاطعات الاردوينو Arduino Interrupts مفهوم المقاطعة : إعتبر سيارة سريعة الحركة ، إذا صدمت سيارة أخرى فجأة في الاتجاه المعاكس ، فإن أول شيء يحدث هو أن مستشعر التسارع accelerometer الموجود في السيارة يستشعر حدوث عدم تسارع de-acceleration (تباطؤ) مفاجئ ويؤدي إلى مقاطعة خارجية للميكروكونترولر (المتحكم الدقيق) الموجود في السيارة ، ثم ينتج المتحكم إشارة كهربائية لنشر الأكياس الهوائية على الفور. يقوم المتحكم الموجود في السيارة بمراقبة العديد من الأشياء في وقت واحد مثل استشعار سرعة السيارة ، والتحقق من أجهزة الاستشعار الأخرى ، والتحكم في درجة حرارة مكيف الهواء وما إلى ذلك. فما الذي يجعل الفتح المفاجىء لكيس الهواء في ثوانٍ؟ يتم استخدام إشارة المقاطعة Interrupt هنا والتي لها الأولوية القصوى للجميع. مثال بسيط آخر على المقاطات Interrupts هو الهواتف المحمولة التي تعمل باللمس والتي لها الأولوية القصوى للإحساس باللمس "Touch". لدى كل جهاز إلكتروني تقريبًا نوع من المقاطعات لإيقاف (مقاطعة) العملية المعتادة والقيام ببعض الأشياء ذات الأولوية العليا عند حدث معين. يتم استئناف العملية العادية بعد قضاء المقاطعة. من الناحية الفنية ، تعد المقاطعات Interrupts آلية يمكن بواسطتها تعليق (إيقاف) الإدخال / الإخراج أو التعليمة من التنفيذ العادي للمعالج والحصول على خدماته كما لوأن لها أولوية مرتفعة . على سبيل المثال ، يمكن مقاطعة المعالج الذي يقوم بتنفيذ عادي من قبل بعض أجهزة الاستشعار لتنفيذ عملية معينة موجودة في ISR (روتين خدمة المقاطعة). بعد تنفيذ المعالج ISR يمكن مرة أخرى استئناف التنفيذ العادي. أنواع المقاطعات : هناك نوعان من المقاطعات: مقاطعة الأجهزة (الهاردوير) Hardware Interrupt : يحدث ذلك عندما يحدث حدث خارجي مثل تغيير حالة طرف المقاطعة الخارجي حالته من LOW إلى HIGH أو LIGH إلى LOW . مقاطعة البرمجيات Software Interrupt : يحدث وفقا للتعليمات من البرمجيات . على سبيل المثال مقاطعات المؤقت Timer هي مقاطعة برمجية . المقاطعات في الاردوينو : الآن سوف نرى كيفية استخدام المقاطعات في لوحة الاردوينو ، والتى لها نوعان من المقاطعات: • مقاطعة خارجية External Interrupt . • مقاطعة تغيير الطرف Pin Change Interrupt. المقاطعة الخارجية External Interrupt : يتم تفسير هذه المقاطعة بواسطة الأجهزة hardware وتكون سريعة جداً. يمكن تعيين هذه المقاطعات ليتم تشغيلها في حالة حدوث مستويات "صاعدة " RISING أو "هابطة " FALLING أو الحالة LOW. فى الاردوينو أونو UNO والنانو NANO تخصص الأطراف الرقمية 2 و 3 للمقاطعة الخارجية . مقاطعات تغيير الطرف Pin Change Interrupts : يمكن أن يكون للاردوينو أطراف مقاطعة أكثر تمكن enabled باستخدام المقاطعات Pin Change . في لوحات الاردوينو القائمة على المتحكمات ATmega168 / 328 ، يمكن استخدام أي الأطراف أو جميع أطراف الإشارة العشرين كأطراف مقاطعة. يمكن أيضًا تشغيلها باستخدام الحواف الصاعدة RISING أو الهابطة FALLING . استخدام المقاطعات الخارجية في الاردوينو : من أجل استخدام المقاطعات في الاردوينو ، يجب فهم المفاهيم التالية. روتين خدمة المقاطعة Interrupt Service Routine (ISR) : روتين خدمة المقاطعة ISR أو معالج المقاطعة Interrupt handler هو حدث يحتوي على مجموعة صغيرة من التعليمات . عند حدوث مقاطعة خارجية ، يقوم المعالج أولاً بتنفيذ هذه التعليمات البرمجية الموجودة في ISR ويعود مرة أخرى إلى الحالة التي ترك فيها التنفيذ العادي. بناء جملة ISR فى الاردوينو كما يلى : كود:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode); الوسيط الأول : كود:
digitalPinToInterrupt(pin) في الاردوينو أونو Uno ، ونانو NANO الأطراف المستخدمة للمقاطعة هي 2,3 وفى الميجا mega هى 2,3,18,19,20,21 . يتم تحديد طرف الدخل المستخدم للمقاطعة الخارجية هنا. الوسيط الثانى : ISR: هي دالة تستدعى عند إجراء مقاطعة خارجية. الوسيط الثالث : Mode : نوع الانتقال إلى التشغيل trigger ، على سبيل المثال falling ، rising ، إلخ. • RISING : لتشغيل مقاطعة عندما ينتقل طرف من LOW إلى HIGH. • FALLING : لتشغيل مقاطعة عندما ينتقل طرف من HIGH إلى LOW . • CHANGE : لتشغيل المقاطعة عندما ينتقل طرف من LOW إلى HIGH أو من HIGH إلى LOW (أي عندما تتغير حالة الطرف ). بعض الشروط أثناء استخدام المقاطعة : • روتين خدمة مقاطعة المقاطعة (ISR) يجب أن يكون أقصر ما يمكن. • الدالة Delay () لا تعمل داخل ISR ويجب تجنبها. في هذا التدريب الخاص بمقاطعة الاردوينو ، يتم زيادة عدد number من 0 (العمل العادى) ويتم استخدام زري ضغط لتشغيل مقاطعة ، كل واحد متصل بطرف D2 & D3. يتم استخدام ليد LED لبيان المقاطعة. في حالة الضغط على زر الضغط الأول ، يتم تشغيل الليد ON ويظهر العرض interrupt2 ويختفى ، وعندما يتم الضغط على زر الضغط الثانى ، يتم إيقاف تشغيل الليد OFF ويظهر العرض interrupt1 ويختفى . الدائرة الكهربية : ![]() يتم توصيل اثنين من أزرار الضغط للاردوينو أونو في الأطراف D2 و D3. يتم استخدامها لعمل مقاطعتين خارجيتين ، أحدهما لتشغيل ليد LED والآخر لإيقاف تشغيل الليد LED. كل زر ضغط لديه مقاومة سحب لأسفل بقيمة 10k متصلة بالأرضى. لذلك عند الضغط على زر الضغط ، يكون المنطق HIGH (1) وعندما لا يتم الضغط عليه يكون المنطق LOW (0) . مقاومة السحب لأسفل إلزامية ، وإلا ستكون هناك قيم عائمة عند طرفى الدخل D2 & D3. كما يتم استخدام ليد LED لبيان أن المقاطعة قد تم تشغيلها أو الضغط على زر. برمجة مقاطعة الاردوينو : في هذا التدريب ، يتم زيادة عدد من 0 والذي يتم عرضه بشكل مستمر على شاشة LCD (16x2) المتصلة مع الاردوينو أونو ، كلما تم الضغط على الزر الأيمن (طرف المقاطعة D3) ، يتم تشغيل الليد LED ويظهر العرض Interrupt2 ، وعند الضغط على الزر الأيسر (طرف المقاطعة D2) يتم إيقاف تشغيل الليد LED ويظهر العرض Interrupt1. البرنامج : كود:
//Interrupts using Arduino
//Circuit Digest
#include<LiquidCrystal.h> // Including lcd display library
LiquidCrystal lcd (7,8,9,10,11,12); // Define LCD display pins RS,E,D4,D5,D6,D7
volatile int output = LOW;
int i = 0;
void setup()
{
lcd.begin(16,2); // setting LCD as 16x2 type
lcd.setCursor(0,0);
lcd.print("CIRCUIT DIGEST");
lcd.setCursor(0,1);
lcd.print("ArduinoInterrupt");
delay(3000);
lcd.clear();
pinMode(13,OUTPUT);
attachInterrupt(digitalPinToInterrupt(2),buttonPressed1,RISING); // function for creating external interrupts at pin2 on Rising (LOW to HIGH)
attachInterrupt(digitalPinToInterrupt(3),buttonPressed2,RISING); // function for creating external interrupts at pin3 on Rising (LOW to HIGH)
}
void loop()
{
lcd.clear();
lcd.print("COUNTER:");
lcd.print(i);
++i;
delay(1000);
digitalWrite(13,output); //Turns LED ON or OFF depending upon output value
}
void buttonPressed1() //ISR function excutes when push button at pinD2 is pressed
{
output = LOW; //Change Output value to LOW
lcd.setCursor(0,1);
lcd.print("Interrupt 1");
}
void buttonPressed2() //ISR function excutes when push button at pinD3 is pressed
{
output = HIGH; //Change Output value to HIGH
lcd.setCursor(0,1);
lcd.print("Interrupt2");
}
الوصف : 1- فى البداية ً يتم تضمين ملف الرأس لشاشة LCD ومن ثم يتم تعريف أطراف LCD المستخدمة في الاتصال مع الاردوينو .أيضا يتم إعلان المتغيرات . لاحظ إلان المتغير output المستخدم بروتين خدمة المقاطعة باعتباره volatile . كود:
#include<LiquidCrystal.h> LiquidCrystal lcd (7,8,9,10,11,12); // Define LCD display pins RS, E, D4, D5, D6, D7 volatile int output = LOW; int i = 0; 2- داخل الدالة setup ، يتم عرض بعد الرسائل الافتتاحية على شاشة LCD . كود:
void setup()
{
lcd.begin(16,2); // setting LCD as 16x2 type
lcd.setCursor(0,0);
lcd.print("CIRCUIT DIGEST");
lcd.setCursor(0,1);
lcd.print("ArduinoInterrupt");
delay(3000);
lcd.clear();
pinMode(13,OUTPUT);
attachInterrupt(digitalPinToInterrupt(2),buttonPressed1,RISING); // function for creating external interrupts at pin2 on Rising (LOW to HIGH)
attachInterrupt(digitalPinToInterrupt(3),buttonPressed2,RISING); // function for creating external interrupts at pin3 on Rising (LOW to HIGH)
}
3- ثم في نفس الدالة setup يجب تحديد أطراف الدخل والخرج . يتم توصيل الطرف D13 بأنود الليد LED ، لذلك يجب تعريف هذا الطرف على أنه خرج . كود:
pinMode(13,OUTPUT); 4- الآن الجزء الرئيسي المهم في البرمجة هو الدالة attachInterrupt() ، ويتم تضمينها أيضا داخل الدالة setup . كود:
attachInterrupt(digitalPinToInterrupt(2),buttonPressed1,RISING); // function for creating external interrupts at pin2 on Rising (LOW to HIGH) attachInterrupt(digitalPinToInterrupt(3),buttonPressed2,RISING); // function for creating external interrupts at pin3 on Rising (LOW to HIGH) هنا ، يتم تحديد أن الطرف 2 هو للمقاطعة الخارجية ، ويتم استدعاء الدالة buttonPressed1 عندما يكون هناك RISING (LOW to HIGH) عند D2. والطرف 3 هو أيضًا للمقاطعة الخارجية ويتم استدعاء الدالة buttonPressed2 عندما يكون هناك RISING على الطرف D3. 5- داخل الدالة loop ، يتم زيادة العدد (i) من الصفر وطباعته على شاشة LCD(16x2) . كود:
void loop()
{
lcd.clear();
lcd.print("COUNTER:");
lcd.print(i);
++i;
delay(1000);
digitalWrite(13,output); //Turns LED ON or OFF depending upon output value
}
في نفس الدالة loop ، يتم استخدام الدالة digitalWrite على الطرف D13 حيث يتم توصيل أنود الليد LED. اعتمادًا على قيمة المتغير output، سيتم تشغيل الليد LED أو إيقاف تشغيله . كود:
digitalWrite(13,output); //Turns LED ON or OFF depending upon output value 6- الجزء الأكثر أهمية هو إنشاء دالة معالج المقاطعة وفقًا للاسم المستخدم في الدالة attachInterrupt. نظرا لأنه تم استخدام أطراف المقاطعة 2 و 3 لذلك مطلوب اثنين ISR كما يلى : كود:
void buttonPressed1() //ISR function excutes when push button at pinD2 is pressed
{
output = LOW; //Change Output value to LOW
lcd.setCursor(0,1);
lcd.print("Interrupt 1");
}
يتم تنفيذ هذه الدالة عند الضغط على زر الضغط على الطرف D2 (RISING EDGE) . تعمل هذه الدالة على تغيير حالة الخرج إلى LOW مما يؤدي إلى إيقاف تشغيل الليد LED وطباعة “interrupt1” على شاشة LCD. كود:
void buttonPressed2() //ISR function executes when push button at pinD3 is pressed
{
output = HIGH; //Change Output value to HIGH
lcd.setCursor(0,1);
lcd.print("Interrupt2");
}
يتم تنفيذ هذه الدالة عند الضغط على زر الضغط على الطرف D3. تعمل هذه الدالة على تغيير حالة output إلى HIGH مما يؤدي إلى تشغيل الليد LED وطباعة “interrupt2” على شاشة LCD. |
|
||||||
|
الاردوينو والمهام المتعددة Multitasking وكيفية استخدام الدالة millis() قاد تعدد المهام أجهزة الكمبيوتر إلى ثورة حيث يمكن تشغيل برنامج واحد أو أكثر في وقت واحد مما يزيد من الكفاءة والمرونة والقدرة على التكيف والإنتاجية. في الأنظمة المضمّنة embedded ، يمكن لميكروكنترولر أيضًا التعامل مع تعدد المهام وتنفيذ مهمتين أو أكثر في وقت واحد دون إيقاف التعليمات الحالية. في هذا التدريب سوف نتعلم كيف يؤدي Arduino تعدد المهام. بشكل عام ، يتم استخدام الدالة delay() في Arduino للقيام بمهمة دورية مثل وميض ليد LED Blinking ولكن هذه الدالة توقف البرنامج لبعض الوقت المحدد ولا تسمح بإجراء عمليات أخرى. لذلك يوضح هذا التدريب كيف يمكننا تجنب استخدام الدالة delay() واستبدالها بالدالة millis() لأداء أكثر من مهمة في وقت واحد وجعل Arduino متحكم متعدد المهام. قبل الخوض في التفاصيل ، لنبدأ بتفهم تعدد المهام. ماهو "تعدد المهام" Multitasking ؟ تعدد المهام يعني ببساطة تنفيذ أكثر من مهمة أو برنامج في وقت واحد في نفس الوقت. تقريبا جميع أنظمة التشغيل لها ميزة تعدد المهام. يُعرف هذا النوع من أنظمة التشغيل باسم MOS (نظام التشغيل متعدد المهام). يمكن أن يكون MOS نظام تشغيل الكمبيوتر المحمول أو المكتبي . مثال جيد على تعدد المهام في أجهزة الكمبيوتر هو عندما يقوم المستخدمون بتشغيل تطبيق البريد الإلكتروني ، ومتصفح الإنترنت ، ومشغل الوسائط ، والألعاب ، في نفس الوقت وإذا كان المستخدمون لا يرغبون في استخدام التطبيق يتم تشغيله في الخلفية إذا لم يتم إغلاقه. يستخدم المستخدم النهائي كل هذه التطبيقات في نفس الوقت لكن نظام التشغيل يأخذ هذا المفهوم بشكل مختلفًا بعض الشيء. دعونا نناقش كيف يدير نظام التشغيل تعدد المهام. ![]() كما هو موضح في الشكل أعلاه ، تقسم وحدة المعالجة المركزية الوقت على ثلاثة أجزاء متساوية وتعيين كل جزء لكل مهمة / تطبيق. هذه هي الطريقة التي يتم بها تعدد المهام في معظم الأنظمة. سيكون هذا المفهوم هو نفسه تقريبًا بالنسبة إلى تعدد مهام الاردوينو ، باستثناء توزيع الوقت سيكون مختلفًا بعض الشيء. نظرًا لأن Arduino يعمل بتردد وذاكرة الوصول العشوائي (RAM) منخفض مقارنة بالكمبيوتر ، فإن الوقت الممنوح لكل مهمة سيكون مختلفًا أيضًا. اردوينو أيضا لديه الدالة delay() التي تستخدم على نطاق واسع. ولكن قبل البدء ، دعنا نناقش لماذا يجب ألا نستخدم الدالة delay() في أي مشروع. لماذا يجب تجنب استخدام الدالة delay() إذا تم النظر في الوثائق المرجعية للاردوينو ، نجد أن هناك نوعان من دوال التأخير ، الأول هو delay() والثاني هو delayMicroseconds() . كلتا الدالتان متطابقتان من حيث توليد التأخير. الفرق الوحيد هو أنه في الدالة delay() ، يكون الوسيط الذي يتم تمريره عدد صحيح بالمللي ثانية أي إذا كتبنا delay(1000) سيكون التأخير هو 1000 مللي ثانية أي ثانية واحدة. بالمثل ، في الدالة delayMicroseconds() ، يكون الوسيط الذى يتم تمريره بالميكروثانية أي إذا كتبنا delayMicroseconds(1000) ، فسيكون التأخير 1000 ميكروثانية أي 1 مللي ثانية. هنا تأتي النقطة ، كلتا الدالتين توقفان مؤقتًا البرنامج لمقدار الوقت المنقضي في دالة التأخير. لذلك إذا كنا نعطي تأخيرًا لمدة ثانية واحدة ، فلن يتمكن المعالج من الانتقال إلى التعليمات التالية حتى تمر ثانية واحدة. وبالمثل ، إذا كان التأخير 10 ثوانٍ ، فسيتوقف البرنامج لمدة 10 ثوانٍ ولن يسمح للمعالج بالانتقال إلى التعليمات التالية حتى تمر 10 ثوانٍ. هذا يعوق أداء المتحكم من حيث السرعة وتنفيذ التعليمات. أفضل مثال لتوضيح عيب دالة التأخير هو استخدام عدد 2 زر ضاغط . لنفرض أننا نريد تبديل toggle اثنين من الليدات باستخدام زرى الضغط . لذلك إذا تم الضغط على أحد زرى الضغط ، فيجب أن يضيء الليد المقابل لمدة ثانيتين ، وبالمثل إذا تم الضغط على الزر الثاني ، فيجب أن يتوهج الليد المقابل لمدة 4 ثوانٍ. ولكن عندما نستخدم delay ، إذا ضغط المستخدم على الزر الأول ، فسيتوقف البرنامج لمدة ثانيتين وإذا ضغط المستخدم على الزر الثاني قبل تأخير لمدة ثانيتين ، فلن يقبل المتحكم الإدخال حيث أن البرنامج في مرحلة التوقف halt . تشير الوثائق الرسمية لاردوينو بوضوح إلى ذلك في وصف دالة التأخير . يمكنك المراجعة والتحقق من ذلك ليكون أكثر وضوحًا. لماذا استخدام الدالة millis() ؟ للتغلب على المشكلة الناتجة عن التأخير ، يجب على المبرمج استخدام الدالة millis() والتي هي سهلة الاستخدام بمجرد أن تصبح معتادا عليها ، وسوف تستخدم أداء وحدة المعالجة المركزية بنسبة 100 ٪ دون توليد أي تأخير في تنفيذ التعليمات. الدالة millis() هي دالة تقوم فقط بإرجاع مقدار المللي ثانية التي انقضت منذ بدأت لوحة Arduino في تشغيل البرنامج الحالي دون تجميد البرنامج. سيتم تجاوز overflow هذا الرقم الزمني (أي العودة إلى الصفر) ، بعد حوالي 50 يومًا. تماما مثل ما أن الاردوينو لها الدالة delayMicroseconds() ، فإن لديه النسخة micro من الدالة millis() وهى micros() . الفرق بين micros و millis هو أنه سيتم تجاوز micros() بعد حوالي 70 دقيقة ، مقارنة مع millis() وهو 50 يومًا. بناءً على التطبيق ، يمكنك استخدام millis() أو micros() . إستخدام millis() بدلا من delay() : لاستخدام millis() للتوقيت والتأخير ، تحتاج إلى تسجيل وتخزين الوقت الذي حدث فيه الإجراء لبدء الوقت ثم التحقق على فترات زمنية ما إذا كان الوقت المحدد قد انقضى. هكذا كما ذكر ، يتم تخزين الوقت الحالي في متغير. كود:
unsigned long currentMillis = millis(); نحتاج إلى متغيرين آخرين لمعرفة ما إذا كان الوقت المطلوب قد مر. لقد قمنا بتخزين الوقت الحالي في المتغير currentMillis ، لكننا نحتاج أيضًا إلى معرفة متى بدأت فترة التوقيت ومدة هذه الفترة. لذلك يتم الإعلان عن period و PreviousMillis. سيخبرنا الفاصل الزمني بالتأخير الزمني وسيخزن PreviousMillis آخر مرة حدث فيها الحدث. كود:
unsigned long previousMillis; unsigned long period = 1000; لفهم ذلك ، دعنا نأخذ مثالاً على وميض ليد LED بسيط. ستخبرنا period = 1000 بأن الليد LED سوف يومض لمدة ثانية واحدة أو 1000 مللي ثانية. ![]() كود:
const int ledPin = 4; // the LED pin number connected
int ledState = LOW; // used to set the LED state
unsigned long previousMillis = 0; //will store last time LED was blinked
const long period = 1000; // period at which to blink in ms
void setup() {
pinMode(ledPin, OUTPUT); // set ledpin as output
}
void loop() {
unsigned long currentMillis = millis(); // store the current time
if (currentMillis - previousMillis >= period) { // check if 1000ms passed
previousMillis = currentMillis; // save the last time you blinked the LED
if (ledState == LOW) { // if the LED is off turn it on and vice-versa
ledState = HIGH;
} else {
ledState = LOW;
}
digitalWrite(ledPin, ledState);//set LED with ledState to blink again
}
}
هنا العبارة <if (currentMillis - previousMillis >= period)> تتحقق من ما إذا مر 1000ms . إذا مر 1000ms ، عندئذ يومض الليد ومرة أخرى يأتى إلى نفس الحالة ، ويستمر ذلك . هذا كل شيء ، لقد تعلمنا استخدام millis بدلاً من delay . هذه الطريقة لن توقف البرنامج لفترة زمنية محددة. المقاطعات Interrupts في الاردوينو تعمل كما هو الحال في الميكروكنترولر الأخرى. تحتوي لوحة Arduino UNO على طرفين منفصلين لتوصيل المقاطعات هى الطرف 2 والطرف 3 . راجع المقاطعة فى الاردوينو. سنقوم هنا بعرض المهام المتعددة للاردوينو من خلال التعامل مع مهمتين في نفس الوقت. ستشمل المهام وميض اثنين من الليدات في تأخير زمني مختلف جنبا إلى جنب مع زر ضغط الذي سيتم استخدامه للتحكم على حالة ON / OFF لليد . لذلك سيتم تنفيذ ثلاث مهام في وقت واحد. الدائرة الكهربية : ![]() برمجة الاردوينو أونو للمهام المتعددة Programming Arduino UNO for Multitasking تتطلب برمجة الاردوينو أونو للمهام المتعددة فقط المنطق وراء كيفية عمل millis() الموضح أعلاه. يوصى بممارسة وميض ليد باستخدام millis() مرارًا وتكرارًا لجعل المنطق واضحًا ولتجعل نفسك مرتاحًا مع millis() قبل البدء في برمجة الاردوينو أونو للقيام بمهام متعددة. في هذا التدريب ، يتم استخدام المقاطعة أيضًا مع millis() في وقت واحد من أجل تعدد المهام. الزر سيكون مقاطعة. لذلك كلما تم توليد مقاطعة ، مثل الضغط على زر ، سوف يتحول الليد وضع التشغيل on أو إيقاف التشغيل off . 1- فى بداية البرنامج : • يتم إعلان أرقام الأطراف حيث يتم توصيل الليدات والزر الضاغط . كود:
int led1 = 6; int led2 = 7; int toggleLed = 5; int pushButton = 2; • بعد ذلك نعلن عن متغيرًات لتخزين حالة الليدات للاستخدام المستقبلي. كود:
int ledState1 = LOW; int ledState2 = LOW; • تمامًا كما هو موضح أعلاه في مثال الوميض ، يتم إعلان المتغيرات period و previousmillisللمقارنة وتوليد التأخير لليدات . يومض الليد الأول بعد كل ثانية ويومض الليد الثانى بعد كل 200 مللي ثانية. كود:
unsigned long previousMillis1 = 0; const long period1 = 1000; unsigned long previousMillis2 = 0; const long period2 = 200; • كما يتم استخدام دالة millis لتوليد تأخير منع تأثير الارتداد debounce لتجنب الضغطات المتعددة لزر الضغط. كود:
int debouncePeriod = 20; int debounceMillis = 0; كود:
bool buttonPushed = false; int ledChange = LOW; int lastState = HIGH; 2- فى الدالة setup : • يتم تحديد (تعريف) عمل الطرف الذي سيعمل كدخل أو كخرج . كود:
pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(toggleLed, OUTPUT); pinMode(pushButton, INPUT); • كما يتم تحديد (تعريف) طرف المقاطعة عن طريق ربط attaching المقاطعة مع تعريف ISR ووضع Mode المقاطعة. لاحظ أنه يوصى باستخدام digitalPinToInterrupt(pin_number) عند إعلان الدالة attachInterrupt() لترجمة الرقم الرقمي الفعلي إلى رقم المقاطعة المحدد. كود:
attachInterrupt(digitalPinToInterrupt(pushButton), pushButton_ISR, CHANGE); 3- تتم كتابة روتين خدمة المقاطعة وسيؤدي فقط إلى تغيير العلم buttonPushed. لاحظ أن روتين خدمة المقاطعة يجب أن يكون قصيرا قدر الإمكان. كود:
void pushButton_ISR()
{
buttonPushed = true;
}
4- تبدأ الدالة loop بتخزين قيمة millis في المتغير CurrentMillis والذي سيخزن قيمة الوقت المنقضي في كل مرة تتكرر فيها الحلقة. كود:
unsigned long currentMillis = millis(); يوجد ثلاث مهام متعددة ، وميض ليد عند كل ثانية ، ووميض ليد ثانى كل 200 مللي ثانية ، وإذا تم الضغط على زر الضغط ، يتم تبديل تشغيل/إيقاف ON / OFF ليد ثالث . لذلك سوف نكتب ثلاثة أجزاء للقيام بهذه المهمة. • المهمة الأولى هى تبديل حالة LED بعد كل ثانية واحدة من خلال مقارنة millis المنقضي. كود:
if (currentMillis - previousMillis1 >= period1) {
previousMillis1 = currentMillis;
if (ledState1 == LOW) {
ledState1 = HIGH;
} else {
ledState1 = LOW;
}
digitalWrite(led1, ledState1);
}
• المهمة الثانية ، وبشكل مشابه ، يتم تبديل ليد بعد كل 200 مللي ثانية من خلال مقارنة millis المنقضي. كود:
if (currentMillis - previousMillis2 >= period2) {
previousMillis2 = currentMillis;
if (ledState2 == LOW) {
ledState2 = HIGH;
} else {
ledState2 = LOW;
}
digitalWrite(led2, ledState2);
}
• المهمة الثالثة ، أخيرًا ، يتم مراقبة العلم buttonPushed وبعد إنشاء تأخير إلغاء الارتداد 20 مللي ثانية ، فقط يتم تبديل حالة الليد LED التي تتوافق مع زر الضغط المرفق كمقاطعة. كود:
if (buttonPushed = true) // check if ISR is called
{
if ((currentMillis - debounceMillis) > debouncePeriod && buttonPushed) // generate 20ms debounce delay to avoid multiple presses
{
debounceMillis = currentMillis; // save the last debounce delay time
if (digitalRead(pushButton) == LOW && lastState == HIGH) // change the led after push button is pressed
{
ledChange = ! ledChange;
digitalWrite(toggleLed, ledChange);
lastState = LOW;
}
else if (digitalRead(pushButton) == HIGH && lastState == LOW)
{
lastState = HIGH;
}
buttonPushed = false;
}
}
البرنامج : كود:
/* Arduino Multitasking
Author : CircuitDigest (circuitdigest.com)
*/
int led1 = 6; // led1 connected at pin 6
int led2 = 7; // led2 connected at pin 7
int toggleLed = 5; // push button controlled led connected at pin 5
int pushButton = 2; // push button connected at pin 2 which is also interrupt pin
int ledState1 = LOW; // to determine the states of led1 and led2
int ledState2 = LOW;
unsigned long previousMillis1 = 0; //store last time LED1 was blinked
const long period1 = 1000; // period at which led1 blinks in ms
unsigned long previousMillis2 = 0; //store last time LED2 was blinked
const long period2 = 200; // period at which led1 blinks in ms
int debouncePeriod = 20; // debounce delay of 20ms
int debounceMillis = 0; // similar to previousMillis
bool buttonPushed = false; // interrupt routine button status
int ledChange = LOW; // to track the led status last
int lastState = HIGH; // to track last button state
void setup() {
pinMode(led1, OUTPUT); // define pins as input or output
pinMode(led2, OUTPUT);
pinMode(toggleLed, OUTPUT);
pinMode(pushButton, INPUT);
attachInterrupt(digitalPinToInterrupt(pushButton), pushButton_ISR, CHANGE); // use interrupt pin2
}
void pushButton_ISR()
{
buttonPushed = true; // ISR should be as short as possible
}
void loop() {
unsigned long currentMillis = millis(); // store the current time
if (currentMillis - previousMillis1 >= period1) { // check if 1000ms passed
previousMillis1 = currentMillis; // save the last time you blinked the LED
if (ledState1 == LOW) { // if the LED is off turn it on and vice-versa
ledState1 = HIGH; //change led state for next iteration
} else {
ledState1 = LOW;
}
digitalWrite(led1, ledState1); //set LED with ledState to blink again
}
if (currentMillis - previousMillis2 >= period2) { // check if 1000ms passed
previousMillis2 = currentMillis; // save the last time you blinked the LED
if (ledState2 == LOW) { // if the LED is off turn it on and vice-versa
ledState2 = HIGH;
} else {
ledState2 = LOW;
}
digitalWrite(led2, ledState2);//set LED with ledState to blink again
}
if (buttonPushed = true) // check if ISR is called
{
if ((currentMillis - debounceMillis) > debouncePeriod && buttonPushed) // generate 20ms debounce delay to avoid multiple presses
{
debounceMillis = currentMillis; // save the last debounce delay time
if (digitalRead(pushButton) == LOW && lastState == HIGH) // change the led after push button is pressed
{
ledChange = ! ledChange;
digitalWrite(toggleLed, ledChange);
lastState = LOW;
}
else if (digitalRead(pushButton) == HIGH && lastState == LOW)
{
lastState = HIGH;
}
buttonPushed = false;
}
}
}
|
|
جميع الحقوق محفوظة 2026
|


