تجربة ربط لوحة مفاتيح PS2 مع أردوينو

2014-02-11

في المقالة السابقة شرحنا مبدأ عمل PS2 والآن سنطبق ذلك عمليا

ولأني لا أعلم كيف أحصل على منفذ PS2 ولا أريد اقتلاعه من لوحة أم أحضرت وصلة تحتوي مدخل PS2 وأسلاك

وصلة من PS2 إلى USB

ثم قمت بفكها وقص الأسلاك وتعريتها

الوصلة بعد فتحها

ثم بدأت أحاول معرفة ترتيب الأسنان وكل سن متصل بأي سلك عبر ضوء صغير ومصدر طاقة (يمكنك استعمال بطارية أو مخرج 3 فولت في لوح أردوينو)

فكانت النتيجة كما يلي (قد لا تكون نفسها عندك):

  • الأحمر هو مدخل الطاقة VCC
  • الأسود للأرض GND
  • الأبيض هو نبضات الساعة
  • الأخضر هو نبضات البيانات

نحتاج أن نصل السلك الأحمر مع مصدر 5 فولت في لوح أردوينو والأسود مع الأرض في لوح أردوينو. ويمكنك وصل سلك البيانات مع أي مدخل رقمي في أردوينو لكن من المهم جدا اختيار أين ستصل سلك الساعة حيث يجب أن يدعم طلبات المقاطعة. في هذا المثال سأوصله بمنفذ المقاطعة الأول (أي رقم صفر وهو INT0) في أونو هو رقم 2 وفي ليوناردو هو رقم 3. انظر جدول المقاطعات في صفحة دالة attachInterrupt في مرجع أردوينو

وحتى يتم ذلك تلقائيا سأفحص نوع المتحكم الدقيق عبر if defined فأعرف PS2_INT و PS2_CLK و PS2_DATA وهي أسماء من عندي تشير لرقم المقاطعة ورقم منفذ الساعة ورقم منفذ البيانات الذي اخترته

// use INT0 for both UNO and Leonardo #define PS2_INT 0 #if defined(__AVR_ATmega328__) // UNO here #define PS2_CLK 2 #define PS2_DATA 3 #elif defined(__AVR_ATmega32U4__) // Leonardo here #define PS2_CLK 3 #define PS2_DATA 2 #endif

بروتوكول PS2 شبيه جدا ببروتوكول I2C حيث أنه يعتمد على سلكين أحدهما لنبضات الساعة والآخر للبيانات. هذين السلكين يجب أن يكونا مرفوعي الفولتية عبر مقاومة رفع pull up وطبعا لن نحتاج إلى مقاومة خارجية حيث يمكننا استعمال الوضع INPUT_PULLUP عبر دالة pinMode وبهذا تكون فولتية السلكين عالية عند تركهما وعند بدء الإرسال يقوم الطرف المرسل (لوحة المفاتيح في حالتنا) بربط الخط بالأرض (فتنزل الفولتية) تشبه الفكرة فكرة "حرارة" الهاتف أو خط التيليغراف. المرسل يضع سلك البيانات على الفولتية المطلوبة عندما يكون خط الساعة عالي وبعد أن يصل خط البيانات للقيمة المطلوبة يخفضه خط الساعة في إشارة إلى جاهزية الخط وينتظر فترة من الزمن ليعيد الكرة من جديد (بتردد بين 20 إلى 30 ألف نبضة في الثانية وهو رقم صغير عند مقارنته مع سرعة ساعة المتحكم والتي هي 16 مليون نبضة في الثانية).

لهذا يكون كود إعداد المتحكم الدقيق هكذا (مع إعداد المنفذ التسلسل حتى نستخدم المرقاب التسلسلي)

void setup() { // initialize the digital pin as an output. pinMode(PS2_CLK, INPUT_PULLUP); pinMode(PS2_DATA, INPUT_PULLUP); attachInterrupt(PS2_INT, ps2interrupt, FALLING); Serial.begin(9600); }

وهنا استعملنا دالة attachInterrupt كي ننفذ دالة خاصة بنا اسمها ps2interrupt كلما هبط خط الساعة (حيث يكون الوقت مناسبا لقراءة البيانات).

تلك الدالة المفروض بها استقبال بت من بتات البيانات المرسلة وعددها 11-بتا واحدا فواحد بدءا من المنزلة الأقل قيمة (تسمى LSB). البت الأول دائما صفر وهو علامة البداية ثم 8 بتات ثم بت فحص السلامة الفردي (أي يكون 1 بعد عدد زوجي من البتات ليكون في المحصلة لدينا عدد فردي من البتات على وضعية 1) ثم بت علامة النهاية وقيمته دائما 1.

إليك مثال يجمع البتات مع تجاهل البتات الثلاثة الإضافية (دون فحص سلامتها)

void ps2interrupt() { if (digitalRead(PS2_DATA)) bits|=1<<bits_counter; ++bits_counter; if (bits_counter==11) { res=bits>>1; got_key=1; bits=0; bits_counter=0; } }

لاحظ ما يلي

  • استخدام عملية أو | لوضع البت في bits
  • عد المنازل في المتغير bits_counter
  • إزاحة البت إلى المنزلة المطلوبة عبر >>
  • وضع النتيجة في res عند وصول 11 بت ثم البدء من الصفر
  • وضع علامة في got_key عند الانتهاء

هذا يعني أنه علينا تعريف المتغيرات المتطايرة التالية:

volatile unsigned char bits_counter=0, got_key=0, res=0; volatile int bits=0;

وأريد دالة الحلقة تظل تنتظر علامة got_key فإن حصلت عليها طبعت قيمة res عبر المنفذ التسلسلي هكذا

void loop() { if (got_key) { Serial.print("got "); Serial.print((int)res); Serial.println(" dec"); got_key=0; } }

كان بإمكاني نقل كود الطباعة إلى دالة ps2interrupt لكن تذكر تلك دالة مقاطعة وعلى دالة المقاطعة العودة بأسرع وقت.

الفيم التي نحصل عليها تسمى keyboard scancode وهي موضحة في هذه الصورة:

قيم scancode للمفاتيح بالستعشري

وهناك رموز خاصة مثل:

  • 240 وتكتب F0 بالستعشري وتعني رفع الضغط عن المفتاح
  • 224 تكتب E0 بالستعشري وهي لبيان المفاتيح الممتدة extended keys

مثلا عند الضغط على مفتاح الرقم 1 في اللوحة الرئيسية (وليس الذي في لوحة الأرقام) نحصل على 22 بالعشري (16 بالستعشري) وعند ترك المفتاح نحصل على 240 ثم 22.

نقاط الضعف وإمكانية التحسين

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

الكود كاملا

// use INT0 for both UNO and Leonardo #define PS2_INT 0 #if defined(__AVR_ATmega328__) // UNO here #define PS2_CLK 2 #define PS2_DATA 3 #elif defined(__AVR_ATmega32U4__) // Leonardo here #define PS2_CLK 3 #define PS2_DATA 2 #endif volatile int bits_counter=0, got_key=0, bits=0; volatile unsigned char res=0; void setup() { // initialize the digital pin as an output. pinMode(PS2_CLK, INPUT_PULLUP); pinMode(PS2_DATA, INPUT_PULLUP); attachInterrupt(PS2_INT, ps2interrupt, FALLING); Serial.begin(9600); } void ps2interrupt() { if (digitalRead(PS2_DATA)) bits|=1<<bits_counter; ++bits_counter; if (bits_counter==11) { res=bits>>1; got_key=1; bits=0; bits_counter=0; } } void loop() { if (got_key) { Serial.print("got "); Serial.print((int)res); Serial.println(" dec"); got_key=0; } }

مصادر ومراجع

4


محمد عنيني
محمد عنينيمنذ 3 سنوات

جميل جدا.. جزاك الله خيرا على الموضوع الرائع.. هذا ما يسمى إبداع!

ما رأيك لو تعاونّا في بناء مكتبة لها، أنا متأكد بأن هناك العديد من التطبيقات الرائعة التي يمكن تطبيقها باستخدامها؟

0

مؤيد السعدي
مؤيد السعديمنذ 3 سنوات

هناك مكتبة موجودة

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

1

محمد عنيني
محمد عنينيمنذ 3 سنوات

نعم، كنت أقصد مكتبة خاصّة بك مع بعض التخصيص (ربما لوحة مفاتيح عربية)، وفكرتك جميلة أيضا.. لربما فتح هذا باباً جديداً لاستخدام الأردوينو مثل ألعاب الفيديو.

0

yaser
yaserمنذ 3 سنوات

السلام عليكم ، انوي ان اصنع ؤوبوت اتحكم به ) السيرامام خلف يمين يسار و اتحكم بالايدي) لاسلكيا من خلال يد بلاي ستيشن ، ما الادوات التي تلمزمني و ما يتوجب علي فعله ؟ شكرا لعطائكم مع فائق الاحترام و التقدير

0

محمد عنيني
محمد عنينيمنذ 3 سنوات

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

0

مؤيد السعدي
مؤيد السعديمنذ 3 سنوات

الأخ ياسر يمكنك استعمال يد play station الأول PSX وذلك بهذه الطريقة

http://www.epanorama.net/documents/joystick/tvgames.html#playstation

1

Test User