قم بتوصيل عصا التحكم من Dendy إلى Raspberry pi

ذات مرة ، بعد أن رأيت ما يكفي من جميع أنواع "بينما يلعب الجميع" ، أردت أيضًا أن ألعب 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)))
        {
	 /* This strobe code is just for convenience.  If it were
	    with the code in input / *.c, it would more accurately represent
	    what's really going on.  But who wants accuracy? ;)
	    Seriously, though, this shouldn't be a problem.
	 */
	 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 =

وبشكل عام ، كل شيء يعمل. تركت الأساس إذا قررت فجأة شراء عصا تحكم ثانية للعب معًا في نفس الدبابات.

» رابط لإثبات
» تم استخدام بيانات من الموقع
»شكر خاص لهذا الشخص الذي ساعدني على فهم رمز المحاكي

Source: https://habr.com/ru/post/ar398285/


All Articles