ذات مرة ، بعد أن رأيت ما يكفي من جميع أنواع "بينما يلعب الجميع" ، أردت أيضًا أن ألعب Raspberry pi. نعم ، لا تلعب فقط ، بل العب باستخدام جهاز حقيقي. لماذا في مترو الأنفاق مقابل 150 روبل تم شراء عصا التحكم من داندي (حسنًا ، ليس من داندي ، ولكن سيمباس جونيور). أولئك الذين يهتمون بما جاء منه يمكنهم النقر على الزر أدناه. في نهاية المقال سيكون هناك رابط للدليل.جمعنا أصدقاؤنا الصينيون مع الشعار - لا توجد جودة ، ولكن انتظروا. على الفور تم لحام كابل أصلي بمقطع عرضي من الموصلات من 2 ميكرون مربع ، واستبداله بكابل من بعض محول الواجهة الصناعية ، والذي حصل بعد التشغيل التالي ، كان يحتوي على 5 أسلاك فقط.قبل إجراء تغييرات على الرمز ، كان عليك معرفة كيفية عمل لوحة الألعاب نفسها. لوحة الألعاب لديها سجل التحول. تحتوي لوحة الألعاب على 5 أسلاك - 2 - طاقة و 3 معلومات - مزلاج (ستروب) وساعة (نبض) وبيانات. عندما يتم توفير وحدة منطقية إلى Latch ، يتم حفظ حالة إدخالات سجل التحول ، وعند الإخراج - البيانات ، تتوفر حالة الزر "A" على الفور ، وعندما يتغير المستوى المنطقي على خط الساعة عند الإخراج - تتغير البيانات ، تظهر مستويات الجهد المقابلة لحالة الأزرار السبعة الأخرى في شكل متسلسل. الزر المضغوط يتوافق مع - 0 ، وليس الضغط - 1. علاوة على ذلك ، بالنسبة للعبة كل شيء هو عكس ذلك تمامًا ، فمن الضروري القيام بالانعكاس. يوضح الشكل أدناه مخطط لوحة الألعاب.
تبع ذلك اختيار المحاكي. وقع الاختيار على إصدار fceu القديم 0.98.12 ، نظرًا لأنه يحتوي على وحدات نمطية ممتازة ويحاكي بنية وحدة التحكم بدقة تامة ، وهو مكتوب في C. تبع ذلك اختيار مكتبة للعمل مع GPIO ، اخترت bcm2835 من Mike McCauley ، وهو مكتوب أيضًا بلغة C ولديه أداء جيد.نظرًا لأنني مبتدئ في البرمجة ، كان علي أن أنتقل إلى أحد المشاهير من نفس "بينما يلعب الجميع" ، مع طلب للتعليق على أقسام التعليمات البرمجية. ودس أنفك في تلك الوظائف المسؤولة عن نقل حالة الأزرار إلى اللعبة. شرحوا لي بلغة يسهل الوصول إليها ماذا وكيف. وبالتالي ، فإن ملف input.c مسؤول عن محاكاة الإدخال ، وهنا ستحدث التغييرات الرئيسية معه. هناك العديد من الوظائف المسؤولة عن محاكاة لوحة الألعاب - FCEU_UpdateInput و ReadGP و DECLFW (4016) ، في الواقع ، هناك المزيد ، وهذه هي الوظائف الرئيسية. بالإضافة إلى input.c ، كان علي إجراء تغييرات على file.c و fceu.c. في الحالة الأولى ، كانت هناك أخطاء في ملف file.c ، ولكن هذه المشكلة هي google ، وهناك تصحيح لهذا الملف ، وفي ملف fceu.c أضفت تهيئة مكتبة bcm2835 في الوظيفة int FCEUI_Initialize (void):bcm2835_init();
إضافة ملف الرأس مسبقًا#include <bcm2835.h>
الآن input.c ، أضفت أيضًا ملف رأس مكتبة bcm2835 (على غرار fceu.c) وملف رأس مكتبة <unistd.h> للعمل مع استخدام النوم. بعد ذلك ، أعلنت عن منافذ GPIO التي ستشارك: #define LATCH RPI_V2_GPIO_P1_11
#define CLK RPI_V2_GPIO_P1_13
#define DATA RPI_V2_GPIO_P1_15
في وظيفة InitializeInput (void) الفارغة ، أضفت رمزًا سجلت فيه وضع التشغيل لكل منفذ GPIO ، وأعيد تعيين المنافذ المسؤولة عن Latch (Strobe) والساعة على الفور إلى 0. bcm2835_gpio_fsel(LATCH, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_fsel(CLK, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_fsel(DATA, BCM2835_GPIO_FSEL_INPT);
bcm2835_gpio_set_pud(DATA, BCM2835_GPIO_PUD_UP);
bcm2835_gpio_write(CLK, LOW);
bcm2835_gpio_write(LATCH, LOW);
الآن إلى الوظائف:وهكذا DECLFW (4016) - هي المسؤولة عن محاكاة إشارة المزلاج (ستروب). كما قيل ، لقراءة حالة الأزرار تحتاج إلى تطبيق Latch - 1 لفترة من الوقت. يوجد متغير Laststrobe يتم فيه كتابة القيمة الأخيرة المكتوبة في هذا السجل. إذا كان Laststrobe يساوي 0 ، فسيتم كتابة المنطقي 1 ، على التوالي ، ويتم أيضًا تغذية دبوس GPIO ، المسمى المزلاج ، 1 وبعد إعادة تعيين 1 tos إلى 0. وإذا كان Laststrobe يساوي 1 ، فسيتم تجاهل مقطع الرمز هذا.static DECLFW(B4016)
{
if (FCExp)
if (FCExp->Write)
FCExp->Write(V & 7);
if (JPorts[0]->Write)
JPorts[0]->Write(V & 1);
if(JPorts[1]->Write)
JPorts[1]->Write(V&1);
if((LastStrobe&1) && (!(V&1)))
{
if(JPorts[0]->Strobe)
JPorts[0]->Strobe(0);
if(JPorts[1]->Strobe)
JPorts[1]->Strobe(1);
if(FCExp)
if(FCExp->Strobe)
FCExp->Strobe();
}
if (LastStrobe==0)
{
bcm2835_gpio_write(LATCH, HIGH);
usleep(1);
bcm2835_gpio_write(LATCH, LOW);
}
LastStrobe=V&0x1;
}
حسنًا ، الآن اقتراع عصا التحكم نفسها ، إفراغ FCEU_UpdateInput (void) - في هذه الوظيفة ، تتم قراءة البيانات من محركات الإدخال التي تم تحديدها عندما تم تكوين المحاكي ، أو عند بدء تشغيله عن طريق إدخال مفاتيح معينة ، على سبيل المثال ، لوحة ألعاب ، لوحة دوران ، بندقية خفيفة ، إلخ. . ، كل ما يمكن توصيله بوحدة التحكم. يولد بايت من حالة أزرار أزرار اللعب gamepads [0] ... joy [3] ، بكمية من 2 إلى 4 ، حيث يمكنك تمكين محاكاة Pribluda لتوصيل جهازي ألعاب آخرين. هذا هو المكان الذي حدثت فيه التغييرات الرئيسية. نظرًا لأنني لست بحاجة إلى استخدام القدرة على العمل مع 4 لوحات ألعاب وتلقي البيانات من برامج التشغيل الأخرى ، فقد ألقيت جميع التعليمات البرمجية وأدخلت خاصتي: joy[0] = 0;
joy[1] = 0;
for (i = 0; i <= 7; i++)
{
joy[0] ^= bcm2835_gpio_lev(DATA) << i;
joy[0] ^= (1 << i);
joy[1] ^= bcm2835_gpio_lev(DATA) << i;
joy[1] ^= (1 << i);
bcm2835_gpio_write(CLK, HIGH);
usleep(1);
bcm2835_gpio_write(CLK, LOW);
usleep(1);
}
علاوة على ذلك ، أقوم على الفور بتكوين وحدتي بايت ، على التوالي ، من عصا التحكم الأولى والثانية. نظرًا لأن العديد من الألعاب تقرأ حالة الأزرار من منفذين في نفس الوقت ، فليس هناك مفهوم للمنفذ ذي الأولوية. ولكن هناك ألعاب يوجد مثل هذا المفهوم - على سبيل المثال ، جميع Mario ، Kirby ، Terminator 2 ، إلخ. أي أنهم يقرؤون حالة الأزرار فقط من المنفذ الأول (في Mario للاعب الأول ، للثاني فقط من الثاني) ، أي من التسجيل 4016. من المهم أيضًا تعيين قيمة صفر عند استدعاء هذه الوظيفة ، وإلا سيتم حفظ القيمة السابقة فيها ، و جديد بالفعل فرض عليهم. من حيث المبدأ ، كان من الممكن ترك البايت لعصا التحكم الثانية مساوية للصفر ، لكنني جعلت من الممكن لعب ماريو معًا.ReadGP - يستخرج بالفعل البتات من بايتات الفرح [0] ... الفرح [3] ، ويعيد المتغير ret حالة الزر المحدد في الوقت الحالي إلى اللعبة ، ويتم تعيين عدد الزر بواسطة المتغير joy_readbit [w] ، حيث w هو رقم منفذ عصا التحكم ، الأول أو الثاني. ولكن في هذه الوظيفة لم أجري أي تغييرات. غادر كما هو.لتجميع ناجح ، في ملف Makefile (الذي تم تشكيله بعد تنفيذ الأمر Configure) ، الموجود في دليل src ، أضف -lbcm2835 -lm -lrt إلى المكان الذي تتم كتابة تبعيات المكتبة فيه. الخط:LIBS =
وبشكل عام ، كل شيء يعمل. تركت الأساس إذا قررت فجأة شراء عصا تحكم ثانية للعب معًا في نفس الدبابات.» رابط لإثبات
» تم استخدام بيانات من الموقع
»شكر خاص لهذا الشخص الذي ساعدني على فهم رمز المحاكي