كورس تعليمي يهدف الى اكسابك المعرفة اللازمة والمهارات التقنية المتعلقة ببرمجة وتطوير الأنظمة المدمجة وفهم خصائصها ومكوناتها
الصفحة الرئيسية
قائمة الدروس
خدمة RSS
في (ص 20) من دليل المستخدم الذي قمنا بتحميله في الدرس السابق نجد مخطط البورد schematics والتي تبين لنا الأطراف التي تتصل بها الأزرار SW1 و SW2:
![]() |
وهذا موقعها على البورد:
![]() |
حيث يتضح لنا أن:
بالإضافة الى أننا سنتعامل مع الإضاءات الملونة التي تعاملنا معها سابقاً:
نلاحظ أن جميع الأزرار والإضاءات متصلة بالمنفذ F، ولذلك فإن جميع السجلات التي سنتعامل معها ستكون خاصة بهذا المنفذ.
سنقوم بمشيئة الله بكتابة برنامج يتعامل مع الأزرار والإضاءات في البورد حيث سيختلف فيها الإضاءة التي تعمل حسب الزر المضغوط. وفيما يلي جدول يختصر هذه الحالات:
حالة الأزرار | حالة الإضاءة |
---|---|
الضغط على SW1 و SW2 معاً | الإضاءة الحمراء تعمل |
الضغط على SW1 فقط | الإضاءة الزرقاء تعمل |
الضغط على SW2 فقط | الإضاءة الخضراء تعمل |
عدم الضغط على أي زر | لا تعمل أي من الإضاءات |
للقيام بذلك، فإنه يتوجب علينا تتبع الخطوات التالية:
مما سبق، يتضح لنا أن المنفذ الذي نريد تفعيله هو Port F، ونقوم بذلك عن طريق كتابة 1 الى البت رقم خمسة bit 5 كما يلي:
SYSCTL_RCGCGPIO_R = (1U << 5); // 0010 0000
ثم ننتظر قليلاً قبل بدء التعامل مع المنفذ لنتأكد من مرور الوقت الكافي لتفعيل المنفذ:
volatile unsigned long wait;
wait = SYSCTL_RCGCGPIO_R;
يوجد على هذه البورد عدة أطراف مقفلة لا نستطيع الكتابة اليها الا بعد فتح القفل وهي PC0 و PC1 و PC2 و PC3 و PD7 و PF0 وماعداها من أطراف لا يتوجب علينا القيام بهذه الخطوة بشأنها.
ولإلغاء قفل PF0 فإننا سنستخدم السجل GPIOLOCK (دليل البيانات ص 684):
![]() |
وذلك عن طريق كتابة الرقم 0x4C4F434B
الى هذا السجل كما يلي:
#define GPIO_PORTF_LOCK_R (*((volatile unsigned long *)0x40025520))
GPIO_PORTF_LOCK_R = 0x4C4F434B;
بعد الغاء القفل عن الطرف PF0، نقوم بالسماح بالتعديل عليه عن طريق السجل GPIOCR (دليل البيانات ص685):
![]() |
وذلك عن طريق كتابة 1 في البت الذي يقابل الطرف PF0 وهو bit 0:
#define GPIO_PORTF_CR_R (*((volatile unsigned long *)0x40025524))
GPIO_PORTF_CR_R = (1U << 0);
في هذا اليرنامج نريد تفعيل الإضاءة الموجوده على المنفذ F في الأطراف 1 و 2 و 3 وجعلها output. ولذلك نقوم بكتابة 1 في البت المقابلة لكل طرف. وسنجعل الأزرار مدخلات input وذلك بكتابة 0 في البت المقابل للطرف.
سنقوم أولاً بتحديد جميع المدخلات والمخرجات وما يقابلها من بت bits:
#define SW2 (1U << 0)
#define LED_RED (1U << 1)
#define LED_BLUE (1U << 2)
#define LED_GREEN (1U << 3)
#define SW1 (1U << 4)
ثم سنجعل من أطراف الإضاءة مدخلات:
GPIO_PORTF_DIR_R = (LED_RED|LED_BLUE|LED_GREEN);
وبعد ذلك نجعل أطراف الأزرار مخرجات:
GPIO_PORTF_DIR_R &= ~(SW1|SW2);
لو عدنا الى (ص 20) في دليل المستخدم فإننا سنرى في الرسم التخطيطي الخاص بالأزرار أنه عند الضغط عليها فإن الطرف المتصل بالزر سيقرأ 0 حيث تتصل الدائرة بـالـ ground. ولكن في حالة عدم الضغط على الزر فإن القراءة ستبقى عائمة floating وغير مستقرة لأن الأزرار ليست متصلة بمقاومة رفع pull-up resistor (للمزيد).
![]() |
ولذلك فإننا نقوم بتفعيل ما يسمى بالـ internal pull up resistor بواسطة السجل GPIOPUR والذي نجد تفاصيله في (ص 677) من دليل البيانات:
![]() |
#define GPIO_PORTF_PUR_R (*((volatile unsigned long *)0x40025510))
GPIO_PORTF_PUR_R = (SW1|SW2);
ولو كنا نستخدم مقاومة خفض pull down بدلاً من مقاومة رفع pull up لكنا نقرأ 0 في حالة عدم الضغط على الزر و 1 في حالة الضغط عليه.
مثل ما ذكرنا سابقاً، فنحن مهتمين بالأطراف من 0 الى 4 في المنفذ F. ولتفعيلها نقوم بكتابة 1 في البت المقابل لكل طرف كما يلي:
GPIO_PORTF_DEN_R = (SW2|LED_RED|LED_BLUE|LED_GREEN|SW1);
الأزرار لها خاصية negative logic بمعنى أن قيمتها 1 في حالة عدم الضغط عليها و 0 اذا ما تم الضغط عليها. وهي عكس الإضاءات التي بها خاصية الـ positive logic حيث اذا ارسلنا لها 1 فإنها ستضيء واذا أرسلنا 0 فإنها ستطفئ.
في عبارة الـ switch في البرنامج المتعلق بهذا الدرس نختبر محتوى السجل GPIO_PORTF_DATA_R
مع القيمة 0x11:
0x11 = 0001 0001
لقد أخترنا القيمة 0x11 لأنها تستخدم 1 في البت 0 وهو الخاص بالطرف 0 المتصل بـ SW2. وتستخدم 1 في البت 4 وهو يقابل الطرف 4 المتصل بـ SW1.
فلو أفترضنا أن GPIO_PORTF_DATA_R
يحمل القيمة 0000 0000
- بمعنى أن جميع الأزرار مضغوطه بغض النظر عن أياً كانت قيمة الإضاءات - فإن نتيجة إختبار الـ switch سينتج لنا 0000 0000
مما يحقق شرط الحالة الأولى:
GPIO_PORTF_DATA_R = 0000 0000
(GPIO_PORTF_DATA_R & 0x11) // result: 0000 0000
case 0x00: // SW1 & SW2 pressed
// الجزء هذا سينفذ
break;
وقس على ذلك بقية الحالات، حيث أن:
قم بإنشاء مشروع جديد كما فعلنا في الدرس الثالث وأضف الكود التالي:
#define SYSCTL_RCGCGPIO_R (*((volatile unsigned long *)0x400FE608))
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_PUR_R (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_LOCK_R (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R (*((volatile unsigned long *)0x40025524))
#define SW2 (1U << 0)
#define LED_RED (1U << 1)
#define LED_BLUE (1U << 2)
#define LED_GREEN (1U << 3)
#define SW1 (1U << 4)
void delay (void) {
for (int i=0; i<5000000; i++);
}
int main (void) {
volatile unsigned long wait;
// Initialize clock
SYSCTL_RCGCGPIO_R = (1U << 5); // 0010 0000
wait = SYSCTL_RCGCGPIO_R;
// Unlock PF0
GPIO_PORTF_LOCK_R = 0x4C4F434B;
GPIO_PORTF_CR_R = SW2;
// Set pin direction
GPIO_PORTF_DIR_R = (LED_RED|LED_BLUE|LED_GREEN); // 0000 1110
GPIO_PORTF_DIR_R &= ~(SW1|SW2); // 0000 1110;
// Set PF0 pull up resistor
GPIO_PORTF_PUR_R = (SW1|SW2); // 0001 0001
// Enable pins
GPIO_PORTF_DEN_R = (SW2|LED_RED|LED_BLUE|LED_GREEN|SW1); // 0001 1111
while (1) {
switch (GPIO_PORTF_DATA_R & 0x11)
{
case 0x00: // SW1 & SW2 pressed
GPIO_PORTF_DATA_R = LED_RED;
break;
case 0x01: // SW1 pressed only
GPIO_PORTF_DATA_R = LED_BLUE;
break;
case 0x10: // SW2 pressed only
GPIO_PORTF_DATA_R = LED_GREEN;
break;
default:
GPIO_PORTF_DATA_R &= ~(LED_RED|LED_BLUE|LED_GREEN);
}
}
}
أو قم بنسخه من الرابط التالي:
https://github.com/alhabish/embedded-course/blob/gh-pages/assets/files/article_08/main.c
ملاحظة: هذه المقالة تحت التحديث المستمر،، وملاحظاتكم وإقتراحاتكم ستساعد بإذن الله في إخراجها بالصورة التي كتبت من أجلها وهي تمهيد الطريق أمامكم لتعلم برمجة الأنظمة المدمجة